msvcrt: Use EnumSystemLocalesEx instead of directly accessing kernel32 resources.
[wine.git] / dlls / dbghelp / dbghelp.c
blob6d775b633f89796e4050e89edc81aa725c68c58b
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:%04lx>", addr->Segment, (DWORD)addr->Offset);
141 case AddrMode1632:
142 return wine_dbg_sprintf("1632<%04x:%08lx>", addr->Segment, (DWORD)addr->Offset);
143 case AddrModeReal:
144 return wine_dbg_sprintf("real<%04x:%04lx>", 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 static WCHAR* make_default_search_path(void)
180 WCHAR* search_path;
181 WCHAR* p;
182 unsigned sym_path_len;
183 unsigned alt_sym_path_len;
185 sym_path_len = GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", NULL, 0);
186 alt_sym_path_len = GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
188 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
189 * If the variables exist, the lengths include a null-terminator. We use that
190 * space for the semicolons, and only add the initial dot and the final null. */
191 search_path = HeapAlloc(GetProcessHeap(), 0,
192 (1 + sym_path_len + alt_sym_path_len + 1) * sizeof(WCHAR));
193 if (!search_path) return NULL;
195 p = search_path;
196 *p++ = L'.';
197 if (sym_path_len)
199 *p++ = L';';
200 GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", p, sym_path_len);
201 p += sym_path_len - 1;
204 if (alt_sym_path_len)
206 *p++ = L';';
207 GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", p, alt_sym_path_len);
208 p += alt_sym_path_len - 1;
210 *p = L'\0';
212 return search_path;
215 /******************************************************************
216 * SymSetSearchPathW (DBGHELP.@)
219 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
221 struct process* pcs = process_find_by_handle(hProcess);
222 WCHAR* search_path_buffer;
224 if (!pcs) return FALSE;
226 if (searchPath)
228 search_path_buffer = HeapAlloc(GetProcessHeap(), 0,
229 (lstrlenW(searchPath) + 1) * sizeof(WCHAR));
230 if (!search_path_buffer) return FALSE;
231 lstrcpyW(search_path_buffer, searchPath);
233 else
235 search_path_buffer = make_default_search_path();
236 if (!search_path_buffer) return FALSE;
238 HeapFree(GetProcessHeap(), 0, pcs->search_path);
239 pcs->search_path = search_path_buffer;
240 return TRUE;
243 /******************************************************************
244 * SymSetSearchPath (DBGHELP.@)
247 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
249 BOOL ret = FALSE;
250 unsigned len;
251 WCHAR* sp = NULL;
253 if (searchPath)
255 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
256 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
257 if (!sp) return FALSE;
258 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
261 ret = SymSetSearchPathW(hProcess, sp);
263 HeapFree(GetProcessHeap(), 0, sp);
264 return ret;
267 /***********************************************************************
268 * SymGetSearchPathW (DBGHELP.@)
270 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
271 DWORD SearchPathLength)
273 struct process* pcs = process_find_by_handle(hProcess);
274 if (!pcs) return FALSE;
276 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
277 return TRUE;
280 /***********************************************************************
281 * SymGetSearchPath (DBGHELP.@)
283 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
284 DWORD SearchPathLength)
286 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
287 BOOL ret = FALSE;
289 if (buffer)
291 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
292 if (ret)
293 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
294 szSearchPath, SearchPathLength, NULL, NULL);
295 HeapFree(GetProcessHeap(), 0, buffer);
297 return ret;
300 /******************************************************************
301 * invade_process
303 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
304 * this assumes that hProcess is a handle on a valid process
306 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
308 WCHAR tmp[MAX_PATH];
309 HANDLE hProcess = user;
311 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, tmp, ARRAY_SIZE(tmp)))
312 lstrcpynW(tmp, name, ARRAY_SIZE(tmp));
314 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
315 return TRUE;
318 const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
320 size_t name_len;
321 const WCHAR *iter;
323 if (!process->environment) return NULL;
324 name_len = lstrlenW(name);
326 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1)
328 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=')
329 return iter + name_len + 1;
332 return NULL;
335 /******************************************************************
336 * check_live_target
339 static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64)
341 PROCESS_BASIC_INFORMATION pbi;
342 ULONG_PTR base = 0, env = 0;
344 if (!GetProcessId(pcs->handle)) return FALSE;
345 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
347 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation,
348 &pbi, sizeof(pbi), NULL ))
349 return FALSE;
351 if (!pcs->is_64bit)
353 const char* peb32_addr;
354 DWORD env32;
355 PEB32 peb32;
357 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48);
358 peb32_addr = (const char*)pbi.PebBaseAddress;
359 if (!wow64 && child_wow64)
360 /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */
361 peb32_addr += 0x1000;
362 if (!ReadProcessMemory(pcs->handle, peb32_addr, &peb32, sizeof(peb32), NULL)) return FALSE;
363 if (!ReadProcessMemory(pcs->handle, peb32_addr + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE;
364 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32;
366 else
368 PEB peb;
369 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE;
370 if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + FIELD_OFFSET(PEB, CloudFileFlags), &base, sizeof(base), NULL)) return FALSE;
371 ReadProcessMemory(pcs->handle, (char *)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment), &env, sizeof(env), NULL);
374 /* read debuggee environment block */
375 if (env)
377 size_t buf_size = 0, i, last_null = -1;
378 WCHAR *buf = NULL;
382 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1));
383 if (buf)
385 WCHAR *new_buf;
386 if (!(new_buf = realloc(buf, buf_size + read_size))) break;
387 buf = new_buf;
389 else if(!(buf = malloc(read_size))) break;
391 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break;
392 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++)
394 if (buf[i]) continue;
395 if (last_null + 1 == i)
397 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR));
398 buf = NULL;
399 break;
401 last_null = i;
403 env += read_size;
404 buf_size += read_size;
406 while (buf);
407 free(buf);
410 if (!base) return FALSE;
412 TRACE("got debug info address %#Ix from PEB %p\n", base, pbi.PebBaseAddress);
413 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
414 WARN("couldn't load process debug info at %#Ix\n", base);
415 return TRUE;
418 /******************************************************************
419 * SymInitializeW (DBGHELP.@)
421 * The initialisation of a dbghelp's context.
422 * Note that hProcess doesn't need to be a valid process handle (except
423 * when fInvadeProcess is TRUE).
424 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
425 * containing PE (and NE) module(s), here's how we handle it:
426 * - we load every module (ELF, NE, PE) passed in SymLoadModule
427 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
428 * synchronization: hProcess should be a valid process handle, and we hook
429 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
430 * our internal ELF modules representation (loading / unloading). This way,
431 * we'll pair every loaded builtin PE module with its ELF counterpart (and
432 * access its debug information).
433 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
434 * hProcess refers to a running process. We use some heuristics here, so YMMV.
435 * If we detect a live target, then we get the same handling as if
436 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
437 * we won't be able to make the peering between a builtin PE module and its ELF
438 * counterpart. Hence we won't be able to provide the requested debug
439 * information. We'll however be able to load native PE modules (and their
440 * debug information) without any trouble.
441 * Note also that this scheme can be intertwined with the deferred loading
442 * mechanism (ie only load the debug information when we actually need it).
444 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
446 struct process* pcs;
447 BOOL wow64, child_wow64;
449 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
451 if (process_find_by_handle(hProcess))
453 WARN("the symbols for this process have already been initialized!\n");
455 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
456 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
457 Native still returns TRUE even if the process has already been initialized. */
458 return TRUE;
461 IsWow64Process(GetCurrentProcess(), &wow64);
463 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64))
464 return FALSE;
466 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
467 if (!pcs) return FALSE;
469 pcs->handle = hProcess;
470 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64;
471 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */
473 if (UserSearchPath)
475 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
476 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
477 UserSearchPath);
479 else
481 pcs->search_path = make_default_search_path();
484 pcs->lmodules = NULL;
485 pcs->dbg_hdr_addr = 0;
486 pcs->next = process_first;
487 process_first = pcs;
489 if (check_live_target(pcs, wow64, child_wow64))
491 if (fInvadeProcess)
492 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
493 if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
495 else if (fInvadeProcess)
497 SymCleanup(hProcess);
498 SetLastError(ERROR_INVALID_PARAMETER);
499 return FALSE;
502 return TRUE;
505 /******************************************************************
506 * SymInitialize (DBGHELP.@)
510 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
512 WCHAR* sp = NULL;
513 BOOL ret;
515 if (UserSearchPath)
517 unsigned len;
519 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
520 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
521 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
524 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
525 HeapFree(GetProcessHeap(), 0, sp);
526 return ret;
529 /******************************************************************
530 * SymCleanup (DBGHELP.@)
533 BOOL WINAPI SymCleanup(HANDLE hProcess)
535 struct process** ppcs;
536 struct process* next;
538 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
540 if ((*ppcs)->handle == hProcess)
542 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
544 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
545 free((*ppcs)->environment);
546 next = (*ppcs)->next;
547 HeapFree(GetProcessHeap(), 0, *ppcs);
548 *ppcs = next;
549 return TRUE;
553 ERR("this process has not had SymInitialize() called for it!\n");
554 return FALSE;
557 /******************************************************************
558 * SymSetOptions (DBGHELP.@)
561 DWORD WINAPI SymSetOptions(DWORD opts)
563 struct process* pcs;
565 for (pcs = process_first; pcs; pcs = pcs->next)
567 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
569 return dbghelp_options = opts;
572 /******************************************************************
573 * SymGetOptions (DBGHELP.@)
576 DWORD WINAPI SymGetOptions(void)
578 return dbghelp_options;
581 /******************************************************************
582 * SymSetExtendedOption (DBGHELP.@)
585 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
587 BOOL old = FALSE;
589 switch(option)
591 case SYMOPT_EX_WINE_NATIVE_MODULES:
592 old = dbghelp_opt_native;
593 dbghelp_opt_native = value;
594 break;
595 default:
596 FIXME("Unsupported option %d with value %d\n", option, value);
599 return old;
602 /******************************************************************
603 * SymGetExtendedOption (DBGHELP.@)
606 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
608 switch(option)
610 case SYMOPT_EX_WINE_NATIVE_MODULES:
611 return dbghelp_opt_native;
612 default:
613 FIXME("Unsupported option %d\n", option);
616 return FALSE;
619 /******************************************************************
620 * SymSetParentWindow (DBGHELP.@)
623 BOOL WINAPI SymSetParentWindow(HWND hwnd)
625 /* Save hwnd so it can be used as parent window */
626 FIXME("(%p): stub\n", hwnd);
627 return TRUE;
630 /******************************************************************
631 * SymSetContext (DBGHELP.@)
634 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
635 PIMAGEHLP_CONTEXT Context)
637 struct process* pcs;
639 TRACE("(%p %p %p)\n", hProcess, StackFrame, Context);
641 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
642 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
643 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
644 pcs->ctx_frame.StackOffset == StackFrame->StackOffset &&
645 pcs->ctx_frame.InstructionOffset == StackFrame->InstructionOffset)
647 TRACE("Setting same frame {rtn=%I64x frm=%I64x stk=%I64x}\n",
648 pcs->ctx_frame.ReturnOffset,
649 pcs->ctx_frame.FrameOffset,
650 pcs->ctx_frame.StackOffset);
651 SetLastError(ERROR_SUCCESS);
652 return FALSE;
655 if (!SymSetScopeFromAddr(hProcess, StackFrame->InstructionOffset))
656 return FALSE;
657 pcs->ctx_frame = *StackFrame;
658 /* Context is not (no longer?) used */
660 return TRUE;
663 /******************************************************************
664 * SymSetScopeFromAddr (DBGHELP.@)
666 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr)
668 struct module_pair pair;
669 struct symt_ht* sym;
671 TRACE("(%p %#I64x)\n", hProcess, addr);
673 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
674 pair.pcs->localscope_pc = addr;
675 if ((sym = symt_find_nearest(pair.effective, addr)) != NULL && sym->symt.tag == SymTagFunction)
676 pair.pcs->localscope_symt = &sym->symt;
677 else
678 pair.pcs->localscope_symt = NULL;
680 return TRUE;
683 /******************************************************************
684 * SymSetScopeFromIndex (DBGHELP.@)
686 BOOL WINAPI SymSetScopeFromIndex(HANDLE hProcess, ULONG64 addr, DWORD index)
688 struct module_pair pair;
689 struct symt* sym;
691 TRACE("(%p %#I64x %lu)\n", hProcess, addr, index);
693 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
694 sym = symt_index2ptr(pair.effective, index);
695 if (!symt_check_tag(sym, SymTagFunction)) return FALSE;
697 pair.pcs->localscope_pc = ((struct symt_function*)sym)->address; /* FIXME of FuncDebugStart when it exists? */
698 pair.pcs->localscope_symt = sym;
700 return TRUE;
703 /******************************************************************
704 * SymSetScopeFromInlineContext (DBGHELP.@)
706 BOOL WINAPI SymSetScopeFromInlineContext(HANDLE hProcess, ULONG64 addr, DWORD inlinectx)
708 struct module_pair pair;
709 struct symt_inlinesite* inlined;
711 TRACE("(%p %I64x %lx)\n", hProcess, addr, inlinectx);
713 switch (IFC_MODE(inlinectx))
715 case IFC_MODE_IGNORE:
716 case IFC_MODE_REGULAR: return SymSetScopeFromAddr(hProcess, addr);
717 case IFC_MODE_INLINE:
718 if (!module_init_pair(&pair, hProcess, addr)) return FALSE;
719 inlined = symt_find_inlined_site(pair.effective, addr, inlinectx);
720 if (inlined)
722 pair.pcs->localscope_pc = addr;
723 pair.pcs->localscope_symt = &inlined->func.symt;
724 return TRUE;
726 return FALSE;
727 default:
728 SetLastError(ERROR_INVALID_PARAMETER);
729 return FALSE;
733 /******************************************************************
734 * reg_cb64to32 (internal)
736 * Registered callback for converting information from 64 bit to 32 bit
738 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
740 struct process* pcs = process_find_by_handle(hProcess);
741 void* data32;
742 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
743 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
745 if (!pcs) return FALSE;
746 switch (action)
748 case CBA_DEBUG_INFO:
749 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
750 case CBA_SET_OPTIONS:
751 case CBA_SYMBOLS_UNLOADED:
752 data32 = (void*)(DWORD_PTR)data;
753 break;
754 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
755 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
756 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
757 case CBA_DEFERRED_SYMBOL_LOAD_START:
758 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
759 if (!validate_addr64(idsl64->BaseOfImage))
760 return FALSE;
761 idsl.SizeOfStruct = sizeof(idsl);
762 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
763 idsl.CheckSum = idsl64->CheckSum;
764 idsl.TimeDateStamp = idsl64->TimeDateStamp;
765 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
766 idsl.Reparse = idsl64->Reparse;
767 data32 = &idsl;
768 break;
769 case CBA_DUPLICATE_SYMBOL:
770 case CBA_EVENT:
771 case CBA_READ_MEMORY:
772 default:
773 FIXME("No mapping for action %lu\n", action);
774 return FALSE;
776 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
779 /******************************************************************
780 * pcs_callback (internal)
782 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
784 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
786 TRACE("%p %lu %p\n", pcs, action, data);
788 if (!pcs->reg_cb) return FALSE;
789 if (!pcs->reg_is_unicode)
791 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
793 switch (action)
795 case CBA_DEBUG_INFO:
796 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
797 case CBA_SET_OPTIONS:
798 case CBA_SYMBOLS_UNLOADED:
799 break;
800 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
801 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
802 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
803 case CBA_DEFERRED_SYMBOL_LOAD_START:
804 idslW = data;
805 idsl.SizeOfStruct = sizeof(idsl);
806 idsl.BaseOfImage = idslW->BaseOfImage;
807 idsl.CheckSum = idslW->CheckSum;
808 idsl.TimeDateStamp = idslW->TimeDateStamp;
809 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
810 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
811 idsl.Reparse = idslW->Reparse;
812 data = &idsl;
813 break;
814 case CBA_DUPLICATE_SYMBOL:
815 case CBA_EVENT:
816 case CBA_READ_MEMORY:
817 default:
818 FIXME("No mapping for action %lu\n", action);
819 return FALSE;
822 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
825 /******************************************************************
826 * sym_register_cb
828 * Helper for registering a callback.
830 static BOOL sym_register_cb(HANDLE hProcess,
831 PSYMBOL_REGISTERED_CALLBACK64 cb,
832 PSYMBOL_REGISTERED_CALLBACK cb32,
833 DWORD64 user, BOOL unicode)
835 struct process* pcs = process_find_by_handle(hProcess);
837 if (!pcs) return FALSE;
838 pcs->reg_cb = cb;
839 pcs->reg_cb32 = cb32;
840 pcs->reg_is_unicode = unicode;
841 pcs->reg_user = user;
843 return TRUE;
846 /***********************************************************************
847 * SymRegisterCallback (DBGHELP.@)
849 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
850 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
851 PVOID UserContext)
853 TRACE("(%p, %p, %p)\n",
854 hProcess, CallbackFunction, UserContext);
855 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
858 /***********************************************************************
859 * SymRegisterCallback64 (DBGHELP.@)
861 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
862 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
863 ULONG64 UserContext)
865 TRACE("(%p, %p, %s)\n",
866 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
867 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
870 /***********************************************************************
871 * SymRegisterCallbackW64 (DBGHELP.@)
873 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
874 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
875 ULONG64 UserContext)
877 TRACE("(%p, %p, %s)\n",
878 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
879 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
882 /* This is imagehlp version not dbghelp !! */
883 static API_VERSION api_version = { 4, 0, 2, 0 };
885 /***********************************************************************
886 * ImagehlpApiVersion (DBGHELP.@)
888 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
890 return &api_version;
893 /***********************************************************************
894 * ImagehlpApiVersionEx (DBGHELP.@)
896 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
898 if (!AppVersion) return NULL;
900 AppVersion->MajorVersion = api_version.MajorVersion;
901 AppVersion->MinorVersion = api_version.MinorVersion;
902 AppVersion->Revision = api_version.Revision;
903 AppVersion->Reserved = api_version.Reserved;
905 return AppVersion;
908 /******************************************************************
909 * ExtensionApiVersion (DBGHELP.@)
911 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
913 static EXT_API_VERSION eav = {5, 5, 5, 0};
914 return &eav;
917 /******************************************************************
918 * WinDbgExtensionDllInit (DBGHELP.@)
920 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
921 unsigned short major, unsigned short minor)
925 DWORD calc_crc32(HANDLE handle)
927 BYTE buffer[8192];
928 DWORD crc = 0;
929 DWORD len;
931 SetFilePointer(handle, 0, 0, FILE_BEGIN);
932 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len)
933 crc = RtlComputeCrc32(crc, buffer, len);
934 return crc;