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 #ifndef DBGHELP_STATIC_LIB
22
23 #include <unistd.h>
24 #include "dbghelp_private.h"
25 #include "winternl.h"
26 #include "winerror.h"
27 #include "psapi.h"
28 #include "wine/debug.h"
29 #include "wdbgexts.h"
30 #include "winnls.h"
31 #else
32 #include "dbghelp_private.h"
33 #include "wdbgexts.h"
34 #endif
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
37
38 /* TODO
39 * - support for symbols' types is still partly missing
40 * + C++ support
41 * + we should store the underlying type for an enum in the symt_enum struct
42 * + for enums, we store the names & values (associated to the enum type),
43 * but those values are not directly usable from a debugger (that's why, I
44 * assume, that we have also to define constants for enum values, as
45 * Codeview does BTW.
46 * + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
47 * all the types stored/used in the modules (like char*)
48 * - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
49 * functions, and even across function blocks...). Basically, for *Next* to work
50 * it requires an address after the prolog of the func (the base address of the
51 * func doesn't work)
52 * - most options (dbghelp_options) are not used (loading lines...)
53 * - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
54 * we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
55 * we could use hash if name isn't a RE, and fall back to a full search when we
56 * get a full RE
57 * - msc:
58 * + we should add parameters' types to the function's signature
59 * while processing a function's parameters
60 * + add support for function-less labels (as MSC seems to define them)
61 * + C++ management
62 * - stabs:
63 * + when, in a same module, the same definition is used in several compilation
64 * units, we get several definitions of the same object (especially
65 * struct/union). we should find a way not to duplicate them
66 * + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
67 * global variable is defined several times (at different scopes). We are
68 * getting several of those while looking for a unique symbol. Part of the
69 * issue is that we don't give a scope to a static variable inside a function
70 * + C++ management
71 */
72
73 unsigned dbghelp_options = SYMOPT_UNDNAME;
74 BOOL dbghelp_opt_native = FALSE;
75 #ifndef DBGHELP_STATIC_LIB
76 SYSTEM_INFO sysinfo;
77 #endif
78
79 static struct process* process_first /* = NULL */;
80
81 #ifndef DBGHELP_STATIC_LIB
DllMain(HINSTANCE instance,DWORD reason,LPVOID reserved)82 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
83 {
84 switch (reason)
85 {
86 case DLL_PROCESS_ATTACH:
87 GetSystemInfo(&sysinfo);
88 DisableThreadLibraryCalls(instance);
89 break;
90 }
91 return TRUE;
92 }
93 #endif
94
95 /******************************************************************
96 * process_find_by_handle
97 *
98 */
process_find_by_handle(HANDLE hProcess)99 struct process* process_find_by_handle(HANDLE hProcess)
100 {
101 struct process* p;
102
103 for (p = process_first; p && p->handle != hProcess; p = p->next);
104 if (!p) SetLastError(ERROR_INVALID_HANDLE);
105 return p;
106 }
107
108 /******************************************************************
109 * validate_addr64 (internal)
110 *
111 */
validate_addr64(DWORD64 addr)112 BOOL validate_addr64(DWORD64 addr)
113 {
114 if (sizeof(void*) == sizeof(int) && (addr >> 32))
115 {
116 FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
117 SetLastError(ERROR_INVALID_PARAMETER);
118 return FALSE;
119 }
120 return TRUE;
121 }
122
123 /******************************************************************
124 * fetch_buffer
125 *
126 * Ensures process' internal buffer is large enough.
127 */
fetch_buffer(struct process * pcs,unsigned size)128 void* fetch_buffer(struct process* pcs, unsigned size)
129 {
130 if (size > pcs->buffer_size)
131 {
132 if (pcs->buffer)
133 pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
134 else
135 pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
136 pcs->buffer_size = (pcs->buffer) ? size : 0;
137 }
138 return pcs->buffer;
139 }
140
141 #ifndef DBGHELP_STATIC_LIB
wine_dbgstr_addr(const ADDRESS64 * addr)142 const char* wine_dbgstr_addr(const ADDRESS64* addr)
143 {
144 if (!addr) return "(null)";
145 switch (addr->Mode)
146 {
147 case AddrModeFlat:
148 return wine_dbg_sprintf("flat<%s>", wine_dbgstr_longlong(addr->Offset));
149 case AddrMode1616:
150 return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
151 case AddrMode1632:
152 return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, (DWORD)addr->Offset);
153 case AddrModeReal:
154 return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, (DWORD)addr->Offset);
155 default:
156 return "unknown";
157 }
158 }
159 #endif
160
161 extern struct cpu cpu_i386, cpu_x86_64, cpu_arm, cpu_arm64;
162
163 #ifndef DBGHELP_STATIC_LIB
164 static struct cpu* dbghelp_cpus[] = {&cpu_i386, &cpu_x86_64, &cpu_arm, &cpu_arm64, NULL};
165 #else
166 static struct cpu* dbghelp_cpus[] = {&cpu_i386, NULL};
167 #endif
168
169 struct cpu* dbghelp_current_cpu =
170 #if defined(__i386__) || defined(DBGHELP_STATIC_LIB)
171 &cpu_i386
172 #elif defined(__x86_64__)
173 &cpu_x86_64
174 #elif defined(__arm__)
175 &cpu_arm
176 #elif defined(__aarch64__)
177 &cpu_arm64
178 #else
179 #error define support for your CPU
180 #endif
181 ;
182
cpu_find(DWORD machine)183 struct cpu* cpu_find(DWORD machine)
184 {
185 struct cpu** cpu;
186
187 for (cpu = dbghelp_cpus ; *cpu; cpu++)
188 {
189 if (cpu[0]->machine == machine) return cpu[0];
190 }
191 return NULL;
192 }
193
make_default_search_path(void)194 static WCHAR* make_default_search_path(void)
195 {
196 WCHAR* search_path;
197 WCHAR* p;
198 unsigned sym_path_len;
199 unsigned alt_sym_path_len;
200
201 sym_path_len = GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", NULL, 0);
202 alt_sym_path_len = GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", NULL, 0);
203
204 /* The default symbol path is ".[;%_NT_SYMBOL_PATH%][;%_NT_ALT_SYMBOL_PATH%]".
205 * If the variables exist, the lengths include a null-terminator. We use that
206 * space for the semicolons, and only add the initial dot and the final null. */
207 search_path = HeapAlloc(GetProcessHeap(), 0,
208 (1 + sym_path_len + alt_sym_path_len + 1) * sizeof(WCHAR));
209 if (!search_path) return NULL;
210
211 p = search_path;
212 *p++ = L'.';
213 if (sym_path_len)
214 {
215 *p++ = L';';
216 GetEnvironmentVariableW(L"_NT_SYMBOL_PATH", p, sym_path_len);
217 p += sym_path_len - 1;
218 }
219
220 if (alt_sym_path_len)
221 {
222 *p++ = L';';
223 GetEnvironmentVariableW(L"_NT_ALT_SYMBOL_PATH", p, alt_sym_path_len);
224 p += alt_sym_path_len - 1;
225 }
226 *p = L'\0';
227
228 return search_path;
229 }
230
231 /******************************************************************
232 * SymSetSearchPathW (DBGHELP.@)
233 *
234 */
SymSetSearchPathW(HANDLE hProcess,PCWSTR searchPath)235 BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
236 {
237 struct process* pcs = process_find_by_handle(hProcess);
238 WCHAR* search_path_buffer;
239
240 if (!pcs) return FALSE;
241
242 if (searchPath)
243 {
244 search_path_buffer = HeapAlloc(GetProcessHeap(), 0,
245 (lstrlenW(searchPath) + 1) * sizeof(WCHAR));
246 if (!search_path_buffer) return FALSE;
247 lstrcpyW(search_path_buffer, searchPath);
248 }
249 else
250 {
251 search_path_buffer = make_default_search_path();
252 if (!search_path_buffer) return FALSE;
253 }
254 HeapFree(GetProcessHeap(), 0, pcs->search_path);
255 pcs->search_path = search_path_buffer;
256 return TRUE;
257 }
258
259 /******************************************************************
260 * SymSetSearchPath (DBGHELP.@)
261 *
262 */
SymSetSearchPath(HANDLE hProcess,PCSTR searchPath)263 BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
264 {
265 BOOL ret = FALSE;
266 unsigned len;
267 WCHAR* sp = NULL;
268
269 if (searchPath)
270 {
271 len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
272 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
273 if (!sp) return FALSE;
274 MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
275 }
276
277 ret = SymSetSearchPathW(hProcess, sp);
278
279 HeapFree(GetProcessHeap(), 0, sp);
280 return ret;
281 }
282
283 /***********************************************************************
284 * SymGetSearchPathW (DBGHELP.@)
285 */
SymGetSearchPathW(HANDLE hProcess,PWSTR szSearchPath,DWORD SearchPathLength)286 BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, PWSTR szSearchPath,
287 DWORD SearchPathLength)
288 {
289 struct process* pcs = process_find_by_handle(hProcess);
290 if (!pcs) return FALSE;
291
292 lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
293 return TRUE;
294 }
295
296 /***********************************************************************
297 * SymGetSearchPath (DBGHELP.@)
298 */
SymGetSearchPath(HANDLE hProcess,PSTR szSearchPath,DWORD SearchPathLength)299 BOOL WINAPI SymGetSearchPath(HANDLE hProcess, PSTR szSearchPath,
300 DWORD SearchPathLength)
301 {
302 WCHAR* buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
303 BOOL ret = FALSE;
304
305 if (buffer)
306 {
307 ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
308 if (ret)
309 WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
310 szSearchPath, SearchPathLength, NULL, NULL);
311 HeapFree(GetProcessHeap(), 0, buffer);
312 }
313 return ret;
314 }
315
316 #ifndef DBGHELP_STATIC_LIB
317 /******************************************************************
318 * invade_process
319 *
320 * SymInitialize helper: loads in dbghelp all known (and loaded modules)
321 * this assumes that hProcess is a handle on a valid process
322 */
process_invade_cb(PCWSTR name,ULONG64 base,ULONG size,PVOID user)323 static BOOL WINAPI process_invade_cb(PCWSTR name, ULONG64 base, ULONG size, PVOID user)
324 {
325 WCHAR tmp[MAX_PATH];
326 HANDLE hProcess = user;
327
328 if (!GetModuleFileNameExW(hProcess, (HMODULE)(DWORD_PTR)base, tmp, ARRAY_SIZE(tmp)))
329 lstrcpynW(tmp, name, ARRAY_SIZE(tmp));
330
331 SymLoadModuleExW(hProcess, 0, tmp, name, base, size, NULL, 0);
332 return TRUE;
333 }
334
process_getenv(const struct process * process,const WCHAR * name)335 const WCHAR *process_getenv(const struct process *process, const WCHAR *name)
336 {
337 size_t name_len;
338 const WCHAR *iter;
339
340 if (!process->environment) return NULL;
341 name_len = lstrlenW(name);
342
343 for (iter = process->environment; *iter; iter += lstrlenW(iter) + 1)
344 {
345 if (!wcsnicmp(iter, name, name_len) && iter[name_len] == '=')
346 return iter + name_len + 1;
347 }
348
349 return NULL;
350 }
351
352 /******************************************************************
353 * check_live_target
354 *
355 */
check_live_target(struct process * pcs)356 static BOOL check_live_target(struct process* pcs)
357 {
358 PROCESS_BASIC_INFORMATION pbi;
359 ULONG_PTR base = 0, env = 0;
360
361 if (!GetProcessId(pcs->handle)) return FALSE;
362 if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
363
364 if (NtQueryInformationProcess( pcs->handle, ProcessBasicInformation,
365 &pbi, sizeof(pbi), NULL ))
366 return FALSE;
367
368 if (!pcs->is_64bit)
369 {
370 DWORD env32;
371 PEB32 peb32;
372 C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48);
373 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb32, sizeof(peb32), NULL)) return FALSE;
374 base = peb32.Reserved[0];
375 if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32;
376 }
377 else
378 {
379 PEB peb;
380 if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE;
381 base = peb.Reserved[0];
382 ReadProcessMemory(pcs->handle, &peb.ProcessParameters->Environment, &env, sizeof(env), NULL);
383 }
384
385 #ifdef __REACTOS__
386 /* Wine store their loader base address in peb.reserved[0] and load its symbol from there.
387 * ReactOS does not care about it, we are just happy if we managed to read the value */
388 base = 1;
389 #endif
390
391 /* read debuggee environment block */
392 if (env)
393 {
394 size_t buf_size = 0, i, last_null = -1;
395 WCHAR *buf = NULL;
396
397 do
398 {
399 size_t read_size = sysinfo.dwAllocationGranularity - (env & (sysinfo.dwAllocationGranularity - 1));
400 if (buf)
401 {
402 WCHAR *new_buf;
403 if (!(new_buf = realloc(buf, buf_size + read_size))) break;
404 buf = new_buf;
405 }
406 else if(!(buf = malloc(read_size))) break;
407
408 if (!read_process_memory(pcs, env, (char*)buf + buf_size, read_size)) break;
409 for (i = buf_size / sizeof(WCHAR); i < (buf_size + read_size) / sizeof(WCHAR); i++)
410 {
411 if (buf[i]) continue;
412 if (last_null + 1 == i)
413 {
414 pcs->environment = realloc(buf, (i + 1) * sizeof(WCHAR));
415 buf = NULL;
416 break;
417 }
418 last_null = i;
419 }
420 env += read_size;
421 buf_size += read_size;
422 }
423 while (buf);
424 free(buf);
425 }
426
427 if (!base) return FALSE;
428
429 TRACE("got debug info address %#lx from PEB %p\n", base, pbi.PebBaseAddress);
430 #ifndef __REACTOS__
431 if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base))
432 WARN("couldn't load process debug info at %#lx\n", base);
433 #endif
434 return TRUE;
435 }
436 #endif
437
438 /******************************************************************
439 * SymInitializeW (DBGHELP.@)
440 *
441 * The initialisation of a dbghelp's context.
442 * Note that hProcess doesn't need to be a valid process handle (except
443 * when fInvadeProcess is TRUE).
444 * Since we also allow loading ELF (pure) libraries and Wine ELF libraries
445 * containing PE (and NE) module(s), here's how we handle it:
446 * - we load every module (ELF, NE, PE) passed in SymLoadModule
447 * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
448 * synchronization: hProcess should be a valid process handle, and we hook
449 * ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
450 * our internal ELF modules representation (loading / unloading). This way,
451 * we'll pair every loaded builtin PE module with its ELF counterpart (and
452 * access its debug information).
453 * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the
454 * hProcess refers to a running process. We use some heuristics here, so YMMV.
455 * If we detect a live target, then we get the same handling as if
456 * fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
457 * we won't be able to make the peering between a builtin PE module and its ELF
458 * counterpart. Hence we won't be able to provide the requested debug
459 * information. We'll however be able to load native PE modules (and their
460 * debug information) without any trouble.
461 * Note also that this scheme can be intertwined with the deferred loading
462 * mechanism (ie only load the debug information when we actually need it).
463 */
SymInitializeW(HANDLE hProcess,PCWSTR UserSearchPath,BOOL fInvadeProcess)464 BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
465 {
466 struct process* pcs;
467 BOOL wow64, child_wow64;
468
469 TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
470
471 if (process_find_by_handle(hProcess))
472 {
473 WARN("the symbols for this process have already been initialized!\n");
474
475 /* MSDN says to only call this function once unless SymCleanup() has been called since the last call.
476 It also says to call SymRefreshModuleList() instead if you just want the module list refreshed.
477 Native still returns TRUE even if the process has already been initialized. */
478 return TRUE;
479 }
480
481 IsWow64Process(GetCurrentProcess(), &wow64);
482
483 if (GetProcessId(hProcess) && !IsWow64Process(hProcess, &child_wow64))
484 return FALSE;
485
486 pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
487 if (!pcs) return FALSE;
488
489 pcs->handle = hProcess;
490 pcs->is_64bit = (sizeof(void *) == 8 || wow64) && !child_wow64;
491 pcs->loader = &no_loader_ops; /* platform-specific initialization will override it if loader debug info can be found */
492
493 if (UserSearchPath)
494 {
495 pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,
496 (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
497 UserSearchPath);
498 }
499 else
500 {
501 pcs->search_path = make_default_search_path();
502 }
503
504 pcs->lmodules = NULL;
505 pcs->dbg_hdr_addr = 0;
506 pcs->next = process_first;
507 process_first = pcs;
508
509 #ifndef DBGHELP_STATIC_LIB
510 if (check_live_target(pcs))
511 {
512 if (fInvadeProcess)
513 EnumerateLoadedModulesW64(hProcess, process_invade_cb, hProcess);
514 if (pcs->loader) pcs->loader->synchronize_module_list(pcs);
515 }
516 else if (fInvadeProcess)
517 #else
518 if (fInvadeProcess)
519 #endif
520 {
521 SymCleanup(hProcess);
522 SetLastError(ERROR_INVALID_PARAMETER);
523 return FALSE;
524 }
525
526 return TRUE;
527 }
528
529 /******************************************************************
530 * SymInitialize (DBGHELP.@)
531 *
532 *
533 */
SymInitialize(HANDLE hProcess,PCSTR UserSearchPath,BOOL fInvadeProcess)534 BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
535 {
536 WCHAR* sp = NULL;
537 BOOL ret;
538
539 if (UserSearchPath)
540 {
541 unsigned len;
542
543 len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
544 sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
545 MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
546 }
547
548 ret = SymInitializeW(hProcess, sp, fInvadeProcess);
549 HeapFree(GetProcessHeap(), 0, sp);
550 return ret;
551 }
552
553 /******************************************************************
554 * SymCleanup (DBGHELP.@)
555 *
556 */
SymCleanup(HANDLE hProcess)557 BOOL WINAPI SymCleanup(HANDLE hProcess)
558 {
559 struct process** ppcs;
560 struct process* next;
561
562 for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
563 {
564 if ((*ppcs)->handle == hProcess)
565 {
566 while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
567
568 HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
569 free((*ppcs)->environment);
570 next = (*ppcs)->next;
571 HeapFree(GetProcessHeap(), 0, *ppcs);
572 *ppcs = next;
573 return TRUE;
574 }
575 }
576
577 ERR("this process has not had SymInitialize() called for it!\n");
578 return FALSE;
579 }
580
581 /******************************************************************
582 * SymSetOptions (DBGHELP.@)
583 *
584 */
SymSetOptions(DWORD opts)585 DWORD WINAPI SymSetOptions(DWORD opts)
586 {
587 struct process* pcs;
588
589 for (pcs = process_first; pcs; pcs = pcs->next)
590 {
591 pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
592 }
593 return dbghelp_options = opts;
594 }
595
596 /******************************************************************
597 * SymGetOptions (DBGHELP.@)
598 *
599 */
SymGetOptions(void)600 DWORD WINAPI SymGetOptions(void)
601 {
602 return dbghelp_options;
603 }
604
605 /******************************************************************
606 * SymSetExtendedOption (DBGHELP.@)
607 *
608 */
SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option,BOOL value)609 BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value)
610 {
611 BOOL old = FALSE;
612
613 switch(option)
614 {
615 case SYMOPT_EX_WINE_NATIVE_MODULES:
616 old = dbghelp_opt_native;
617 dbghelp_opt_native = value;
618 break;
619 default:
620 FIXME("Unsupported option %d with value %d\n", option, value);
621 }
622
623 return old;
624 }
625
626 /******************************************************************
627 * SymGetExtendedOption (DBGHELP.@)
628 *
629 */
SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)630 BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option)
631 {
632 switch(option)
633 {
634 case SYMOPT_EX_WINE_NATIVE_MODULES:
635 return dbghelp_opt_native;
636 default:
637 FIXME("Unsupported option %d\n", option);
638 }
639
640 return FALSE;
641 }
642
643 /******************************************************************
644 * SymSetParentWindow (DBGHELP.@)
645 *
646 */
SymSetParentWindow(HWND hwnd)647 BOOL WINAPI SymSetParentWindow(HWND hwnd)
648 {
649 /* Save hwnd so it can be used as parent window */
650 FIXME("(%p): stub\n", hwnd);
651 return TRUE;
652 }
653
654 /******************************************************************
655 * SymSetContext (DBGHELP.@)
656 *
657 */
SymSetContext(HANDLE hProcess,PIMAGEHLP_STACK_FRAME StackFrame,PIMAGEHLP_CONTEXT Context)658 BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
659 PIMAGEHLP_CONTEXT Context)
660 {
661 struct process* pcs = process_find_by_handle(hProcess);
662 if (!pcs) return FALSE;
663
664 if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
665 pcs->ctx_frame.FrameOffset == StackFrame->FrameOffset &&
666 pcs->ctx_frame.StackOffset == StackFrame->StackOffset)
667 {
668 TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
669 wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
670 wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
671 wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
672 pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
673 SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
674 return FALSE;
675 }
676
677 pcs->ctx_frame = *StackFrame;
678 /* MSDN states that Context is not (no longer?) used */
679 return TRUE;
680 }
681
682 /******************************************************************
683 * reg_cb64to32 (internal)
684 *
685 * Registered callback for converting information from 64 bit to 32 bit
686 */
reg_cb64to32(HANDLE hProcess,ULONG action,ULONG64 data,ULONG64 user)687 static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
688 {
689 struct process* pcs = process_find_by_handle(hProcess);
690 void* data32;
691 IMAGEHLP_DEFERRED_SYMBOL_LOAD64* idsl64;
692 IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
693
694 if (!pcs) return FALSE;
695 switch (action)
696 {
697 case CBA_DEBUG_INFO:
698 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
699 case CBA_SET_OPTIONS:
700 case CBA_SYMBOLS_UNLOADED:
701 data32 = (void*)(DWORD_PTR)data;
702 break;
703 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
704 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
705 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
706 case CBA_DEFERRED_SYMBOL_LOAD_START:
707 idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD_PTR)data;
708 if (!validate_addr64(idsl64->BaseOfImage))
709 return FALSE;
710 idsl.SizeOfStruct = sizeof(idsl);
711 idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
712 idsl.CheckSum = idsl64->CheckSum;
713 idsl.TimeDateStamp = idsl64->TimeDateStamp;
714 memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
715 idsl.Reparse = idsl64->Reparse;
716 data32 = &idsl;
717 break;
718 case CBA_DUPLICATE_SYMBOL:
719 case CBA_EVENT:
720 case CBA_READ_MEMORY:
721 default:
722 FIXME("No mapping for action %u\n", action);
723 return FALSE;
724 }
725 return pcs->reg_cb32(hProcess, action, data32, (PVOID)(DWORD_PTR)user);
726 }
727
728 /******************************************************************
729 * pcs_callback (internal)
730 */
pcs_callback(const struct process * pcs,ULONG action,void * data)731 BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
732 {
733 IMAGEHLP_DEFERRED_SYMBOL_LOAD64 idsl;
734
735 TRACE("%p %u %p\n", pcs, action, data);
736
737 if (!pcs->reg_cb) return FALSE;
738 if (!pcs->reg_is_unicode)
739 {
740 IMAGEHLP_DEFERRED_SYMBOL_LOADW64* idslW;
741
742 switch (action)
743 {
744 case CBA_DEBUG_INFO:
745 case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
746 case CBA_SET_OPTIONS:
747 case CBA_SYMBOLS_UNLOADED:
748 break;
749 case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
750 case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
751 case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
752 case CBA_DEFERRED_SYMBOL_LOAD_START:
753 idslW = data;
754 idsl.SizeOfStruct = sizeof(idsl);
755 idsl.BaseOfImage = idslW->BaseOfImage;
756 idsl.CheckSum = idslW->CheckSum;
757 idsl.TimeDateStamp = idslW->TimeDateStamp;
758 WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
759 idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
760 idsl.Reparse = idslW->Reparse;
761 data = &idsl;
762 break;
763 case CBA_DUPLICATE_SYMBOL:
764 case CBA_EVENT:
765 case CBA_READ_MEMORY:
766 default:
767 FIXME("No mapping for action %u\n", action);
768 return FALSE;
769 }
770 }
771 return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
772 }
773
774 /******************************************************************
775 * sym_register_cb
776 *
777 * Helper for registering a callback.
778 */
sym_register_cb(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK64 cb,PSYMBOL_REGISTERED_CALLBACK cb32,DWORD64 user,BOOL unicode)779 static BOOL sym_register_cb(HANDLE hProcess,
780 PSYMBOL_REGISTERED_CALLBACK64 cb,
781 PSYMBOL_REGISTERED_CALLBACK cb32,
782 DWORD64 user, BOOL unicode)
783 {
784 struct process* pcs = process_find_by_handle(hProcess);
785
786 if (!pcs) return FALSE;
787 pcs->reg_cb = cb;
788 pcs->reg_cb32 = cb32;
789 pcs->reg_is_unicode = unicode;
790 pcs->reg_user = user;
791
792 return TRUE;
793 }
794
795 /***********************************************************************
796 * SymRegisterCallback (DBGHELP.@)
797 */
SymRegisterCallback(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK CallbackFunction,PVOID UserContext)798 BOOL WINAPI SymRegisterCallback(HANDLE hProcess,
799 PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
800 PVOID UserContext)
801 {
802 TRACE("(%p, %p, %p)\n",
803 hProcess, CallbackFunction, UserContext);
804 return sym_register_cb(hProcess, reg_cb64to32, CallbackFunction, (DWORD_PTR)UserContext, FALSE);
805 }
806
807 /***********************************************************************
808 * SymRegisterCallback64 (DBGHELP.@)
809 */
SymRegisterCallback64(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,ULONG64 UserContext)810 BOOL WINAPI SymRegisterCallback64(HANDLE hProcess,
811 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
812 ULONG64 UserContext)
813 {
814 TRACE("(%p, %p, %s)\n",
815 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
816 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, FALSE);
817 }
818
819 /***********************************************************************
820 * SymRegisterCallbackW64 (DBGHELP.@)
821 */
SymRegisterCallbackW64(HANDLE hProcess,PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,ULONG64 UserContext)822 BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess,
823 PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
824 ULONG64 UserContext)
825 {
826 TRACE("(%p, %p, %s)\n",
827 hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
828 return sym_register_cb(hProcess, CallbackFunction, NULL, UserContext, TRUE);
829 }
830
831 /* This is imagehlp version not dbghelp !! */
832 static API_VERSION api_version = { 4, 0, 2, 0 };
833
834 /***********************************************************************
835 * ImagehlpApiVersion (DBGHELP.@)
836 */
ImagehlpApiVersion(VOID)837 LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
838 {
839 return &api_version;
840 }
841
842 /***********************************************************************
843 * ImagehlpApiVersionEx (DBGHELP.@)
844 */
ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)845 LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
846 {
847 if (!AppVersion) return NULL;
848
849 AppVersion->MajorVersion = api_version.MajorVersion;
850 AppVersion->MinorVersion = api_version.MinorVersion;
851 AppVersion->Revision = api_version.Revision;
852 AppVersion->Reserved = api_version.Reserved;
853
854 return AppVersion;
855 }
856
857 /******************************************************************
858 * ExtensionApiVersion (DBGHELP.@)
859 */
ExtensionApiVersion(void)860 LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
861 {
862 static EXT_API_VERSION eav = {5, 5, 5, 0};
863 return &eav;
864 }
865
866 /******************************************************************
867 * WinDbgExtensionDllInit (DBGHELP.@)
868 */
WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,unsigned short major,unsigned short minor)869 void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
870 unsigned short major, unsigned short minor)
871 {
872 }
873
calc_crc32(HANDLE handle)874 DWORD calc_crc32(HANDLE handle)
875 {
876 BYTE buffer[8192];
877 DWORD crc = 0;
878 DWORD len;
879
880 SetFilePointer(handle, 0, 0, FILE_BEGIN);
881 while (ReadFile(handle, buffer, sizeof(buffer), &len, NULL) && len)
882 crc = RtlComputeCrc32(crc, buffer, len);
883 return crc;
884 }
885