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 /****************************************************************** 195 * SymSetSearchPathW (DBGHELP.@) 196 * 197 */ 198 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath) 199 { 200 struct process* pcs = process_find_by_handle(hProcess); 201 202 if (!pcs) return FALSE; 203 if (!searchPath) return FALSE; 204 205 HeapFree(GetProcessHeap(), 0, pcs->search_path); 206 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0, 207 (lstrlenW(searchPath) + 1) * sizeof(WCHAR)), 208 searchPath); 209 return TRUE; 210 } 211 212 /****************************************************************** 213 * SymSetSearchPath (DBGHELP.@) 214 * 215 */ 216 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath) 217 { 218 BOOL ret = FALSE; 219 unsigned len; 220 WCHAR* sp; 221 222 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0); 223 if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) 224 { 225 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len); 226 227 ret = SymSetSearchPathW(hProcess, sp); 228 HeapFree(GetProcessHeap(), 0, sp); 229 } 230 return ret; 231 } 232 233 /*********************************************************************** 234 * SymGetSearchPathW (DBGHELP.@) 235 */ 236 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath, 237 DWORD SearchPathLength) 238 { 239 struct process* pcs = process_find_by_handle(hProcess); 240 if (!pcs) return FALSE; 241 242 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength); 243 return TRUE; 244 } 245 246 /*********************************************************************** 247 * SymGetSearchPath (DBGHELP.@) 248 */ 249 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath, 250 DWORD SearchPathLength) 251 { 252 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR)); 253 BOOL ret = FALSE; 254 255 if (buffer) 256 { 257 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength); 258 if (ret) 259 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength, 260 szSearchPath, SearchPathLength, NULL, NULL); 261 HeapFree(GetProcessHeap(), 0, buffer); 262 } 263 return ret; 264 } 265 266 #ifndef DBGHELP_STATIC_LIB 267 /****************************************************************** 268 * invade_process 269 * 270 * SymInitialize helper: loads in dbghelp all known (and loaded modules) 271 * this assumes that hProcess is a handle on a valid process 272 */ 273 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user) 274 { 275 WCHAR tmp[MAX_PATH]; 276 HANDLE hProcess = user; 277 278 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, tmp, ARRAY_SIZE(tmp))) 279 lstrcpynW(tmp, name, ARRAY_SIZE(tmp)); 280 281 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0); 282 return TRUE; 283 } 284 285 const WCHAR *process_getenv(const struct process *process, const WCHAR *name) 286 { 287 size_t name_len; 288 const WCHAR *iter; 289 290 if (!process->environment) return NULL; 291 name_len = lstrlenW(name); 292 293 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1) 294 { 295 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=') 296 return iter + name_len + 1; 297 } 298 299 return NULL; 300 } 301 302 /****************************************************************** 303 * check_live_target 304 * 305 */ 306 static BOOL check_live_target(struct process* pcs) 307 { 308 PROCESS_BASIC_INFORMATION pbi; 309 ULONG_PTR base = 0, env = 0; 310 311 if (!GetProcessId(pcs->handle)) return FALSE; 312 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE; 313 314 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation, 315 &pbi, sizeof(pbi), NULL )) 316 return FALSE; 317 318 if (!pcs->is_64bit) 319 { 320 DWORD env32; 321 PEB32 peb32; 322 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48); 323 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE; 324 base = peb32.Reserved[0]; 325 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32; 326 } 327 else 328 { 329 PEB peb; 330 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE; 331 base = peb.Reserved[0]; 332 ReadProcessMemory(pcs->handle, &peb.ProcessParameters->Environment, &env, sizeof(env), NULL); 333 } 334 335 #ifdef __REACTOS__ 336 /* Wine store their loader base address in peb.reserved[0] and load its symbol from there. 337 * ReactOS does not care about it, we are just happy if we managed to read the value */ 338 base = 1; 339 #endif 340 341 /* read debuggee environment block */ 342 if (env) 343 { 344 size_t buf_size = 0, i, last_null = -1; 345 WCHAR *buf = NULL; 346 347 do 348 { 349 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1)); 350 if (buf) 351 { 352 WCHAR *new_buf; 353 if (!(new_buf = realloc(buf, buf_size + read_size))) break; 354 buf = new_buf; 355 } 356 else if(!(buf = malloc(read_size))) break; 357 358 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break; 359 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++) 360 { 361 if (buf[i]) continue; 362 if (last_null + 1 == i) 363 { 364 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR)); 365 buf = NULL; 366 break; 367 } 368 last_null = i; 369 } 370 env += read_size; 371 buf_size += read_size; 372 } 373 while (buf); 374 free(buf); 375 } 376 377 if (!base) return FALSE; 378 379 TRACE("got debug info address %#lx from PEB %p\n", base, pbi.PebBaseAddress); 380 #ifndef __REACTOS__ 381 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base)) 382 WARN("couldn't load process debug info at %#lx\n", base); 383 #endif 384 return TRUE; 385 } 386 #endif 387 388 /****************************************************************** 389 * SymInitializeW (DBGHELP.@) 390 * 391 * The initialisation of a dbghelp's context. 392 * Note that hProcess doesn't need to be a valid process handle (except 393 * when fInvadeProcess is TRUE). 394 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries 395 * containing PE (and NE) module(s), here's how we handle it: 396 * - we load every module (ELF, NE, PE) passed in SymLoadModule 397 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF 398 * synchronization: hProcess should be a valid process handle, and we hook 399 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with 400 * our internal ELF modules representation (loading / unloading). This way, 401 * we'll pair every loaded builtin PE module with its ELF counterpart (and 402 * access its debug information). 403 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the 404 * hProcess refers to a running process. We use some heuristics here, so YMMV. 405 * If we detect a live target, then we get the same handling as if 406 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise, 407 * we won't be able to make the peering between a builtin PE module and its ELF 408 * counterpart. Hence we won't be able to provide the requested debug 409 * information. We'll however be able to load native PE modules (and their 410 * debug information) without any trouble. 411 * Note also that this scheme can be intertwined with the deferred loading 412 * mechanism (ie only load the debug information when we actually need it). 413 */ 414 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess) 415 { 416 struct process* pcs; 417 BOOL wow64, child_wow64; 418 419 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess); 420 421 if (process_find_by_handle(hProcess)) 422 { 423 WARN("the symbols for this process have already been initialized!\n"); 424 425 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call. 426 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed. 427 Native still returns TRUE even if the process has already been initialized. */ 428 return TRUE; 429 } 430 431 IsWow64Process(GetCurrentProcess(), &wow64); 432 433 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64)) 434 return FALSE; 435 436 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs)); 437 if (!pcs) return FALSE; 438 439 pcs->handle = hProcess; 440 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64; 441 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */ 442 443 if (UserSearchPath) 444 { 445 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0, 446 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)), 447 UserSearchPath); 448 } 449 else 450 { 451 unsigned size; 452 unsigned len; 453 static const WCHAR sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0}; 454 static const WCHAR alt_sym_path[] = {'_','N','T','_','A','L','T','E','R','N','A','T','E','_','S','Y','M','B','O','L','_','P','A','T','H',0}; 455 456 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR)); 457 while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len) 458 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR)); 459 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR)); 460 461 len = GetEnvironmentVariableW(sym_path, NULL, 0); 462 if (len) 463 { 464 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR)); 465 pcs->search_path[size] = ';'; 466 GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len); 467 size += 1 + len; 468 } 469 len = GetEnvironmentVariableW(alt_sym_path, NULL, 0); 470 if (len) 471 { 472 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR)); 473 pcs->search_path[size] = ';'; 474 GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len); 475 } 476 } 477 478 pcs->lmodules = NULL; 479 pcs->dbg_hdr_addr = 0; 480 pcs->next = process_first; 481 process_first = pcs; 482 483 #ifndef DBGHELP_STATIC_LIB 484 if (check_live_target(pcs)) 485 { 486 if (fInvadeProcess) 487 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess); 488 if (pcs->loader) pcs->loader->synchronize_module_list(pcs); 489 } 490 else if (fInvadeProcess) 491 #else 492 if (fInvadeProcess) 493 #endif 494 { 495 SymCleanup(hProcess); 496 SetLastError(ERROR_INVALID_PARAMETER); 497 return FALSE; 498 } 499 500 return TRUE; 501 } 502 503 /****************************************************************** 504 * SymInitialize (DBGHELP.@) 505 * 506 * 507 */ 508 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess) 509 { 510 WCHAR* sp = NULL; 511 BOOL ret; 512 513 if (UserSearchPath) 514 { 515 unsigned len; 516 517 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0); 518 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 519 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len); 520 } 521 522 ret = SymInitializeW(hProcess, sp, fInvadeProcess); 523 HeapFree(GetProcessHeap(), 0, sp); 524 return ret; 525 } 526 527 /****************************************************************** 528 * SymCleanup (DBGHELP.@) 529 * 530 */ 531 BOOL WINAPI SymCleanup(HANDLE hProcess) 532 { 533 struct process** ppcs; 534 struct process* next; 535 536 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next) 537 { 538 if ((*ppcs)->handle == hProcess) 539 { 540 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules); 541 542 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path); 543 free((*ppcs)->environment); 544 next = (*ppcs)->next; 545 HeapFree(GetProcessHeap(), 0, *ppcs); 546 *ppcs = next; 547 return TRUE; 548 } 549 } 550 551 ERR("this process has not had SymInitialize() called for it!\n"); 552 return FALSE; 553 } 554 555 /****************************************************************** 556 * SymSetOptions (DBGHELP.@) 557 * 558 */ 559 DWORD WINAPI SymSetOptions(DWORD opts) 560 { 561 struct process* pcs; 562 563 for (pcs = process_first; pcs; pcs = pcs->next) 564 { 565 pcs_callback(pcs, CBA_SET_OPTIONS, &opts); 566 } 567 return dbghelp_options = opts; 568 } 569 570 /****************************************************************** 571 * SymGetOptions (DBGHELP.@) 572 * 573 */ 574 DWORD WINAPI SymGetOptions(void) 575 { 576 return dbghelp_options; 577 } 578 579 /****************************************************************** 580 * SymSetExtendedOption (DBGHELP.@) 581 * 582 */ 583 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value) 584 { 585 BOOL old = FALSE; 586 587 switch(option) 588 { 589 case SYMOPT_EX_WINE_NATIVE_MODULES: 590 old = dbghelp_opt_native; 591 dbghelp_opt_native = value; 592 break; 593 default: 594 FIXME("Unsupported option %d with value %d\n", option, value); 595 } 596 597 return old; 598 } 599 600 /****************************************************************** 601 * SymGetExtendedOption (DBGHELP.@) 602 * 603 */ 604 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option) 605 { 606 switch(option) 607 { 608 case SYMOPT_EX_WINE_NATIVE_MODULES: 609 return dbghelp_opt_native; 610 default: 611 FIXME("Unsupported option %d\n", option); 612 } 613 614 return FALSE; 615 } 616 617 /****************************************************************** 618 * SymSetParentWindow (DBGHELP.@) 619 * 620 */ 621 BOOL WINAPI SymSetParentWindow(HWND hwnd) 622 { 623 /* Save hwnd so it can be used as parent window */ 624 FIXME("(%p): stub\n", hwnd); 625 return TRUE; 626 } 627 628 /****************************************************************** 629 * SymSetContext (DBGHELP.@) 630 * 631 */ 632 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame, 633 PIMAGEHLP_CONTEXT Context) 634 { 635 struct process* pcs = process_find_by_handle(hProcess); 636 if (!pcs) return FALSE; 637 638 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset && 639 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset && 640 pcs->ctx_frame.StackOffset == StackFrame->StackOffset) 641 { 642 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n", 643 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset), 644 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset), 645 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset)); 646 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset; 647 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */ 648 return FALSE; 649 } 650 651 pcs->ctx_frame = *StackFrame; 652 /* MSDN states that Context is not (no longer?) used */ 653 return TRUE; 654 } 655 656 /****************************************************************** 657 * reg_cb64to32 (internal) 658 * 659 * Registered callback for converting information from 64 bit to 32 bit 660 */ 661 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user) 662 { 663 struct process* pcs = process_find_by_handle(hProcess); 664 void* data32; 665 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64; 666 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl; 667 668 if (!pcs) return FALSE; 669 switch (action) 670 { 671 case CBA_DEBUG_INFO: 672 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: 673 case CBA_SET_OPTIONS: 674 case CBA_SYMBOLS_UNLOADED: 675 data32 = (void*)(DWORD_PTR)data; 676 break; 677 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: 678 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: 679 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: 680 case CBA_DEFERRED_SYMBOL_LOAD_START: 681 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data; 682 if (!validate_addr64(idsl64->BaseOfImage)) 683 return FALSE; 684 idsl.SizeOfStruct = sizeof(idsl); 685 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage; 686 idsl.CheckSum = idsl64->CheckSum; 687 idsl.TimeDateStamp = idsl64->TimeDateStamp; 688 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName)); 689 idsl.Reparse = idsl64->Reparse; 690 data32 = &idsl; 691 break; 692 case CBA_DUPLICATE_SYMBOL: 693 case CBA_EVENT: 694 case CBA_READ_MEMORY: 695 default: 696 FIXME("No mapping for action %u\n", action); 697 return FALSE; 698 } 699 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user); 700 } 701 702 /****************************************************************** 703 * pcs_callback (internal) 704 */ 705 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data) 706 { 707 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl; 708 709 TRACE("%p %u %p\n", pcs, action, data); 710 711 if (!pcs->reg_cb) return FALSE; 712 if (!pcs->reg_is_unicode) 713 { 714 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW; 715 716 switch (action) 717 { 718 case CBA_DEBUG_INFO: 719 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL: 720 case CBA_SET_OPTIONS: 721 case CBA_SYMBOLS_UNLOADED: 722 break; 723 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE: 724 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE: 725 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL: 726 case CBA_DEFERRED_SYMBOL_LOAD_START: 727 idslW = data; 728 idsl.SizeOfStruct = sizeof(idsl); 729 idsl.BaseOfImage = idslW->BaseOfImage; 730 idsl.CheckSum = idslW->CheckSum; 731 idsl.TimeDateStamp = idslW->TimeDateStamp; 732 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1, 733 idsl.FileName, sizeof(idsl.FileName), NULL, NULL); 734 idsl.Reparse = idslW->Reparse; 735 data = &idsl; 736 break; 737 case CBA_DUPLICATE_SYMBOL: 738 case CBA_EVENT: 739 case CBA_READ_MEMORY: 740 default: 741 FIXME("No mapping for action %u\n", action); 742 return FALSE; 743 } 744 } 745 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user); 746 } 747 748 /****************************************************************** 749 * sym_register_cb 750 * 751 * Helper for registering a callback. 752 */ 753 static BOOL sym_register_cb(HANDLE hProcess, 754 PSYMBOL_REGISTERED_CALLBACK64 cb, 755 PSYMBOL_REGISTERED_CALLBACK cb32, 756 DWORD64 user, BOOL unicode) 757 { 758 struct process* pcs = process_find_by_handle(hProcess); 759 760 if (!pcs) return FALSE; 761 pcs->reg_cb = cb; 762 pcs->reg_cb32 = cb32; 763 pcs->reg_is_unicode = unicode; 764 pcs->reg_user = user; 765 766 return TRUE; 767 } 768 769 /*********************************************************************** 770 * SymRegisterCallback (DBGHELP.@) 771 */ 772 BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 773 PSYMBOL_REGISTERED_CALLBACK CallbackFunction, 774 PVOID UserContext) 775 { 776 TRACE("(%p, %p, %p)\n", 777 hProcess, CallbackFunction, UserContext); 778 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE); 779 } 780 781 /*********************************************************************** 782 * SymRegisterCallback64 (DBGHELP.@) 783 */ 784 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 785 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, 786 ULONG64 UserContext) 787 { 788 TRACE("(%p, %p, %s)\n", 789 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); 790 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE); 791 } 792 793 /*********************************************************************** 794 * SymRegisterCallbackW64 (DBGHELP.@) 795 */ 796 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, 797 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, 798 ULONG64 UserContext) 799 { 800 TRACE("(%p, %p, %s)\n", 801 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext)); 802 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE); 803 } 804 805 /* This is imagehlp version not dbghelp !! */ 806 static API_VERSION api_version = { 4, 0, 2, 0 }; 807 808 /*********************************************************************** 809 * ImagehlpApiVersion (DBGHELP.@) 810 */ 811 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID) 812 { 813 return &api_version; 814 } 815 816 /*********************************************************************** 817 * ImagehlpApiVersionEx (DBGHELP.@) 818 */ 819 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion) 820 { 821 if (!AppVersion) return NULL; 822 823 AppVersion->MajorVersion = api_version.MajorVersion; 824 AppVersion->MinorVersion = api_version.MinorVersion; 825 AppVersion->Revision = api_version.Revision; 826 AppVersion->Reserved = api_version.Reserved; 827 828 return AppVersion; 829 } 830 831 /****************************************************************** 832 * ExtensionApiVersion (DBGHELP.@) 833 */ 834 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void) 835 { 836 static EXT_API_VERSION eav = {5, 5, 5, 0}; 837 return &eav; 838 } 839 840 /****************************************************************** 841 * WinDbgExtensionDllInit (DBGHELP.@) 842 */ 843 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis, 844 unsigned short major, unsigned short minor) 845 { 846 } 847 848 DWORD calc_crc32(HANDLE handle) 849 { 850 BYTE buffer[8192]; 851 DWORD crc = 0; 852 DWORD len; 853 854 SetFilePointer(handle, 0, 0, FILE_BEGIN); 855 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len) 856 crc = RtlComputeCrc32(crc, buffer, len); 857 return crc; 858 } 859