include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / dbghelp / dbghelp.c
blob4e6938cb557e570600b44c006dc640a59ae4dc57
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 BOOL dbghelp_opt_extension_api = FALSE;
71 BOOL dbghelp_opt_real_path = FALSE;
72 BOOL dbghelp_opt_source_actual_path = FALSE;
73 SYSTEM_INFO sysinfo;
75 static struct process* process_first /* = NULL */;
77 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
79 switch (reason)
81 case DLL_PROCESS_ATTACH:
82 GetSystemInfo(&sysinfo);
83 DisableThreadLibraryCalls(instance);
84 break;
86 return TRUE;
89 /******************************************************************
90 * process_find_by_handle
93 struct process* process_find_by_handle(HANDLE hProcess)
95 struct process* p;
97 for (p = process_first; p && p->handle != hProcess; p = p->next);
98 if (!p) SetLastError(ERROR_INVALID_HANDLE);
99 return p;
102 /******************************************************************
103 * validate_addr64 (internal)
106 BOOL validate_addr64(DWORD64 addr)
108 if (sizeof(void*) == sizeof(int) && (addr >> 32))
110 FIXME("Unsupported address %I64x\n", addr);
111 SetLastError(ERROR_INVALID_PARAMETER);
112 return FALSE;
114 return TRUE;
117 /******************************************************************
118 * fetch_buffer
120 * Ensures process' internal buffer is large enough.
122 void* fetch_buffer(struct process* pcs, unsigned size)
124 if (size > pcs->buffer_size)
126 if (pcs->buffer)
127 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
128 else
129 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
130 pcs->buffer_size = (pcs->buffer) ? size : 0;
132 return pcs->buffer;
135 const char* wine_dbgstr_addr(const ADDRESS64* addr)
137 if (!addr) return "(null)";
138 switch (addr->Mode)
140 case AddrModeFlat:
141 return wine_dbg_sprintf("flat<%I64x>", addr->Offset);
142 case AddrMode1616:
143 return wine_dbg_sprintf("1616<%04x:%04lx>", addr->Segment, (DWORD)addr->Offset);
144 case AddrMode1632:
145 return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, (DWORD)addr->Offset);
146 case AddrModeReal:
147 return wine_dbg_sprintf("real<%04x:%04lx>", addr->Segment, (DWORD)addr->Offset);
148 default:
149 return "unknown";
153 extern struct cpu cpu_i386, cpu_x86_64, cpu_arm, cpu_arm64;
155 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_arm, &cpu_arm64, NULL};
156 struct cpu* dbghelp_current_cpu =
157 #if defined(__i386__)
158 &cpu_i386
159 #elif defined(__x86_64__)
160 &cpu_x86_64
161 #elif defined(__arm__)
162 &cpu_arm
163 #elif defined(__aarch64__)
164 &cpu_arm64
165 #else
166 #error define support for your CPU
167 #endif
170 struct cpu* cpu_find(DWORD machine)
172 struct cpu** cpu;
174 for (cpu = dbghelp_cpus ; *cpu; cpu++)
176 if (cpu[0]->machine == machine) return cpu[0];
178 return NULL;
181 static WCHAR* make_default_search_path(void)
183 WCHAR* search_path;
184 WCHAR* p;
185 unsigned sym_path_len;
186 unsigned alt_sym_path_len;
188 sym_path_len = GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", NULL, 0);
189 alt_sym_path_len = GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
191 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
192 * If the variables exist, the lengths include a null-terminator. We use that
193 * space for the semicolons, and only add the initial dot and the final null. */
194 search_path = HeapAlloc(GetProcessHeap(), 0,
195 (1 + sym_path_len + alt_sym_path_len + 1) * sizeof(WCHAR));
196 if (!search_path) return NULL;
198 p = search_path;
199 *p++ = L'.';
200 if (sym_path_len)
202 *p++ = L';';
203 GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", p, sym_path_len);
204 p += sym_path_len - 1;
207 if (alt_sym_path_len)
209 *p++ = L';';
210 GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", p, alt_sym_path_len);
211 p += alt_sym_path_len - 1;
213 *p = L'\0';
215 return search_path;
218 /******************************************************************
219 * SymSetSearchPathW (DBGHELP.@)
222 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
224 struct process* pcs = process_find_by_handle(hProcess);
225 WCHAR* search_path_buffer;
227 if (!pcs) return FALSE;
229 if (searchPath)
231 search_path_buffer = HeapAlloc(GetProcessHeap(), 0,
232 (lstrlenW(searchPath) + 1) * sizeof(WCHAR));
233 if (!search_path_buffer) return FALSE;
234 lstrcpyW(search_path_buffer, searchPath);
236 else
238 search_path_buffer = make_default_search_path();
239 if (!search_path_buffer) return FALSE;
241 HeapFree(GetProcessHeap(), 0, pcs->search_path);
242 pcs->search_path = search_path_buffer;
243 return TRUE;
246 /******************************************************************
247 * SymSetSearchPath (DBGHELP.@)
250 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
252 BOOL ret = FALSE;
253 unsigned len;
254 WCHAR* sp = NULL;
256 if (searchPath)
258 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
259 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
260 if (!sp) return FALSE;
261 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
264 ret = SymSetSearchPathW(hProcess, sp);
266 HeapFree(GetProcessHeap(), 0, sp);
267 return ret;
270 /***********************************************************************
271 * SymGetSearchPathW (DBGHELP.@)
273 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
274 DWORD SearchPathLength)
276 struct process* pcs = process_find_by_handle(hProcess);
277 if (!pcs) return FALSE;
279 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
280 return TRUE;
283 /***********************************************************************
284 * SymGetSearchPath (DBGHELP.@)
286 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
287 DWORD SearchPathLength)
289 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
290 BOOL ret = FALSE;
292 if (buffer)
294 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
295 if (ret)
296 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
297 szSearchPath, SearchPathLength, NULL, NULL);
298 HeapFree(GetProcessHeap(), 0, buffer);
300 return ret;
303 /******************************************************************
304 * invade_process
306 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
307 * this assumes that hProcess is a handle on a valid process
309 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
311 HANDLE hProcess = user;
313 SymLoadModuleExW(hProcess, 0, name, NULL, base, size, NULL, 0);
314 return TRUE;
317 const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
319 size_t name_len;
320 const WCHAR *iter;
322 if (!process->environment) return NULL;
323 name_len = lstrlenW(name);
325 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1)
327 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=')
328 return iter + name_len + 1;
331 return NULL;
334 const struct cpu* process_get_cpu(const struct process* pcs)
336 const struct module* m = pcs->lmodules;
338 /* return cpu of main module, which is the first module in process's modules list */
339 return (m) ? m->cpu : dbghelp_current_cpu;
342 /******************************************************************
343 * check_live_target
346 static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64)
348 PROCESS_BASIC_INFORMATION pbi;
349 DWORD64 base = 0, env = 0;
350 const char* peb_addr;
352 if (!GetProcessId(pcs->handle)) return FALSE;
353 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
355 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation,
356 &pbi, sizeof(pbi), NULL ))
357 return FALSE;
359 /* Note: we have to deal with the PEB64 and PEB32 in debuggee process
360 * while debugger can be in same or different bitness.
361 * For a 64 bit debuggee, use PEB64 and underlying ELF/system 64 (easy).
362 * For a 32 bit debuggee,
363 * - for environment variables, we need PEB32
364 * - for ELF/system base address, we need PEB32 when run in pure 32bit
365 * or run in old wow configuration, but PEB64 when run in new wow
366 * configuration.
367 * - this must be read from a debugger in either 32 or 64 bit setup.
369 peb_addr = (const char*)pbi.PebBaseAddress;
370 if (!pcs->is_64bit)
372 DWORD env32;
373 PEB32 peb32;
375 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48);
377 if (!wow64 && child_wow64)
378 /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */
379 peb_addr += 0x1000;
380 if (!ReadProcessMemory(pcs->handle, peb_addr, &peb32, sizeof(peb32), NULL)) return FALSE;
381 base = *(const DWORD*)((const char*)&peb32 + 0x460 /* CloudFileFlags */);
382 pcs->is_host_64bit = FALSE;
383 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32;
385 if (pcs->is_64bit || base == 0)
387 PEB64 peb;
389 if (!pcs->is_64bit) peb_addr -= 0x1000; /* PEB32 => PEB64 */
390 if (!ReadProcessMemory(pcs->handle, peb_addr, &peb, sizeof(peb), NULL)) return FALSE;
391 base = *(const DWORD64*)&peb.CloudFileFlags;
392 pcs->is_host_64bit = TRUE;
393 if (pcs->is_64bit)
394 ReadProcessMemory(pcs->handle,
395 (char *)(ULONG_PTR)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment),
396 &env, sizeof(env), NULL);
399 /* read debuggee environment block */
400 if (env)
402 size_t buf_size = 0, i, last_null = -1;
403 WCHAR *buf = NULL;
404 WCHAR *new_buf;
408 size_t read_size = sysinfo.dwPageSize - (env & (sysinfo.dwPageSize - 1));
409 if (!(new_buf = realloc(buf, buf_size + read_size))) break;
410 buf = new_buf;
412 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break;
413 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++)
415 if (buf[i]) continue;
416 if (last_null + 1 == i)
418 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR));
419 buf = NULL;
420 break;
422 last_null = i;
424 env += read_size;
425 buf_size += read_size;
427 while (buf);
428 free(buf);
431 if (!base) return FALSE;
433 TRACE("got debug info address %#I64x from PEB %p\n", base, pbi.PebBaseAddress);
434 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
435 WARN("couldn't load process debug info at %#I64x\n", base);
436 return TRUE;
439 /******************************************************************
440 * SymInitializeW (DBGHELP.@)
442 * The initialisation of a dbghelp's context.
443 * Note that hProcess doesn't need to be a valid process handle (except
444 * when fInvadeProcess is TRUE).
445 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
446 * containing PE (and NE) module(s), here's how we handle it:
447 * - we load every module (ELF, NE, PE) passed in SymLoadModule
448 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
449 * synchronization: hProcess should be a valid process handle, and we hook
450 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
451 * our internal ELF modules representation (loading / unloading). This way,
452 * we'll pair every loaded builtin PE module with its ELF counterpart (and
453 * access its debug information).
454 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
455 * hProcess refers to a running process. We use some heuristics here, so YMMV.
456 * If we detect a live target, then we get the same handling as if
457 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
458 * we won't be able to make the peering between a builtin PE module and its ELF
459 * counterpart. Hence we won't be able to provide the requested debug
460 * information. We'll however be able to load native PE modules (and their
461 * debug information) without any trouble.
462 * Note also that this scheme can be intertwined with the deferred loading
463 * mechanism (ie only load the debug information when we actually need it).
465 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
467 struct process* pcs;
468 BOOL wow64, child_wow64;
470 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
472 if (process_find_by_handle(hProcess))
474 WARN("the symbols for this process have already been initialized!\n");
476 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
477 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
478 Native still returns TRUE even if the process has already been initialized. */
479 return TRUE;
482 IsWow64Process(GetCurrentProcess(), &wow64);
484 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64))
485 return FALSE;
487 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
488 if (!pcs) return FALSE;
490 pcs->handle = hProcess;
491 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64;
492 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */
494 if (UserSearchPath)
496 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
497 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
498 UserSearchPath);
500 else
502 pcs->search_path = make_default_search_path();
505 pcs->lmodules = NULL;
506 pcs->dbg_hdr_addr = 0;
507 pcs->next = process_first;
508 process_first = pcs;
510 if (check_live_target(pcs, wow64, child_wow64))
512 if (fInvadeProcess)
513 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
514 if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
516 else if (fInvadeProcess)
518 SymCleanup(hProcess);
519 SetLastError(ERROR_INVALID_PARAMETER);
520 return FALSE;
523 return TRUE;
526 /******************************************************************
527 * SymInitialize (DBGHELP.@)
531 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
533 WCHAR* sp = NULL;
534 BOOL ret;
536 if (UserSearchPath)
538 unsigned len;
540 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
541 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
542 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
545 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
546 HeapFree(GetProcessHeap(), 0, sp);
547 return ret;
550 /******************************************************************
551 * SymCleanup (DBGHELP.@)
554 BOOL WINAPI SymCleanup(HANDLE hProcess)
556 struct process** ppcs;
557 struct process* next;
559 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
561 if ((*ppcs)->handle == hProcess)
563 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
565 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
566 free((*ppcs)->environment);
567 next = (*ppcs)->next;
568 HeapFree(GetProcessHeap(), 0, *ppcs);
569 *ppcs = next;
570 return TRUE;
574 ERR("this process has not had SymInitialize() called for it!\n");
575 return FALSE;
578 /******************************************************************
579 * SymSetOptions (DBGHELP.@)
582 DWORD WINAPI SymSetOptions(DWORD opts)
584 struct process* pcs;
586 for (pcs = process_first; pcs; pcs = pcs->next)
588 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
590 return dbghelp_options = opts;
593 /******************************************************************
594 * SymGetOptions (DBGHELP.@)
597 DWORD WINAPI SymGetOptions(void)
599 return dbghelp_options;
602 /******************************************************************
603 * SymSetExtendedOption (DBGHELP.@)
606 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
608 BOOL old = FALSE;
610 switch(option)
612 case SYMOPT_EX_WINE_NATIVE_MODULES:
613 old = dbghelp_opt_native;
614 dbghelp_opt_native = value;
615 break;
616 case SYMOPT_EX_WINE_EXTENSION_API:
617 old = dbghelp_opt_extension_api;
618 dbghelp_opt_extension_api = value;
619 break;
620 case SYMOPT_EX_WINE_MODULE_REAL_PATH:
621 old = dbghelp_opt_real_path;
622 dbghelp_opt_real_path = value;
623 break;
624 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH:
625 old = dbghelp_opt_source_actual_path;
626 dbghelp_opt_source_actual_path = value;
627 break;
628 default:
629 FIXME("Unsupported option %d with value %d\n", option, value);
632 return old;
635 /******************************************************************
636 * SymGetExtendedOption (DBGHELP.@)
639 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
641 switch(option)
643 case SYMOPT_EX_WINE_NATIVE_MODULES:
644 return dbghelp_opt_native;
645 case SYMOPT_EX_WINE_EXTENSION_API:
646 return dbghelp_opt_extension_api;
647 case SYMOPT_EX_WINE_MODULE_REAL_PATH:
648 return dbghelp_opt_real_path;
649 case SYMOPT_EX_WINE_SOURCE_ACTUAL_PATH:
650 return dbghelp_opt_source_actual_path;
651 default:
652 FIXME("Unsupported option %d\n", option);
655 return FALSE;
658 /******************************************************************
659 * SymSetParentWindow (DBGHELP.@)
662 BOOL WINAPI SymSetParentWindow(HWND hwnd)
664 /* Save hwnd so it can be used as parent window */
665 FIXME("(%p): stub\n", hwnd);
666 return TRUE;
669 /******************************************************************
670 * SymSetContext (DBGHELP.@)
673 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
674 PIMAGEHLP_CONTEXT Context)
676 struct process* pcs;
678 TRACE("(%p %p %p)\n", hProcess, StackFrame, Context);
680 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
681 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
682 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
683 pcs->ctx_frame.StackOffset == StackFrame->StackOffset &&
684 pcs->ctx_frame.InstructionOffset == StackFrame->InstructionOffset)
686 TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n",
687 pcs->ctx_frame.ReturnOffset,
688 pcs->ctx_frame.FrameOffset,
689 pcs->ctx_frame.StackOffset);
690 SetLastError(ERROR_SUCCESS);
691 return FALSE;
694 if (!SymSetScopeFromAddr(hProcess, StackFrame->InstructionOffset))
695 return FALSE;
696 pcs->ctx_frame = *StackFrame;
697 /* Context is not (no longer?) used */
699 return TRUE;
702 /******************************************************************
703 * SymSetScopeFromAddr (DBGHELP.@)
705 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr)
707 struct module_pair pair;
708 struct symt_ht* sym;
710 TRACE("(%p %#I64x)\n", hProcess, addr);
712 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
713 pair.pcs->localscope_pc = addr;
714 if ((sym = symt_find_symbol_at(pair.effective, addr)) != NULL && sym->symt.tag == SymTagFunction)
715 pair.pcs->localscope_symt = &sym->symt;
716 else
717 pair.pcs->localscope_symt = NULL;
719 return TRUE;
722 /******************************************************************
723 * SymSetScopeFromIndex (DBGHELP.@)
725 BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index)
727 struct module_pair pair;
728 struct symt* sym;
730 TRACE("(%p %#I64x %lu)\n", hProcess, addr, index);
732 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
733 sym = symt_index2ptr(pair.effective, index);
734 if (!symt_check_tag(sym, SymTagFunction)) return FALSE;
736 pair.pcs->localscope_pc = ((struct symt_function*)sym)->ranges[0].low; /* FIXME of FuncDebugStart when it exists? */
737 pair.pcs->localscope_symt = sym;
739 return TRUE;
742 /******************************************************************
743 * SymSetScopeFromInlineContext (DBGHELP.@)
745 BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx)
747 struct module_pair pair;
748 struct symt_function* inlined;
750 TRACE("(%p %I64x %lx)\n", hProcess, addr, inlinectx);
752 switch (IFC_MODE(inlinectx))
754 case IFC_MODE_INLINE:
755 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
756 inlined = symt_find_inlined_site(pair.effective, addr, inlinectx);
757 if (inlined)
759 pair.pcs->localscope_pc = addr;
760 pair.pcs->localscope_symt = &inlined->symt;
761 return TRUE;
763 /* fall through */
764 case IFC_MODE_IGNORE:
765 case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr);
766 default:
767 SetLastError(ERROR_INVALID_PARAMETER);
768 return FALSE;
772 /******************************************************************
773 * reg_cb64to32 (internal)
775 * Registered callback for converting information from 64 bit to 32 bit
777 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
779 struct process* pcs = process_find_by_handle(hProcess);
780 void* data32;
781 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
782 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
784 if (!pcs) return FALSE;
785 switch (action)
787 case CBA_DEBUG_INFO:
788 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
789 case CBA_SET_OPTIONS:
790 case CBA_SYMBOLS_UNLOADED:
791 data32 = (void*)(DWORD_PTR)data;
792 break;
793 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
794 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
795 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
796 case CBA_DEFERRED_SYMBOL_LOAD_START:
797 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
798 if (!validate_addr64(idsl64->BaseOfImage))
799 return FALSE;
800 idsl.SizeOfStruct = sizeof(idsl);
801 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
802 idsl.CheckSum = idsl64->CheckSum;
803 idsl.TimeDateStamp = idsl64->TimeDateStamp;
804 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
805 idsl.Reparse = idsl64->Reparse;
806 data32 = &idsl;
807 break;
808 case CBA_DUPLICATE_SYMBOL:
809 case CBA_EVENT:
810 case CBA_READ_MEMORY:
811 default:
812 FIXME("No mapping for action %lu\n", action);
813 return FALSE;
815 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
818 /******************************************************************
819 * pcs_callback (internal)
821 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
823 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
825 TRACE("%p %lu %p\n", pcs, action, data);
827 if (!pcs->reg_cb) return FALSE;
828 if (!pcs->reg_is_unicode)
830 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
832 switch (action)
834 case CBA_DEBUG_INFO:
835 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
836 case CBA_SET_OPTIONS:
837 case CBA_SYMBOLS_UNLOADED:
838 break;
839 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
840 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
841 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
842 case CBA_DEFERRED_SYMBOL_LOAD_START:
843 idslW = data;
844 idsl.SizeOfStruct = sizeof(idsl);
845 idsl.BaseOfImage = idslW->BaseOfImage;
846 idsl.CheckSum = idslW->CheckSum;
847 idsl.TimeDateStamp = idslW->TimeDateStamp;
848 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
849 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
850 idsl.Reparse = idslW->Reparse;
851 data = &idsl;
852 break;
853 case CBA_DUPLICATE_SYMBOL:
854 case CBA_EVENT:
855 case CBA_READ_MEMORY:
856 default:
857 FIXME("No mapping for action %lu\n", action);
858 return FALSE;
861 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
864 /******************************************************************
865 * sym_register_cb
867 * Helper for registering a callback.
869 static BOOL sym_register_cb(HANDLE hProcess,
870 PSYMBOL_REGISTERED_CALLBACK64 cb,
871 PSYMBOL_REGISTERED_CALLBACK cb32,
872 DWORD64 user, BOOL unicode)
874 struct process* pcs = process_find_by_handle(hProcess);
876 if (!pcs) return FALSE;
877 pcs->reg_cb = cb;
878 pcs->reg_cb32 = cb32;
879 pcs->reg_is_unicode = unicode;
880 pcs->reg_user = user;
882 return TRUE;
885 /***********************************************************************
886 * SymRegisterCallback (DBGHELP.@)
888 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
889 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
890 PVOID UserContext)
892 TRACE("(%p, %p, %p)\n",
893 hProcess, CallbackFunction, UserContext);
894 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
897 /***********************************************************************
898 * SymRegisterCallback64 (DBGHELP.@)
900 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
901 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
902 ULONG64 UserContext)
904 TRACE("(%p, %p, %I64x)\n", hProcess, CallbackFunction, UserContext);
905 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
908 /***********************************************************************
909 * SymRegisterCallbackW64 (DBGHELP.@)
911 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
912 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
913 ULONG64 UserContext)
915 TRACE("(%p, %p, %I64x)\n", hProcess, CallbackFunction, UserContext);
916 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
919 /* This is imagehlp version not dbghelp !! */
920 static API_VERSION api_version = { 4, 0, 2, 0 };
922 /***********************************************************************
923 * ImagehlpApiVersion (DBGHELP.@)
925 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
927 return &api_version;
930 /***********************************************************************
931 * ImagehlpApiVersionEx (DBGHELP.@)
933 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
935 if (!AppVersion) return NULL;
937 AppVersion->MajorVersion = api_version.MajorVersion;
938 AppVersion->MinorVersion = api_version.MinorVersion;
939 AppVersion->Revision = api_version.Revision;
940 AppVersion->Reserved = api_version.Reserved;
942 return AppVersion;
945 /******************************************************************
946 * ExtensionApiVersion (DBGHELP.@)
948 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
950 static EXT_API_VERSION eav = {5, 5, 5, 0};
951 return &eav;
954 /******************************************************************
955 * WinDbgExtensionDllInit (DBGHELP.@)
957 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
958 unsigned short major, unsigned short minor)
962 DWORD calc_crc32(HANDLE handle)
964 BYTE buffer[8192];
965 DWORD crc = 0;
966 DWORD len;
968 SetFilePointer(handle, 0, 0, FILE_BEGIN);
969 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len)
970 crc = RtlComputeCrc32(crc, buffer, len);
971 return crc;