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_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 /******************************************************************
179 * SymSetSearchPathW (DBGHELP.@)
182 BOOL WINAPI
SymSetSearchPathW(HANDLE hProcess
, PCWSTR searchPath
)
184 struct process
* pcs
= process_find_by_handle(hProcess
);
186 if (!pcs
) return FALSE
;
187 if (!searchPath
) return FALSE
;
189 HeapFree(GetProcessHeap(), 0, pcs
->search_path
);
190 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
191 (lstrlenW(searchPath
) + 1) * sizeof(WCHAR
)),
196 /******************************************************************
197 * SymSetSearchPath (DBGHELP.@)
200 BOOL WINAPI
SymSetSearchPath(HANDLE hProcess
, PCSTR searchPath
)
206 len
= MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, NULL
, 0);
207 if ((sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
209 MultiByteToWideChar(CP_ACP
, 0, searchPath
, -1, sp
, len
);
211 ret
= SymSetSearchPathW(hProcess
, sp
);
212 HeapFree(GetProcessHeap(), 0, sp
);
217 /***********************************************************************
218 * SymGetSearchPathW (DBGHELP.@)
220 BOOL WINAPI
SymGetSearchPathW(HANDLE hProcess
, PWSTR szSearchPath
,
221 DWORD SearchPathLength
)
223 struct process
* pcs
= process_find_by_handle(hProcess
);
224 if (!pcs
) return FALSE
;
226 lstrcpynW(szSearchPath
, pcs
->search_path
, SearchPathLength
);
230 /***********************************************************************
231 * SymGetSearchPath (DBGHELP.@)
233 BOOL WINAPI
SymGetSearchPath(HANDLE hProcess
, PSTR szSearchPath
,
234 DWORD SearchPathLength
)
236 WCHAR
* buffer
= HeapAlloc(GetProcessHeap(), 0, SearchPathLength
* sizeof(WCHAR
));
241 ret
= SymGetSearchPathW(hProcess
, buffer
, SearchPathLength
);
243 WideCharToMultiByte(CP_ACP
, 0, buffer
, SearchPathLength
,
244 szSearchPath
, SearchPathLength
, NULL
, NULL
);
245 HeapFree(GetProcessHeap(), 0, buffer
);
250 /******************************************************************
253 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
254 * this assumes that hProcess is a handle on a valid process
256 static BOOL WINAPI
process_invade_cb(PCWSTR name
, ULONG64 base
, ULONG size
, PVOID user
)
259 HANDLE hProcess
= user
;
261 if (!GetModuleFileNameExW(hProcess
, (HMODULE
)(DWORD_PTR
)base
, tmp
, ARRAY_SIZE(tmp
)))
262 lstrcpynW(tmp
, name
, ARRAY_SIZE(tmp
));
264 SymLoadModuleExW(hProcess
, 0, tmp
, name
, base
, size
, NULL
, 0);
268 const WCHAR
*process_getenv(const struct process
*process
, const WCHAR
*name
)
273 if (!process
->environment
) return NULL
;
274 name_len
= lstrlenW(name
);
276 for (iter
= process
->environment
; *iter
; iter
+= lstrlenW(iter
) + 1)
278 if (!wcsnicmp(iter
, name
, name_len
) && iter
[name_len
] == '=')
279 return iter
+ name_len
+ 1;
285 /******************************************************************
289 static BOOL
check_live_target(struct process
* pcs
)
291 PROCESS_BASIC_INFORMATION pbi
;
292 ULONG_PTR base
= 0, env
= 0;
294 if (!GetProcessId(pcs
->handle
)) return FALSE
;
295 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL
, 0)) return FALSE
;
297 if (NtQueryInformationProcess( pcs
->handle
, ProcessBasicInformation
,
298 &pbi
, sizeof(pbi
), NULL
))
305 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
) == 0x48);
306 if (!ReadProcessMemory(pcs
->handle
, pbi
.PebBaseAddress
, &peb32
, sizeof(peb32
), NULL
)) return FALSE
;
307 if (!ReadProcessMemory(pcs
->handle
, (char *)pbi
.PebBaseAddress
+ 0x460 /* CloudFileFlags */, &base
, sizeof(base
), NULL
)) return FALSE
;
308 if (read_process_memory(pcs
, peb32
.ProcessParameters
+ 0x48, &env32
, sizeof(env32
))) env
= env32
;
313 if (!ReadProcessMemory(pcs
->handle
, pbi
.PebBaseAddress
, &peb
, sizeof(peb
), NULL
)) return FALSE
;
314 if (!ReadProcessMemory(pcs
->handle
, (char *)pbi
.PebBaseAddress
+ FIELD_OFFSET(PEB
, CloudFileFlags
), &base
, sizeof(base
), NULL
)) return FALSE
;
315 ReadProcessMemory(pcs
->handle
, (char *)peb
.ProcessParameters
+ FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS
, Environment
), &env
, sizeof(env
), NULL
);
318 /* read debuggee environment block */
321 size_t buf_size
= 0, i
, last_null
= -1;
326 size_t read_size
= sysinfo
.dwAllocationGranularity
- (env
& (sysinfo
.dwAllocationGranularity
- 1));
330 if (!(new_buf
= realloc(buf
, buf_size
+ read_size
))) break;
333 else if(!(buf
= malloc(read_size
))) break;
335 if (!read_process_memory(pcs
, env
, (char*)buf
+ buf_size
, read_size
)) break;
336 for (i
= buf_size
/ sizeof(WCHAR
); i
< (buf_size
+ read_size
) / sizeof(WCHAR
); i
++)
338 if (buf
[i
]) continue;
339 if (last_null
+ 1 == i
)
341 pcs
->environment
= realloc(buf
, (i
+ 1) * sizeof(WCHAR
));
348 buf_size
+= read_size
;
354 if (!base
) return FALSE
;
356 TRACE("got debug info address %#lx from PEB %p\n", base
, pbi
.PebBaseAddress
);
357 if (!elf_read_wine_loader_dbg_info(pcs
, base
) && !macho_read_wine_loader_dbg_info(pcs
, base
))
358 WARN("couldn't load process debug info at %#lx\n", base
);
362 /******************************************************************
363 * SymInitializeW (DBGHELP.@)
365 * The initialisation of a dbghelp's context.
366 * Note that hProcess doesn't need to be a valid process handle (except
367 * when fInvadeProcess is TRUE).
368 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
369 * containing PE (and NE) module(s), here's how we handle it:
370 * - we load every module (ELF, NE, PE) passed in SymLoadModule
371 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
372 * synchronization: hProcess should be a valid process handle, and we hook
373 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
374 * our internal ELF modules representation (loading / unloading). This way,
375 * we'll pair every loaded builtin PE module with its ELF counterpart (and
376 * access its debug information).
377 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
378 * hProcess refers to a running process. We use some heuristics here, so YMMV.
379 * If we detect a live target, then we get the same handling as if
380 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
381 * we won't be able to make the peering between a builtin PE module and its ELF
382 * counterpart. Hence we won't be able to provide the requested debug
383 * information. We'll however be able to load native PE modules (and their
384 * debug information) without any trouble.
385 * Note also that this scheme can be intertwined with the deferred loading
386 * mechanism (ie only load the debug information when we actually need it).
388 BOOL WINAPI
SymInitializeW(HANDLE hProcess
, PCWSTR UserSearchPath
, BOOL fInvadeProcess
)
391 BOOL wow64
, child_wow64
;
393 TRACE("(%p %s %u)\n", hProcess
, debugstr_w(UserSearchPath
), fInvadeProcess
);
395 if (process_find_by_handle(hProcess
))
397 WARN("the symbols for this process have already been initialized!\n");
399 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
400 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
401 Native still returns TRUE even if the process has already been initialized. */
405 IsWow64Process(GetCurrentProcess(), &wow64
);
407 if (GetProcessId(hProcess
) && !IsWow64Process(hProcess
, &child_wow64
))
410 pcs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*pcs
));
411 if (!pcs
) return FALSE
;
413 pcs
->handle
= hProcess
;
414 pcs
->is_64bit
= (sizeof(void *) == 8 || wow64
) && !child_wow64
;
415 pcs
->loader
= &no_loader_ops
; /* platform-specific initialization will override it if loader debug info can be found */
419 pcs
->search_path
= lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
420 (lstrlenW(UserSearchPath
) + 1) * sizeof(WCHAR
)),
427 static const WCHAR sym_path
[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
428 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};
430 pcs
->search_path
= HeapAlloc(GetProcessHeap(), 0, (len
= MAX_PATH
) * sizeof(WCHAR
));
431 while ((size
= GetCurrentDirectoryW(len
, pcs
->search_path
)) >= len
)
432 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (len
*= 2) * sizeof(WCHAR
));
433 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1) * sizeof(WCHAR
));
435 len
= GetEnvironmentVariableW(sym_path
, NULL
, 0);
438 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
439 pcs
->search_path
[size
] = ';';
440 GetEnvironmentVariableW(sym_path
, pcs
->search_path
+ size
+ 1, len
);
443 len
= GetEnvironmentVariableW(alt_sym_path
, NULL
, 0);
446 pcs
->search_path
= HeapReAlloc(GetProcessHeap(), 0, pcs
->search_path
, (size
+ 1 + len
+ 1) * sizeof(WCHAR
));
447 pcs
->search_path
[size
] = ';';
448 GetEnvironmentVariableW(alt_sym_path
, pcs
->search_path
+ size
+ 1, len
);
452 pcs
->lmodules
= NULL
;
453 pcs
->dbg_hdr_addr
= 0;
454 pcs
->next
= process_first
;
457 if (check_live_target(pcs
))
460 EnumerateLoadedModulesW64(hProcess
, process_invade_cb
, hProcess
);
461 if (pcs
->loader
) pcs
->loader
->synchronize_module_list(pcs
);
463 else if (fInvadeProcess
)
465 SymCleanup(hProcess
);
466 SetLastError(ERROR_INVALID_PARAMETER
);
473 /******************************************************************
474 * SymInitialize (DBGHELP.@)
478 BOOL WINAPI
SymInitialize(HANDLE hProcess
, PCSTR UserSearchPath
, BOOL fInvadeProcess
)
487 len
= MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, NULL
, 0);
488 sp
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
489 MultiByteToWideChar(CP_ACP
, 0, UserSearchPath
, -1, sp
, len
);
492 ret
= SymInitializeW(hProcess
, sp
, fInvadeProcess
);
493 HeapFree(GetProcessHeap(), 0, sp
);
497 /******************************************************************
498 * SymCleanup (DBGHELP.@)
501 BOOL WINAPI
SymCleanup(HANDLE hProcess
)
503 struct process
** ppcs
;
504 struct process
* next
;
506 for (ppcs
= &process_first
; *ppcs
; ppcs
= &(*ppcs
)->next
)
508 if ((*ppcs
)->handle
== hProcess
)
510 while ((*ppcs
)->lmodules
) module_remove(*ppcs
, (*ppcs
)->lmodules
);
512 HeapFree(GetProcessHeap(), 0, (*ppcs
)->search_path
);
513 free((*ppcs
)->environment
);
514 next
= (*ppcs
)->next
;
515 HeapFree(GetProcessHeap(), 0, *ppcs
);
521 ERR("this process has not had SymInitialize() called for it!\n");
525 /******************************************************************
526 * SymSetOptions (DBGHELP.@)
529 DWORD WINAPI
SymSetOptions(DWORD opts
)
533 for (pcs
= process_first
; pcs
; pcs
= pcs
->next
)
535 pcs_callback(pcs
, CBA_SET_OPTIONS
, &opts
);
537 return dbghelp_options
= opts
;
540 /******************************************************************
541 * SymGetOptions (DBGHELP.@)
544 DWORD WINAPI
SymGetOptions(void)
546 return dbghelp_options
;
549 /******************************************************************
550 * SymSetExtendedOption (DBGHELP.@)
553 BOOL WINAPI
SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
, BOOL value
)
559 case SYMOPT_EX_WINE_NATIVE_MODULES
:
560 old
= dbghelp_opt_native
;
561 dbghelp_opt_native
= value
;
564 FIXME("Unsupported option %d with value %d\n", option
, value
);
570 /******************************************************************
571 * SymGetExtendedOption (DBGHELP.@)
574 BOOL WINAPI
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option
)
578 case SYMOPT_EX_WINE_NATIVE_MODULES
:
579 return dbghelp_opt_native
;
581 FIXME("Unsupported option %d\n", option
);
587 /******************************************************************
588 * SymSetParentWindow (DBGHELP.@)
591 BOOL WINAPI
SymSetParentWindow(HWND hwnd
)
593 /* Save hwnd so it can be used as parent window */
594 FIXME("(%p): stub\n", hwnd
);
598 /******************************************************************
599 * SymSetContext (DBGHELP.@)
602 BOOL WINAPI
SymSetContext(HANDLE hProcess
, PIMAGEHLP_STACK_FRAME StackFrame
,
603 PIMAGEHLP_CONTEXT Context
)
605 struct process
* pcs
= process_find_by_handle(hProcess
);
606 if (!pcs
) return FALSE
;
608 if (pcs
->ctx_frame
.ReturnOffset
== StackFrame
->ReturnOffset
&&
609 pcs
->ctx_frame
.FrameOffset
== StackFrame
->FrameOffset
&&
610 pcs
->ctx_frame
.StackOffset
== StackFrame
->StackOffset
)
612 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
613 wine_dbgstr_longlong(pcs
->ctx_frame
.ReturnOffset
),
614 wine_dbgstr_longlong(pcs
->ctx_frame
.FrameOffset
),
615 wine_dbgstr_longlong(pcs
->ctx_frame
.StackOffset
));
616 pcs
->ctx_frame
.InstructionOffset
= StackFrame
->InstructionOffset
;
617 SetLastError(ERROR_ACCESS_DENIED
); /* latest MSDN says ERROR_SUCCESS */
621 pcs
->ctx_frame
= *StackFrame
;
622 /* MSDN states that Context is not (no longer?) used */
626 /******************************************************************
627 * reg_cb64to32 (internal)
629 * Registered callback for converting information from 64 bit to 32 bit
631 static BOOL CALLBACK
reg_cb64to32(HANDLE hProcess
, ULONG action
, ULONG64 data
, ULONG64 user
)
633 struct process
* pcs
= process_find_by_handle(hProcess
);
635 IMAGEHLP_DEFERRED_SYMBOL_LOAD64
* idsl64
;
636 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl
;
638 if (!pcs
) return FALSE
;
642 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
643 case CBA_SET_OPTIONS
:
644 case CBA_SYMBOLS_UNLOADED
:
645 data32
= (void*)(DWORD_PTR
)data
;
647 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
648 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
649 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
650 case CBA_DEFERRED_SYMBOL_LOAD_START
:
651 idsl64
= (IMAGEHLP_DEFERRED_SYMBOL_LOAD64
*)(DWORD_PTR
)data
;
652 if (!validate_addr64(idsl64
->BaseOfImage
))
654 idsl
.SizeOfStruct
= sizeof(idsl
);
655 idsl
.BaseOfImage
= (DWORD
)idsl64
->BaseOfImage
;
656 idsl
.CheckSum
= idsl64
->CheckSum
;
657 idsl
.TimeDateStamp
= idsl64
->TimeDateStamp
;
658 memcpy(idsl
.FileName
, idsl64
->FileName
, sizeof(idsl
.FileName
));
659 idsl
.Reparse
= idsl64
->Reparse
;
662 case CBA_DUPLICATE_SYMBOL
:
664 case CBA_READ_MEMORY
:
666 FIXME("No mapping for action %u\n", action
);
669 return pcs
->reg_cb32(hProcess
, action
, data32
, (PVOID
)(DWORD_PTR
)user
);
672 /******************************************************************
673 * pcs_callback (internal)
675 BOOL
pcs_callback(const struct process
* pcs
, ULONG action
, void* data
)
677 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl
;
679 TRACE("%p %u %p\n", pcs
, action
, data
);
681 if (!pcs
->reg_cb
) return FALSE
;
682 if (!pcs
->reg_is_unicode
)
684 IMAGEHLP_DEFERRED_SYMBOL_LOADW64
* idslW
;
689 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL
:
690 case CBA_SET_OPTIONS
:
691 case CBA_SYMBOLS_UNLOADED
:
693 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE
:
694 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE
:
695 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL
:
696 case CBA_DEFERRED_SYMBOL_LOAD_START
:
698 idsl
.SizeOfStruct
= sizeof(idsl
);
699 idsl
.BaseOfImage
= idslW
->BaseOfImage
;
700 idsl
.CheckSum
= idslW
->CheckSum
;
701 idsl
.TimeDateStamp
= idslW
->TimeDateStamp
;
702 WideCharToMultiByte(CP_ACP
, 0, idslW
->FileName
, -1,
703 idsl
.FileName
, sizeof(idsl
.FileName
), NULL
, NULL
);
704 idsl
.Reparse
= idslW
->Reparse
;
707 case CBA_DUPLICATE_SYMBOL
:
709 case CBA_READ_MEMORY
:
711 FIXME("No mapping for action %u\n", action
);
715 return pcs
->reg_cb(pcs
->handle
, action
, (ULONG64
)(DWORD_PTR
)data
, pcs
->reg_user
);
718 /******************************************************************
721 * Helper for registering a callback.
723 static BOOL
sym_register_cb(HANDLE hProcess
,
724 PSYMBOL_REGISTERED_CALLBACK64 cb
,
725 PSYMBOL_REGISTERED_CALLBACK cb32
,
726 DWORD64 user
, BOOL unicode
)
728 struct process
* pcs
= process_find_by_handle(hProcess
);
730 if (!pcs
) return FALSE
;
732 pcs
->reg_cb32
= cb32
;
733 pcs
->reg_is_unicode
= unicode
;
734 pcs
->reg_user
= user
;
739 /***********************************************************************
740 * SymRegisterCallback (DBGHELP.@)
742 BOOL WINAPI
SymRegisterCallback(HANDLE hProcess
,
743 PSYMBOL_REGISTERED_CALLBACK CallbackFunction
,
746 TRACE("(%p, %p, %p)\n",
747 hProcess
, CallbackFunction
, UserContext
);
748 return sym_register_cb(hProcess
, reg_cb64to32
, CallbackFunction
, (DWORD_PTR
)UserContext
, FALSE
);
751 /***********************************************************************
752 * SymRegisterCallback64 (DBGHELP.@)
754 BOOL WINAPI
SymRegisterCallback64(HANDLE hProcess
,
755 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
758 TRACE("(%p, %p, %s)\n",
759 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
760 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, FALSE
);
763 /***********************************************************************
764 * SymRegisterCallbackW64 (DBGHELP.@)
766 BOOL WINAPI
SymRegisterCallbackW64(HANDLE hProcess
,
767 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction
,
770 TRACE("(%p, %p, %s)\n",
771 hProcess
, CallbackFunction
, wine_dbgstr_longlong(UserContext
));
772 return sym_register_cb(hProcess
, CallbackFunction
, NULL
, UserContext
, TRUE
);
775 /* This is imagehlp version not dbghelp !! */
776 static API_VERSION api_version
= { 4, 0, 2, 0 };
778 /***********************************************************************
779 * ImagehlpApiVersion (DBGHELP.@)
781 LPAPI_VERSION WINAPI
ImagehlpApiVersion(VOID
)
786 /***********************************************************************
787 * ImagehlpApiVersionEx (DBGHELP.@)
789 LPAPI_VERSION WINAPI
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion
)
791 if (!AppVersion
) return NULL
;
793 AppVersion
->MajorVersion
= api_version
.MajorVersion
;
794 AppVersion
->MinorVersion
= api_version
.MinorVersion
;
795 AppVersion
->Revision
= api_version
.Revision
;
796 AppVersion
->Reserved
= api_version
.Reserved
;
801 /******************************************************************
802 * ExtensionApiVersion (DBGHELP.@)
804 LPEXT_API_VERSION WINAPI
ExtensionApiVersion(void)
806 static EXT_API_VERSION eav
= {5, 5, 5, 0};
810 /******************************************************************
811 * WinDbgExtensionDllInit (DBGHELP.@)
813 void WINAPI
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis
,
814 unsigned short major
, unsigned short minor
)
818 DWORD
calc_crc32(HANDLE handle
)
824 SetFilePointer(handle
, 0, 0, FILE_BEGIN
);
825 while (ReadFile(handle
, buffer
, sizeof(buffer
), &len
, NULL
) && len
)
826 crc
= RtlComputeCrc32(crc
, buffer
, len
);