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