dxdiagn: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / dbghelp / dbghelp.c
blob3ce3ef6f70701375de27687f77a78373bc21134b
1 /*
2 * File dbghelp.c - generic routines (process) for dbghelp DLL
4 * Copyright (C) 2004, Eric Pouech
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.
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.
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
22 #include <unistd.h>
23 #include "dbghelp_private.h"
24 #include "winternl.h"
25 #include "winerror.h"
26 #include "psapi.h"
27 #include "wine/debug.h"
28 #include "wdbgexts.h"
29 #include "winnls.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
33 /* TODO
34 * - support for symbols' types is still partly missing
35 * + C++ support
36 * + we should store the underlying type for an enum in the symt_enum struct
37 * + for enums, we store the names & values (associated to the enum type),
38 * but those values are not directly usable from a debugger (that's why, I
39 * assume, that we have also to define constants for enum values, as
40 * Codeview does BTW.
41 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
42 * all the types stored/used in the modules (like char*)
43 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
44 * functions, and even across function blocks...). Basically, for *Next* to work
45 * it requires an address after the prolog of the func (the base address of the
46 * func doesn't work)
47 * - most options (dbghelp_options) are not used (loading lines...)
48 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
49 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
50 * we could use hash if name isn't a RE, and fall back to a full search when we
51 * get a full RE
52 * - msc:
53 * + we should add parameters' types to the function's signature
54 * while processing a function's parameters
55 * + add support for function-less labels (as MSC seems to define them)
56 * + C++ management
57 * - stabs:
58 * + when, in a same module, the same definition is used in several compilation
59 * units, we get several definitions of the same object (especially
60 * struct/union). we should find a way not to duplicate them
61 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
62 * global variable is defined several times (at different scopes). We are
63 * getting several of those while looking for a unique symbol. Part of the
64 * issue is that we don't give a scope to a static variable inside a function
65 * + C++ management
68 unsigned dbghelp_options = SYMOPT_UNDNAME;
69 BOOL dbghelp_opt_native = FALSE;
70 BOOL dbghelp_opt_real_path = FALSE;
71 BOOL dbghelp_opt_source_actual_path = FALSE;
72 SYSTEM_INFO sysinfo;
74 static struct process* process_first /* = NULL */;
76 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
78 switch (reason)
80 case DLL_PROCESS_ATTACH:
81 GetSystemInfo(&sysinfo);
82 DisableThreadLibraryCalls(instance);
83 break;
85 return TRUE;
88 /******************************************************************
89 * process_find_by_handle
92 struct process* process_find_by_handle(HANDLE hProcess)
94 struct process* p;
96 for (p = process_first; p && p->handle != hProcess; p = p->next);
97 if (!p) SetLastError(ERROR_INVALID_HANDLE);
98 return p;
101 /******************************************************************
102 * validate_addr64 (internal)
105 BOOL validate_addr64(DWORD64 addr)
107 if (sizeof(void*) == sizeof(int) && (addr >> 32))
109 FIXME("Unsupported address %I64x\n", addr);
110 SetLastError(ERROR_INVALID_PARAMETER);
111 return FALSE;
113 return TRUE;
116 /******************************************************************
117 * fetch_buffer
119 * Ensures process' internal buffer is large enough.
121 void* fetch_buffer(struct process* pcs, unsigned size)
123 if (size > pcs->buffer_size)
125 if (pcs->buffer)
126 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
127 else
128 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
129 pcs->buffer_size = (pcs->buffer) ? size : 0;
131 return pcs->buffer;
134 const char* wine_dbgstr_addr(const ADDRESS64* addr)
136 if (!addr) return "(null)";
137 switch (addr->Mode)
139 case AddrModeFlat:
140 return wine_dbg_sprintf("flat<%I64x>", addr->Offset);
141 case AddrMode1616:
142 return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, (DWORD)addr->Offset);
143 case AddrMode1632:
144 return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, (DWORD)addr->Offset);
145 case AddrModeReal:
146 return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, (DWORD)addr->Offset);
147 default:
148 return "unknown";
152 extern struct cpu cpu_i386, cpu_x86_64, cpu_arm, cpu_arm64;
154 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_arm, &cpu_arm64, NULL};
155 struct cpu* dbghelp_current_cpu =
156 #if defined(__i386__)
157 &cpu_i386
158 #elif defined(__x86_64__)
159 &cpu_x86_64
160 #elif defined(__arm__)
161 &cpu_arm
162 #elif defined(__aarch64__)
163 &cpu_arm64
164 #else
165 #error define support for your CPU
166 #endif
169 struct cpu* cpu_find(DWORD machine)
171 struct cpu** cpu;
173 for (cpu = dbghelp_cpus ; *cpu; cpu++)
175 if (cpu[0]->machine == machine) return cpu[0];
177 return NULL;
180 static WCHAR* make_default_search_path(void)
182 WCHAR* search_path;
183 WCHAR* p;
184 unsigned sym_path_len;
185 unsigned alt_sym_path_len;
187 sym_path_len = GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", NULL, 0);
188 alt_sym_path_len = GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
190 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
191 * If the variables exist, the lengths include a null-terminator. We use that
192 * space for the semicolons, and only add the initial dot and the final null. */
193 search_path = HeapAlloc(GetProcessHeap(), 0,
194 (1 + sym_path_len + alt_sym_path_len + 1) * sizeof(WCHAR));
195 if (!search_path) return NULL;
197 p = search_path;
198 *p++ = L'.';
199 if (sym_path_len)
201 *p++ = L';';
202 GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", p, sym_path_len);
203 p += sym_path_len - 1;
206 if (alt_sym_path_len)
208 *p++ = L';';
209 GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", p, alt_sym_path_len);
210 p += alt_sym_path_len - 1;
212 *p = L'\0';
214 return search_path;
217 /******************************************************************
218 * SymSetSearchPathW (DBGHELP.@)
221 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
223 struct process* pcs = process_find_by_handle(hProcess);
224 WCHAR* search_path_buffer;
226 if (!pcs) return FALSE;
228 if (searchPath)
230 search_path_buffer = HeapAlloc(GetProcessHeap(), 0,
231 (lstrlenW(searchPath) + 1) * sizeof(WCHAR));
232 if (!search_path_buffer) return FALSE;
233 lstrcpyW(search_path_buffer, searchPath);
235 else
237 search_path_buffer = make_default_search_path();
238 if (!search_path_buffer) return FALSE;
240 HeapFree(GetProcessHeap(), 0, pcs->search_path);
241 pcs->search_path = search_path_buffer;
242 return TRUE;
245 /******************************************************************
246 * SymSetSearchPath (DBGHELP.@)
249 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
251 BOOL ret = FALSE;
252 unsigned len;
253 WCHAR* sp = NULL;
255 if (searchPath)
257 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
258 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
259 if (!sp) return FALSE;
260 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
263 ret = SymSetSearchPathW(hProcess, sp);
265 HeapFree(GetProcessHeap(), 0, sp);
266 return ret;
269 /***********************************************************************
270 * SymGetSearchPathW (DBGHELP.@)
272 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
273 DWORD SearchPathLength)
275 struct process* pcs = process_find_by_handle(hProcess);
276 if (!pcs) return FALSE;
278 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
279 return TRUE;
282 /***********************************************************************
283 * SymGetSearchPath (DBGHELP.@)
285 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
286 DWORD SearchPathLength)
288 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
289 BOOL ret = FALSE;
291 if (buffer)
293 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
294 if (ret)
295 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
296 szSearchPath, SearchPathLength, NULL, NULL);
297 HeapFree(GetProcessHeap(), 0, buffer);
299 return ret;
302 /******************************************************************
303 * invade_process
305 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
306 * this assumes that hProcess is a handle on a valid process
308 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
310 HANDLE hProcess = user;
312 SymLoadModuleExW(hProcess, 0, name, NULL, base, size, NULL, 0);
313 return TRUE;
316 const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
318 size_t name_len;
319 const WCHAR *iter;
321 if (!process->environment) return NULL;
322 name_len = lstrlenW(name);
324 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1)
326 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=')
327 return iter + name_len + 1;
330 return NULL;
333 const struct cpu* process_get_cpu(const struct process* pcs)
335 const struct module* m = pcs->lmodules;
337 /* return cpu of main module, which is the first module in process's modules list */
338 return (m) ? m->cpu : dbghelp_current_cpu;
341 /******************************************************************
342 * check_live_target
345 static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64)
347 PROCESS_BASIC_INFORMATION pbi;
348 DWORD64 base = 0, env = 0;
349 const char* peb_addr;
351 if (!GetProcessId(pcs->handle)) return FALSE;
352 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
354 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation,
355 &pbi, sizeof(pbi), NULL ))
356 return FALSE;
358 /* Note: we have to deal with the PEB64 and PEB32 in debuggee process
359 * while debugger can be in same or different bitness.
360 * For a 64 bit debuggee, use PEB64 and underlying ELF/system 64 (easy).
361 * For a 32 bit debuggee,
362 * - for environment variables, we need PEB32
363 * - for ELF/system base address, we need PEB32 when run in pure 32bit
364 * or run in old wow configuration, but PEB64 when run in new wow
365 * configuration.
366 * - this must be read from a debugger in either 32 or 64 bit setup.
368 peb_addr = (const char*)pbi.PebBaseAddress;
369 if (!pcs->is_64bit)
371 DWORD env32;
372 PEB32 peb32;
374 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48);
376 if (!wow64 && child_wow64)
377 /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */
378 peb_addr += 0x1000;
379 if (!ReadProcessMemory(pcs->handle, peb_addr, &peb32, sizeof(peb32), NULL)) return FALSE;
380 base = *(const DWORD*)((const char*)&peb32 + 0x460 /* CloudFileFlags */);
381 pcs->is_system_64bit = FALSE;
382 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32;
384 if (pcs->is_64bit || base == 0)
386 PEB64 peb;
388 if (!pcs->is_64bit) peb_addr -= 0x1000; /* PEB32 => PEB64 */
389 if (!ReadProcessMemory(pcs->handle, peb_addr, &peb, sizeof(peb), NULL)) return FALSE;
390 base = *(const DWORD64*)&peb.CloudFileFlags;
391 pcs->is_system_64bit = TRUE;
392 if (pcs->is_64bit)
393 ReadProcessMemory(pcs->handle,
394 (char *)(ULONG_PTR)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment),
395 &env, sizeof(env), NULL);
398 /* read debuggee environment block */
399 if (env)
401 size_t buf_size = 0, i, last_null = -1;
402 WCHAR *buf = NULL;
406 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1));
407 if (buf)
409 WCHAR *new_buf;
410 if (!(new_buf = realloc(buf, buf_size + read_size))) break;
411 buf = new_buf;
413 else if(!(buf = malloc(read_size))) break;
415 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break;
416 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++)
418 if (buf[i]) continue;
419 if (last_null + 1 == i)
421 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR));
422 buf = NULL;
423 break;
425 last_null = i;
427 env += read_size;
428 buf_size += read_size;
430 while (buf);
431 free(buf);
434 if (!base) return FALSE;
436 TRACE("got debug info address %#I64x from PEB %p\n", base, pbi.PebBaseAddress);
437 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
438 WARN("couldn't load process debug info at %#I64x\n", base);
439 return TRUE;
442 /******************************************************************
443 * SymInitializeW (DBGHELP.@)
445 * The initialisation of a dbghelp's context.
446 * Note that hProcess doesn't need to be a valid process handle (except
447 * when fInvadeProcess is TRUE).
448 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
449 * containing PE (and NE) module(s), here's how we handle it:
450 * - we load every module (ELF, NE, PE) passed in SymLoadModule
451 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
452 * synchronization: hProcess should be a valid process handle, and we hook
453 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
454 * our internal ELF modules representation (loading / unloading). This way,
455 * we'll pair every loaded builtin PE module with its ELF counterpart (and
456 * access its debug information).
457 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
458 * hProcess refers to a running process. We use some heuristics here, so YMMV.
459 * If we detect a live target, then we get the same handling as if
460 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
461 * we won't be able to make the peering between a builtin PE module and its ELF
462 * counterpart. Hence we won't be able to provide the requested debug
463 * information. We'll however be able to load native PE modules (and their
464 * debug information) without any trouble.
465 * Note also that this scheme can be intertwined with the deferred loading
466 * mechanism (ie only load the debug information when we actually need it).
468 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
470 struct process* pcs;
471 BOOL wow64, child_wow64;
473 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
475 if (process_find_by_handle(hProcess))
477 WARN("the symbols for this process have already been initialized!\n");
479 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
480 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
481 Native still returns TRUE even if the process has already been initialized. */
482 return TRUE;
485 IsWow64Process(GetCurrentProcess(), &wow64);
487 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64))
488 return FALSE;
490 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
491 if (!pcs) return FALSE;
493 pcs->handle = hProcess;
494 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64;
495 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */
497 if (UserSearchPath)
499 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
500 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
501 UserSearchPath);
503 else
505 pcs->search_path = make_default_search_path();
508 pcs->lmodules = NULL;
509 pcs->dbg_hdr_addr = 0;
510 pcs->next = process_first;
511 process_first = pcs;
513 if (check_live_target(pcs, wow64, child_wow64))
515 if (fInvadeProcess)
516 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
517 if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
519 else if (fInvadeProcess)
521 SymCleanup(hProcess);
522 SetLastError(ERROR_INVALID_PARAMETER);
523 return FALSE;
526 return TRUE;
529 /******************************************************************
530 * SymInitialize (DBGHELP.@)
534 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
536 WCHAR* sp = NULL;
537 BOOL ret;
539 if (UserSearchPath)
541 unsigned len;
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);
548 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
549 HeapFree(GetProcessHeap(), 0, sp);
550 return ret;
553 /******************************************************************
554 * SymCleanup (DBGHELP.@)
557 BOOL WINAPI SymCleanup(HANDLE hProcess)
559 struct process** ppcs;
560 struct process* next;
562 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
564 if ((*ppcs)->handle == hProcess)
566 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
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;
577 ERR("this process has not had SymInitialize() called for it!\n");
578 return FALSE;
581 /******************************************************************
582 * SymSetOptions (DBGHELP.@)
585 DWORD WINAPI SymSetOptions(DWORD opts)
587 struct process* pcs;
589 for (pcs = process_first; pcs; pcs = pcs->next)
591 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
593 return dbghelp_options = opts;
596 /******************************************************************
597 * SymGetOptions (DBGHELP.@)
600 DWORD WINAPI SymGetOptions(void)
602 return dbghelp_options;
605 /******************************************************************
606 * SymSetExtendedOption (DBGHELP.@)
609 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
611 BOOL old = FALSE;
613 switch(option)
615 case SYMOPT_EX_WINE_NATIVE_MODULES:
616 old = dbghelp_opt_native;
617 dbghelp_opt_native = value;
618 break;
619 case SYMOPT_EX_WINE_MODULE_REAL_PATH:
620 old = dbghelp_opt_real_path;
621 dbghelp_opt_real_path = value;
622 break;
623 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH:
624 old = dbghelp_opt_source_actual_path;
625 dbghelp_opt_source_actual_path = value;
626 break;
627 default:
628 FIXME("Unsupported option %d with value %d\n", option, value);
631 return old;
634 /******************************************************************
635 * SymGetExtendedOption (DBGHELP.@)
638 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
640 switch(option)
642 case SYMOPT_EX_WINE_NATIVE_MODULES:
643 return dbghelp_opt_native;
644 case SYMOPT_EX_WINE_MODULE_REAL_PATH:
645 return dbghelp_opt_real_path;
646 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH:
647 return dbghelp_opt_source_actual_path;
648 default:
649 FIXME("Unsupported option %d\n", option);
652 return FALSE;
655 /******************************************************************
656 * SymSetParentWindow (DBGHELP.@)
659 BOOL WINAPI SymSetParentWindow(HWND hwnd)
661 /* Save hwnd so it can be used as parent window */
662 FIXME("(%p): stub\n", hwnd);
663 return TRUE;
666 /******************************************************************
667 * SymSetContext (DBGHELP.@)
670 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
671 PIMAGEHLP_CONTEXT Context)
673 struct process* pcs;
675 TRACE("(%p %p %p)\n", hProcess, StackFrame, Context);
677 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
678 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
679 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
680 pcs->ctx_frame.StackOffset == StackFrame->StackOffset &&
681 pcs->ctx_frame.InstructionOffset == StackFrame->InstructionOffset)
683 TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n",
684 pcs->ctx_frame.ReturnOffset,
685 pcs->ctx_frame.FrameOffset,
686 pcs->ctx_frame.StackOffset);
687 SetLastError(ERROR_SUCCESS);
688 return FALSE;
691 if (!SymSetScopeFromAddr(hProcess, StackFrame->InstructionOffset))
692 return FALSE;
693 pcs->ctx_frame = *StackFrame;
694 /* Context is not (no longer?) used */
696 return TRUE;
699 /******************************************************************
700 * SymSetScopeFromAddr (DBGHELP.@)
702 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr)
704 struct module_pair pair;
705 struct symt_ht* sym;
707 TRACE("(%p %#I64x)\n", hProcess, addr);
709 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
710 pair.pcs->localscope_pc = addr;
711 if ((sym = symt_find_symbol_at(pair.effective, addr)) != NULL && sym->symt.tag == SymTagFunction)
712 pair.pcs->localscope_symt = &sym->symt;
713 else
714 pair.pcs->localscope_symt = NULL;
716 return TRUE;
719 /******************************************************************
720 * SymSetScopeFromIndex (DBGHELP.@)
722 BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index)
724 struct module_pair pair;
725 struct symt* sym;
727 TRACE("(%p %#I64x %lu)\n", hProcess, addr, index);
729 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
730 sym = symt_index2ptr(pair.effective, index);
731 if (!symt_check_tag(sym, SymTagFunction)) return FALSE;
733 pair.pcs->localscope_pc = ((struct symt_function*)sym)->ranges[0].low; /* FIXME of FuncDebugStart when it exists? */
734 pair.pcs->localscope_symt = sym;
736 return TRUE;
739 /******************************************************************
740 * SymSetScopeFromInlineContext (DBGHELP.@)
742 BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx)
744 struct module_pair pair;
745 struct symt_function* inlined;
747 TRACE("(%p %I64x %lx)\n", hProcess, addr, inlinectx);
749 switch (IFC_MODE(inlinectx))
751 case IFC_MODE_INLINE:
752 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
753 inlined = symt_find_inlined_site(pair.effective, addr, inlinectx);
754 if (inlined)
756 pair.pcs->localscope_pc = addr;
757 pair.pcs->localscope_symt = &inlined->symt;
758 return TRUE;
760 /* fall through */
761 case IFC_MODE_IGNORE:
762 case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr);
763 default:
764 SetLastError(ERROR_INVALID_PARAMETER);
765 return FALSE;
769 /******************************************************************
770 * reg_cb64to32 (internal)
772 * Registered callback for converting information from 64 bit to 32 bit
774 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
776 struct process* pcs = process_find_by_handle(hProcess);
777 void* data32;
778 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
779 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
781 if (!pcs) return FALSE;
782 switch (action)
784 case CBA_DEBUG_INFO:
785 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
786 case CBA_SET_OPTIONS:
787 case CBA_SYMBOLS_UNLOADED:
788 data32 = (void*)(DWORD_PTR)data;
789 break;
790 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
791 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
792 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
793 case CBA_DEFERRED_SYMBOL_LOAD_START:
794 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
795 if (!validate_addr64(idsl64->BaseOfImage))
796 return FALSE;
797 idsl.SizeOfStruct = sizeof(idsl);
798 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
799 idsl.CheckSum = idsl64->CheckSum;
800 idsl.TimeDateStamp = idsl64->TimeDateStamp;
801 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
802 idsl.Reparse = idsl64->Reparse;
803 data32 = &idsl;
804 break;
805 case CBA_DUPLICATE_SYMBOL:
806 case CBA_EVENT:
807 case CBA_READ_MEMORY:
808 default:
809 FIXME("No mapping for action %lu\n", action);
810 return FALSE;
812 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
815 /******************************************************************
816 * pcs_callback (internal)
818 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
820 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
822 TRACE("%p %lu %p\n", pcs, action, data);
824 if (!pcs->reg_cb) return FALSE;
825 if (!pcs->reg_is_unicode)
827 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
829 switch (action)
831 case CBA_DEBUG_INFO:
832 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
833 case CBA_SET_OPTIONS:
834 case CBA_SYMBOLS_UNLOADED:
835 break;
836 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
837 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
838 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
839 case CBA_DEFERRED_SYMBOL_LOAD_START:
840 idslW = data;
841 idsl.SizeOfStruct = sizeof(idsl);
842 idsl.BaseOfImage = idslW->BaseOfImage;
843 idsl.CheckSum = idslW->CheckSum;
844 idsl.TimeDateStamp = idslW->TimeDateStamp;
845 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
846 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
847 idsl.Reparse = idslW->Reparse;
848 data = &idsl;
849 break;
850 case CBA_DUPLICATE_SYMBOL:
851 case CBA_EVENT:
852 case CBA_READ_MEMORY:
853 default:
854 FIXME("No mapping for action %lu\n", action);
855 return FALSE;
858 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
861 /******************************************************************
862 * sym_register_cb
864 * Helper for registering a callback.
866 static BOOL sym_register_cb(HANDLE hProcess,
867 PSYMBOL_REGISTERED_CALLBACK64 cb,
868 PSYMBOL_REGISTERED_CALLBACK cb32,
869 DWORD64 user, BOOL unicode)
871 struct process* pcs = process_find_by_handle(hProcess);
873 if (!pcs) return FALSE;
874 pcs->reg_cb = cb;
875 pcs->reg_cb32 = cb32;
876 pcs->reg_is_unicode = unicode;
877 pcs->reg_user = user;
879 return TRUE;
882 /***********************************************************************
883 * SymRegisterCallback (DBGHELP.@)
885 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
886 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
887 PVOID UserContext)
889 TRACE("(%p, %p, %p)\n",
890 hProcess, CallbackFunction, UserContext);
891 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
894 /***********************************************************************
895 * SymRegisterCallback64 (DBGHELP.@)
897 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
898 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
899 ULONG64 UserContext)
901 TRACE("(%p, %p, %I64x)\n", hProcess, CallbackFunction, UserContext);
902 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
905 /***********************************************************************
906 * SymRegisterCallbackW64 (DBGHELP.@)
908 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
909 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
910 ULONG64 UserContext)
912 TRACE("(%p, %p, %I64x)\n", hProcess, CallbackFunction, UserContext);
913 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
916 /* This is imagehlp version not dbghelp !! */
917 static API_VERSION api_version = { 4, 0, 2, 0 };
919 /***********************************************************************
920 * ImagehlpApiVersion (DBGHELP.@)
922 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
924 return &api_version;
927 /***********************************************************************
928 * ImagehlpApiVersionEx (DBGHELP.@)
930 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
932 if (!AppVersion) return NULL;
934 AppVersion->MajorVersion = api_version.MajorVersion;
935 AppVersion->MinorVersion = api_version.MinorVersion;
936 AppVersion->Revision = api_version.Revision;
937 AppVersion->Reserved = api_version.Reserved;
939 return AppVersion;
942 /******************************************************************
943 * ExtensionApiVersion (DBGHELP.@)
945 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
947 static EXT_API_VERSION eav = {5, 5, 5, 0};
948 return &eav;
951 /******************************************************************
952 * WinDbgExtensionDllInit (DBGHELP.@)
954 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
955 unsigned short major, unsigned short minor)
959 DWORD calc_crc32(HANDLE handle)
961 BYTE buffer[8192];
962 DWORD crc = 0;
963 DWORD len;
965 SetFilePointer(handle, 0, 0, FILE_BEGIN);
966 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len)
967 crc = RtlComputeCrc32(crc, buffer, len);
968 return crc;