1 /* 2 * File dbghelp.c - generic routines (process) for dbghelp DLL 3 * 4 * Copyright (C) 2004, Eric Pouech 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #ifndef DBGHELP_STATIC_LIB 22 23 #include <unistd.h> 24 #include "dbghelp_private.h" 25 #include "winternl.h" 26 #include "winerror.h" 27 #include "psapi.h" 28 #include "wine/debug.h" 29 #include "wdbgexts.h" 30 #include "winnls.h" 31 #else 32 #include "dbghelp_private.h" 33 #include "wdbgexts.h" 34 #endif 35 36 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 37 38 /* TODO 39 * - support for symbols' types is still partly missing 40 * + C++ support 41 * + we should store the underlying type for an enum in the symt_enum struct 42 * + for enums, we store the names & values (associated to the enum type), 43 * but those values are not directly usable from a debugger (that's why, I 44 * assume, that we have also to define constants for enum values, as 45 * Codeview does BTW. 46 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not 47 * all the types stored/used in the modules (like char*) 48 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across 49 * functions, and even across function blocks...). Basically, for *Next* to work 50 * it requires an address after the prolog of the func (the base address of the 51 * func doesn't work) 52 * - most options (dbghelp_options) are not used (loading lines...) 53 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when 54 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore, 55 * we could use hash if name isn't a RE, and fall back to a full search when we 56 * get a full RE 57 * - msc: 58 * + we should add parameters' types to the function's signature 59 * while processing a function's parameters 60 * + add support for function-less labels (as MSC seems to define them) 61 * + C++ management 62 * - stabs: 63 * + when, in a same module, the same definition is used in several compilation 64 * units, we get several definitions of the same object (especially 65 * struct/union). we should find a way not to duplicate them 66 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static 67 * global variable is defined several times (at different scopes). We are 68 * getting several of those while looking for a unique symbol. Part of the 69 * issue is that we don't give a scope to a static variable inside a function 70 * + C++ management 71 */ 72 73 unsigned dbghelp_options = SYMOPT_UNDNAME; 74 BOOL dbghelp_opt_native = FALSE; 75 #ifndef DBGHELP_STATIC_LIB 76 SYSTEM_INFO sysinfo; 77 #endif 78 79 static struct process* process_first /* = NULL */; 80 81 #ifndef DBGHELP_STATIC_LIB 82 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) 83 { 84 switch (reason) 85 { 86 case DLL_PROCESS_ATTACH: 87 GetSystemInfo(&sysinfo); 88 DisableThreadLibraryCalls(instance); 89 break; 90 } 91 return TRUE; 92 } 93 #endif 94 95 /****************************************************************** 96 * process_find_by_handle 97 * 98 */ 99 struct process* process_find_by_handle(HANDLE hProcess) 100 { 101 struct process* p; 102 103 for (p = process_first; p && p->handle != hProcess; p = p->next); 104 if (!p) SetLastError(ERROR_INVALID_HANDLE); 105 return p; 106 } 107 108 /****************************************************************** 109 * validate_addr64 (internal) 110 * 111 */ 112 BOOL validate_addr64(DWORD64 addr) 113 { 114 if (sizeof(void*) == sizeof(int) && (addr >> 32)) 115 { 116 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr)); 117 SetLastError(ERROR_INVALID_PARAMETER); 118 return FALSE; 119 } 120 return TRUE; 121 } 122 123 /****************************************************************** 124 * fetch_buffer 125 * 126 * Ensures process' internal buffer is large enough. 127 */ 128 void* fetch_buffer(struct process* pcs, unsigned size) 129 { 130 if (size > pcs->buffer_size) 131 { 132 if (pcs->buffer) 133 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size); 134 else 135 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size); 136 pcs->buffer_size = (pcs->buffer) ? size : 0; 137 } 138 return pcs->buffer; 139 } 140 141 #ifndef DBGHELP_STATIC_LIB 142 const char* wine_dbgstr_addr(const ADDRESS64* addr) 143 { 144 if (!addr) return "(null)"; 145 switch (addr->Mode) 146 { 147 case AddrModeFlat: 148 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset)); 149 case AddrMode1616: 150 return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); 151 case AddrMode1632: 152 return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset); 153 case AddrModeReal: 154 return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset); 155 default: 156 return "unknown"; 157 } 158 } 159 #endif 160 161 extern struct cpu cpu_i386, cpu_x86_64, cpu_arm, cpu_arm64; 162 163 #ifndef DBGHELP_STATIC_LIB 164 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_arm, &cpu_arm64, NULL}; 165 #else 166 static struct cpu* dbghelp_cpus[] = {&cpu_i386, NULL}; 167 #endif 168 169 struct cpu* dbghelp_current_cpu = 170 #if defined(__i386__) || defined(DBGHELP_STATIC_LIB) 171 &cpu_i386 172 #elif defined(__x86_64__) 173 &cpu_x86_64 174 #elif defined(__arm__) 175 &cpu_arm 176 #elif defined(__aarch64__) 177 &cpu_arm64 178 #else 179 #error define support for your CPU 180 #endif 181 ; 182 183 struct cpu* cpu_find(DWORD machine) 184 { 185 struct cpu** cpu; 186 187 for (cpu = dbghelp_cpus ; *cpu; cpu++) 188 { 189 if (cpu[0]->machine == machine) return cpu[0]; 190 } 191 return NULL; 192 } 193 194 static WCHAR* make_default_search_path(void) 195 { 196 WCHAR* search_path; 197 WCHAR* p; 198 unsigned sym_path_len; 199 unsigned alt_sym_path_len; 200 201 sym_path_len = GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", NULL, 0); 202 alt_sym_path_len = GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", NULL, 0); 203 204 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]". 205 * If the variables exist, the lengths include a null-terminator. We use that 206 * space for the semicolons, and only add the initial dot and the final null. */ 207 search_path = HeapAlloc(GetProcessHeap(), 0, 208 (1 + sym_path_len + alt_sym_path_len + 1) * sizeof(WCHAR)); 209 if (!search_path) return NULL; 210 211 p = search_path; 212 *p++ = L'.'; 213 if (sym_path_len) 214 { 215 *p++ = L';'; 216 GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", p, sym_path_len); 217 p += sym_path_len - 1; 218 } 219 220 if (alt_sym_path_len) 221 { 222 *p++ = L';'; 223 GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", p, alt_sym_path_len); 224 p += alt_sym_path_len - 1; 225 } 226 *p = L'\0'; 227 228 return search_path; 229 } 230 231 /****************************************************************** 232 * SymSetSearchPathW (DBGHELP.@) 233 * 234 */ 235 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath) 236 { 237 struct process* pcs = process_find_by_handle(hProcess); 238 WCHAR* search_path_buffer; 239 240 if (!pcs) return FALSE; 241 242 if (searchPath) 243 { 244 search_path_buffer = HeapAlloc(GetProcessHeap(), 0, 245 (lstrlenW(searchPath) + 1) * sizeof(WCHAR)); 246 if (!search_path_buffer) return FALSE; 247 lstrcpyW(search_path_buffer, searchPath); 248 } 249 else 250 { 251 search_path_buffer = make_default_search_path(); 252 if (!search_path_buffer) return FALSE; 253 } 254 HeapFree(GetProcessHeap(), 0, pcs->search_path); 255 pcs->search_path = search_path_buffer; 256 return TRUE; 257 } 258 259 /****************************************************************** 260 * SymSetSearchPath (DBGHELP.@) 261 * 262 */ 263 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath) 264 { 265 BOOL ret = FALSE; 266 unsigned len; 267 WCHAR* sp = NULL; 268 269 if (searchPath) 270 { 271 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0); 272 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 273 if (!sp) return FALSE; 274 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len); 275 } 276 277 ret = SymSetSearchPathW(hProcess, sp); 278 279 HeapFree(GetProcessHeap(), 0, sp); 280 return ret; 281 } 282 283 /*********************************************************************** 284 * SymGetSearchPathW (DBGHELP.@) 285 */ 286 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath, 287 DWORD SearchPathLength) 288 { 289 struct process* pcs = process_find_by_handle(hProcess); 290 if (!pcs) return FALSE; 291 292 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength); 293 return TRUE; 294 } 295 296 /*********************************************************************** 297 * SymGetSearchPath (DBGHELP.@) 298 */ 299 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath, 300 DWORD SearchPathLength) 301 { 302 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR)); 303 BOOL ret = FALSE; 304 305 if (buffer) 306 { 307 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength); 308 if (ret) 309 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength, 310 szSearchPath, SearchPathLength, NULL, NULL); 311 HeapFree(GetProcessHeap(), 0, buffer); 312 } 313 return ret; 314 } 315 316 #ifndef DBGHELP_STATIC_LIB 317 /****************************************************************** 318 * invade_process 319 * 320 * SymInitialize helper: loads in dbghelp all known (and loaded modules) 321 * this assumes that hProcess is a handle on a valid process 322 */ 323 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user) 324 { 325 WCHAR tmp[MAX_PATH]; 326 HANDLE hProcess = user; 327 328 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, tmp, ARRAY_SIZE(tmp))) 329 lstrcpynW(tmp, name, ARRAY_SIZE(tmp)); 330 331 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0); 332 return TRUE; 333 } 334 335 const WCHAR *process_getenv(const struct process *process, const WCHAR *name) 336 { 337 size_t name_len; 338 const WCHAR *iter; 339 340 if (!process->environment) return NULL; 341 name_len = lstrlenW(name); 342 343 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1) 344 { 345 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=') 346 return iter + name_len + 1; 347 } 348 349 return NULL; 350 } 351 352 /****************************************************************** 353 * check_live_target 354 * 355 */ 356 static BOOL check_live_target(struct process* pcs) 357 { 358 PROCESS_BASIC_INFORMATION pbi; 359 ULONG_PTR base = 0, env = 0; 360 361 if (!GetProcessId(pcs->handle)) return FALSE; 362 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE; 363 364 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation, 365 &pbi, sizeof(pbi), NULL )) 366 return FALSE; 367 368 if (!pcs->is_64bit) 369 { 370 DWORD env32; 371 PEB32 peb32; 372 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48); 373 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE; 374 base = peb32.Reserved[0]; 375 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32; 376 } 377 else 378 { 379 PEB peb; 380 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE; 381 base = peb.Reserved[0]; 382 ReadProcessMemory(pcs->handle, &peb.ProcessParameters->Environment, &env, sizeof(env), NULL); 383 } 384 385 #ifdef __REACTOS__ 386 /* Wine store their loader base address in peb.reserved[0] and load its symbol from there. 387 * ReactOS does not care about it, we are just happy if we managed to read the value */ 388 base = 1; 389 #endif 390 391 /* read debuggee environment block */ 392 if (env) 393 { 394 size_t buf_size = 0, i, last_null = -1; 395 WCHAR *buf = NULL; 396 397 do 398 { 399 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1)); 400 if (buf) 401 { 402 WCHAR *new_buf; 403 if (!(new_buf = realloc(buf, buf_size + read_size))) break; 404 buf = new_buf; 405 } 406 else if(!(buf = malloc(read_size))) break; 407 408 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break; 409 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++) 410 { 411 if (buf[i]) continue; 412 if (last_null + 1 == i) 413 { 414 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR)); 415 buf = NULL; 416 break; 417 } 418 last_null = i; 419 } 420 env += read_size; 421 buf_size += read_size; 422 } 423 while (buf); 424 free(buf); 425 } 426 427 if (!base) return FALSE; 428 429 TRACE("got debug info address %#lx from PEB %p\n", base, pbi.PebBaseAddress); 430 #ifndef __REACTOS__ 431 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base)) 432 WARN("couldn't load process debug info at %#lx\n", base); 433 #endif 434 return TRUE; 435 } 436 #endif 437 438 /****************************************************************** 439 * SymInitializeW (DBGHELP.@) 440 * 441 * The initialisation of a dbghelp's context. 442 * Note that hProcess doesn't need to be a valid process handle (except 443 * when fInvadeProcess is TRUE). 444 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries 445 * containing PE (and NE) module(s), here's how we handle it: 446 * - we load every module (ELF, NE, PE) passed in SymLoadModule 447 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF 448 * synchronization: hProcess should be a valid process handle, and we hook 449 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with 450 * our internal ELF modules representation (loading / unloading). This way, 451 * we'll pair every loaded builtin PE module with its ELF counterpart (and 452 * access its debug information). 453 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the 454 * hProcess refers to a running process. We use some heuristics here, so YMMV. 455 * If we detect a live target, then we get the same handling as if 456 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise, 457 * we won't be able to make the peering between a builtin PE module and its ELF 458 * counterpart. Hence we won't be able to provide the requested debug 459 * information. We'll however be able to load native PE modules (and their 460 * debug information) without any trouble. 461 * Note also that this scheme can be intertwined with the deferred loading 462 * mechanism (ie only load the debug information when we actually need it). 463 */ 464 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess) 465 { 466 struct process* pcs; 467 BOOL wow64, child_wow64; 468 469 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess); 470 471 if (process_find_by_handle(hProcess)) 472 { 473 WARN("the symbols for this process have already been initialized!\n"); 474 475 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call. 476 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed. 477 Native still returns TRUE even if the process has already been initialized. */ 478 return TRUE; 479 } 480 481 IsWow64Process(GetCurrentProcess(), &wow64); 482 483 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64)) 484 return FALSE; 485 486 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs)); 487 if (!pcs) return FALSE; 488 489 pcs->handle = hProcess; 490 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64; 491 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */ 492 493 if (UserSearchPath) 494 { 495 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0, 496 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)), 497 UserSearchPath); 498 } 499 else 500 { 501 pcs->search_path = make_default_search_path(); 502 } 503 504 pcs->lmodules = NULL; 505 pcs->dbg_hdr_addr = 0; 506 pcs->next = process_first; 507 process_first = pcs; 508 509 #ifndef DBGHELP_STATIC_LIB 510 if (check_live_target(pcs)) 511 { 512 if (fInvadeProcess) 513 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess); 514 if (pcs->loader) pcs->loader->synchronize_module_list(pcs); 515 } 516 else if (fInvadeProcess) 517 #else 518 if (fInvadeProcess) 519 #endif 520 { 521 SymCleanup(hProcess); 522 SetLastError(ERROR_INVALID_PARAMETER); 523 return FALSE; 524 } 525 526 return TRUE; 527 } 528 529 /****************************************************************** 530 * SymInitialize (DBGHELP.@) 531 * 532 * 533 */ 534 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess) 535 { 536 WCHAR* sp = NULL; 537 BOOL ret; 538 539 if (UserSearchPath) 540 { 541 unsigned len; 542 543 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0); 544 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 545 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len); 546 } 547 548 ret = SymInitializeW(hProcess, sp, fInvadeProcess); 549 HeapFree(GetProcessHeap(), 0, sp); 550 return ret; 551 } 552 553 /****************************************************************** 554 * SymCleanup (DBGHELP.@) 555 * 556 */ 557 BOOL WINAPI SymCleanup(HANDLE hProcess) 558 { 559 struct process** ppcs; 560 struct process* next; 561 562 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next) 563 { 564 if ((*ppcs)->handle == hProcess) 565 { 566 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules); 567 568 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path); 569 free((*ppcs)->environment); 570 next = (*ppcs)->next; 571 HeapFree(GetProcessHeap(), 0, *ppcs); 572 *ppcs = next; 573 return TRUE; 574 } 575 } 576 577 ERR("this process has not had SymInitialize() called for it!\n"); 578 return FALSE; 579 } 580 581 /****************************************************************** 582 * SymSetOptions (DBGHELP.@) 583 * 584 */ 585 DWORD WINAPI SymSetOptions(DWORD opts) 586 { 587 struct process* pcs; 588 589 for (pcs = process_first; pcs; pcs = pcs->next) 590 { 591 pcs_callback(pcs, CBA_SET_OPTIONS, &opts); 592 } 593 return dbghelp_options = opts; 594 } 595 596 /****************************************************************** 597 * SymGetOptions (DBGHELP.@) 598 * 599 */ 600 DWORD WINAPI SymGetOptions(void) 601 { 602 return dbghelp_options; 603 } 604 605 /****************************************************************** 606 * SymSetExtendedOption (DBGHELP.@) 607 * 608 */ 609 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value) 610 { 611 BOOL old = FALSE; 612 613 switch(option) 614 { 615 case SYMOPT_EX_WINE_NATIVE_MODULES: 616 old = dbghelp_opt_native; 617 dbghelp_opt_native = value; 618 break; 619 default: 620 FIXME("Unsupported option %d with value %d\n", option, value); 621 } 622 623 return old; 624 } 625 626 /****************************************************************** 627 * SymGetExtendedOption (DBGHELP.@) 628 * 629 */ 630 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option) 631 { 632 switch(option) 633 { 634 case SYMOPT_EX_WINE_NATIVE_MODULES: 635 return dbghelp_opt_native; 636 default: 637 FIXME("Unsupported option %d\n", option); 638 } 639 640 return FALSE; 641 } 642 643 /****************************************************************** 644 * SymSetParentWindow (DBGHELP.@) 645 * 646 */ 647 BOOL WINAPI SymSetParentWindow(HWND hwnd) 648 { 649 /* Save hwnd so it can be used as parent window */ 650 FIXME("(%p): stub\n", hwnd); 651 return TRUE; 652 } 653 654 /****************************************************************** 655 * SymSetContext (DBGHELP.@) 656 * 657 */ 658 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, 659 PIMAGEHLP_CONTEXT Context) 660 { 661 struct process* pcs = process_find_by_handle(hProcess); 662 if (!pcs) return FALSE; 663 664 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && 665 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && 666 pcs->ctx_frame.StackOffset == StackFrame->StackOffset) 667 { 668 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n", 669 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset), 670 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset), 671 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset)); 672 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset; 673 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */ 674 return FALSE; 675 } 676 677 pcs->ctx_frame = *StackFrame; 678 /* MSDN states that Context is not (no longer?) used */ 679 return TRUE; 680 } 681 682 /****************************************************************** 683 * reg_cb64to32 (internal) 684 * 685 * Registered callback for converting information from 64 bit to 32 bit 686 */ 687 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user) 688 { 689 struct process* pcs = process_find_by_handle(hProcess); 690 void* data32; 691 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64; 692 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl; 693 694 if (!pcs) return FALSE; 695 switch (action) 696 { 697 case CBA_DEBUG_INFO: 698 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: 699 case CBA_SET_OPTIONS: 700 case CBA_SYMBOLS_UNLOADED: 701 data32 = (void*)(DWORD_PTR)data; 702 break; 703 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: 704 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: 705 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: 706 case CBA_DEFERRED_SYMBOL_LOAD_START: 707 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data; 708 if (!validate_addr64(idsl64->BaseOfImage)) 709 return FALSE; 710 idsl.SizeOfStruct = sizeof(idsl); 711 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage; 712 idsl.CheckSum = idsl64->CheckSum; 713 idsl.TimeDateStamp = idsl64->TimeDateStamp; 714 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName)); 715 idsl.Reparse = idsl64->Reparse; 716 data32 = &idsl; 717 break; 718 case CBA_DUPLICATE_SYMBOL: 719 case CBA_EVENT: 720 case CBA_READ_MEMORY: 721 default: 722 FIXME("No mapping for action %u\n", action); 723 return FALSE; 724 } 725 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user); 726 } 727 728 /****************************************************************** 729 * pcs_callback (internal) 730 */ 731 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) 732 { 733 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl; 734 735 TRACE("%p %u %p\n", pcs, action, data); 736 737 if (!pcs->reg_cb) return FALSE; 738 if (!pcs->reg_is_unicode) 739 { 740 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW; 741 742 switch (action) 743 { 744 case CBA_DEBUG_INFO: 745 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: 746 case CBA_SET_OPTIONS: 747 case CBA_SYMBOLS_UNLOADED: 748 break; 749 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: 750 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: 751 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: 752 case CBA_DEFERRED_SYMBOL_LOAD_START: 753 idslW = data; 754 idsl.SizeOfStruct = sizeof(idsl); 755 idsl.BaseOfImage = idslW->BaseOfImage; 756 idsl.CheckSum = idslW->CheckSum; 757 idsl.TimeDateStamp = idslW->TimeDateStamp; 758 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1, 759 idsl.FileName, sizeof(idsl.FileName), NULL, NULL); 760 idsl.Reparse = idslW->Reparse; 761 data = &idsl; 762 break; 763 case CBA_DUPLICATE_SYMBOL: 764 case CBA_EVENT: 765 case CBA_READ_MEMORY: 766 default: 767 FIXME("No mapping for action %u\n", action); 768 return FALSE; 769 } 770 } 771 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user); 772 } 773 774 /****************************************************************** 775 * sym_register_cb 776 * 777 * Helper for registering a callback. 778 */ 779 static BOOL sym_register_cb(HANDLE hProcess, 780 PSYMBOL_REGISTERED_CALLBACK64 cb, 781 PSYMBOL_REGISTERED_CALLBACK cb32, 782 DWORD64 user, BOOL unicode) 783 { 784 struct process* pcs = process_find_by_handle(hProcess); 785 786 if (!pcs) return FALSE; 787 pcs->reg_cb = cb; 788 pcs->reg_cb32 = cb32; 789 pcs->reg_is_unicode = unicode; 790 pcs->reg_user = user; 791 792 return TRUE; 793 } 794 795 /*********************************************************************** 796 * SymRegisterCallback (DBGHELP.@) 797 */ 798 BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 799 PSYMBOL_REGISTERED_CALLBACK CallbackFunction, 800 PVOID UserContext) 801 { 802 TRACE("(%p, %p, %p)\n", 803 hProcess, CallbackFunction, UserContext); 804 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE); 805 } 806 807 /*********************************************************************** 808 * SymRegisterCallback64 (DBGHELP.@) 809 */ 810 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 811 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, 812 ULONG64 UserContext) 813 { 814 TRACE("(%p, %p, %s)\n", 815 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); 816 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE); 817 } 818 819 /*********************************************************************** 820 * SymRegisterCallbackW64 (DBGHELP.@) 821 */ 822 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, 823 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, 824 ULONG64 UserContext) 825 { 826 TRACE("(%p, %p, %s)\n", 827 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); 828 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE); 829 } 830 831 /* This is imagehlp version not dbghelp !! */ 832 static API_VERSION api_version = { 4, 0, 2, 0 }; 833 834 /*********************************************************************** 835 * ImagehlpApiVersion (DBGHELP.@) 836 */ 837 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID) 838 { 839 return &api_version; 840 } 841 842 /*********************************************************************** 843 * ImagehlpApiVersionEx (DBGHELP.@) 844 */ 845 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion) 846 { 847 if (!AppVersion) return NULL; 848 849 AppVersion->MajorVersion = api_version.MajorVersion; 850 AppVersion->MinorVersion = api_version.MinorVersion; 851 AppVersion->Revision = api_version.Revision; 852 AppVersion->Reserved = api_version.Reserved; 853 854 return AppVersion; 855 } 856 857 /****************************************************************** 858 * ExtensionApiVersion (DBGHELP.@) 859 */ 860 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void) 861 { 862 static EXT_API_VERSION eav = {5, 5, 5, 0}; 863 return &eav; 864 } 865 866 /****************************************************************** 867 * WinDbgExtensionDllInit (DBGHELP.@) 868 */ 869 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis, 870 unsigned short major, unsigned short minor) 871 { 872 } 873 874 DWORD calc_crc32(HANDLE handle) 875 { 876 BYTE buffer[8192]; 877 DWORD crc = 0; 878 DWORD len; 879 880 SetFilePointer(handle, 0, 0, FILE_BEGIN); 881 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len) 882 crc = RtlComputeCrc32(crc, buffer, len); 883 return crc; 884 } 885