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
23 #include "dbghelp_private.h"
27 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp
);
34 * - support for symbols' types is still partly missing
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
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
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
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)
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
68 unsigned dbghelp_options
= SYMOPT_UNDNAME
;
69 BOOL dbghelp_opt_native
= FALSE
;
70 BOOL dbghelp_opt_extension_api
= FALSE
;
71 BOOL dbghelp_opt_real_path
= FALSE
;
72 BOOL dbghelp_opt_source_actual_path
= FALSE
;
75 static struct process
* process_first
/* = NULL */;
77 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
81 case DLL_PROCESS_ATTACH
:
82 GetSystemInfo(&sysinfo
);
83 DisableThreadLibraryCalls(instance
);
89 /******************************************************************
90 * process_find_by_handle
93 struct process
* process_find_by_handle(HANDLE hProcess
)
97 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
98 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
102 /******************************************************************
103 * validate_addr64 (internal)
106 BOOL
validate_addr64(DWORD64 addr
)
108 if (sizeof(void*) == sizeof(int) && (addr
>> 32))
110 FIXME("Unsupported address %I64x\n", addr
);
111 SetLastError(ERROR_INVALID_PARAMETER
);
117 /******************************************************************
120 * Ensures process' internal buffer is large enough.
122 void* fetch_buffer(struct process
* pcs
, unsigned size
)
124 if (size
> pcs
->buffer_size
)
127 pcs
->buffer
= HeapReAlloc(GetProcessHeap(), 0, pcs
->buffer
, size
);
129 pcs
->buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
130 pcs
->buffer_size
= (pcs
->buffer
) ? size
: 0;
135 const char* wine_dbgstr_addr(const ADDRESS64
* addr
)
137 if (!addr
) return "(null)";
141 return wine_dbg_sprintf("flat<%I64x>", addr
->Offset
);
143 return wine_dbg_sprintf("1616<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
145 return wine_dbg_sprintf("1632<%04x:%08lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
147 return wine_dbg_sprintf("real<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
153 extern struct cpu cpu_i386
, cpu_x86_64
, cpu_arm
, cpu_arm64
;
155 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, &cpu_x86_64
, &cpu_arm
, &cpu_arm64
, NULL
};
156 struct cpu
* dbghelp_current_cpu
=
157 #if defined(__i386__)
159 #elif defined(__x86_64__)
161 #elif defined(__arm__)
163 #elif defined(__aarch64__)
166 #error define support for your CPU
170 struct cpu
* cpu_find(DWORD machine
)
174 for (cpu
= dbghelp_cpus
; *cpu
; cpu
++)
176 if (cpu
[0]->machine
== machine
) return cpu
[0];
181 static WCHAR
* make_default_search_path(void)
185 unsigned sym_path_len
;
186 unsigned alt_sym_path_len
;
188 sym_path_len
= GetEnvironmentVariableW(L
"_NT_SYMBOL_PATH", NULL
, 0);
189 alt_sym_path_len
= GetEnvironmentVariableW(L
"_NT_ALT_SYMBOL_PATH", NULL
, 0);
191 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
192 * If the variables exist, the lengths include a null-terminator. We use that
193 * space for the semicolons, and only add the initial dot and the final null. */
194 search_path
= HeapAlloc(GetProcessHeap(), 0,
195 (1 + sym_path_len
+ alt_sym_path_len
+ 1) * sizeof(WCHAR
));
196 if (!search_path
) return NULL
;
203 GetEnvironmentVariableW(L
"_NT_SYMBOL_PATH", p
, sym_path_len
);
204 p
+= sym_path_len
- 1;
207 if (alt_sym_path_len
)
210 GetEnvironmentVariableW(L
"_NT_ALT_SYMBOL_PATH", p
, alt_sym_path_len
);
211 p
+= alt_sym_path_len
- 1;
218 /******************************************************************
219 * SymSetSearchPathW (DBGHELP.@)
222 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
224 struct process
* pcs
= process_find_by_handle(hProcess
);
225 WCHAR
* search_path_buffer
;
227 if (!pcs
) return FALSE
;
231 search_path_buffer
= HeapAlloc(GetProcessHeap(), 0,
232 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
));
233 if (!search_path_buffer
) return FALSE
;
234 lstrcpyW(search_path_buffer
, searchPath
);
238 search_path_buffer
= make_default_search_path();
239 if (!search_path_buffer
) return FALSE
;
241 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
242 pcs
->search_path
= search_path_buffer
;
246 /******************************************************************
247 * SymSetSearchPath (DBGHELP.@)
250 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
258 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
259 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
260 if (!sp
) return FALSE
;
261 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
264 ret
= SymSetSearchPathW(hProcess
, sp
);
266 HeapFree(GetProcessHeap(), 0, sp
);
270 /***********************************************************************
271 * SymGetSearchPathW (DBGHELP.@)
273 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
274 DWORD SearchPathLength
)
276 struct process
* pcs
= process_find_by_handle(hProcess
);
277 if (!pcs
) return FALSE
;
279 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
283 /***********************************************************************
284 * SymGetSearchPath (DBGHELP.@)
286 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
287 DWORD SearchPathLength
)
289 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
294 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
296 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
297 szSearchPath
, SearchPathLength
, NULL
, NULL
);
298 HeapFree(GetProcessHeap(), 0, buffer
);
303 /******************************************************************
306 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
307 * this assumes that hProcess is a handle on a valid process
309 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
311 HANDLE hProcess
= user
;
313 SymLoadModuleExW(hProcess
, 0, name
, NULL
, base
, size
, NULL
, 0);
317 const WCHAR
*process_getenv(const struct process
*process
, const WCHAR
*name
)
322 if (!process
->environment
) return NULL
;
323 name_len
= lstrlenW(name
);
325 for (iter
= process
->environment
; *iter
; iter
+= lstrlenW(iter
) + 1)
327 if (!wcsnicmp(iter
, name
, name_len
) && iter
[name_len
] == '=')
328 return iter
+ name_len
+ 1;
334 const struct cpu
* process_get_cpu(const struct process
* pcs
)
336 const struct module
* m
= pcs
->lmodules
;
338 /* return cpu of main module, which is the first module in process's modules list */
339 return (m
) ? m
->cpu
: dbghelp_current_cpu
;
342 /******************************************************************
346 static BOOL
check_live_target(struct process
* pcs
, BOOL wow64
, BOOL child_wow64
)
348 PROCESS_BASIC_INFORMATION pbi
;
349 DWORD64 base
= 0, env
= 0;
350 const char* peb_addr
;
352 if (!GetProcessId(pcs
->handle
)) return FALSE
;
353 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
355 if (NtQueryInformationProcess( pcs
->handle
, ProcessBasicInformation
,
356 &pbi
, sizeof(pbi
), NULL
))
359 /* Note: we have to deal with the PEB64 and PEB32 in debuggee process
360 * while debugger can be in same or different bitness.
361 * For a 64 bit debuggee, use PEB64 and underlying ELF/system 64 (easy).
362 * For a 32 bit debuggee,
363 * - for environment variables, we need PEB32
364 * - for ELF/system base address, we need PEB32 when run in pure 32bit
365 * or run in old wow configuration, but PEB64 when run in new wow
367 * - this must be read from a debugger in either 32 or 64 bit setup.
369 peb_addr
= (const char*)pbi
.PebBaseAddress
;
375 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
) == 0x48);
377 if (!wow64
&& child_wow64
)
378 /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */
380 if (!ReadProcessMemory(pcs
->handle
, peb_addr
, &peb32
, sizeof(peb32
), NULL
)) return FALSE
;
381 base
= *(const DWORD
*)((const char*)&peb32
+ 0x460 /* CloudFileFlags */);
382 pcs
->is_host_64bit
= FALSE
;
383 if (read_process_memory(pcs
, peb32
.ProcessParameters
+ 0x48, &env32
, sizeof(env32
))) env
= env32
;
385 if (pcs
->is_64bit
|| base
== 0)
389 if (!pcs
->is_64bit
) peb_addr
-= 0x1000; /* PEB32 => PEB64 */
390 if (!ReadProcessMemory(pcs
->handle
, peb_addr
, &peb
, sizeof(peb
), NULL
)) return FALSE
;
391 base
= *(const DWORD64
*)&peb
.CloudFileFlags
;
392 pcs
->is_host_64bit
= TRUE
;
394 ReadProcessMemory(pcs
->handle
,
395 (char *)(ULONG_PTR
)peb
.ProcessParameters
+ FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
),
396 &env
, sizeof(env
), NULL
);
399 /* read debuggee environment block */
402 size_t buf_size
= 0, i
, last_null
= -1;
408 size_t read_size
= sysinfo
.dwPageSize
- (env
& (sysinfo
.dwPageSize
- 1));
409 if (!(new_buf
= realloc(buf
, buf_size
+ read_size
))) break;
412 if (!read_process_memory(pcs
, env
, (char*)buf
+ buf_size
, read_size
)) break;
413 for (i
= buf_size
/ sizeof(WCHAR
); i
< (buf_size
+ read_size
) / sizeof(WCHAR
); i
++)
415 if (buf
[i
]) continue;
416 if (last_null
+ 1 == i
)
418 pcs
->environment
= realloc(buf
, (i
+ 1) * sizeof(WCHAR
));
425 buf_size
+= read_size
;
431 if (!base
) return FALSE
;
433 TRACE("got debug info address %#I64x from PEB %p\n", base
, pbi
.PebBaseAddress
);
434 if (!elf_read_wine_loader_dbg_info(pcs
, base
) && !macho_read_wine_loader_dbg_info(pcs
, base
))
435 WARN("couldn't load process debug info at %#I64x\n", base
);
439 /******************************************************************
440 * SymInitializeW (DBGHELP.@)
442 * The initialisation of a dbghelp's context.
443 * Note that hProcess doesn't need to be a valid process handle (except
444 * when fInvadeProcess is TRUE).
445 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
446 * containing PE (and NE) module(s), here's how we handle it:
447 * - we load every module (ELF, NE, PE) passed in SymLoadModule
448 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
449 * synchronization: hProcess should be a valid process handle, and we hook
450 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
451 * our internal ELF modules representation (loading / unloading). This way,
452 * we'll pair every loaded builtin PE module with its ELF counterpart (and
453 * access its debug information).
454 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
455 * hProcess refers to a running process. We use some heuristics here, so YMMV.
456 * If we detect a live target, then we get the same handling as if
457 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
458 * we won't be able to make the peering between a builtin PE module and its ELF
459 * counterpart. Hence we won't be able to provide the requested debug
460 * information. We'll however be able to load native PE modules (and their
461 * debug information) without any trouble.
462 * Note also that this scheme can be intertwined with the deferred loading
463 * mechanism (ie only load the debug information when we actually need it).
465 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
468 BOOL wow64
, child_wow64
;
470 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
472 if (process_find_by_handle(hProcess
))
474 WARN("the symbols for this process have already been initialized!\n");
476 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
477 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
478 Native still returns TRUE even if the process has already been initialized. */
482 IsWow64Process(GetCurrentProcess(), &wow64
);
484 if (GetProcessId(hProcess
) && !IsWow64Process(hProcess
, &child_wow64
))
487 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
488 if (!pcs
) return FALSE
;
490 pcs
->handle
= hProcess
;
491 pcs
->is_64bit
= (sizeof(void *) == 8 || wow64
) && !child_wow64
;
492 pcs
->loader
= &no_loader_ops
; /* platform-specific initialization will override it if loader debug info can be found */
496 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
497 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
502 pcs
->search_path
= make_default_search_path();
505 pcs
->lmodules
= NULL
;
506 pcs
->dbg_hdr_addr
= 0;
507 pcs
->next
= process_first
;
510 if (check_live_target(pcs
, wow64
, child_wow64
))
513 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
514 if (pcs
->loader
) pcs
->loader
->synchronize_module_list(pcs
);
516 else if (fInvadeProcess
)
518 SymCleanup(hProcess
);
519 SetLastError(ERROR_INVALID_PARAMETER
);
526 /******************************************************************
527 * SymInitialize (DBGHELP.@)
531 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
540 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
541 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
542 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
545 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
546 HeapFree(GetProcessHeap(), 0, sp
);
550 /******************************************************************
551 * SymCleanup (DBGHELP.@)
554 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
556 struct process
** ppcs
;
557 struct process
* next
;
559 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
561 if ((*ppcs
)->handle
== hProcess
)
563 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
565 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
566 free((*ppcs
)->environment
);
567 next
= (*ppcs
)->next
;
568 HeapFree(GetProcessHeap(), 0, *ppcs
);
574 ERR("this process has not had SymInitialize() called for it!\n");
578 /******************************************************************
579 * SymSetOptions (DBGHELP.@)
582 DWORD WINAPI
SymSetOptions(DWORD opts
)
586 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
588 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
590 return dbghelp_options
= opts
;
593 /******************************************************************
594 * SymGetOptions (DBGHELP.@)
597 DWORD WINAPI
SymGetOptions(void)
599 return dbghelp_options
;
602 /******************************************************************
603 * SymSetExtendedOption (DBGHELP.@)
606 BOOL WINAPI
SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
, BOOL value
)
612 case SYMOPT_EX_WINE_NATIVE_MODULES
:
613 old
= dbghelp_opt_native
;
614 dbghelp_opt_native
= value
;
616 case SYMOPT_EX_WINE_EXTENSION_API
:
617 old
= dbghelp_opt_extension_api
;
618 dbghelp_opt_extension_api
= value
;
620 case SYMOPT_EX_WINE_MODULE_REAL_PATH
:
621 old
= dbghelp_opt_real_path
;
622 dbghelp_opt_real_path
= value
;
624 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH
:
625 old
= dbghelp_opt_source_actual_path
;
626 dbghelp_opt_source_actual_path
= value
;
629 FIXME("Unsupported option %d with value %d\n", option
, value
);
635 /******************************************************************
636 * SymGetExtendedOption (DBGHELP.@)
639 BOOL WINAPI
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
)
643 case SYMOPT_EX_WINE_NATIVE_MODULES
:
644 return dbghelp_opt_native
;
645 case SYMOPT_EX_WINE_EXTENSION_API
:
646 return dbghelp_opt_extension_api
;
647 case SYMOPT_EX_WINE_MODULE_REAL_PATH
:
648 return dbghelp_opt_real_path
;
649 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH
:
650 return dbghelp_opt_source_actual_path
;
652 FIXME("Unsupported option %d\n", option
);
658 /******************************************************************
659 * SymSetParentWindow (DBGHELP.@)
662 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
664 /* Save hwnd so it can be used as parent window */
665 FIXME("(%p): stub\n", hwnd
);
669 /******************************************************************
670 * SymSetContext (DBGHELP.@)
673 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
674 PIMAGEHLP_CONTEXT Context
)
678 TRACE("(%p %p %p)\n", hProcess
, StackFrame
, Context
);
680 if (!(pcs
= process_find_by_handle(hProcess
))) return FALSE
;
681 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
682 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
683 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
&&
684 pcs
->ctx_frame
.InstructionOffset
== StackFrame
->InstructionOffset
)
686 TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n",
687 pcs
->ctx_frame
.ReturnOffset
,
688 pcs
->ctx_frame
.FrameOffset
,
689 pcs
->ctx_frame
.StackOffset
);
690 SetLastError(ERROR_SUCCESS
);
694 if (!SymSetScopeFromAddr(hProcess
, StackFrame
->InstructionOffset
))
696 pcs
->ctx_frame
= *StackFrame
;
697 /* Context is not (no longer?) used */
702 /******************************************************************
703 * SymSetScopeFromAddr (DBGHELP.@)
705 BOOL WINAPI
SymSetScopeFromAddr(HANDLE hProcess
, ULONG64 addr
)
707 struct module_pair pair
;
710 TRACE("(%p %#I64x)\n", hProcess
, addr
);
712 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
713 pair
.pcs
->localscope_pc
= addr
;
714 if ((sym
= symt_find_symbol_at(pair
.effective
, addr
)) != NULL
&& sym
->symt
.tag
== SymTagFunction
)
715 pair
.pcs
->localscope_symt
= &sym
->symt
;
717 pair
.pcs
->localscope_symt
= NULL
;
722 /******************************************************************
723 * SymSetScopeFromIndex (DBGHELP.@)
725 BOOL WINAPI
SymSetScopeFromIndex(HANDLE hProcess
, ULONG64 addr
, DWORD index
)
727 struct module_pair pair
;
730 TRACE("(%p %#I64x %lu)\n", hProcess
, addr
, index
);
732 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
733 sym
= symt_index2ptr(pair
.effective
, index
);
734 if (!symt_check_tag(sym
, SymTagFunction
)) return FALSE
;
736 pair
.pcs
->localscope_pc
= ((struct symt_function
*)sym
)->ranges
[0].low
; /* FIXME of FuncDebugStart when it exists? */
737 pair
.pcs
->localscope_symt
= sym
;
742 /******************************************************************
743 * SymSetScopeFromInlineContext (DBGHELP.@)
745 BOOL WINAPI
SymSetScopeFromInlineContext(HANDLE hProcess
, ULONG64 addr
, DWORD inlinectx
)
747 struct module_pair pair
;
748 struct symt_function
* inlined
;
750 TRACE("(%p %I64x %lx)\n", hProcess
, addr
, inlinectx
);
752 switch (IFC_MODE(inlinectx
))
754 case IFC_MODE_INLINE
:
755 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
756 inlined
= symt_find_inlined_site(pair
.effective
, addr
, inlinectx
);
759 pair
.pcs
->localscope_pc
= addr
;
760 pair
.pcs
->localscope_symt
= &inlined
->symt
;
764 case IFC_MODE_IGNORE
:
765 case IFC_MODE_REGULAR
: return SymSetScopeFromAddr(hProcess
, addr
);
767 SetLastError(ERROR_INVALID_PARAMETER
);
772 /******************************************************************
773 * reg_cb64to32 (internal)
775 * Registered callback for converting information from 64 bit to 32 bit
777 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
779 struct process
* pcs
= process_find_by_handle(hProcess
);
781 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
782 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
784 if (!pcs
) return FALSE
;
788 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
789 case CBA_SET_OPTIONS
:
790 case CBA_SYMBOLS_UNLOADED
:
791 data32
= (void*)(DWORD_PTR
)data
;
793 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
794 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
795 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
796 case CBA_DEFERRED_SYMBOL_LOAD_START
:
797 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
798 if (!validate_addr64(idsl64
->BaseOfImage
))
800 idsl
.SizeOfStruct
= sizeof(idsl
);
801 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
802 idsl
.CheckSum
= idsl64
->CheckSum
;
803 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
804 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
805 idsl
.Reparse
= idsl64
->Reparse
;
808 case CBA_DUPLICATE_SYMBOL
:
810 case CBA_READ_MEMORY
:
812 FIXME("No mapping for action %lu\n", action
);
815 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
818 /******************************************************************
819 * pcs_callback (internal)
821 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
823 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
825 TRACE("%p %lu %p\n", pcs
, action
, data
);
827 if (!pcs
->reg_cb
) return FALSE
;
828 if (!pcs
->reg_is_unicode
)
830 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
835 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
836 case CBA_SET_OPTIONS
:
837 case CBA_SYMBOLS_UNLOADED
:
839 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
840 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
841 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
842 case CBA_DEFERRED_SYMBOL_LOAD_START
:
844 idsl
.SizeOfStruct
= sizeof(idsl
);
845 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
846 idsl
.CheckSum
= idslW
->CheckSum
;
847 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
848 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
849 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
850 idsl
.Reparse
= idslW
->Reparse
;
853 case CBA_DUPLICATE_SYMBOL
:
855 case CBA_READ_MEMORY
:
857 FIXME("No mapping for action %lu\n", action
);
861 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
864 /******************************************************************
867 * Helper for registering a callback.
869 static BOOL
sym_register_cb(HANDLE hProcess
,
870 PSYMBOL_REGISTERED_CALLBACK64 cb
,
871 PSYMBOL_REGISTERED_CALLBACK cb32
,
872 DWORD64 user
, BOOL unicode
)
874 struct process
* pcs
= process_find_by_handle(hProcess
);
876 if (!pcs
) return FALSE
;
878 pcs
->reg_cb32
= cb32
;
879 pcs
->reg_is_unicode
= unicode
;
880 pcs
->reg_user
= user
;
885 /***********************************************************************
886 * SymRegisterCallback (DBGHELP.@)
888 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
889 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
892 TRACE("(%p, %p, %p)\n",
893 hProcess
, CallbackFunction
, UserContext
);
894 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
897 /***********************************************************************
898 * SymRegisterCallback64 (DBGHELP.@)
900 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
901 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
904 TRACE("(%p, %p, %I64x)\n", hProcess
, CallbackFunction
, UserContext
);
905 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
908 /***********************************************************************
909 * SymRegisterCallbackW64 (DBGHELP.@)
911 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
912 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
915 TRACE("(%p, %p, %I64x)\n", hProcess
, CallbackFunction
, UserContext
);
916 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
919 /* This is imagehlp version not dbghelp !! */
920 static API_VERSION api_version
= { 4, 0, 2, 0 };
922 /***********************************************************************
923 * ImagehlpApiVersion (DBGHELP.@)
925 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
930 /***********************************************************************
931 * ImagehlpApiVersionEx (DBGHELP.@)
933 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
935 if (!AppVersion
) return NULL
;
937 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
938 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
939 AppVersion
->Revision
= api_version
.Revision
;
940 AppVersion
->Reserved
= api_version
.Reserved
;
945 /******************************************************************
946 * ExtensionApiVersion (DBGHELP.@)
948 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
950 static EXT_API_VERSION eav
= {5, 5, 5, 0};
954 /******************************************************************
955 * WinDbgExtensionDllInit (DBGHELP.@)
957 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
958 unsigned short major
, unsigned short minor
)
962 DWORD
calc_crc32(HANDLE handle
)
968 SetFilePointer(handle
, 0, 0, FILE_BEGIN
);
969 while (ReadFile(handle
, buffer
, sizeof(buffer
), &len
, NULL
) && len
)
970 crc
= RtlComputeCrc32(crc
, buffer
, len
);