1 /*
2 * File module.c - module handling for the wine debugger
3 *
4 * Copyright (C) 1993, Eric Youngdale.
5 * 2000-2007, Eric Pouech
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "dbghelp_private.h"
28 #include "image_private.h"
29 #ifndef DBGHELP_STATIC_LIB
30 #include "psapi.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33 #include "wine/heap.h"
34 #endif
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
37
38 #define NOTE_GNU_BUILD_ID 3
39
40 const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'};
41 #ifndef __REACTOS__
42 const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'};
43 #endif
44 static const WCHAR S_DotSoW[] = {'.','s','o','\0'};
45 const WCHAR S_SlashW[] = {'/','\0'};
46
47 static const WCHAR S_AcmW[] = {'.','a','c','m','\0'};
48 static const WCHAR S_DllW[] = {'.','d','l','l','\0'};
49 static const WCHAR S_DrvW[] = {'.','d','r','v','\0'};
50 static const WCHAR S_ExeW[] = {'.','e','x','e','\0'};
51 static const WCHAR S_OcxW[] = {'.','o','c','x','\0'};
52 static const WCHAR S_VxdW[] = {'.','v','x','d','\0'};
53 static const WCHAR * const ext[] = {S_AcmW, S_DllW, S_DrvW, S_ExeW, S_OcxW, S_VxdW, NULL};
54
match_ext(const WCHAR * ptr,size_t len)55 static int match_ext(const WCHAR* ptr, size_t len)
56 {
57 const WCHAR* const *e;
58 size_t l;
59
60 for (e = ext; *e; e++)
61 {
62 l = lstrlenW(*e);
63 if (l >= len) return 0;
64 if (wcsnicmp(&ptr[len - l], *e, l)) continue;
65 return l;
66 }
67 return 0;
68 }
69
get_filename(const WCHAR * name,const WCHAR * endptr)70 static const WCHAR* get_filename(const WCHAR* name, const WCHAR* endptr)
71 {
72 const WCHAR* ptr;
73
74 if (!endptr) endptr = name + lstrlenW(name);
75 for (ptr = endptr - 1; ptr >= name; ptr--)
76 {
77 if (*ptr == '/' || *ptr == '\\') break;
78 }
79 return ++ptr;
80 }
81
82 #ifndef __REACTOS__
is_wine_loader(const WCHAR * module)83 static BOOL is_wine_loader(const WCHAR *module)
84 {
85 static const WCHAR wineW[] = {'w','i','n','e',0};
86 static const WCHAR suffixW[] = {'6','4',0};
87 const WCHAR *filename = get_filename(module, NULL);
88 const char *ptr;
89 BOOL ret = FALSE;
90 WCHAR *buffer;
91 DWORD len;
92
93 if ((ptr = getenv("WINELOADER")))
94 {
95 ptr = file_nameA(ptr);
96 len = 2 + MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, NULL, 0 );
97 buffer = heap_alloc( len * sizeof(WCHAR) );
98 MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, buffer, len );
99 }
100 else
101 {
102 buffer = heap_alloc( sizeof(wineW) + 2 * sizeof(WCHAR) );
103 lstrcpyW( buffer, wineW );
104 }
105
106 if (!wcscmp( filename, buffer ))
107 ret = TRUE;
108
109 lstrcatW( buffer, suffixW );
110 if (!wcscmp( filename, buffer ))
111 ret = TRUE;
112
113 heap_free( buffer );
114 return ret;
115 }
116 #endif
117
module_fill_module(const WCHAR * in,WCHAR * out,size_t size)118 static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
119 {
120 const WCHAR *ptr, *endptr;
121 size_t len, l;
122
123 ptr = get_filename(in, endptr = in + lstrlenW(in));
124 len = min(endptr - ptr, size - 1);
125 memcpy(out, ptr, len * sizeof(WCHAR));
126 out[len] = '\0';
127 if (len > 4 && (l = match_ext(out, len)))
128 out[len - l] = '\0';
129 #ifndef __REACTOS__
130 else if (is_wine_loader(out))
131 lstrcpynW(out, S_WineLoaderW, size);
132 #endif
133 else
134 {
135 if (len > 3 && !wcsicmp(&out[len - 3], S_DotSoW) &&
136 (l = match_ext(out, len - 3)))
137 lstrcpyW(&out[len - l - 3], S_ElfW);
138 }
139 while ((*out = towlower(*out))) out++;
140 }
141
module_set_module(struct module * module,const WCHAR * name)142 void module_set_module(struct module* module, const WCHAR* name)
143 {
144 module_fill_module(name, module->module.ModuleName, ARRAY_SIZE(module->module.ModuleName));
145 module_fill_module(name, module->modulename, ARRAY_SIZE(module->modulename));
146 }
147
148 #ifndef __REACTOS__
149 /* Returned string must be freed by caller */
get_wine_loader_name(struct process * pcs)150 WCHAR *get_wine_loader_name(struct process *pcs)
151 {
152 static const WCHAR wineW[] = {'w','i','n','e',0};
153 static const WCHAR suffixW[] = {'6','4',0};
154 WCHAR *buffer, *p;
155 const char *env;
156
157 /* All binaries are loaded with WINELOADER (if run from tree) or by the
158 * main executable
159 */
160 if ((env = getenv("WINELOADER")))
161 {
162 DWORD len = 2 + MultiByteToWideChar( CP_UNIXCP, 0, env, -1, NULL, 0 );
163 buffer = heap_alloc( len * sizeof(WCHAR) );
164 MultiByteToWideChar( CP_UNIXCP, 0, env, -1, buffer, len );
165 }
166 else
167 {
168 buffer = heap_alloc( sizeof(wineW) + 2 * sizeof(WCHAR) );
169 lstrcpyW( buffer, wineW );
170 }
171
172 p = buffer + lstrlenW( buffer ) - lstrlenW( suffixW );
173 if (p > buffer && !wcscmp( p, suffixW ))
174 *p = 0;
175
176 if (pcs->is_64bit)
177 lstrcatW(buffer, suffixW);
178
179 TRACE( "returning %s\n", debugstr_w(buffer) );
180 return buffer;
181 }
182 #endif
183
get_module_type(enum module_type type,BOOL virtual)184 static const char* get_module_type(enum module_type type, BOOL virtual)
185 {
186 switch (type)
187 {
188 case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
189 case DMT_PE: return virtual ? "Virtual PE" : "PE";
190 case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O";
191 default: return "---";
192 }
193 }
194
195 /***********************************************************************
196 * Creates and links a new module to a process
197 */
module_new(struct process * pcs,const WCHAR * name,enum module_type type,BOOL virtual,DWORD64 mod_addr,DWORD64 size,ULONG_PTR stamp,ULONG_PTR checksum)198 struct module* module_new(struct process* pcs, const WCHAR* name,
199 enum module_type type, BOOL virtual,
200 DWORD64 mod_addr, DWORD64 size,
201 ULONG_PTR stamp, ULONG_PTR checksum)
202 {
203 struct module* module;
204 unsigned i;
205
206 assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO);
207 if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module))))
208 return NULL;
209
210 module->next = pcs->lmodules;
211 pcs->lmodules = module;
212
213 TRACE("=> %s %s-%s %s\n",
214 get_module_type(type, virtual),
215 wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size),
216 debugstr_w(name));
217
218 pool_init(&module->pool, 65536);
219
220 module->process = pcs;
221 module->module.SizeOfStruct = sizeof(module->module);
222 module->module.BaseOfImage = mod_addr;
223 module->module.ImageSize = size;
224 module_set_module(module, name);
225 module->module.ImageName[0] = '\0';
226 lstrcpynW(module->module.LoadedImageName, name, ARRAY_SIZE(module->module.LoadedImageName));
227 module->module.SymType = SymNone;
228 module->module.NumSyms = 0;
229 module->module.TimeDateStamp = stamp;
230 module->module.CheckSum = checksum;
231
232 memset(module->module.LoadedPdbName, 0, sizeof(module->module.LoadedPdbName));
233 module->module.CVSig = 0;
234 memset(module->module.CVData, 0, sizeof(module->module.CVData));
235 module->module.PdbSig = 0;
236 memset(&module->module.PdbSig70, 0, sizeof(module->module.PdbSig70));
237 module->module.PdbAge = 0;
238 module->module.PdbUnmatched = FALSE;
239 module->module.DbgUnmatched = FALSE;
240 module->module.LineNumbers = FALSE;
241 module->module.GlobalSymbols = FALSE;
242 module->module.TypeInfo = FALSE;
243 module->module.SourceIndexed = FALSE;
244 module->module.Publics = FALSE;
245
246 module->reloc_delta = 0;
247 module->type = type;
248 module->is_virtual = virtual;
249 for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL;
250 module->sortlist_valid = FALSE;
251 module->sorttab_size = 0;
252 module->addr_sorttab = NULL;
253 module->num_sorttab = 0;
254 module->num_symbols = 0;
255
256 vector_init(&module->vsymt, sizeof(struct symt*), 128);
257 /* FIXME: this seems a bit too high (on a per module basis)
258 * need some statistics about this
259 */
260 hash_table_init(&module->pool, &module->ht_symbols, 4096);
261 hash_table_init(&module->pool, &module->ht_types, 4096);
262 #ifdef __x86_64__
263 hash_table_init(&module->pool, &module->ht_symaddr, 4096);
264 #endif
265 vector_init(&module->vtypes, sizeof(struct symt*), 32);
266
267 module->sources_used = 0;
268 module->sources_alloc = 0;
269 module->sources = 0;
270 wine_rb_init(&module->sources_offsets_tree, source_rb_compare);
271
272 return module;
273 }
274
275 /***********************************************************************
276 * module_find_by_nameW
277 *
278 */
module_find_by_nameW(const struct process * pcs,const WCHAR * name)279 struct module* module_find_by_nameW(const struct process* pcs, const WCHAR* name)
280 {
281 struct module* module;
282
283 for (module = pcs->lmodules; module; module = module->next)
284 {
285 if (!wcsicmp(name, module->module.ModuleName)) return module;
286 }
287 SetLastError(ERROR_INVALID_NAME);
288 return NULL;
289 }
290
module_find_by_nameA(const struct process * pcs,const char * name)291 struct module* module_find_by_nameA(const struct process* pcs, const char* name)
292 {
293 WCHAR wname[MAX_PATH];
294
295 MultiByteToWideChar(CP_ACP, 0, name, -1, wname, ARRAY_SIZE(wname));
296 return module_find_by_nameW(pcs, wname);
297 }
298
299 /***********************************************************************
300 * module_is_already_loaded
301 *
302 */
module_is_already_loaded(const struct process * pcs,const WCHAR * name)303 struct module* module_is_already_loaded(const struct process* pcs, const WCHAR* name)
304 {
305 struct module* module;
306 const WCHAR* filename;
307
308 /* first compare the loaded image name... */
309 for (module = pcs->lmodules; module; module = module->next)
310 {
311 if (!wcsicmp(name, module->module.LoadedImageName))
312 return module;
313 }
314 /* then compare the standard filenames (without the path) ... */
315 filename = get_filename(name, NULL);
316 for (module = pcs->lmodules; module; module = module->next)
317 {
318 if (!wcsicmp(filename, get_filename(module->module.LoadedImageName, NULL)))
319 return module;
320 }
321 SetLastError(ERROR_INVALID_NAME);
322 return NULL;
323 }
324
325 /***********************************************************************
326 * module_get_container
327 *
328 */
module_get_container(const struct process * pcs,const struct module * inner)329 static struct module* module_get_container(const struct process* pcs,
330 const struct module* inner)
331 {
332 struct module* module;
333
334 for (module = pcs->lmodules; module; module = module->next)
335 {
336 if (module != inner &&
337 module->module.BaseOfImage <= inner->module.BaseOfImage &&
338 module->module.BaseOfImage + module->module.ImageSize >=
339 inner->module.BaseOfImage + inner->module.ImageSize)
340 return module;
341 }
342 return NULL;
343 }
344
345 /***********************************************************************
346 * module_get_containee
347 *
348 */
module_get_containee(const struct process * pcs,const struct module * outer)349 struct module* module_get_containee(const struct process* pcs, const struct module* outer)
350 {
351 struct module* module;
352
353 for (module = pcs->lmodules; module; module = module->next)
354 {
355 if (module != outer &&
356 outer->module.BaseOfImage <= module->module.BaseOfImage &&
357 outer->module.BaseOfImage + outer->module.ImageSize >=
358 module->module.BaseOfImage + module->module.ImageSize)
359 return module;
360 }
361 return NULL;
362 }
363
364 /******************************************************************
365 * module_get_debug
366 *
367 * get the debug information from a module:
368 * - if the module's type is deferred, then force loading of debug info (and return
369 * the module itself)
370 * - if the module has no debug info and has an ELF container, then return the ELF
371 * container (and also force the ELF container's debug info loading if deferred)
372 * - otherwise return the module itself if it has some debug info
373 */
module_get_debug(struct module_pair * pair)374 BOOL module_get_debug(struct module_pair* pair)
375 {
376 IMAGEHLP_DEFERRED_SYMBOL_LOADW64 idslW64;
377
378 if (!pair->requested) return FALSE;
379 /* for a PE builtin, always get info from container */
380 if (!(pair->effective = module_get_container(pair->pcs, pair->requested)))
381 pair->effective = pair->requested;
382 /* if deferred, force loading */
383 if (pair->effective->module.SymType == SymDeferred)
384 {
385 BOOL ret;
386
387 if (pair->effective->is_virtual) ret = FALSE;
388 else if (pair->effective->type == DMT_PE)
389 {
390 idslW64.SizeOfStruct = sizeof(idslW64);
391 idslW64.BaseOfImage = pair->effective->module.BaseOfImage;
392 idslW64.CheckSum = pair->effective->module.CheckSum;
393 idslW64.TimeDateStamp = pair->effective->module.TimeDateStamp;
394 memcpy(idslW64.FileName, pair->effective->module.ImageName,
395 sizeof(pair->effective->module.ImageName));
396 idslW64.Reparse = FALSE;
397 idslW64.hFile = INVALID_HANDLE_VALUE;
398
399 pcs_callback(pair->pcs, CBA_DEFERRED_SYMBOL_LOAD_START, &idslW64);
400 ret = pe_load_debug_info(pair->pcs, pair->effective);
401 pcs_callback(pair->pcs,
402 ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
403 &idslW64);
404 }
405 else ret = pair->pcs->loader->load_debug_info(pair->pcs, pair->effective);
406
407 if (!ret) pair->effective->module.SymType = SymNone;
408 assert(pair->effective->module.SymType != SymDeferred);
409 pair->effective->module.NumSyms = pair->effective->ht_symbols.num_elts;
410 }
411 return pair->effective->module.SymType != SymNone;
412 }
413
414 /***********************************************************************
415 * module_find_by_addr
416 *
417 * either the addr where module is loaded, or any address inside the
418 * module
419 */
module_find_by_addr(const struct process * pcs,DWORD64 addr,enum module_type type)420 struct module* module_find_by_addr(const struct process* pcs, DWORD64 addr,
421 enum module_type type)
422 {
423 struct module* module;
424
425 if (type == DMT_UNKNOWN)
426 {
427 if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
428 (module = module_find_by_addr(pcs, addr, DMT_ELF)) ||
429 (module = module_find_by_addr(pcs, addr, DMT_MACHO)))
430 return module;
431 }
432 else
433 {
434 for (module = pcs->lmodules; module; module = module->next)
435 {
436 if (type == module->type && addr >= module->module.BaseOfImage &&
437 addr < module->module.BaseOfImage + module->module.ImageSize)
438 return module;
439 }
440 }
441 SetLastError(ERROR_MOD_NOT_FOUND);
442 return module;
443 }
444
445 /******************************************************************
446 * module_is_container_loaded
447 *
448 * checks whether the native container, for a (supposed) PE builtin is
449 * already loaded
450 */
module_is_container_loaded(const struct process * pcs,const WCHAR * ImageName,DWORD64 base)451 static BOOL module_is_container_loaded(const struct process* pcs,
452 const WCHAR* ImageName, DWORD64 base)
453 {
454 size_t len;
455 struct module* module;
456 PCWSTR filename, modname;
457
458 if (!base) return FALSE;
459 filename = get_filename(ImageName, NULL);
460 len = lstrlenW(filename);
461
462 for (module = pcs->lmodules; module; module = module->next)
463 {
464 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
465 base >= module->module.BaseOfImage &&
466 base < module->module.BaseOfImage + module->module.ImageSize)
467 {
468 modname = get_filename(module->module.LoadedImageName, NULL);
469 if (!wcsnicmp(modname, filename, len) &&
470 !memcmp(modname + len, S_DotSoW, 3 * sizeof(WCHAR)))
471 {
472 return TRUE;
473 }
474 }
475 }
476 /* likely a native PE module */
477 WARN("Couldn't find container for %s\n", debugstr_w(ImageName));
478 return FALSE;
479 }
480
image_check_debug_link(const WCHAR * file,struct image_file_map * fmap,DWORD link_crc)481 static BOOL image_check_debug_link(const WCHAR* file, struct image_file_map* fmap, DWORD link_crc)
482 {
483 DWORD read_bytes;
484 HANDLE handle;
485 #ifndef DBGHELP_STATIC_LIB
486 WCHAR *path;
487 #endif
488 WORD magic;
489 BOOL ret;
490
491 #ifndef DBGHELP_STATIC_LIB
492 path = get_dos_file_name(file);
493 handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
494 heap_free(path);
495 #else
496 handle = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
497 #endif
498 if (handle == INVALID_HANDLE_VALUE) return FALSE;
499
500 if (link_crc)
501 {
502 DWORD crc = calc_crc32(handle);
503 if (crc != link_crc)
504 {
505 WARN("Bad CRC for file %s (got %08x while expecting %08x)\n", debugstr_w(file), crc, link_crc);
506 CloseHandle(handle);
507 return FALSE;
508 }
509 }
510
511 SetFilePointer(handle, 0, 0, FILE_BEGIN);
512 if (ReadFile(handle, &magic, sizeof(magic), &read_bytes, NULL) && magic == IMAGE_DOS_SIGNATURE)
513 ret = pe_map_file(handle, fmap, DMT_PE);
514 else
515 #ifndef __REACTOS__
516 ret = elf_map_handle(handle, fmap);
517 #else
518 ret = FALSE;
519 #endif
520 CloseHandle(handle);
521 return ret;
522 }
523
524 /******************************************************************
525 * image_locate_debug_link
526 *
527 * Locate a filename from a .gnu_debuglink section, using the same
528 * strategy as gdb:
529 * "If the full name of the directory containing the executable is
530 * execdir, and the executable has a debug link that specifies the
531 * name debugfile, then GDB will automatically search for the
532 * debugging information file in three places:
533 * - the directory containing the executable file (that is, it
534 * will look for a file named `execdir/debugfile',
535 * - a subdirectory of that directory named `.debug' (that is, the
536 * file `execdir/.debug/debugfile', and
537 * - a subdirectory of the global debug file directory that includes
538 * the executable's full path, and the name from the link (that is,
539 * the file `globaldebugdir/execdir/debugfile', where globaldebugdir
540 * is the global debug file directory, and execdir has been turned
541 * into a relative path)." (from GDB manual)
542 */
image_locate_debug_link(const struct module * module,struct image_file_map * fmap,const char * filename,DWORD crc)543 static BOOL image_locate_debug_link(const struct module* module, struct image_file_map* fmap, const char* filename, DWORD crc)
544 {
545 #ifndef __REACTOS__
546 static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
547 #else
548 static const WCHAR globalDebugDirW[] = {'\0'};
549 #endif
550 static const WCHAR dotDebugW[] = {'.','d','e','b','u','g','/'};
551 const size_t globalDebugDirLen = ARRAY_SIZE(globalDebugDirW);
552 size_t filename_len, path_len;
553 WCHAR* p = NULL;
554 WCHAR* slash;
555 WCHAR* slash2;
556 struct image_file_map* fmap_link = NULL;
557
558 fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
559 if (!fmap_link) return FALSE;
560
561 filename_len = MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, NULL, 0);
562 path_len = lstrlenW(module->module.LoadedImageName);
563 if (module->real_path) path_len = max(path_len, lstrlenW(module->real_path));
564 p = HeapAlloc(GetProcessHeap(), 0,
565 (globalDebugDirLen + path_len + 6 + 1 + filename_len + 1) * sizeof(WCHAR));
566 if (!p) goto found;
567
568 /* we prebuild the string with "execdir" */
569 lstrcpyW(p, module->module.LoadedImageName);
570 slash = p;
571 if ((slash2 = wcsrchr(slash, '/'))) slash = slash2 + 1;
572 if ((slash2 = wcsrchr(slash, '\\'))) slash = slash2 + 1;
573
574 /* testing execdir/filename */
575 MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
576 if (image_check_debug_link(p, fmap_link, crc)) goto found;
577
578 /* testing execdir/.debug/filename */
579 memcpy(slash, dotDebugW, sizeof(dotDebugW));
580 MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash + ARRAY_SIZE(dotDebugW), filename_len);
581 if (image_check_debug_link(p, fmap_link, crc)) goto found;
582
583 if (module->real_path)
584 {
585 lstrcpyW(p, module->real_path);
586 slash = p;
587 if ((slash2 = wcsrchr(slash, '/'))) slash = slash2 + 1;
588 if ((slash2 = wcsrchr(slash, '\\'))) slash = slash2 + 1;
589 MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
590 if (image_check_debug_link(p, fmap_link, crc)) goto found;
591 }
592
593 /* testing globaldebugdir/execdir/filename */
594 memmove(p + globalDebugDirLen, p, (slash - p) * sizeof(WCHAR));
595 memcpy(p, globalDebugDirW, globalDebugDirLen * sizeof(WCHAR));
596 slash += globalDebugDirLen;
597 MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
598 if (image_check_debug_link(p, fmap_link, crc)) goto found;
599
600 /* finally testing filename */
601 if (image_check_debug_link(slash, fmap_link, crc)) goto found;
602
603
604 WARN("Couldn't locate or map %s\n", filename);
605 HeapFree(GetProcessHeap(), 0, p);
606 HeapFree(GetProcessHeap(), 0, fmap_link);
607 return FALSE;
608
609 found:
610 TRACE("Located debug information file %s at %s\n", filename, debugstr_w(p));
611 HeapFree(GetProcessHeap(), 0, p);
612 fmap->alternate = fmap_link;
613 return TRUE;
614 }
615
616 /******************************************************************
617 * image_locate_build_id_target
618 *
619 * Try to find the .so file containing the debug info out of the build-id note information
620 */
image_locate_build_id_target(struct image_file_map * fmap,const BYTE * id,unsigned idlen)621 static BOOL image_locate_build_id_target(struct image_file_map* fmap, const BYTE* id, unsigned idlen)
622 {
623 static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
624 static const WCHAR buildidW[] = {'.','b','u','i','l','d','-','i','d','/'};
625 static const WCHAR dotDebug0W[] = {'.','d','e','b','u','g',0};
626 struct image_file_map* fmap_link = NULL;
627 WCHAR* p;
628 WCHAR* z;
629 const BYTE* idend = id + idlen;
630
631 fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
632 if (!fmap_link) return FALSE;
633
634 p = HeapAlloc(GetProcessHeap(), 0,
635 sizeof(globalDebugDirW) + sizeof(buildidW) +
636 (idlen * 2 + 1) * sizeof(WCHAR) + sizeof(dotDebug0W));
637 z = p;
638 memcpy(z, globalDebugDirW, sizeof(globalDebugDirW));
639 z += ARRAY_SIZE(globalDebugDirW);
640 memcpy(z, buildidW, sizeof(buildidW));
641 z += ARRAY_SIZE(buildidW);
642
643 if (id < idend)
644 {
645 *z++ = "0123456789abcdef"[*id >> 4 ];
646 *z++ = "0123456789abcdef"[*id & 0x0F];
647 id++;
648 }
649 if (id < idend)
650 *z++ = '/';
651 while (id < idend)
652 {
653 *z++ = "0123456789abcdef"[*id >> 4 ];
654 *z++ = "0123456789abcdef"[*id & 0x0F];
655 id++;
656 }
657 memcpy(z, dotDebug0W, sizeof(dotDebug0W));
658 TRACE("checking %s\n", wine_dbgstr_w(p));
659
660 if (image_check_debug_link(p, fmap_link, 0))
661 {
662 struct image_section_map buildid_sect;
663 if (image_find_section(fmap_link, ".note.gnu.build-id", &buildid_sect))
664 {
665 const UINT32* note;
666
667 note = (const UINT32*)image_map_section(&buildid_sect);
668 if (note != IMAGE_NO_MAP)
669 {
670 /* the usual ELF note structure: name-size desc-size type <name> <desc> */
671 if (note[2] == NOTE_GNU_BUILD_ID)
672 {
673 if (note[1] == idlen &&
674 !memcmp(note + 3 + ((note[0] + 3) >> 2), idend - idlen, idlen))
675 {
676 TRACE("Located debug information file at %s\n", debugstr_w(p));
677 HeapFree(GetProcessHeap(), 0, p);
678 fmap->alternate = fmap_link;
679 return TRUE;
680 }
681 WARN("mismatch in buildid information for %s\n", wine_dbgstr_w(p));
682 }
683 }
684 image_unmap_section(&buildid_sect);
685 }
686 image_unmap_file(fmap_link);
687 }
688
689 TRACE("not found\n");
690 HeapFree(GetProcessHeap(), 0, p);
691 HeapFree(GetProcessHeap(), 0, fmap_link);
692 return FALSE;
693 }
694
695 /******************************************************************
696 * image_check_alternate
697 *
698 * Load alternate files for a given image file, looking at either .note.gnu_build-id
699 * or .gnu_debuglink sections.
700 */
image_check_alternate(struct image_file_map * fmap,const struct module * module)701 BOOL image_check_alternate(struct image_file_map* fmap, const struct module* module)
702 {
703 BOOL ret = FALSE;
704 BOOL found = FALSE;
705 struct image_section_map buildid_sect, debuglink_sect;
706
707 /* if present, add the .gnu_debuglink file as an alternate to current one */
708 if (image_find_section(fmap, ".note.gnu.build-id", &buildid_sect))
709 {
710 const UINT32* note;
711
712 found = TRUE;
713 note = (const UINT32*)image_map_section(&buildid_sect);
714 if (note != IMAGE_NO_MAP)
715 {
716 /* the usual ELF note structure: name-size desc-size type <name> <desc> */
717 if (note[2] == NOTE_GNU_BUILD_ID)
718 {
719 ret = image_locate_build_id_target(fmap, (const BYTE*)(note + 3 + ((note[0] + 3) >> 2)), note[1]);
720 }
721 }
722 image_unmap_section(&buildid_sect);
723 }
724 /* if present, add the .gnu_debuglink file as an alternate to current one */
725 if (!ret && image_find_section(fmap, ".gnu_debuglink", &debuglink_sect))
726 {
727 const char* dbg_link;
728
729 found = TRUE;
730 dbg_link = (const char*)image_map_section(&debuglink_sect);
731 if (dbg_link != IMAGE_NO_MAP)
732 {
733 /* The content of a debug link section is:
734 * 1/ a NULL terminated string, containing the file name for the
735 * debug info
736 * 2/ padding on 4 byte boundary
737 * 3/ CRC of the linked file
738 */
739 DWORD crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
740 ret = image_locate_debug_link(module, fmap, dbg_link, crc);
741 if (!ret)
742 WARN("Couldn't load linked debug file for %s\n",
743 debugstr_w(module->module.ModuleName));
744 }
745 image_unmap_section(&debuglink_sect);
746 }
747 return found ? ret : TRUE;
748 }
749
750 /***********************************************************************
751 * SymLoadModule (DBGHELP.@)
752 */
SymLoadModule(HANDLE hProcess,HANDLE hFile,PCSTR ImageName,PCSTR ModuleName,DWORD BaseOfDll,DWORD SizeOfDll)753 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
754 PCSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
755 {
756 return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll,
757 SizeOfDll, NULL, 0);
758 }
759
760 /***********************************************************************
761 * SymLoadModuleEx (DBGHELP.@)
762 */
SymLoadModuleEx(HANDLE hProcess,HANDLE hFile,PCSTR ImageName,PCSTR ModuleName,DWORD64 BaseOfDll,DWORD DllSize,PMODLOAD_DATA Data,DWORD Flags)763 DWORD64 WINAPI SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
764 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
765 PMODLOAD_DATA Data, DWORD Flags)
766 {
767 PWSTR wImageName, wModuleName;
768 unsigned len;
769 DWORD64 ret;
770
771 TRACE("(%p %p %s %s %s %08x %p %08x)\n",
772 hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
773 wine_dbgstr_longlong(BaseOfDll), DllSize, Data, Flags);
774
775 if (ImageName)
776 {
777 len = MultiByteToWideChar(CP_ACP, 0, ImageName, -1, NULL, 0);
778 wImageName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
779 MultiByteToWideChar(CP_ACP, 0, ImageName, -1, wImageName, len);
780 }
781 else wImageName = NULL;
782 if (ModuleName)
783 {
784 len = MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, NULL, 0);
785 wModuleName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
786 MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, wModuleName, len);
787 }
788 else wModuleName = NULL;
789
790 ret = SymLoadModuleExW(hProcess, hFile, wImageName, wModuleName,
791 BaseOfDll, DllSize, Data, Flags);
792 HeapFree(GetProcessHeap(), 0, wImageName);
793 HeapFree(GetProcessHeap(), 0, wModuleName);
794 return ret;
795 }
796
797 /***********************************************************************
798 * SymLoadModuleExW (DBGHELP.@)
799 */
SymLoadModuleExW(HANDLE hProcess,HANDLE hFile,PCWSTR wImageName,PCWSTR wModuleName,DWORD64 BaseOfDll,DWORD SizeOfDll,PMODLOAD_DATA Data,DWORD Flags)800 DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageName,
801 PCWSTR wModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll,
802 PMODLOAD_DATA Data, DWORD Flags)
803 {
804 struct process* pcs;
805 struct module* module = NULL;
806
807 TRACE("(%p %p %s %s %s %08x %p %08x)\n",
808 hProcess, hFile, debugstr_w(wImageName), debugstr_w(wModuleName),
809 wine_dbgstr_longlong(BaseOfDll), SizeOfDll, Data, Flags);
810
811 if (Data)
812 FIXME("Unsupported load data parameter %p for %s\n",
813 Data, debugstr_w(wImageName));
814 if (!validate_addr64(BaseOfDll)) return FALSE;
815
816 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
817
818 if (Flags & SLMFLAG_VIRTUAL)
819 {
820 if (!wImageName) return FALSE;
821 module = module_new(pcs, wImageName, DMT_PE, TRUE, BaseOfDll, SizeOfDll, 0, 0);
822 if (!module) return FALSE;
823 if (wModuleName) module_set_module(module, wModuleName);
824 module->module.SymType = SymVirtual;
825
826 return TRUE;
827 }
828 if (Flags & ~(SLMFLAG_VIRTUAL))
829 FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
830
831 pcs->loader->synchronize_module_list(pcs);
832
833 /* this is a Wine extension to the API just to redo the synchronisation */
834 if (!wImageName && !hFile) return 0;
835
836 /* check if the module is already loaded, or if it's a builtin PE module with
837 * an containing ELF module
838 */
839 if (wImageName)
840 {
841 module = module_is_already_loaded(pcs, wImageName);
842 if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll))
843 {
844 /* force the loading of DLL as builtin */
845 module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
846 }
847 }
848 if (!module)
849 {
850 /* otherwise, try a regular PE module */
851 if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) &&
852 wImageName)
853 {
854 /* and finally an ELF or Mach-O module */
855 module = pcs->loader->load_module(pcs, wImageName, BaseOfDll);
856 }
857 }
858 if (!module)
859 {
860 WARN("Couldn't locate %s\n", debugstr_w(wImageName));
861 return 0;
862 }
863 module->module.NumSyms = module->ht_symbols.num_elts;
864 /* by default module_new fills module.ModuleName from a derivation
865 * of LoadedImageName. Overwrite it, if we have better information
866 */
867 if (wModuleName)
868 module_set_module(module, wModuleName);
869 if (wImageName)
870 lstrcpynW(module->module.ImageName, wImageName, ARRAY_SIZE(module->module.ImageName));
871
872 return module->module.BaseOfImage;
873 }
874
875 /***********************************************************************
876 * SymLoadModule64 (DBGHELP.@)
877 */
SymLoadModule64(HANDLE hProcess,HANDLE hFile,PCSTR ImageName,PCSTR ModuleName,DWORD64 BaseOfDll,DWORD SizeOfDll)878 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
879 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
880 {
881 return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll,
882 NULL, 0);
883 }
884
885 /******************************************************************
886 * module_remove
887 *
888 */
module_remove(struct process * pcs,struct module * module)889 BOOL module_remove(struct process* pcs, struct module* module)
890 {
891 struct module_format*modfmt;
892 struct module** p;
893 unsigned i;
894
895 TRACE("%s (%p)\n", debugstr_w(module->module.ModuleName), module);
896
897 for (i = 0; i < DFI_LAST; i++)
898 {
899 if ((modfmt = module->format_info[i]) && modfmt->remove)
900 modfmt->remove(pcs, module->format_info[i]);
901 }
902 hash_table_destroy(&module->ht_symbols);
903 hash_table_destroy(&module->ht_types);
904 HeapFree(GetProcessHeap(), 0, module->sources);
905 HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
906 HeapFree(GetProcessHeap(), 0, module->real_path);
907 pool_destroy(&module->pool);
908 /* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here
909 * so do we
910 */
911 for (p = &pcs->lmodules; *p; p = &(*p)->next)
912 {
913 if (*p == module)
914 {
915 *p = module->next;
916 HeapFree(GetProcessHeap(), 0, module);
917 return TRUE;
918 }
919 }
920 FIXME("This shouldn't happen\n");
921 return FALSE;
922 }
923
924 /******************************************************************
925 * SymUnloadModule (DBGHELP.@)
926 *
927 */
SymUnloadModule(HANDLE hProcess,DWORD BaseOfDll)928 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
929 {
930 struct process* pcs;
931 struct module* module;
932
933 pcs = process_find_by_handle(hProcess);
934 if (!pcs) return FALSE;
935 module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
936 if (!module) return FALSE;
937 return module_remove(pcs, module);
938 }
939
940 /******************************************************************
941 * SymUnloadModule64 (DBGHELP.@)
942 *
943 */
SymUnloadModule64(HANDLE hProcess,DWORD64 BaseOfDll)944 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
945 {
946 struct process* pcs;
947 struct module* module;
948
949 pcs = process_find_by_handle(hProcess);
950 if (!pcs) return FALSE;
951 if (!validate_addr64(BaseOfDll)) return FALSE;
952 module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
953 if (!module) return FALSE;
954 return module_remove(pcs, module);
955 }
956
957 /******************************************************************
958 * SymEnumerateModules (DBGHELP.@)
959 *
960 */
961 struct enum_modW64_32
962 {
963 PSYM_ENUMMODULES_CALLBACK cb;
964 PVOID user;
965 char module[MAX_PATH];
966 };
967
enum_modW64_32(PCWSTR name,DWORD64 base,PVOID user)968 static BOOL CALLBACK enum_modW64_32(PCWSTR name, DWORD64 base, PVOID user)
969 {
970 struct enum_modW64_32* x = user;
971
972 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
973 return x->cb(x->module, (DWORD)base, x->user);
974 }
975
SymEnumerateModules(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,PVOID UserContext)976 BOOL WINAPI SymEnumerateModules(HANDLE hProcess,
977 PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
978 PVOID UserContext)
979 {
980 struct enum_modW64_32 x;
981
982 x.cb = EnumModulesCallback;
983 x.user = UserContext;
984
985 return SymEnumerateModulesW64(hProcess, enum_modW64_32, &x);
986 }
987
988 /******************************************************************
989 * SymEnumerateModules64 (DBGHELP.@)
990 *
991 */
992 struct enum_modW64_64
993 {
994 PSYM_ENUMMODULES_CALLBACK64 cb;
995 PVOID user;
996 char module[MAX_PATH];
997 };
998
enum_modW64_64(PCWSTR name,DWORD64 base,PVOID user)999 static BOOL CALLBACK enum_modW64_64(PCWSTR name, DWORD64 base, PVOID user)
1000 {
1001 struct enum_modW64_64* x = user;
1002
1003 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1004 return x->cb(x->module, base, x->user);
1005 }
1006
SymEnumerateModules64(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,PVOID UserContext)1007 BOOL WINAPI SymEnumerateModules64(HANDLE hProcess,
1008 PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
1009 PVOID UserContext)
1010 {
1011 struct enum_modW64_64 x;
1012
1013 x.cb = EnumModulesCallback;
1014 x.user = UserContext;
1015
1016 return SymEnumerateModulesW64(hProcess, enum_modW64_64, &x);
1017 }
1018
1019 /******************************************************************
1020 * SymEnumerateModulesW64 (DBGHELP.@)
1021 *
1022 */
SymEnumerateModulesW64(HANDLE hProcess,PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,PVOID UserContext)1023 BOOL WINAPI SymEnumerateModulesW64(HANDLE hProcess,
1024 PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,
1025 PVOID UserContext)
1026 {
1027 struct process* pcs = process_find_by_handle(hProcess);
1028 struct module* module;
1029
1030 if (!pcs) return FALSE;
1031
1032 for (module = pcs->lmodules; module; module = module->next)
1033 {
1034 if (!dbghelp_opt_native &&
1035 (module->type == DMT_ELF || module->type == DMT_MACHO))
1036 continue;
1037 if (!EnumModulesCallback(module->modulename,
1038 module->module.BaseOfImage, UserContext))
1039 break;
1040 }
1041 return TRUE;
1042 }
1043
1044 #ifndef DBGHELP_STATIC_LIB
1045 /******************************************************************
1046 * EnumerateLoadedModules64 (DBGHELP.@)
1047 *
1048 */
1049 struct enum_load_modW64_64
1050 {
1051 PENUMLOADED_MODULES_CALLBACK64 cb;
1052 PVOID user;
1053 char module[MAX_PATH];
1054 };
1055
enum_load_modW64_64(PCWSTR name,DWORD64 base,ULONG size,PVOID user)1056 static BOOL CALLBACK enum_load_modW64_64(PCWSTR name, DWORD64 base, ULONG size,
1057 PVOID user)
1058 {
1059 struct enum_load_modW64_64* x = user;
1060
1061 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1062 return x->cb(x->module, base, size, x->user);
1063 }
1064
EnumerateLoadedModules64(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,PVOID UserContext)1065 BOOL WINAPI EnumerateLoadedModules64(HANDLE hProcess,
1066 PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,
1067 PVOID UserContext)
1068 {
1069 struct enum_load_modW64_64 x;
1070
1071 x.cb = EnumLoadedModulesCallback;
1072 x.user = UserContext;
1073
1074 return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_64, &x);
1075 }
1076
1077 /******************************************************************
1078 * EnumerateLoadedModules (DBGHELP.@)
1079 *
1080 */
1081 struct enum_load_modW64_32
1082 {
1083 PENUMLOADED_MODULES_CALLBACK cb;
1084 PVOID user;
1085 char module[MAX_PATH];
1086 };
1087
enum_load_modW64_32(PCWSTR name,DWORD64 base,ULONG size,PVOID user)1088 static BOOL CALLBACK enum_load_modW64_32(PCWSTR name, DWORD64 base, ULONG size,
1089 PVOID user)
1090 {
1091 struct enum_load_modW64_32* x = user;
1092 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1093 return x->cb(x->module, (DWORD)base, size, x->user);
1094 }
1095
EnumerateLoadedModules(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,PVOID UserContext)1096 BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
1097 PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
1098 PVOID UserContext)
1099 {
1100 struct enum_load_modW64_32 x;
1101
1102 x.cb = EnumLoadedModulesCallback;
1103 x.user = UserContext;
1104
1105 return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x);
1106 }
1107
1108 /******************************************************************
1109 * EnumerateLoadedModulesW64 (DBGHELP.@)
1110 *
1111 */
EnumerateLoadedModulesW64(HANDLE hProcess,PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,PVOID UserContext)1112 BOOL WINAPI EnumerateLoadedModulesW64(HANDLE hProcess,
1113 PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,
1114 PVOID UserContext)
1115 {
1116 HMODULE* hMods;
1117 WCHAR baseW[256], modW[256];
1118 DWORD i, sz;
1119 MODULEINFO mi;
1120
1121 hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
1122 if (!hMods) return FALSE;
1123
1124 if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
1125 {
1126 /* hProcess should also be a valid process handle !! */
1127 FIXME("If this happens, bump the number in mod\n");
1128 HeapFree(GetProcessHeap(), 0, hMods);
1129 return FALSE;
1130 }
1131 sz /= sizeof(HMODULE);
1132 for (i = 0; i < sz; i++)
1133 {
1134 if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
1135 !GetModuleBaseNameW(hProcess, hMods[i], baseW, ARRAY_SIZE(baseW)))
1136 continue;
1137 module_fill_module(baseW, modW, ARRAY_SIZE(modW));
1138 EnumLoadedModulesCallback(modW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage,
1139 UserContext);
1140 }
1141 HeapFree(GetProcessHeap(), 0, hMods);
1142
1143 return sz != 0 && i == sz;
1144 }
1145
1146 #endif /* DBGHELP_STATIC_LIB */
1147
dbghelp_str_WtoA(const WCHAR * src,char * dst,int dst_len)1148 static void dbghelp_str_WtoA(const WCHAR *src, char *dst, int dst_len)
1149 {
1150 WideCharToMultiByte(CP_ACP, 0, src, -1, dst, dst_len - 1, NULL, NULL);
1151 dst[dst_len - 1] = 0;
1152 }
1153
1154 /******************************************************************
1155 * SymGetModuleInfo (DBGHELP.@)
1156 *
1157 */
SymGetModuleInfo(HANDLE hProcess,DWORD dwAddr,PIMAGEHLP_MODULE ModuleInfo)1158 BOOL WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
1159 PIMAGEHLP_MODULE ModuleInfo)
1160 {
1161 IMAGEHLP_MODULE mi;
1162 IMAGEHLP_MODULEW64 miw64;
1163
1164 if (sizeof(mi) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
1165
1166 miw64.SizeOfStruct = sizeof(miw64);
1167 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1168
1169 mi.SizeOfStruct = ModuleInfo->SizeOfStruct;
1170 mi.BaseOfImage = miw64.BaseOfImage;
1171 mi.ImageSize = miw64.ImageSize;
1172 mi.TimeDateStamp = miw64.TimeDateStamp;
1173 mi.CheckSum = miw64.CheckSum;
1174 mi.NumSyms = miw64.NumSyms;
1175 mi.SymType = miw64.SymType;
1176 dbghelp_str_WtoA(miw64.ModuleName, mi.ModuleName, sizeof(mi.ModuleName));
1177 dbghelp_str_WtoA(miw64.ImageName, mi.ImageName, sizeof(mi.ImageName));
1178 dbghelp_str_WtoA(miw64.LoadedImageName, mi.LoadedImageName, sizeof(mi.LoadedImageName));
1179
1180 memcpy(ModuleInfo, &mi, ModuleInfo->SizeOfStruct);
1181
1182 return TRUE;
1183 }
1184
1185 /******************************************************************
1186 * SymGetModuleInfoW (DBGHELP.@)
1187 *
1188 */
SymGetModuleInfoW(HANDLE hProcess,DWORD dwAddr,PIMAGEHLP_MODULEW ModuleInfo)1189 BOOL WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr,
1190 PIMAGEHLP_MODULEW ModuleInfo)
1191 {
1192 IMAGEHLP_MODULEW64 miw64;
1193 IMAGEHLP_MODULEW miw;
1194
1195 if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
1196
1197 miw64.SizeOfStruct = sizeof(miw64);
1198 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1199
1200 miw.SizeOfStruct = ModuleInfo->SizeOfStruct;
1201 miw.BaseOfImage = miw64.BaseOfImage;
1202 miw.ImageSize = miw64.ImageSize;
1203 miw.TimeDateStamp = miw64.TimeDateStamp;
1204 miw.CheckSum = miw64.CheckSum;
1205 miw.NumSyms = miw64.NumSyms;
1206 miw.SymType = miw64.SymType;
1207 lstrcpyW(miw.ModuleName, miw64.ModuleName);
1208 lstrcpyW(miw.ImageName, miw64.ImageName);
1209 lstrcpyW(miw.LoadedImageName, miw64.LoadedImageName);
1210 memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
1211
1212 return TRUE;
1213 }
1214
1215 /******************************************************************
1216 * SymGetModuleInfo64 (DBGHELP.@)
1217 *
1218 */
SymGetModuleInfo64(HANDLE hProcess,DWORD64 dwAddr,PIMAGEHLP_MODULE64 ModuleInfo)1219 BOOL WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr,
1220 PIMAGEHLP_MODULE64 ModuleInfo)
1221 {
1222 IMAGEHLP_MODULE64 mi64;
1223 IMAGEHLP_MODULEW64 miw64;
1224
1225 if (sizeof(mi64) < ModuleInfo->SizeOfStruct)
1226 {
1227 SetLastError(ERROR_MOD_NOT_FOUND); /* NOTE: native returns this error */
1228 WARN("Wrong size %u\n", ModuleInfo->SizeOfStruct);
1229 return FALSE;
1230 }
1231
1232 miw64.SizeOfStruct = sizeof(miw64);
1233 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1234
1235 mi64.SizeOfStruct = ModuleInfo->SizeOfStruct;
1236 mi64.BaseOfImage = miw64.BaseOfImage;
1237 mi64.ImageSize = miw64.ImageSize;
1238 mi64.TimeDateStamp = miw64.TimeDateStamp;
1239 mi64.CheckSum = miw64.CheckSum;
1240 mi64.NumSyms = miw64.NumSyms;
1241 mi64.SymType = miw64.SymType;
1242 dbghelp_str_WtoA(miw64.ModuleName, mi64.ModuleName, sizeof(mi64.ModuleName));
1243 dbghelp_str_WtoA(miw64.ImageName, mi64.ImageName, sizeof(mi64.ImageName));
1244 dbghelp_str_WtoA(miw64.LoadedImageName, mi64.LoadedImageName, sizeof(mi64.LoadedImageName));
1245 dbghelp_str_WtoA(miw64.LoadedPdbName, mi64.LoadedPdbName, sizeof(mi64.LoadedPdbName));
1246
1247 mi64.CVSig = miw64.CVSig;
1248 dbghelp_str_WtoA(miw64.CVData, mi64.CVData, sizeof(mi64.CVData));
1249 mi64.PdbSig = miw64.PdbSig;
1250 mi64.PdbSig70 = miw64.PdbSig70;
1251 mi64.PdbAge = miw64.PdbAge;
1252 mi64.PdbUnmatched = miw64.PdbUnmatched;
1253 mi64.DbgUnmatched = miw64.DbgUnmatched;
1254 mi64.LineNumbers = miw64.LineNumbers;
1255 mi64.GlobalSymbols = miw64.GlobalSymbols;
1256 mi64.TypeInfo = miw64.TypeInfo;
1257 mi64.SourceIndexed = miw64.SourceIndexed;
1258 mi64.Publics = miw64.Publics;
1259
1260 memcpy(ModuleInfo, &mi64, ModuleInfo->SizeOfStruct);
1261
1262 return TRUE;
1263 }
1264
1265 /******************************************************************
1266 * SymGetModuleInfoW64 (DBGHELP.@)
1267 *
1268 */
SymGetModuleInfoW64(HANDLE hProcess,DWORD64 dwAddr,PIMAGEHLP_MODULEW64 ModuleInfo)1269 BOOL WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr,
1270 PIMAGEHLP_MODULEW64 ModuleInfo)
1271 {
1272 struct process* pcs = process_find_by_handle(hProcess);
1273 struct module* module;
1274 IMAGEHLP_MODULEW64 miw64;
1275
1276 TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
1277
1278 if (!pcs) return FALSE;
1279 if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
1280 module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1281 if (!module) return FALSE;
1282
1283 miw64 = module->module;
1284
1285 /* update debug information from container if any */
1286 if (module->module.SymType == SymNone)
1287 {
1288 module = module_get_container(pcs, module);
1289 if (module && module->module.SymType != SymNone)
1290 {
1291 miw64.SymType = module->module.SymType;
1292 miw64.NumSyms = module->module.NumSyms;
1293 }
1294 }
1295 memcpy(ModuleInfo, &miw64, ModuleInfo->SizeOfStruct);
1296 return TRUE;
1297 }
1298
1299 /***********************************************************************
1300 * SymGetModuleBase (DBGHELP.@)
1301 */
SymGetModuleBase(HANDLE hProcess,DWORD dwAddr)1302 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
1303 {
1304 DWORD64 ret;
1305
1306 ret = SymGetModuleBase64(hProcess, dwAddr);
1307 return validate_addr64(ret) ? ret : 0;
1308 }
1309
1310 /***********************************************************************
1311 * SymGetModuleBase64 (DBGHELP.@)
1312 */
SymGetModuleBase64(HANDLE hProcess,DWORD64 dwAddr)1313 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
1314 {
1315 struct process* pcs = process_find_by_handle(hProcess);
1316 struct module* module;
1317
1318 if (!pcs) return 0;
1319 module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1320 if (!module) return 0;
1321 return module->module.BaseOfImage;
1322 }
1323
1324 /******************************************************************
1325 * module_reset_debug_info
1326 * Removes any debug information linked to a given module.
1327 */
module_reset_debug_info(struct module * module)1328 void module_reset_debug_info(struct module* module)
1329 {
1330 module->sortlist_valid = TRUE;
1331 module->sorttab_size = 0;
1332 module->addr_sorttab = NULL;
1333 module->num_sorttab = module->num_symbols = 0;
1334 hash_table_destroy(&module->ht_symbols);
1335 module->ht_symbols.num_buckets = 0;
1336 module->ht_symbols.buckets = NULL;
1337 hash_table_destroy(&module->ht_types);
1338 module->ht_types.num_buckets = 0;
1339 module->ht_types.buckets = NULL;
1340 module->vtypes.num_elts = 0;
1341 hash_table_destroy(&module->ht_symbols);
1342 module->sources_used = module->sources_alloc = 0;
1343 module->sources = NULL;
1344 }
1345
1346 /******************************************************************
1347 * SymRefreshModuleList (DBGHELP.@)
1348 */
SymRefreshModuleList(HANDLE hProcess)1349 BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
1350 {
1351 struct process* pcs;
1352
1353 TRACE("(%p)\n", hProcess);
1354
1355 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
1356
1357 return pcs->loader->synchronize_module_list(pcs);
1358 }
1359
1360 /***********************************************************************
1361 * SymFunctionTableAccess (DBGHELP.@)
1362 */
SymFunctionTableAccess(HANDLE hProcess,DWORD AddrBase)1363 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
1364 {
1365 return SymFunctionTableAccess64(hProcess, AddrBase);
1366 }
1367
1368 /***********************************************************************
1369 * SymFunctionTableAccess64 (DBGHELP.@)
1370 */
SymFunctionTableAccess64(HANDLE hProcess,DWORD64 AddrBase)1371 PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase)
1372 {
1373 struct process* pcs = process_find_by_handle(hProcess);
1374 struct module* module;
1375
1376 if (!pcs || !dbghelp_current_cpu->find_runtime_function) return NULL;
1377 module = module_find_by_addr(pcs, AddrBase, DMT_UNKNOWN);
1378 if (!module) return NULL;
1379
1380 return dbghelp_current_cpu->find_runtime_function(module, AddrBase);
1381 }
1382
native_synchronize_module_list(struct process * pcs)1383 static BOOL native_synchronize_module_list(struct process* pcs)
1384 {
1385 return FALSE;
1386 }
1387
native_load_module(struct process * pcs,const WCHAR * name,ULONG_PTR addr)1388 static struct module* native_load_module(struct process* pcs, const WCHAR* name, ULONG_PTR addr)
1389 {
1390 return NULL;
1391 }
1392
native_load_debug_info(struct process * process,struct module * module)1393 static BOOL native_load_debug_info(struct process* process, struct module* module)
1394 {
1395 return FALSE;
1396 }
1397
native_enum_modules(struct process * process,enum_modules_cb cb,void * user)1398 static BOOL native_enum_modules(struct process *process, enum_modules_cb cb, void* user)
1399 {
1400 return FALSE;
1401 }
1402
native_fetch_file_info(struct process * process,const WCHAR * name,ULONG_PTR load_addr,DWORD_PTR * base,DWORD * size,DWORD * checksum)1403 static BOOL native_fetch_file_info(struct process* process, const WCHAR* name, ULONG_PTR load_addr, DWORD_PTR* base,
1404 DWORD* size, DWORD* checksum)
1405 {
1406 return FALSE;
1407 }
1408
1409 const struct loader_ops no_loader_ops =
1410 {
1411 native_synchronize_module_list,
1412 native_load_module,
1413 native_load_debug_info,
1414 native_enum_modules,
1415 native_fetch_file_info,
1416 };
1417