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