hidclass.sys: Support parsing of explicit usage page.
[wine.git] / dlls / dbghelp / dbghelp.c
blob00d7b61fbd8a2f4f8b18954029a9dc825ad57fad
1 /*
2 * File dbghelp.c - generic routines (process) for dbghelp DLL
4 * Copyright (C) 2004, Eric Pouech
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.
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.
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
22 #include <unistd.h>
23 #include "dbghelp_private.h"
24 #include "winternl.h"
25 #include "winerror.h"
26 #include "psapi.h"
27 #include "wine/debug.h"
28 #include "wdbgexts.h"
29 #include "winnls.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
33 /* TODO
34 * - support for symbols' types is still partly missing
35 * + C++ support
36 * + we should store the underlying type for an enum in the symt_enum struct
37 * + for enums, we store the names & values (associated to the enum type),
38 * but those values are not directly usable from a debugger (that's why, I
39 * assume, that we have also to define constants for enum values, as
40 * Codeview does BTW.
41 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
42 * all the types stored/used in the modules (like char*)
43 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
44 * functions, and even across function blocks...). Basically, for *Next* to work
45 * it requires an address after the prolog of the func (the base address of the
46 * func doesn't work)
47 * - most options (dbghelp_options) are not used (loading lines...)
48 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
49 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
50 * we could use hash if name isn't a RE, and fall back to a full search when we
51 * get a full RE
52 * - msc:
53 * + we should add parameters' types to the function's signature
54 * while processing a function's parameters
55 * + add support for function-less labels (as MSC seems to define them)
56 * + C++ management
57 * - stabs:
58 * + when, in a same module, the same definition is used in several compilation
59 * units, we get several definitions of the same object (especially
60 * struct/union). we should find a way not to duplicate them
61 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
62 * global variable is defined several times (at different scopes). We are
63 * getting several of those while looking for a unique symbol. Part of the
64 * issue is that we don't give a scope to a static variable inside a function
65 * + C++ management
68 unsigned dbghelp_options = SYMOPT_UNDNAME;
69 BOOL dbghelp_opt_native = FALSE;
70 SYSTEM_INFO sysinfo;
72 static struct process* process_first /* = NULL */;
74 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
76 switch (reason)
78 case DLL_PROCESS_ATTACH:
79 GetSystemInfo(&sysinfo);
80 DisableThreadLibraryCalls(instance);
81 break;
83 return TRUE;
86 /******************************************************************
87 * process_find_by_handle
90 struct process* process_find_by_handle(HANDLE hProcess)
92 struct process* p;
94 for (p = process_first; p && p->handle != hProcess; p = p->next);
95 if (!p) SetLastError(ERROR_INVALID_HANDLE);
96 return p;
99 /******************************************************************
100 * validate_addr64 (internal)
103 BOOL validate_addr64(DWORD64 addr)
105 if (sizeof(void*) == sizeof(int) && (addr >> 32))
107 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
108 SetLastError(ERROR_INVALID_PARAMETER);
109 return FALSE;
111 return TRUE;
114 /******************************************************************
115 * fetch_buffer
117 * Ensures process' internal buffer is large enough.
119 void* fetch_buffer(struct process* pcs, unsigned size)
121 if (size > pcs->buffer_size)
123 if (pcs->buffer)
124 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
125 else
126 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
127 pcs->buffer_size = (pcs->buffer) ? size : 0;
129 return pcs->buffer;
132 const char* wine_dbgstr_addr(const ADDRESS64* addr)
134 if (!addr) return "(null)";
135 switch (addr->Mode)
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";
150 extern struct cpu cpu_i386, cpu_x86_64, cpu_arm, cpu_arm64;
152 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_arm, &cpu_arm64, NULL};
153 struct cpu* dbghelp_current_cpu =
154 #if defined(__i386__)
155 &cpu_i386
156 #elif defined(__x86_64__)
157 &cpu_x86_64
158 #elif defined(__arm__)
159 &cpu_arm
160 #elif defined(__aarch64__)
161 &cpu_arm64
162 #else
163 #error define support for your CPU
164 #endif
167 struct cpu* cpu_find(DWORD machine)
169 struct cpu** cpu;
171 for (cpu = dbghelp_cpus ; *cpu; cpu++)
173 if (cpu[0]->machine == machine) return cpu[0];
175 return NULL;
178 /******************************************************************
179 * SymSetSearchPathW (DBGHELP.@)
182 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
184 struct process* pcs = process_find_by_handle(hProcess);
186 if (!pcs) return FALSE;
187 if (!searchPath) return FALSE;
189 HeapFree(GetProcessHeap(), 0, pcs->search_path);
190 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
191 (lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
192 searchPath);
193 return TRUE;
196 /******************************************************************
197 * SymSetSearchPath (DBGHELP.@)
200 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
202 BOOL ret = FALSE;
203 unsigned len;
204 WCHAR* sp;
206 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
207 if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
209 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
211 ret = SymSetSearchPathW(hProcess, sp);
212 HeapFree(GetProcessHeap(), 0, sp);
214 return ret;
217 /***********************************************************************
218 * SymGetSearchPathW (DBGHELP.@)
220 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
221 DWORD SearchPathLength)
223 struct process* pcs = process_find_by_handle(hProcess);
224 if (!pcs) return FALSE;
226 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
227 return TRUE;
230 /***********************************************************************
231 * SymGetSearchPath (DBGHELP.@)
233 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
234 DWORD SearchPathLength)
236 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
237 BOOL ret = FALSE;
239 if (buffer)
241 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
242 if (ret)
243 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
244 szSearchPath, SearchPathLength, NULL, NULL);
245 HeapFree(GetProcessHeap(), 0, buffer);
247 return ret;
250 /******************************************************************
251 * invade_process
253 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
254 * this assumes that hProcess is a handle on a valid process
256 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
258 WCHAR tmp[MAX_PATH];
259 HANDLE hProcess = user;
261 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, tmp, ARRAY_SIZE(tmp)))
262 lstrcpynW(tmp, name, ARRAY_SIZE(tmp));
264 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
265 return TRUE;
268 const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
270 size_t name_len;
271 const WCHAR *iter;
273 if (!process->environment) return NULL;
274 name_len = lstrlenW(name);
276 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1)
278 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=')
279 return iter + name_len + 1;
282 return NULL;
285 /******************************************************************
286 * check_live_target
289 static BOOL check_live_target(struct process* pcs)
291 PROCESS_BASIC_INFORMATION pbi;
292 ULONG_PTR base = 0, env = 0;
294 if (!GetProcessId(pcs->handle)) return FALSE;
295 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
297 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation,
298 &pbi, sizeof(pbi), NULL ))
299 return FALSE;
301 if (!pcs->is_64bit)
303 DWORD env32;
304 PEB32 peb32;
305 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48);
306 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE;
307 if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE;
308 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32;
310 else
312 PEB peb;
313 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE;
314 if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + FIELD_OFFSET(PEB, CloudFileFlags), &base, sizeof(base), NULL)) return FALSE;
315 ReadProcessMemory(pcs->handle, (char *)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment), &env, sizeof(env), NULL);
318 /* read debuggee environment block */
319 if (env)
321 size_t buf_size = 0, i, last_null = -1;
322 WCHAR *buf = NULL;
326 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1));
327 if (buf)
329 WCHAR *new_buf;
330 if (!(new_buf = realloc(buf, buf_size + read_size))) break;
331 buf = new_buf;
333 else if(!(buf = malloc(read_size))) break;
335 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break;
336 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++)
338 if (buf[i]) continue;
339 if (last_null + 1 == i)
341 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR));
342 buf = NULL;
343 break;
345 last_null = i;
347 env += read_size;
348 buf_size += read_size;
350 while (buf);
351 free(buf);
354 if (!base) return FALSE;
356 TRACE("got debug info address %#lx from PEB %p\n", base, pbi.PebBaseAddress);
357 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
358 WARN("couldn't load process debug info at %#lx\n", base);
359 return TRUE;
362 /******************************************************************
363 * SymInitializeW (DBGHELP.@)
365 * The initialisation of a dbghelp's context.
366 * Note that hProcess doesn't need to be a valid process handle (except
367 * when fInvadeProcess is TRUE).
368 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
369 * containing PE (and NE) module(s), here's how we handle it:
370 * - we load every module (ELF, NE, PE) passed in SymLoadModule
371 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
372 * synchronization: hProcess should be a valid process handle, and we hook
373 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
374 * our internal ELF modules representation (loading / unloading). This way,
375 * we'll pair every loaded builtin PE module with its ELF counterpart (and
376 * access its debug information).
377 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
378 * hProcess refers to a running process. We use some heuristics here, so YMMV.
379 * If we detect a live target, then we get the same handling as if
380 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
381 * we won't be able to make the peering between a builtin PE module and its ELF
382 * counterpart. Hence we won't be able to provide the requested debug
383 * information. We'll however be able to load native PE modules (and their
384 * debug information) without any trouble.
385 * Note also that this scheme can be intertwined with the deferred loading
386 * mechanism (ie only load the debug information when we actually need it).
388 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
390 struct process* pcs;
391 BOOL wow64, child_wow64;
393 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
395 if (process_find_by_handle(hProcess))
397 WARN("the symbols for this process have already been initialized!\n");
399 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
400 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
401 Native still returns TRUE even if the process has already been initialized. */
402 return TRUE;
405 IsWow64Process(GetCurrentProcess(), &wow64);
407 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64))
408 return FALSE;
410 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
411 if (!pcs) return FALSE;
413 pcs->handle = hProcess;
414 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64;
415 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */
417 if (UserSearchPath)
419 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
420 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
421 UserSearchPath);
423 else
425 unsigned size;
426 unsigned len;
427 static const WCHAR sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
428 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};
430 pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
431 while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
432 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
433 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
435 len = GetEnvironmentVariableW(sym_path, NULL, 0);
436 if (len)
438 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
439 pcs->search_path[size] = ';';
440 GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
441 size += 1 + len;
443 len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
444 if (len)
446 pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
447 pcs->search_path[size] = ';';
448 GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
452 pcs->lmodules = NULL;
453 pcs->dbg_hdr_addr = 0;
454 pcs->next = process_first;
455 process_first = pcs;
457 if (check_live_target(pcs))
459 if (fInvadeProcess)
460 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
461 if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
463 else if (fInvadeProcess)
465 SymCleanup(hProcess);
466 SetLastError(ERROR_INVALID_PARAMETER);
467 return FALSE;
470 return TRUE;
473 /******************************************************************
474 * SymInitialize (DBGHELP.@)
478 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
480 WCHAR* sp = NULL;
481 BOOL ret;
483 if (UserSearchPath)
485 unsigned len;
487 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
488 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
489 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
492 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
493 HeapFree(GetProcessHeap(), 0, sp);
494 return ret;
497 /******************************************************************
498 * SymCleanup (DBGHELP.@)
501 BOOL WINAPI SymCleanup(HANDLE hProcess)
503 struct process** ppcs;
504 struct process* next;
506 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
508 if ((*ppcs)->handle == hProcess)
510 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
512 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
513 free((*ppcs)->environment);
514 next = (*ppcs)->next;
515 HeapFree(GetProcessHeap(), 0, *ppcs);
516 *ppcs = next;
517 return TRUE;
521 ERR("this process has not had SymInitialize() called for it!\n");
522 return FALSE;
525 /******************************************************************
526 * SymSetOptions (DBGHELP.@)
529 DWORD WINAPI SymSetOptions(DWORD opts)
531 struct process* pcs;
533 for (pcs = process_first; pcs; pcs = pcs->next)
535 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
537 return dbghelp_options = opts;
540 /******************************************************************
541 * SymGetOptions (DBGHELP.@)
544 DWORD WINAPI SymGetOptions(void)
546 return dbghelp_options;
549 /******************************************************************
550 * SymSetExtendedOption (DBGHELP.@)
553 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
555 BOOL old = FALSE;
557 switch(option)
559 case SYMOPT_EX_WINE_NATIVE_MODULES:
560 old = dbghelp_opt_native;
561 dbghelp_opt_native = value;
562 break;
563 default:
564 FIXME("Unsupported option %d with value %d\n", option, value);
567 return old;
570 /******************************************************************
571 * SymGetExtendedOption (DBGHELP.@)
574 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
576 switch(option)
578 case SYMOPT_EX_WINE_NATIVE_MODULES:
579 return dbghelp_opt_native;
580 default:
581 FIXME("Unsupported option %d\n", option);
584 return FALSE;
587 /******************************************************************
588 * SymSetParentWindow (DBGHELP.@)
591 BOOL WINAPI SymSetParentWindow(HWND hwnd)
593 /* Save hwnd so it can be used as parent window */
594 FIXME("(%p): stub\n", hwnd);
595 return TRUE;
598 /******************************************************************
599 * SymSetContext (DBGHELP.@)
602 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
603 PIMAGEHLP_CONTEXT Context)
605 struct process* pcs = process_find_by_handle(hProcess);
606 if (!pcs) return FALSE;
608 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
609 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
610 pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
612 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
613 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
614 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
615 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
616 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
617 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
618 return FALSE;
621 pcs->ctx_frame = *StackFrame;
622 /* MSDN states that Context is not (no longer?) used */
623 return TRUE;
626 /******************************************************************
627 * reg_cb64to32 (internal)
629 * Registered callback for converting information from 64 bit to 32 bit
631 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
633 struct process* pcs = process_find_by_handle(hProcess);
634 void* data32;
635 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
636 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
638 if (!pcs) return FALSE;
639 switch (action)
641 case CBA_DEBUG_INFO:
642 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
643 case CBA_SET_OPTIONS:
644 case CBA_SYMBOLS_UNLOADED:
645 data32 = (void*)(DWORD_PTR)data;
646 break;
647 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
648 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
649 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
650 case CBA_DEFERRED_SYMBOL_LOAD_START:
651 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
652 if (!validate_addr64(idsl64->BaseOfImage))
653 return FALSE;
654 idsl.SizeOfStruct = sizeof(idsl);
655 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
656 idsl.CheckSum = idsl64->CheckSum;
657 idsl.TimeDateStamp = idsl64->TimeDateStamp;
658 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
659 idsl.Reparse = idsl64->Reparse;
660 data32 = &idsl;
661 break;
662 case CBA_DUPLICATE_SYMBOL:
663 case CBA_EVENT:
664 case CBA_READ_MEMORY:
665 default:
666 FIXME("No mapping for action %u\n", action);
667 return FALSE;
669 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
672 /******************************************************************
673 * pcs_callback (internal)
675 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
677 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
679 TRACE("%p %u %p\n", pcs, action, data);
681 if (!pcs->reg_cb) return FALSE;
682 if (!pcs->reg_is_unicode)
684 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
686 switch (action)
688 case CBA_DEBUG_INFO:
689 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
690 case CBA_SET_OPTIONS:
691 case CBA_SYMBOLS_UNLOADED:
692 break;
693 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
694 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
695 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
696 case CBA_DEFERRED_SYMBOL_LOAD_START:
697 idslW = data;
698 idsl.SizeOfStruct = sizeof(idsl);
699 idsl.BaseOfImage = idslW->BaseOfImage;
700 idsl.CheckSum = idslW->CheckSum;
701 idsl.TimeDateStamp = idslW->TimeDateStamp;
702 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
703 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
704 idsl.Reparse = idslW->Reparse;
705 data = &idsl;
706 break;
707 case CBA_DUPLICATE_SYMBOL:
708 case CBA_EVENT:
709 case CBA_READ_MEMORY:
710 default:
711 FIXME("No mapping for action %u\n", action);
712 return FALSE;
715 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
718 /******************************************************************
719 * sym_register_cb
721 * Helper for registering a callback.
723 static BOOL sym_register_cb(HANDLE hProcess,
724 PSYMBOL_REGISTERED_CALLBACK64 cb,
725 PSYMBOL_REGISTERED_CALLBACK cb32,
726 DWORD64 user, BOOL unicode)
728 struct process* pcs = process_find_by_handle(hProcess);
730 if (!pcs) return FALSE;
731 pcs->reg_cb = cb;
732 pcs->reg_cb32 = cb32;
733 pcs->reg_is_unicode = unicode;
734 pcs->reg_user = user;
736 return TRUE;
739 /***********************************************************************
740 * SymRegisterCallback (DBGHELP.@)
742 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
743 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
744 PVOID UserContext)
746 TRACE("(%p, %p, %p)\n",
747 hProcess, CallbackFunction, UserContext);
748 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
751 /***********************************************************************
752 * SymRegisterCallback64 (DBGHELP.@)
754 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
755 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
756 ULONG64 UserContext)
758 TRACE("(%p, %p, %s)\n",
759 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
760 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
763 /***********************************************************************
764 * SymRegisterCallbackW64 (DBGHELP.@)
766 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
767 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
768 ULONG64 UserContext)
770 TRACE("(%p, %p, %s)\n",
771 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
772 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
775 /* This is imagehlp version not dbghelp !! */
776 static API_VERSION api_version = { 4, 0, 2, 0 };
778 /***********************************************************************
779 * ImagehlpApiVersion (DBGHELP.@)
781 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
783 return &api_version;
786 /***********************************************************************
787 * ImagehlpApiVersionEx (DBGHELP.@)
789 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
791 if (!AppVersion) return NULL;
793 AppVersion->MajorVersion = api_version.MajorVersion;
794 AppVersion->MinorVersion = api_version.MinorVersion;
795 AppVersion->Revision = api_version.Revision;
796 AppVersion->Reserved = api_version.Reserved;
798 return AppVersion;
801 /******************************************************************
802 * ExtensionApiVersion (DBGHELP.@)
804 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
806 static EXT_API_VERSION eav = {5, 5, 5, 0};
807 return &eav;
810 /******************************************************************
811 * WinDbgExtensionDllInit (DBGHELP.@)
813 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
814 unsigned short major, unsigned short minor)
818 DWORD calc_crc32(HANDLE handle)
820 BYTE buffer[8192];
821 DWORD crc = 0;
822 DWORD len;
824 SetFilePointer(handle, 0, 0, FILE_BEGIN);
825 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len)
826 crc = RtlComputeCrc32(crc, buffer, len);
827 return crc;