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