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