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_real_path
= FALSE
;
71 BOOL dbghelp_opt_source_actual_path
= FALSE
;
74 static struct process
* process_first
/* = NULL */;
76 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
80 case DLL_PROCESS_ATTACH
:
81 GetSystemInfo(&sysinfo
);
82 DisableThreadLibraryCalls(instance
);
88 /******************************************************************
89 * process_find_by_handle
92 struct process
* process_find_by_handle(HANDLE hProcess
)
96 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
97 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
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
);
116 /******************************************************************
119 * Ensures process' internal buffer is large enough.
121 void* fetch_buffer(struct process
* pcs
, unsigned size
)
123 if (size
> pcs
->buffer_size
)
126 pcs
->buffer
= HeapReAlloc(GetProcessHeap(), 0, pcs
->buffer
, size
);
128 pcs
->buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
129 pcs
->buffer_size
= (pcs
->buffer
) ? size
: 0;
134 const char* wine_dbgstr_addr(const ADDRESS64
* addr
)
136 if (!addr
) return "(null)";
140 return wine_dbg_sprintf("flat<%I64x>", addr
->Offset
);
142 return wine_dbg_sprintf("1616<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
144 return wine_dbg_sprintf("1632<%04x:%08lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
146 return wine_dbg_sprintf("real<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
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__)
158 #elif defined(__x86_64__)
160 #elif defined(__arm__)
162 #elif defined(__aarch64__)
165 #error define support for your CPU
169 struct cpu
* cpu_find(DWORD machine
)
173 for (cpu
= dbghelp_cpus
; *cpu
; cpu
++)
175 if (cpu
[0]->machine
== machine
) return cpu
[0];
180 static WCHAR
* make_default_search_path(void)
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
;
202 GetEnvironmentVariableW(L
"_NT_SYMBOL_PATH", p
, sym_path_len
);
203 p
+= sym_path_len
- 1;
206 if (alt_sym_path_len
)
209 GetEnvironmentVariableW(L
"_NT_ALT_SYMBOL_PATH", p
, alt_sym_path_len
);
210 p
+= alt_sym_path_len
- 1;
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
;
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
);
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
;
245 /******************************************************************
246 * SymSetSearchPath (DBGHELP.@)
249 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR 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
);
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
);
282 /***********************************************************************
283 * SymGetSearchPath (DBGHELP.@)
285 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
286 DWORD SearchPathLength
)
288 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
293 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
295 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
296 szSearchPath
, SearchPathLength
, NULL
, NULL
);
297 HeapFree(GetProcessHeap(), 0, buffer
);
302 /******************************************************************
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);
316 const WCHAR
*process_getenv(const struct process
*process
, const WCHAR
*name
)
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;
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 /******************************************************************
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
))
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
366 * - this must be read from a debugger in either 32 or 64 bit setup.
368 peb_addr
= (const char*)pbi
.PebBaseAddress
;
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 */
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)
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
;
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 */
401 size_t buf_size
= 0, i
, last_null
= -1;
406 size_t read_size
= sysinfo
.dwAllocationGranularity
- (env
& (sysinfo
.dwAllocationGranularity
- 1));
410 if (!(new_buf
= realloc(buf
, buf_size
+ read_size
))) break;
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
));
428 buf_size
+= read_size
;
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
);
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
)
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. */
485 IsWow64Process(GetCurrentProcess(), &wow64
);
487 if (GetProcessId(hProcess
) && !IsWow64Process(hProcess
, &child_wow64
))
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 */
499 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
500 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
505 pcs
->search_path
= make_default_search_path();
508 pcs
->lmodules
= NULL
;
509 pcs
->dbg_hdr_addr
= 0;
510 pcs
->next
= process_first
;
513 if (check_live_target(pcs
, wow64
, child_wow64
))
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
);
529 /******************************************************************
530 * SymInitialize (DBGHELP.@)
534 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
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
);
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
);
577 ERR("this process has not had SymInitialize() called for it!\n");
581 /******************************************************************
582 * SymSetOptions (DBGHELP.@)
585 DWORD WINAPI
SymSetOptions(DWORD opts
)
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
)
615 case SYMOPT_EX_WINE_NATIVE_MODULES
:
616 old
= dbghelp_opt_native
;
617 dbghelp_opt_native
= value
;
619 case SYMOPT_EX_WINE_MODULE_REAL_PATH
:
620 old
= dbghelp_opt_real_path
;
621 dbghelp_opt_real_path
= value
;
623 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH
:
624 old
= dbghelp_opt_source_actual_path
;
625 dbghelp_opt_source_actual_path
= value
;
628 FIXME("Unsupported option %d with value %d\n", option
, value
);
634 /******************************************************************
635 * SymGetExtendedOption (DBGHELP.@)
638 BOOL WINAPI
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS 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
;
649 FIXME("Unsupported option %d\n", option
);
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
);
666 /******************************************************************
667 * SymSetContext (DBGHELP.@)
670 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
671 PIMAGEHLP_CONTEXT Context
)
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
);
691 if (!SymSetScopeFromAddr(hProcess
, StackFrame
->InstructionOffset
))
693 pcs
->ctx_frame
= *StackFrame
;
694 /* Context is not (no longer?) used */
699 /******************************************************************
700 * SymSetScopeFromAddr (DBGHELP.@)
702 BOOL WINAPI
SymSetScopeFromAddr(HANDLE hProcess
, ULONG64 addr
)
704 struct module_pair pair
;
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
;
714 pair
.pcs
->localscope_symt
= NULL
;
719 /******************************************************************
720 * SymSetScopeFromIndex (DBGHELP.@)
722 BOOL WINAPI
SymSetScopeFromIndex(HANDLE hProcess
, ULONG64 addr
, DWORD index
)
724 struct module_pair pair
;
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
;
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
);
756 pair
.pcs
->localscope_pc
= addr
;
757 pair
.pcs
->localscope_symt
= &inlined
->symt
;
761 case IFC_MODE_IGNORE
:
762 case IFC_MODE_REGULAR
: return SymSetScopeFromAddr(hProcess
, addr
);
764 SetLastError(ERROR_INVALID_PARAMETER
);
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
);
778 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
779 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
781 if (!pcs
) return FALSE
;
785 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
786 case CBA_SET_OPTIONS
:
787 case CBA_SYMBOLS_UNLOADED
:
788 data32
= (void*)(DWORD_PTR
)data
;
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
))
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
;
805 case CBA_DUPLICATE_SYMBOL
:
807 case CBA_READ_MEMORY
:
809 FIXME("No mapping for action %lu\n", action
);
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
;
832 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
833 case CBA_SET_OPTIONS
:
834 case CBA_SYMBOLS_UNLOADED
:
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
:
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
;
850 case CBA_DUPLICATE_SYMBOL
:
852 case CBA_READ_MEMORY
:
854 FIXME("No mapping for action %lu\n", action
);
858 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
861 /******************************************************************
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
;
875 pcs
->reg_cb32
= cb32
;
876 pcs
->reg_is_unicode
= unicode
;
877 pcs
->reg_user
= user
;
882 /***********************************************************************
883 * SymRegisterCallback (DBGHELP.@)
885 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
886 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
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
,
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
,
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
)
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
;
942 /******************************************************************
943 * ExtensionApiVersion (DBGHELP.@)
945 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
947 static EXT_API_VERSION eav
= {5, 5, 5, 0};
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
)
965 SetFilePointer(handle
, 0, 0, FILE_BEGIN
);
966 while (ReadFile(handle
, buffer
, sizeof(buffer
), &len
, NULL
) && len
)
967 crc
= RtlComputeCrc32(crc
, buffer
, len
);