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
;
72 static struct process
* process_first
/* = NULL */;
74 BOOL WINAPI
DllMain(HINSTANCE instance
, DWORD reason
, LPVOID reserved
)
78 case DLL_PROCESS_ATTACH
:
79 GetSystemInfo(&sysinfo
);
80 DisableThreadLibraryCalls(instance
);
86 /******************************************************************
87 * process_find_by_handle
90 struct process
* process_find_by_handle(HANDLE hProcess
)
94 for (p
= process_first
; p
&& p
->handle
!= hProcess
; p
= p
->next
);
95 if (!p
) SetLastError(ERROR_INVALID_HANDLE
);
99 /******************************************************************
100 * validate_addr64 (internal)
103 BOOL
validate_addr64(DWORD64 addr
)
105 if (sizeof(void*) == sizeof(int) && (addr
>> 32))
107 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr
));
108 SetLastError(ERROR_INVALID_PARAMETER
);
114 /******************************************************************
117 * Ensures process' internal buffer is large enough.
119 void* fetch_buffer(struct process
* pcs
, unsigned size
)
121 if (size
> pcs
->buffer_size
)
124 pcs
->buffer
= HeapReAlloc(GetProcessHeap(), 0, pcs
->buffer
, size
);
126 pcs
->buffer
= HeapAlloc(GetProcessHeap(), 0, size
);
127 pcs
->buffer_size
= (pcs
->buffer
) ? size
: 0;
132 const char* wine_dbgstr_addr(const ADDRESS64
* addr
)
134 if (!addr
) return "(null)";
138 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr
->Offset
));
140 return wine_dbg_sprintf("1616<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
142 return wine_dbg_sprintf("1632<%04x:%08lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
144 return wine_dbg_sprintf("real<%04x:%04lx>", addr
->Segment
, (DWORD
)addr
->Offset
);
150 extern struct cpu cpu_i386
, cpu_x86_64
, cpu_arm
, cpu_arm64
;
152 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, &cpu_x86_64
, &cpu_arm
, &cpu_arm64
, NULL
};
153 struct cpu
* dbghelp_current_cpu
=
154 #if defined(__i386__)
156 #elif defined(__x86_64__)
158 #elif defined(__arm__)
160 #elif defined(__aarch64__)
163 #error define support for your CPU
167 struct cpu
* cpu_find(DWORD machine
)
171 for (cpu
= dbghelp_cpus
; *cpu
; cpu
++)
173 if (cpu
[0]->machine
== machine
) return cpu
[0];
178 static WCHAR
* make_default_search_path(void)
182 unsigned sym_path_len
;
183 unsigned alt_sym_path_len
;
185 sym_path_len
= GetEnvironmentVariableW(L
"_NT_SYMBOL_PATH", NULL
, 0);
186 alt_sym_path_len
= GetEnvironmentVariableW(L
"_NT_ALT_SYMBOL_PATH", NULL
, 0);
188 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
189 * If the variables exist, the lengths include a null-terminator. We use that
190 * space for the semicolons, and only add the initial dot and the final null. */
191 search_path
= HeapAlloc(GetProcessHeap(), 0,
192 (1 + sym_path_len
+ alt_sym_path_len
+ 1) * sizeof(WCHAR
));
193 if (!search_path
) return NULL
;
200 GetEnvironmentVariableW(L
"_NT_SYMBOL_PATH", p
, sym_path_len
);
201 p
+= sym_path_len
- 1;
204 if (alt_sym_path_len
)
207 GetEnvironmentVariableW(L
"_NT_ALT_SYMBOL_PATH", p
, alt_sym_path_len
);
208 p
+= alt_sym_path_len
- 1;
215 /******************************************************************
216 * SymSetSearchPathW (DBGHELP.@)
219 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
221 struct process
* pcs
= process_find_by_handle(hProcess
);
222 WCHAR
* search_path_buffer
;
224 if (!pcs
) return FALSE
;
228 search_path_buffer
= HeapAlloc(GetProcessHeap(), 0,
229 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
));
230 if (!search_path_buffer
) return FALSE
;
231 lstrcpyW(search_path_buffer
, searchPath
);
235 search_path_buffer
= make_default_search_path();
236 if (!search_path_buffer
) return FALSE
;
238 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
239 pcs
->search_path
= search_path_buffer
;
243 /******************************************************************
244 * SymSetSearchPath (DBGHELP.@)
247 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
255 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
256 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
257 if (!sp
) return FALSE
;
258 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
261 ret
= SymSetSearchPathW(hProcess
, sp
);
263 HeapFree(GetProcessHeap(), 0, sp
);
267 /***********************************************************************
268 * SymGetSearchPathW (DBGHELP.@)
270 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
271 DWORD SearchPathLength
)
273 struct process
* pcs
= process_find_by_handle(hProcess
);
274 if (!pcs
) return FALSE
;
276 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
280 /***********************************************************************
281 * SymGetSearchPath (DBGHELP.@)
283 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
284 DWORD SearchPathLength
)
286 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
291 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
293 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
294 szSearchPath
, SearchPathLength
, NULL
, NULL
);
295 HeapFree(GetProcessHeap(), 0, buffer
);
300 /******************************************************************
303 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
304 * this assumes that hProcess is a handle on a valid process
306 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
309 HANDLE hProcess
= user
;
311 if (!GetModuleFileNameExW(hProcess
, (HMODULE
)(DWORD_PTR
)base
, tmp
, ARRAY_SIZE(tmp
)))
312 lstrcpynW(tmp
, name
, ARRAY_SIZE(tmp
));
314 SymLoadModuleExW(hProcess
, 0, tmp
, name
, base
, size
, NULL
, 0);
318 const WCHAR
*process_getenv(const struct process
*process
, const WCHAR
*name
)
323 if (!process
->environment
) return NULL
;
324 name_len
= lstrlenW(name
);
326 for (iter
= process
->environment
; *iter
; iter
+= lstrlenW(iter
) + 1)
328 if (!wcsnicmp(iter
, name
, name_len
) && iter
[name_len
] == '=')
329 return iter
+ name_len
+ 1;
335 /******************************************************************
339 static BOOL
check_live_target(struct process
* pcs
, BOOL wow64
, BOOL child_wow64
)
341 PROCESS_BASIC_INFORMATION pbi
;
342 ULONG_PTR base
= 0, env
= 0;
344 if (!GetProcessId(pcs
->handle
)) return FALSE
;
345 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
347 if (NtQueryInformationProcess( pcs
->handle
, ProcessBasicInformation
,
348 &pbi
, sizeof(pbi
), NULL
))
353 const char* peb32_addr
;
357 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
) == 0x48);
358 peb32_addr
= (const char*)pbi
.PebBaseAddress
;
359 if (!wow64
&& child_wow64
)
360 /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */
361 peb32_addr
+= 0x1000;
362 if (!ReadProcessMemory(pcs
->handle
, peb32_addr
, &peb32
, sizeof(peb32
), NULL
)) return FALSE
;
363 if (!ReadProcessMemory(pcs
->handle
, peb32_addr
+ 0x460 /* CloudFileFlags */, &base
, sizeof(base
), NULL
)) return FALSE
;
364 if (read_process_memory(pcs
, peb32
.ProcessParameters
+ 0x48, &env32
, sizeof(env32
))) env
= env32
;
369 if (!ReadProcessMemory(pcs
->handle
, pbi
.PebBaseAddress
, &peb
, sizeof(peb
), NULL
)) return FALSE
;
370 if (!ReadProcessMemory(pcs
->handle
, (char *)pbi
.PebBaseAddress
+ FIELD_OFFSET(PEB
, CloudFileFlags
), &base
, sizeof(base
), NULL
)) return FALSE
;
371 ReadProcessMemory(pcs
->handle
, (char *)peb
.ProcessParameters
+ FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
), &env
, sizeof(env
), NULL
);
374 /* read debuggee environment block */
377 size_t buf_size
= 0, i
, last_null
= -1;
382 size_t read_size
= sysinfo
.dwAllocationGranularity
- (env
& (sysinfo
.dwAllocationGranularity
- 1));
386 if (!(new_buf
= realloc(buf
, buf_size
+ read_size
))) break;
389 else if(!(buf
= malloc(read_size
))) break;
391 if (!read_process_memory(pcs
, env
, (char*)buf
+ buf_size
, read_size
)) break;
392 for (i
= buf_size
/ sizeof(WCHAR
); i
< (buf_size
+ read_size
) / sizeof(WCHAR
); i
++)
394 if (buf
[i
]) continue;
395 if (last_null
+ 1 == i
)
397 pcs
->environment
= realloc(buf
, (i
+ 1) * sizeof(WCHAR
));
404 buf_size
+= read_size
;
410 if (!base
) return FALSE
;
412 TRACE("got debug info address %#Ix from PEB %p\n", base
, pbi
.PebBaseAddress
);
413 if (!elf_read_wine_loader_dbg_info(pcs
, base
) && !macho_read_wine_loader_dbg_info(pcs
, base
))
414 WARN("couldn't load process debug info at %#Ix\n", base
);
418 /******************************************************************
419 * SymInitializeW (DBGHELP.@)
421 * The initialisation of a dbghelp's context.
422 * Note that hProcess doesn't need to be a valid process handle (except
423 * when fInvadeProcess is TRUE).
424 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
425 * containing PE (and NE) module(s), here's how we handle it:
426 * - we load every module (ELF, NE, PE) passed in SymLoadModule
427 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
428 * synchronization: hProcess should be a valid process handle, and we hook
429 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
430 * our internal ELF modules representation (loading / unloading). This way,
431 * we'll pair every loaded builtin PE module with its ELF counterpart (and
432 * access its debug information).
433 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
434 * hProcess refers to a running process. We use some heuristics here, so YMMV.
435 * If we detect a live target, then we get the same handling as if
436 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
437 * we won't be able to make the peering between a builtin PE module and its ELF
438 * counterpart. Hence we won't be able to provide the requested debug
439 * information. We'll however be able to load native PE modules (and their
440 * debug information) without any trouble.
441 * Note also that this scheme can be intertwined with the deferred loading
442 * mechanism (ie only load the debug information when we actually need it).
444 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
447 BOOL wow64
, child_wow64
;
449 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
451 if (process_find_by_handle(hProcess
))
453 WARN("the symbols for this process have already been initialized!\n");
455 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
456 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
457 Native still returns TRUE even if the process has already been initialized. */
461 IsWow64Process(GetCurrentProcess(), &wow64
);
463 if (GetProcessId(hProcess
) && !IsWow64Process(hProcess
, &child_wow64
))
466 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
467 if (!pcs
) return FALSE
;
469 pcs
->handle
= hProcess
;
470 pcs
->is_64bit
= (sizeof(void *) == 8 || wow64
) && !child_wow64
;
471 pcs
->loader
= &no_loader_ops
; /* platform-specific initialization will override it if loader debug info can be found */
475 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
476 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
481 pcs
->search_path
= make_default_search_path();
484 pcs
->lmodules
= NULL
;
485 pcs
->dbg_hdr_addr
= 0;
486 pcs
->next
= process_first
;
489 if (check_live_target(pcs
, wow64
, child_wow64
))
492 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
493 if (pcs
->loader
) pcs
->loader
->synchronize_module_list(pcs
);
495 else if (fInvadeProcess
)
497 SymCleanup(hProcess
);
498 SetLastError(ERROR_INVALID_PARAMETER
);
505 /******************************************************************
506 * SymInitialize (DBGHELP.@)
510 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
519 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
520 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
521 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
524 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
525 HeapFree(GetProcessHeap(), 0, sp
);
529 /******************************************************************
530 * SymCleanup (DBGHELP.@)
533 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
535 struct process
** ppcs
;
536 struct process
* next
;
538 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
540 if ((*ppcs
)->handle
== hProcess
)
542 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
544 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
545 free((*ppcs
)->environment
);
546 next
= (*ppcs
)->next
;
547 HeapFree(GetProcessHeap(), 0, *ppcs
);
553 ERR("this process has not had SymInitialize() called for it!\n");
557 /******************************************************************
558 * SymSetOptions (DBGHELP.@)
561 DWORD WINAPI
SymSetOptions(DWORD opts
)
565 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
567 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
569 return dbghelp_options
= opts
;
572 /******************************************************************
573 * SymGetOptions (DBGHELP.@)
576 DWORD WINAPI
SymGetOptions(void)
578 return dbghelp_options
;
581 /******************************************************************
582 * SymSetExtendedOption (DBGHELP.@)
585 BOOL WINAPI
SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
, BOOL value
)
591 case SYMOPT_EX_WINE_NATIVE_MODULES
:
592 old
= dbghelp_opt_native
;
593 dbghelp_opt_native
= value
;
596 FIXME("Unsupported option %d with value %d\n", option
, value
);
602 /******************************************************************
603 * SymGetExtendedOption (DBGHELP.@)
606 BOOL WINAPI
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
)
610 case SYMOPT_EX_WINE_NATIVE_MODULES
:
611 return dbghelp_opt_native
;
613 FIXME("Unsupported option %d\n", option
);
619 /******************************************************************
620 * SymSetParentWindow (DBGHELP.@)
623 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
625 /* Save hwnd so it can be used as parent window */
626 FIXME("(%p): stub\n", hwnd
);
630 /******************************************************************
631 * SymSetContext (DBGHELP.@)
634 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
635 PIMAGEHLP_CONTEXT Context
)
639 TRACE("(%p %p %p)\n", hProcess
, StackFrame
, Context
);
641 if (!(pcs
= process_find_by_handle(hProcess
))) return FALSE
;
642 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
643 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
644 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
&&
645 pcs
->ctx_frame
.InstructionOffset
== StackFrame
->InstructionOffset
)
647 TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n",
648 pcs
->ctx_frame
.ReturnOffset
,
649 pcs
->ctx_frame
.FrameOffset
,
650 pcs
->ctx_frame
.StackOffset
);
651 SetLastError(ERROR_SUCCESS
);
655 if (!SymSetScopeFromAddr(hProcess
, StackFrame
->InstructionOffset
))
657 pcs
->ctx_frame
= *StackFrame
;
658 /* Context is not (no longer?) used */
663 /******************************************************************
664 * SymSetScopeFromAddr (DBGHELP.@)
666 BOOL WINAPI
SymSetScopeFromAddr(HANDLE hProcess
, ULONG64 addr
)
668 struct module_pair pair
;
671 TRACE("(%p %#I64x)\n", hProcess
, addr
);
673 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
674 pair
.pcs
->localscope_pc
= addr
;
675 if ((sym
= symt_find_nearest(pair
.effective
, addr
)) != NULL
&& sym
->symt
.tag
== SymTagFunction
)
676 pair
.pcs
->localscope_symt
= &sym
->symt
;
678 pair
.pcs
->localscope_symt
= NULL
;
683 /******************************************************************
684 * SymSetScopeFromIndex (DBGHELP.@)
686 BOOL WINAPI
SymSetScopeFromIndex(HANDLE hProcess
, ULONG64 addr
, DWORD index
)
688 struct module_pair pair
;
691 TRACE("(%p %#I64x %lu)\n", hProcess
, addr
, index
);
693 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
694 sym
= symt_index2ptr(pair
.effective
, index
);
695 if (!symt_check_tag(sym
, SymTagFunction
)) return FALSE
;
697 pair
.pcs
->localscope_pc
= ((struct symt_function
*)sym
)->address
; /* FIXME of FuncDebugStart when it exists? */
698 pair
.pcs
->localscope_symt
= sym
;
703 /******************************************************************
704 * SymSetScopeFromInlineContext (DBGHELP.@)
706 BOOL WINAPI
SymSetScopeFromInlineContext(HANDLE hProcess
, ULONG64 addr
, DWORD inlinectx
)
708 struct module_pair pair
;
709 struct symt_inlinesite
* inlined
;
711 TRACE("(%p %I64x %lx)\n", hProcess
, addr
, inlinectx
);
713 switch (IFC_MODE(inlinectx
))
715 case IFC_MODE_IGNORE
:
716 case IFC_MODE_REGULAR
: return SymSetScopeFromAddr(hProcess
, addr
);
717 case IFC_MODE_INLINE
:
718 if (!module_init_pair(&pair
, hProcess
, addr
)) return FALSE
;
719 inlined
= symt_find_inlined_site(pair
.effective
, addr
, inlinectx
);
722 pair
.pcs
->localscope_pc
= addr
;
723 pair
.pcs
->localscope_symt
= &inlined
->func
.symt
;
728 SetLastError(ERROR_INVALID_PARAMETER
);
733 /******************************************************************
734 * reg_cb64to32 (internal)
736 * Registered callback for converting information from 64 bit to 32 bit
738 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
740 struct process
* pcs
= process_find_by_handle(hProcess
);
742 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
743 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
745 if (!pcs
) return FALSE
;
749 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
750 case CBA_SET_OPTIONS
:
751 case CBA_SYMBOLS_UNLOADED
:
752 data32
= (void*)(DWORD_PTR
)data
;
754 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
755 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
756 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
757 case CBA_DEFERRED_SYMBOL_LOAD_START
:
758 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
759 if (!validate_addr64(idsl64
->BaseOfImage
))
761 idsl
.SizeOfStruct
= sizeof(idsl
);
762 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
763 idsl
.CheckSum
= idsl64
->CheckSum
;
764 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
765 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
766 idsl
.Reparse
= idsl64
->Reparse
;
769 case CBA_DUPLICATE_SYMBOL
:
771 case CBA_READ_MEMORY
:
773 FIXME("No mapping for action %lu\n", action
);
776 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
779 /******************************************************************
780 * pcs_callback (internal)
782 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
784 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
786 TRACE("%p %lu %p\n", pcs
, action
, data
);
788 if (!pcs
->reg_cb
) return FALSE
;
789 if (!pcs
->reg_is_unicode
)
791 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
796 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
797 case CBA_SET_OPTIONS
:
798 case CBA_SYMBOLS_UNLOADED
:
800 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
801 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
802 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
803 case CBA_DEFERRED_SYMBOL_LOAD_START
:
805 idsl
.SizeOfStruct
= sizeof(idsl
);
806 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
807 idsl
.CheckSum
= idslW
->CheckSum
;
808 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
809 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
810 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
811 idsl
.Reparse
= idslW
->Reparse
;
814 case CBA_DUPLICATE_SYMBOL
:
816 case CBA_READ_MEMORY
:
818 FIXME("No mapping for action %lu\n", action
);
822 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
825 /******************************************************************
828 * Helper for registering a callback.
830 static BOOL
sym_register_cb(HANDLE hProcess
,
831 PSYMBOL_REGISTERED_CALLBACK64 cb
,
832 PSYMBOL_REGISTERED_CALLBACK cb32
,
833 DWORD64 user
, BOOL unicode
)
835 struct process
* pcs
= process_find_by_handle(hProcess
);
837 if (!pcs
) return FALSE
;
839 pcs
->reg_cb32
= cb32
;
840 pcs
->reg_is_unicode
= unicode
;
841 pcs
->reg_user
= user
;
846 /***********************************************************************
847 * SymRegisterCallback (DBGHELP.@)
849 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
850 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
853 TRACE("(%p, %p, %p)\n",
854 hProcess
, CallbackFunction
, UserContext
);
855 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
858 /***********************************************************************
859 * SymRegisterCallback64 (DBGHELP.@)
861 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
862 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
865 TRACE("(%p, %p, %s)\n",
866 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
867 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
870 /***********************************************************************
871 * SymRegisterCallbackW64 (DBGHELP.@)
873 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
874 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
877 TRACE("(%p, %p, %s)\n",
878 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
879 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
882 /* This is imagehlp version not dbghelp !! */
883 static API_VERSION api_version
= { 4, 0, 2, 0 };
885 /***********************************************************************
886 * ImagehlpApiVersion (DBGHELP.@)
888 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
893 /***********************************************************************
894 * ImagehlpApiVersionEx (DBGHELP.@)
896 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
898 if (!AppVersion
) return NULL
;
900 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
901 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
902 AppVersion
->Revision
= api_version
.Revision
;
903 AppVersion
->Reserved
= api_version
.Reserved
;
908 /******************************************************************
909 * ExtensionApiVersion (DBGHELP.@)
911 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
913 static EXT_API_VERSION eav
= {5, 5, 5, 0};
917 /******************************************************************
918 * WinDbgExtensionDllInit (DBGHELP.@)
920 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
921 unsigned short major
, unsigned short minor
)
925 DWORD
calc_crc32(HANDLE handle
)
931 SetFilePointer(handle
, 0, 0, FILE_BEGIN
);
932 while (ReadFile(handle
, buffer
, sizeof(buffer
), &len
, NULL
) && len
)
933 crc
= RtlComputeCrc32(crc
, buffer
, len
);