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:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
142 return wine_dbg_sprintf("1632<%04x:%08x>", addr
->Segment
, (DWORD
)addr
->Offset
);
144 return wine_dbg_sprintf("real<%04x:%04x>", addr
->Segment
, (DWORD
)addr
->Offset
);
150 extern struct cpu cpu_i386
, cpu_x86_64
, cpu_ppc
, cpu_arm
, cpu_arm64
;
152 static struct cpu
* dbghelp_cpus
[] = {&cpu_i386
, &cpu_x86_64
, &cpu_ppc
, &cpu_arm
, &cpu_arm64
, NULL
};
153 struct cpu
* dbghelp_current_cpu
=
154 #if defined(__i386__)
156 #elif defined(__x86_64__)
158 #elif defined(__powerpc__)
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 /******************************************************************
181 * SymSetSearchPathW (DBGHELP.@)
184 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
186 struct process
* pcs
= process_find_by_handle(hProcess
);
188 if (!pcs
) return FALSE
;
189 if (!searchPath
) return FALSE
;
191 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
192 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
193 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
)),
198 /******************************************************************
199 * SymSetSearchPath (DBGHELP.@)
202 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
208 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
209 if ((sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
211 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
213 ret
= SymSetSearchPathW(hProcess
, sp
);
214 HeapFree(GetProcessHeap(), 0, sp
);
219 /***********************************************************************
220 * SymGetSearchPathW (DBGHELP.@)
222 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
223 DWORD SearchPathLength
)
225 struct process
* pcs
= process_find_by_handle(hProcess
);
226 if (!pcs
) return FALSE
;
228 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
232 /***********************************************************************
233 * SymGetSearchPath (DBGHELP.@)
235 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
236 DWORD SearchPathLength
)
238 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
243 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
245 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
246 szSearchPath
, SearchPathLength
, NULL
, NULL
);
247 HeapFree(GetProcessHeap(), 0, buffer
);
252 /******************************************************************
255 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
256 * this assumes that hProcess is a handle on a valid process
258 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
261 HANDLE hProcess
= user
;
263 if (!GetModuleFileNameExW(hProcess
, (HMODULE
)(DWORD_PTR
)base
, tmp
, ARRAY_SIZE(tmp
)))
264 lstrcpynW(tmp
, name
, ARRAY_SIZE(tmp
));
266 SymLoadModuleExW(hProcess
, 0, tmp
, name
, base
, size
, NULL
, 0);
270 /******************************************************************
274 static BOOL
check_live_target(struct process
* pcs
)
276 PROCESS_BASIC_INFORMATION pbi
;
279 if (!GetProcessId(pcs
->handle
)) return FALSE
;
280 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
282 if (NtQueryInformationProcess( pcs
->handle
, ProcessBasicInformation
,
283 &pbi
, sizeof(pbi
), NULL
))
288 PEB32
*peb32
= (PEB32
*)pbi
.PebBaseAddress
;
290 ReadProcessMemory(pcs
->handle
, &peb32
->Reserved
[0], &base32
, sizeof(base32
), NULL
);
293 else ReadProcessMemory(pcs
->handle
, &pbi
.PebBaseAddress
->Reserved
[0], &base
, sizeof(base
), NULL
);
294 if (!base
) return FALSE
;
296 TRACE("got debug info address %#lx from PEB %p\n", base
, pbi
.PebBaseAddress
);
297 return elf_read_wine_loader_dbg_info(pcs
, base
) || macho_read_wine_loader_dbg_info(pcs
, base
);
300 /******************************************************************
301 * SymInitializeW (DBGHELP.@)
303 * The initialisation of a dbghelp's context.
304 * Note that hProcess doesn't need to be a valid process handle (except
305 * when fInvadeProcess is TRUE).
306 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
307 * containing PE (and NE) module(s), here's how we handle it:
308 * - we load every module (ELF, NE, PE) passed in SymLoadModule
309 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
310 * synchronization: hProcess should be a valid process handle, and we hook
311 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
312 * our internal ELF modules representation (loading / unloading). This way,
313 * we'll pair every loaded builtin PE module with its ELF counterpart (and
314 * access its debug information).
315 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
316 * hProcess refers to a running process. We use some heuristics here, so YMMV.
317 * If we detect a live target, then we get the same handling as if
318 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
319 * we won't be able to make the peering between a builtin PE module and its ELF
320 * counterpart. Hence we won't be able to provide the requested debug
321 * information. We'll however be able to load native PE modules (and their
322 * debug information) without any trouble.
323 * Note also that this scheme can be intertwined with the deferred loading
324 * mechanism (ie only load the debug information when we actually need it).
326 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
329 BOOL wow64
, child_wow64
;
331 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
333 if (process_find_by_handle(hProcess
))
335 WARN("the symbols for this process have already been initialized!\n");
337 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
338 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
339 Native still returns TRUE even if the process has already been initialized. */
343 IsWow64Process(GetCurrentProcess(), &wow64
);
345 if (GetProcessId(hProcess
) && !IsWow64Process(hProcess
, &child_wow64
))
348 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
349 if (!pcs
) return FALSE
;
351 pcs
->handle
= hProcess
;
352 pcs
->is_64bit
= (sizeof(void *) == 8 || wow64
) && !child_wow64
;
353 pcs
->loader
= &no_loader_ops
; /* platform-specific initialization will override it if loader debug info can be found */
357 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
358 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
365 static const WCHAR sym_path
[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
366 static const WCHAR alt_sym_path
[] = {'_','N','T','_','A','L','T','E','R','N','A','T','E','_','S','Y','M','B','O','L','_','P','A','T','H',0};
368 pcs
->search_path
= HeapAlloc(GetProcessHeap(), 0, (len
= MAX_PATH
) * sizeof(WCHAR
));
369 while ((size
= GetCurrentDirectoryW(len
, pcs
->search_path
)) >= len
)
370 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (len
*= 2) * sizeof(WCHAR
));
371 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1) * sizeof(WCHAR
));
373 len
= GetEnvironmentVariableW(sym_path
, NULL
, 0);
376 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
377 pcs
->search_path
[size
] = ';';
378 GetEnvironmentVariableW(sym_path
, pcs
->search_path
+ size
+ 1, len
);
381 len
= GetEnvironmentVariableW(alt_sym_path
, NULL
, 0);
384 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
385 pcs
->search_path
[size
] = ';';
386 GetEnvironmentVariableW(alt_sym_path
, pcs
->search_path
+ size
+ 1, len
);
390 pcs
->lmodules
= NULL
;
391 pcs
->dbg_hdr_addr
= 0;
392 pcs
->next
= process_first
;
395 if (check_live_target(pcs
))
398 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
399 pcs
->loader
->synchronize_module_list(pcs
);
401 else if (fInvadeProcess
)
403 SymCleanup(hProcess
);
404 SetLastError(ERROR_INVALID_PARAMETER
);
411 /******************************************************************
412 * SymInitialize (DBGHELP.@)
416 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
425 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
426 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
427 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
430 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
431 HeapFree(GetProcessHeap(), 0, sp
);
435 /******************************************************************
436 * SymCleanup (DBGHELP.@)
439 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
441 struct process
** ppcs
;
442 struct process
* next
;
444 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
446 if ((*ppcs
)->handle
== hProcess
)
448 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
450 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
451 next
= (*ppcs
)->next
;
452 HeapFree(GetProcessHeap(), 0, *ppcs
);
458 ERR("this process has not had SymInitialize() called for it!\n");
462 /******************************************************************
463 * SymSetOptions (DBGHELP.@)
466 DWORD WINAPI
SymSetOptions(DWORD opts
)
470 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
472 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
474 return dbghelp_options
= opts
;
477 /******************************************************************
478 * SymGetOptions (DBGHELP.@)
481 DWORD WINAPI
SymGetOptions(void)
483 return dbghelp_options
;
486 /******************************************************************
487 * SymSetExtendedOption (DBGHELP.@)
490 BOOL WINAPI
SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
, BOOL value
)
496 case SYMOPT_EX_WINE_NATIVE_MODULES
:
497 old
= dbghelp_opt_native
;
498 dbghelp_opt_native
= value
;
501 FIXME("Unsupported option %d with value %d\n", option
, value
);
507 /******************************************************************
508 * SymGetExtendedOption (DBGHELP.@)
511 BOOL WINAPI
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
)
515 case SYMOPT_EX_WINE_NATIVE_MODULES
:
516 return dbghelp_opt_native
;
518 FIXME("Unsupported option %d\n", option
);
524 /******************************************************************
525 * SymSetParentWindow (DBGHELP.@)
528 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
530 /* Save hwnd so it can be used as parent window */
531 FIXME("(%p): stub\n", hwnd
);
535 /******************************************************************
536 * SymSetContext (DBGHELP.@)
539 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
540 PIMAGEHLP_CONTEXT Context
)
542 struct process
* pcs
= process_find_by_handle(hProcess
);
543 if (!pcs
) return FALSE
;
545 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
546 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
547 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
)
549 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
550 wine_dbgstr_longlong(pcs
->ctx_frame
.ReturnOffset
),
551 wine_dbgstr_longlong(pcs
->ctx_frame
.FrameOffset
),
552 wine_dbgstr_longlong(pcs
->ctx_frame
.StackOffset
));
553 pcs
->ctx_frame
.InstructionOffset
= StackFrame
->InstructionOffset
;
554 SetLastError(ERROR_ACCESS_DENIED
); /* latest MSDN says ERROR_SUCCESS */
558 pcs
->ctx_frame
= *StackFrame
;
559 /* MSDN states that Context is not (no longer?) used */
563 /******************************************************************
564 * reg_cb64to32 (internal)
566 * Registered callback for converting information from 64 bit to 32 bit
568 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
570 struct process
* pcs
= process_find_by_handle(hProcess
);
572 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
573 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
575 if (!pcs
) return FALSE
;
579 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
580 case CBA_SET_OPTIONS
:
581 case CBA_SYMBOLS_UNLOADED
:
582 data32
= (void*)(DWORD_PTR
)data
;
584 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
585 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
586 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
587 case CBA_DEFERRED_SYMBOL_LOAD_START
:
588 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
589 if (!validate_addr64(idsl64
->BaseOfImage
))
591 idsl
.SizeOfStruct
= sizeof(idsl
);
592 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
593 idsl
.CheckSum
= idsl64
->CheckSum
;
594 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
595 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
596 idsl
.Reparse
= idsl64
->Reparse
;
599 case CBA_DUPLICATE_SYMBOL
:
601 case CBA_READ_MEMORY
:
603 FIXME("No mapping for action %u\n", action
);
606 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
609 /******************************************************************
610 * pcs_callback (internal)
612 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
614 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
616 TRACE("%p %u %p\n", pcs
, action
, data
);
618 if (!pcs
->reg_cb
) return FALSE
;
619 if (!pcs
->reg_is_unicode
)
621 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
626 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
627 case CBA_SET_OPTIONS
:
628 case CBA_SYMBOLS_UNLOADED
:
630 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
631 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
632 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
633 case CBA_DEFERRED_SYMBOL_LOAD_START
:
635 idsl
.SizeOfStruct
= sizeof(idsl
);
636 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
637 idsl
.CheckSum
= idslW
->CheckSum
;
638 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
639 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
640 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
641 idsl
.Reparse
= idslW
->Reparse
;
644 case CBA_DUPLICATE_SYMBOL
:
646 case CBA_READ_MEMORY
:
648 FIXME("No mapping for action %u\n", action
);
652 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
655 /******************************************************************
658 * Helper for registering a callback.
660 static BOOL
sym_register_cb(HANDLE hProcess
,
661 PSYMBOL_REGISTERED_CALLBACK64 cb
,
662 PSYMBOL_REGISTERED_CALLBACK cb32
,
663 DWORD64 user
, BOOL unicode
)
665 struct process
* pcs
= process_find_by_handle(hProcess
);
667 if (!pcs
) return FALSE
;
669 pcs
->reg_cb32
= cb32
;
670 pcs
->reg_is_unicode
= unicode
;
671 pcs
->reg_user
= user
;
676 /***********************************************************************
677 * SymRegisterCallback (DBGHELP.@)
679 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
680 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
683 TRACE("(%p, %p, %p)\n",
684 hProcess
, CallbackFunction
, UserContext
);
685 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
688 /***********************************************************************
689 * SymRegisterCallback64 (DBGHELP.@)
691 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
692 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
695 TRACE("(%p, %p, %s)\n",
696 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
697 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
700 /***********************************************************************
701 * SymRegisterCallbackW64 (DBGHELP.@)
703 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
704 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
707 TRACE("(%p, %p, %s)\n",
708 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
709 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
712 /* This is imagehlp version not dbghelp !! */
713 static API_VERSION api_version
= { 4, 0, 2, 0 };
715 /***********************************************************************
716 * ImagehlpApiVersion (DBGHELP.@)
718 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
723 /***********************************************************************
724 * ImagehlpApiVersionEx (DBGHELP.@)
726 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
728 if (!AppVersion
) return NULL
;
730 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
731 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
732 AppVersion
->Revision
= api_version
.Revision
;
733 AppVersion
->Reserved
= api_version
.Reserved
;
738 /******************************************************************
739 * ExtensionApiVersion (DBGHELP.@)
741 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
743 static EXT_API_VERSION eav
= {5, 5, 5, 0};
747 /******************************************************************
748 * WinDbgExtensionDllInit (DBGHELP.@)
750 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
751 unsigned short major
, unsigned short minor
)
755 DWORD
calc_crc32(HANDLE handle
)
761 SetFilePointer(handle
, 0, 0, FILE_BEGIN
);
762 while (ReadFile(handle
, buffer
, sizeof(buffer
), &len
, NULL
) && len
)
763 crc
= RtlComputeCrc32(crc
, buffer
, len
);