[CMAKE]
[reactos.git] / dll / win32 / dbghelp / dbghelp.c
1 /*
2 * File dbghelp.c - generic routines (process) for dbghelp DLL
3 *
4 * Copyright (C) 2004, Eric Pouech
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22
23 #include "dbghelp_private.h"
24 #include "winerror.h"
25 #include "psapi.h"
26 #include "wine/debug.h"
27 #include "wdbgexts.h"
28 #include "winnls.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
31
32 /* TODO
33 * - support for symbols' types is still partly missing
34 * + C++ support
35 * + we should store the underlying type for an enum in the symt_enum struct
36 * + for enums, we store the names & values (associated to the enum type),
37 * but those values are not directly usable from a debugger (that's why, I
38 * assume, that we have also to define constants for enum values, as
39 * Codeview does BTW.
40 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
41 * all the types stored/used in the modules (like char*)
42 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
43 * functions, and even across function blocks...). Basically, for *Next* to work
44 * it requires an address after the prolog of the func (the base address of the
45 * func doesn't work)
46 * - most options (dbghelp_options) are not used (loading lines...)
47 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
48 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
49 * we could use hash if name isn't a RE, and fall back to a full search when we
50 * get a full RE
51 * - msc:
52 * + we should add parameters' types to the function's signature
53 * while processing a function's parameters
54 * + add support for function-less labels (as MSC seems to define them)
55 * + C++ management
56 * - stabs:
57 * + when, in a same module, the same definition is used in several compilation
58 * units, we get several definitions of the same object (especially
59 * struct/union). we should find a way not to duplicate them
60 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
61 * global variable is defined several times (at different scopes). We are
62 * getting several of those while looking for a unique symbol. Part of the
63 * issue is that we don't give a scope to a static variable inside a function
64 * + C++ management
65 */
66
67 unsigned dbghelp_options = SYMOPT_UNDNAME;
68 HANDLE hMsvcrt = NULL;
69
70 /***********************************************************************
71 * DllMain (DEBUGHLP.@)
72 */
73 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
74 {
75 switch (fdwReason)
76 {
77 case DLL_PROCESS_ATTACH: break;
78 case DLL_PROCESS_DETACH:
79 if (hMsvcrt) FreeLibrary(hMsvcrt);
80 break;
81 case DLL_THREAD_ATTACH: break;
82 case DLL_THREAD_DETACH: break;
83 default: break;
84 }
85 return TRUE;
86 }
87
88 static struct process* process_first /* = NULL */;
89
90 /******************************************************************
91 * process_find_by_handle
92 *
93 */
94 struct process* process_find_by_handle(HANDLE hProcess)
95 {
96 struct process* p;
97
98 for (p = process_first; p && p->handle != hProcess; p = p->next);
99 if (!p) SetLastError(ERROR_INVALID_HANDLE);
100 return p;
101 }
102
103 /******************************************************************
104 * validate_addr64 (internal)
105 *
106 */
107 BOOL validate_addr64(DWORD64 addr)
108 {
109 if (sizeof(void*) == sizeof(int) && (addr >> 32))
110 {
111 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
112 SetLastError(ERROR_INVALID_PARAMETER);
113 return FALSE;
114 }
115 return TRUE;
116 }
117
118 /******************************************************************
119 * fetch_buffer
120 *
121 * Ensures process' internal buffer is large enough.
122 */
123 void* fetch_buffer(struct process* pcs, unsigned size)
124 {
125 if (size > pcs->buffer_size)
126 {
127 if (pcs->buffer)
128 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
129 else
130 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
131 pcs->buffer_size = (pcs->buffer) ? size : 0;
132 }
133 return pcs->buffer;
134 }
135
136 const char* wine_dbgstr_addr(const ADDRESS64* addr)
137 {
138 if (!addr) return "(null)";
139 switch (addr->Mode)
140 {
141 case AddrModeFlat:
142 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset));
143 case AddrMode1616:
144 return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
145 case AddrMode1632:
146 return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset);
147 case AddrModeReal:
148 return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
149 default:
150 return "unknown";
151 }
152 }
153
154 extern struct cpu cpu_i386, cpu_x86_64;
155
156 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, NULL};
157 struct cpu* dbghelp_current_cpu =
158 #if defined(__i386__)
159 &cpu_i386
160 #elif defined(__x86_64__)
161 &cpu_x86_64
162 #else
163 #error define support for your CPU
164 #endif
165 ;
166
167 struct cpu* cpu_find(DWORD machine)
168 {
169 struct cpu** cpu;
170
171 for (cpu = dbghelp_cpus ; *cpu; cpu++)
172 {
173 if (cpu[0]->machine == machine) return cpu[0];
174 }
175 return NULL;
176 }
177
178 /******************************************************************
179 * SymSetSearchPathW (DBGHELP.@)
180 *
181 */
182 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
183 {
184 struct process* pcs = process_find_by_handle(hProcess);
185
186 if (!pcs) return FALSE;
187 if (!searchPath) return FALSE;
188
189 HeapFree(GetProcessHeap(), 0, pcs->search_path);
190 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
191 (lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
192 searchPath);
193 return TRUE;
194 }
195
196 /******************************************************************
197 * SymSetSearchPath (DBGHELP.@)
198 *
199 */
200 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
201 {
202 BOOL ret = FALSE;
203 unsigned len;
204 WCHAR* sp;
205
206 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
207 if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
208 {
209 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
210
211 ret = SymSetSearchPathW(hProcess, sp);
212 HeapFree(GetProcessHeap(), 0, sp);
213 }
214 return ret;
215 }
216
217 /***********************************************************************
218 * SymGetSearchPathW (DBGHELP.@)
219 */
220 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
221 DWORD SearchPathLength)
222 {
223 struct process* pcs = process_find_by_handle(hProcess);
224 if (!pcs) return FALSE;
225
226 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
227 return TRUE;
228 }
229
230 /***********************************************************************
231 * SymGetSearchPath (DBGHELP.@)
232 */
233 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
234 DWORD SearchPathLength)
235 {
236 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
237 BOOL ret = FALSE;
238
239 if (buffer)
240 {
241 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
242 if (ret)
243 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
244 szSearchPath, SearchPathLength, NULL, NULL);
245 HeapFree(GetProcessHeap(), 0, buffer);
246 }
247 return ret;
248 }
249
250 /******************************************************************
251 * invade_process
252 *
253 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
254 * this assumes that hProcess is a handle on a valid process
255 */
256 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
257 {
258 WCHAR tmp[MAX_PATH];
259 HANDLE hProcess = user;
260
261 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base,
262 tmp, sizeof(tmp) / sizeof(WCHAR)))
263 lstrcpynW(tmp, name, sizeof(tmp) / sizeof(WCHAR));
264
265 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
266 return TRUE;
267 }
268
269 /******************************************************************
270 * check_live_target
271 *
272 */
273 static BOOL check_live_target(struct process* pcs)
274 {
275 if (!GetProcessId(pcs->handle)) return FALSE;
276 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
277 if (!elf_read_wine_loader_dbg_info(pcs))
278 macho_read_wine_loader_dbg_info(pcs);
279 return TRUE;
280 }
281
282 /******************************************************************
283 * SymInitializeW (DBGHELP.@)
284 *
285 * The initialisation of a dbghelp's context.
286 * Note that hProcess doesn't need to be a valid process handle (except
287 * when fInvadeProcess is TRUE).
288 * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries
289 * containing PE (and NE) module(s), here's how we handle it:
290 * - we load every module (ELF, NE, PE) passed in SymLoadModule
291 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
292 * synchronization: hProcess should be a valid process handle, and we hook
293 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
294 * our internal ELF modules representation (loading / unloading). This way,
295 * we'll pair every loaded builtin PE module with its ELF counterpart (and
296 * access its debug information).
297 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
298 * hProcess refers to a running process. We use some heuristics here, so YMMV.
299 * If we detect a live target, then we get the same handling as if
300 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
301 * we won't be able to make the peering between a builtin PE module and its ELF
302 * counterpart. Hence we won't be able to provide the requested debug
303 * information. We'll however be able to load native PE modules (and their
304 * debug information) without any trouble.
305 * Note also that this scheme can be intertwined with the deferred loading
306 * mechanism (ie only load the debug information when we actually need it).
307 */
308 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
309 {
310 struct process* pcs;
311
312 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
313
314 if (process_find_by_handle(hProcess)){
315 WARN("the symbols for this process have already been initialized!\n");
316
317 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
318 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
319 Native still returns TRUE even if the process has already been initialized. */
320 return TRUE;
321 }
322
323 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
324 if (!pcs) return FALSE;
325
326 pcs->handle = hProcess;
327
328 if (UserSearchPath)
329 {
330 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
331 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
332 UserSearchPath);
333 }
334 else
335 {
336 unsigned size;
337 unsigned len;
338 static const WCHAR sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
339 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};
340
341 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
342 while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
343 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
344 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
345
346 len = GetEnvironmentVariableW(sym_path, NULL, 0);
347 if (len)
348 {
349 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
350 pcs->search_path[size] = ';';
351 GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
352 size += 1 + len;
353 }
354 len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
355 if (len)
356 {
357 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
358 pcs->search_path[size] = ';';
359 GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
360 }
361 }
362
363 pcs->lmodules = NULL;
364 pcs->dbg_hdr_addr = 0;
365 pcs->next = process_first;
366 process_first = pcs;
367
368 if (check_live_target(pcs))
369 {
370 if (fInvadeProcess)
371 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
372 elf_synchronize_module_list(pcs);
373 macho_synchronize_module_list(pcs);
374 }
375 else if (fInvadeProcess)
376 {
377 SymCleanup(hProcess);
378 SetLastError(ERROR_INVALID_PARAMETER);
379 return FALSE;
380 }
381
382 return TRUE;
383 }
384
385 /******************************************************************
386 * SymInitialize (DBGHELP.@)
387 *
388 *
389 */
390 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
391 {
392 WCHAR* sp = NULL;
393 BOOL ret;
394
395 if (UserSearchPath)
396 {
397 unsigned len;
398
399 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
400 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
401 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
402 }
403
404 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
405 HeapFree(GetProcessHeap(), 0, sp);
406 return ret;
407 }
408
409 /******************************************************************
410 * SymCleanup (DBGHELP.@)
411 *
412 */
413 BOOL WINAPI SymCleanup(HANDLE hProcess)
414 {
415 struct process** ppcs;
416 struct process* next;
417
418 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
419 {
420 if ((*ppcs)->handle == hProcess)
421 {
422 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
423
424 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
425 next = (*ppcs)->next;
426 HeapFree(GetProcessHeap(), 0, *ppcs);
427 *ppcs = next;
428 return TRUE;
429 }
430 }
431
432 ERR("this process has not had SymInitialize() called for it!\n");
433 return FALSE;
434 }
435
436 /******************************************************************
437 * SymSetOptions (DBGHELP.@)
438 *
439 */
440 DWORD WINAPI SymSetOptions(DWORD opts)
441 {
442 struct process* pcs;
443
444 for (pcs = process_first; pcs; pcs = pcs->next)
445 {
446 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
447 }
448 return dbghelp_options = opts;
449 }
450
451 /******************************************************************
452 * SymGetOptions (DBGHELP.@)
453 *
454 */
455 DWORD WINAPI SymGetOptions(void)
456 {
457 return dbghelp_options;
458 }
459
460 /******************************************************************
461 * SymSetParentWindow (DBGHELP.@)
462 *
463 */
464 BOOL WINAPI SymSetParentWindow(HWND hwnd)
465 {
466 /* Save hwnd so it can be used as parent window */
467 FIXME("(%p): stub\n", hwnd);
468 return TRUE;
469 }
470
471 /******************************************************************
472 * SymSetContext (DBGHELP.@)
473 *
474 */
475 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
476 PIMAGEHLP_CONTEXT Context)
477 {
478 struct process* pcs = process_find_by_handle(hProcess);
479 if (!pcs) return FALSE;
480
481 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
482 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
483 pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
484 {
485 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
486 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
487 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
488 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
489 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
490 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
491 return FALSE;
492 }
493
494 pcs->ctx_frame = *StackFrame;
495 /* MSDN states that Context is not (no longer?) used */
496 return TRUE;
497 }
498
499 /******************************************************************
500 * reg_cb64to32 (internal)
501 *
502 * Registered callback for converting information from 64 bit to 32 bit
503 */
504 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
505 {
506 struct process* pcs = process_find_by_handle(hProcess);
507 void* data32;
508 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
509 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
510
511 if (!pcs) return FALSE;
512 switch (action)
513 {
514 case CBA_DEBUG_INFO:
515 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
516 case CBA_SET_OPTIONS:
517 case CBA_SYMBOLS_UNLOADED:
518 data32 = (void*)(DWORD_PTR)data;
519 break;
520 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
521 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
522 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
523 case CBA_DEFERRED_SYMBOL_LOAD_START:
524 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
525 if (!validate_addr64(idsl64->BaseOfImage))
526 return FALSE;
527 idsl.SizeOfStruct = sizeof(idsl);
528 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
529 idsl.CheckSum = idsl64->CheckSum;
530 idsl.TimeDateStamp = idsl64->TimeDateStamp;
531 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
532 idsl.Reparse = idsl64->Reparse;
533 data32 = &idsl;
534 break;
535 case CBA_DUPLICATE_SYMBOL:
536 case CBA_EVENT:
537 case CBA_READ_MEMORY:
538 default:
539 FIXME("No mapping for action %u\n", action);
540 return FALSE;
541 }
542 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
543 }
544
545 /******************************************************************
546 * pcs_callback (internal)
547 */
548 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
549 {
550 TRACE("%p %u %p\n", pcs, action, data);
551
552 if (!pcs->reg_cb) return FALSE;
553 if (!pcs->reg_is_unicode)
554 {
555 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
556 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
557
558 switch (action)
559 {
560 case CBA_DEBUG_INFO:
561 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
562 case CBA_SET_OPTIONS:
563 case CBA_SYMBOLS_UNLOADED:
564 break;
565 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
566 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
567 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
568 case CBA_DEFERRED_SYMBOL_LOAD_START:
569 idslW = data;
570 idsl.SizeOfStruct = sizeof(idsl);
571 idsl.BaseOfImage = idslW->BaseOfImage;
572 idsl.CheckSum = idslW->CheckSum;
573 idsl.TimeDateStamp = idslW->TimeDateStamp;
574 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
575 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
576 idsl.Reparse = idslW->Reparse;
577 data = &idsl;
578 break;
579 case CBA_DUPLICATE_SYMBOL:
580 case CBA_EVENT:
581 case CBA_READ_MEMORY:
582 default:
583 FIXME("No mapping for action %u\n", action);
584 return FALSE;
585 }
586 }
587 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
588 }
589
590 /******************************************************************
591 * sym_register_cb
592 *
593 * Helper for registering a callback.
594 */
595 static BOOL sym_register_cb(HANDLE hProcess,
596 PSYMBOL_REGISTERED_CALLBACK64 cb,
597 PSYMBOL_REGISTERED_CALLBACK cb32,
598 DWORD64 user, BOOL unicode)
599 {
600 struct process* pcs = process_find_by_handle(hProcess);
601
602 if (!pcs) return FALSE;
603 pcs->reg_cb = cb;
604 pcs->reg_cb32 = cb32;
605 pcs->reg_is_unicode = unicode;
606 pcs->reg_user = user;
607
608 return TRUE;
609 }
610
611 /***********************************************************************
612 * SymRegisterCallback (DBGHELP.@)
613 */
614 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
615 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
616 PVOID UserContext)
617 {
618 TRACE("(%p, %p, %p)\n",
619 hProcess, CallbackFunction, UserContext);
620 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
621 }
622
623 /***********************************************************************
624 * SymRegisterCallback64 (DBGHELP.@)
625 */
626 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
627 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
628 ULONG64 UserContext)
629 {
630 TRACE("(%p, %p, %s)\n",
631 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
632 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
633 }
634
635 /***********************************************************************
636 * SymRegisterCallbackW64 (DBGHELP.@)
637 */
638 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
639 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
640 ULONG64 UserContext)
641 {
642 TRACE("(%p, %p, %s)\n",
643 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
644 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
645 }
646
647 /* This is imagehlp version not dbghelp !! */
648 static API_VERSION api_version = { 4, 0, 2, 0 };
649
650 /***********************************************************************
651 * ImagehlpApiVersion (DBGHELP.@)
652 */
653 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
654 {
655 return &api_version;
656 }
657
658 /***********************************************************************
659 * ImagehlpApiVersionEx (DBGHELP.@)
660 */
661 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
662 {
663 if (!AppVersion) return NULL;
664
665 AppVersion->MajorVersion = api_version.MajorVersion;
666 AppVersion->MinorVersion = api_version.MinorVersion;
667 AppVersion->Revision = api_version.Revision;
668 AppVersion->Reserved = api_version.Reserved;
669
670 return AppVersion;
671 }
672
673 /******************************************************************
674 * ExtensionApiVersion (DBGHELP.@)
675 */
676 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
677 {
678 static EXT_API_VERSION eav = {5, 5, 5, 0};
679 return &eav;
680 }
681
682 /******************************************************************
683 * WinDbgExtensionDllInit (DBGHELP.@)
684 */
685 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
686 unsigned short major, unsigned short minor)
687 {
688 }