[DBGHELP]
[reactos.git] / reactos / dll / win32 / dbghelp / module.c
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 <config.h>
23 //#include <stdlib.h>
24 //#include <stdio.h>
25 //#include <string.h>
26 #include <assert.h>
27
28 #include "dbghelp_private.h"
29
30 #ifndef DBGHELP_STATIC_LIB
31 #include <psapi.h>
32 #include <wine/debug.h>
33 #endif
34 //#include "winternl.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
37
38 const WCHAR S_ElfW[] = {'<','e','l','f','>','\0'};
39 const WCHAR S_WineLoaderW[] = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'};
40 static const WCHAR S_DotSoW[] = {'.','s','o','\0'};
41 static const WCHAR S_DotDylibW[] = {'.','d','y','l','i','b','\0'};
42 static const WCHAR S_DotPdbW[] = {'.','p','d','b','\0'};
43 static const WCHAR S_DotDbgW[] = {'.','d','b','g','\0'};
44 const WCHAR S_SlashW[] = {'/','\0'};
45
46 static const WCHAR S_AcmW[] = {'.','a','c','m','\0'};
47 static const WCHAR S_DllW[] = {'.','d','l','l','\0'};
48 static const WCHAR S_DrvW[] = {'.','d','r','v','\0'};
49 static const WCHAR S_ExeW[] = {'.','e','x','e','\0'};
50 static const WCHAR S_OcxW[] = {'.','o','c','x','\0'};
51 static const WCHAR S_VxdW[] = {'.','v','x','d','\0'};
52 static const WCHAR * const ext[] = {S_AcmW, S_DllW, S_DrvW, S_ExeW, S_OcxW, S_VxdW, NULL};
53
54 static int match_ext(const WCHAR* ptr, size_t len)
55 {
56 const WCHAR* const *e;
57 size_t l;
58
59 for (e = ext; *e; e++)
60 {
61 l = strlenW(*e);
62 if (l >= len) return FALSE;
63 if (strncmpiW(&ptr[len - l], *e, l)) continue;
64 return l;
65 }
66 return 0;
67 }
68
69 static const WCHAR* get_filename(const WCHAR* name, const WCHAR* endptr)
70 {
71 const WCHAR* ptr;
72
73 if (!endptr) endptr = name + strlenW(name);
74 for (ptr = endptr - 1; ptr >= name; ptr--)
75 {
76 if (*ptr == '/' || *ptr == '\\') break;
77 }
78 return ++ptr;
79 }
80
81 static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
82 {
83 const WCHAR *loader = get_wine_loader_name();
84 const WCHAR *ptr, *endptr;
85 size_t len, l;
86
87 ptr = get_filename(in, endptr = in + strlenW(in));
88 len = min(endptr - ptr, size - 1);
89 memcpy(out, ptr, len * sizeof(WCHAR));
90 out[len] = '\0';
91 if (len > 4 && (l = match_ext(out, len)))
92 out[len - l] = '\0';
93 else if (len > strlenW(loader) && !strcmpiW(out + len - strlenW(loader), loader))
94 lstrcpynW(out, S_WineLoaderW, size);
95 else
96 {
97 if (len > 3 && !strcmpiW(&out[len - 3], S_DotSoW) &&
98 (l = match_ext(out, len - 3)))
99 strcpyW(&out[len - l - 3], S_ElfW);
100 }
101 while ((*out = tolowerW(*out))) out++;
102 }
103
104 void module_set_module(struct module* module, const WCHAR* name)
105 {
106 module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName));
107 }
108
109 const WCHAR *get_wine_loader_name(void)
110 {
111 static const int is_win64 = sizeof(void *) > sizeof(int); /* FIXME: should depend on target process */
112 static const WCHAR wineW[] = {'w','i','n','e',0};
113 static const WCHAR suffixW[] = {'6','4',0};
114 static const WCHAR *loader;
115
116 if (!loader)
117 {
118 WCHAR *p, *buffer;
119 const char *ptr;
120
121 /* All binaries are loaded with WINELOADER (if run from tree) or by the
122 * main executable
123 */
124 if ((ptr = getenv("WINELOADER")))
125 {
126 DWORD len = 2 + MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, NULL, 0 );
127 buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
128 MultiByteToWideChar( CP_UNIXCP, 0, ptr, -1, buffer, len );
129 }
130 else
131 {
132 buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(wineW) + 2 * sizeof(WCHAR) );
133 strcpyW( buffer, wineW );
134 }
135 p = buffer + strlenW( buffer ) - strlenW( suffixW );
136 if (p > buffer && !strcmpW( p, suffixW ))
137 {
138 if (!is_win64) *p = 0;
139 }
140 else if (is_win64) strcatW( buffer, suffixW );
141
142 TRACE( "returning %s\n", debugstr_w(buffer) );
143 loader = buffer;
144 }
145 return loader;
146 }
147
148 static const char* get_module_type(enum module_type type, BOOL virtual)
149 {
150 switch (type)
151 {
152 case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
153 case DMT_PE: return virtual ? "Virtual PE" : "PE";
154 case DMT_MACHO: return virtual ? "Virtual Mach-O" : "Mach-O";
155 default: return "---";
156 }
157 }
158
159 /***********************************************************************
160 * Creates and links a new module to a process
161 */
162 struct module* module_new(struct process* pcs, const WCHAR* name,
163 enum module_type type, BOOL virtual,
164 DWORD64 mod_addr, DWORD64 size,
165 unsigned long stamp, unsigned long checksum)
166 {
167 struct module* module;
168 unsigned i;
169
170 assert(type == DMT_ELF || type == DMT_PE || type == DMT_MACHO);
171 if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module))))
172 return NULL;
173
174 module->next = pcs->lmodules;
175 pcs->lmodules = module;
176
177 TRACE("=> %s %s-%s %s\n",
178 get_module_type(type, virtual),
179 wine_dbgstr_longlong(mod_addr), wine_dbgstr_longlong(mod_addr + size),
180 debugstr_w(name));
181
182 pool_init(&module->pool, 65536);
183
184 module->process = pcs;
185 module->module.SizeOfStruct = sizeof(module->module);
186 module->module.BaseOfImage = mod_addr;
187 module->module.ImageSize = size;
188 module_set_module(module, name);
189 module->module.ImageName[0] = '\0';
190 lstrcpynW(module->module.LoadedImageName, name, sizeof(module->module.LoadedImageName) / sizeof(WCHAR));
191 module->module.SymType = SymNone;
192 module->module.NumSyms = 0;
193 module->module.TimeDateStamp = stamp;
194 module->module.CheckSum = checksum;
195
196 memset(module->module.LoadedPdbName, 0, sizeof(module->module.LoadedPdbName));
197 module->module.CVSig = 0;
198 memset(module->module.CVData, 0, sizeof(module->module.CVData));
199 module->module.PdbSig = 0;
200 memset(&module->module.PdbSig70, 0, sizeof(module->module.PdbSig70));
201 module->module.PdbAge = 0;
202 module->module.PdbUnmatched = FALSE;
203 module->module.DbgUnmatched = FALSE;
204 module->module.LineNumbers = FALSE;
205 module->module.GlobalSymbols = FALSE;
206 module->module.TypeInfo = FALSE;
207 module->module.SourceIndexed = FALSE;
208 module->module.Publics = FALSE;
209
210 module->reloc_delta = 0;
211 module->type = type;
212 module->is_virtual = virtual;
213 for (i = 0; i < DFI_LAST; i++) module->format_info[i] = NULL;
214 module->sortlist_valid = FALSE;
215 module->sorttab_size = 0;
216 module->addr_sorttab = NULL;
217 module->num_sorttab = 0;
218 module->num_symbols = 0;
219
220 vector_init(&module->vsymt, sizeof(struct symt*), 128);
221 /* FIXME: this seems a bit too high (on a per module basis)
222 * need some statistics about this
223 */
224 hash_table_init(&module->pool, &module->ht_symbols, 4096);
225 hash_table_init(&module->pool, &module->ht_types, 4096);
226 #ifdef __x86_64__
227 hash_table_init(&module->pool, &module->ht_symaddr, 4096);
228 #endif
229 vector_init(&module->vtypes, sizeof(struct symt*), 32);
230
231 module->sources_used = 0;
232 module->sources_alloc = 0;
233 module->sources = 0;
234 wine_rb_init(&module->sources_offsets_tree, &source_rb_functions);
235
236 return module;
237 }
238
239 /***********************************************************************
240 * module_find_by_nameW
241 *
242 */
243 struct module* module_find_by_nameW(const struct process* pcs, const WCHAR* name)
244 {
245 struct module* module;
246
247 for (module = pcs->lmodules; module; module = module->next)
248 {
249 if (!strcmpiW(name, module->module.ModuleName)) return module;
250 }
251 SetLastError(ERROR_INVALID_NAME);
252 return NULL;
253 }
254
255 struct module* module_find_by_nameA(const struct process* pcs, const char* name)
256 {
257 WCHAR wname[MAX_PATH];
258
259 MultiByteToWideChar(CP_ACP, 0, name, -1, wname, sizeof(wname) / sizeof(WCHAR));
260 return module_find_by_nameW(pcs, wname);
261 }
262
263 /***********************************************************************
264 * module_is_already_loaded
265 *
266 */
267 struct module* module_is_already_loaded(const struct process* pcs, const WCHAR* name)
268 {
269 struct module* module;
270 const WCHAR* filename;
271
272 /* first compare the loaded image name... */
273 for (module = pcs->lmodules; module; module = module->next)
274 {
275 if (!strcmpiW(name, module->module.LoadedImageName))
276 return module;
277 }
278 /* then compare the standard filenames (without the path) ... */
279 filename = get_filename(name, NULL);
280 for (module = pcs->lmodules; module; module = module->next)
281 {
282 if (!strcmpiW(filename, get_filename(module->module.LoadedImageName, NULL)))
283 return module;
284 }
285 SetLastError(ERROR_INVALID_NAME);
286 return NULL;
287 }
288
289 /***********************************************************************
290 * module_get_container
291 *
292 */
293 static struct module* module_get_container(const struct process* pcs,
294 const struct module* inner)
295 {
296 struct module* module;
297
298 for (module = pcs->lmodules; module; module = module->next)
299 {
300 if (module != inner &&
301 module->module.BaseOfImage <= inner->module.BaseOfImage &&
302 module->module.BaseOfImage + module->module.ImageSize >=
303 inner->module.BaseOfImage + inner->module.ImageSize)
304 return module;
305 }
306 return NULL;
307 }
308
309 /***********************************************************************
310 * module_get_containee
311 *
312 */
313 struct module* module_get_containee(const struct process* pcs,
314 const struct module* outter)
315 {
316 struct module* module;
317
318 for (module = pcs->lmodules; module; module = module->next)
319 {
320 if (module != outter &&
321 outter->module.BaseOfImage <= module->module.BaseOfImage &&
322 outter->module.BaseOfImage + outter->module.ImageSize >=
323 module->module.BaseOfImage + module->module.ImageSize)
324 return module;
325 }
326 return NULL;
327 }
328
329 /******************************************************************
330 * module_get_debug
331 *
332 * get the debug information from a module:
333 * - if the module's type is deferred, then force loading of debug info (and return
334 * the module itself)
335 * - if the module has no debug info and has an ELF container, then return the ELF
336 * container (and also force the ELF container's debug info loading if deferred)
337 * - otherwise return the module itself if it has some debug info
338 */
339 BOOL module_get_debug(struct module_pair* pair)
340 {
341 IMAGEHLP_DEFERRED_SYMBOL_LOADW64 idslW64;
342
343 if (!pair->requested) return FALSE;
344 /* for a PE builtin, always get info from container */
345 if (!(pair->effective = module_get_container(pair->pcs, pair->requested)))
346 pair->effective = pair->requested;
347 /* if deferred, force loading */
348 if (pair->effective->module.SymType == SymDeferred)
349 {
350 BOOL ret;
351
352 if (pair->effective->is_virtual) ret = FALSE;
353 else switch (pair->effective->type)
354 {
355 #ifndef DBGHELP_STATIC_LIB
356 case DMT_ELF:
357 ret = elf_load_debug_info(pair->effective);
358 break;
359 #endif
360 case DMT_PE:
361 idslW64.SizeOfStruct = sizeof(idslW64);
362 idslW64.BaseOfImage = pair->effective->module.BaseOfImage;
363 idslW64.CheckSum = pair->effective->module.CheckSum;
364 idslW64.TimeDateStamp = pair->effective->module.TimeDateStamp;
365 memcpy(idslW64.FileName, pair->effective->module.ImageName,
366 sizeof(pair->effective->module.ImageName));
367 idslW64.Reparse = FALSE;
368 idslW64.hFile = INVALID_HANDLE_VALUE;
369
370 pcs_callback(pair->pcs, CBA_DEFERRED_SYMBOL_LOAD_START, &idslW64);
371 ret = pe_load_debug_info(pair->pcs, pair->effective);
372 pcs_callback(pair->pcs,
373 ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
374 &idslW64);
375 break;
376 #ifndef DBGHELP_STATIC_LIB
377 case DMT_MACHO:
378 ret = macho_load_debug_info(pair->effective, NULL);
379 break;
380 #endif
381 default:
382 ret = FALSE;
383 break;
384 }
385 if (!ret) pair->effective->module.SymType = SymNone;
386 assert(pair->effective->module.SymType != SymDeferred);
387 pair->effective->module.NumSyms = pair->effective->ht_symbols.num_elts;
388 }
389 return pair->effective->module.SymType != SymNone;
390 }
391
392 /***********************************************************************
393 * module_find_by_addr
394 *
395 * either the addr where module is loaded, or any address inside the
396 * module
397 */
398 struct module* module_find_by_addr(const struct process* pcs, DWORD64 addr,
399 enum module_type type)
400 {
401 struct module* module;
402
403 if (type == DMT_UNKNOWN)
404 {
405 if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
406 (module = module_find_by_addr(pcs, addr, DMT_ELF)) ||
407 (module = module_find_by_addr(pcs, addr, DMT_MACHO)))
408 return module;
409 }
410 else
411 {
412 for (module = pcs->lmodules; module; module = module->next)
413 {
414 if (type == module->type && addr >= module->module.BaseOfImage &&
415 addr < module->module.BaseOfImage + module->module.ImageSize)
416 return module;
417 }
418 }
419 SetLastError(ERROR_INVALID_ADDRESS);
420 return module;
421 }
422
423 /******************************************************************
424 * module_is_container_loaded
425 *
426 * checks whether the native container, for a (supposed) PE builtin is
427 * already loaded
428 */
429 static BOOL module_is_container_loaded(const struct process* pcs,
430 const WCHAR* ImageName, DWORD64 base)
431 {
432 size_t len;
433 struct module* module;
434 PCWSTR filename, modname;
435
436 if (!base) return FALSE;
437 filename = get_filename(ImageName, NULL);
438 len = strlenW(filename);
439
440 for (module = pcs->lmodules; module; module = module->next)
441 {
442 if ((module->type == DMT_ELF || module->type == DMT_MACHO) &&
443 base >= module->module.BaseOfImage &&
444 base < module->module.BaseOfImage + module->module.ImageSize)
445 {
446 modname = get_filename(module->module.LoadedImageName, NULL);
447 if (!strncmpiW(modname, filename, len) &&
448 !memcmp(modname + len, S_DotSoW, 3 * sizeof(WCHAR)))
449 {
450 return TRUE;
451 }
452 }
453 }
454 /* likely a native PE module */
455 WARN("Couldn't find container for %s\n", debugstr_w(ImageName));
456 return FALSE;
457 }
458
459 /******************************************************************
460 * module_get_type_by_name
461 *
462 * Guesses a filename type from its extension
463 */
464 enum module_type module_get_type_by_name(const WCHAR* name)
465 {
466 int loader_len, len = strlenW(name);
467 const WCHAR *loader;
468
469 /* Skip all version extensions (.[digits]) regex: "(\.\d+)*$" */
470 do
471 {
472 int i = len;
473
474 while (i && isdigit(name[i - 1])) i--;
475
476 if (i && name[i - 1] == '.')
477 len = i - 1;
478 else
479 break;
480 } while (len);
481
482 /* check for terminating .so or .so.[digit] */
483 /* FIXME: Can't rely solely on extension; have to check magic or
484 * stop using .so on Mac OS X. For now, base on platform. */
485 if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3))
486 #ifdef __APPLE__
487 return DMT_MACHO;
488 #else
489 return DMT_ELF;
490 #endif
491
492 if (len > 6 && !strncmpiW(name + len - 6, S_DotDylibW, 6))
493 return DMT_MACHO;
494
495 if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4))
496 return DMT_PDB;
497
498 if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4))
499 return DMT_DBG;
500
501 /* wine is also a native module (Mach-O on Mac OS X, ELF elsewhere) */
502 loader = get_wine_loader_name();
503 loader_len = strlenW( loader );
504 if ((len == loader_len || (len > loader_len && name[len - loader_len - 1] == '/')) &&
505 !strcmpiW(name + len - loader_len, loader))
506 {
507 #ifdef __APPLE__
508 return DMT_MACHO;
509 #else
510 return DMT_ELF;
511 #endif
512 }
513 return DMT_PE;
514 }
515
516 /******************************************************************
517 * refresh_module_list
518 */
519 #ifndef DBGHELP_STATIC_LIB
520 static BOOL refresh_module_list(struct process* pcs)
521 {
522 /* force transparent ELF and Mach-O loading / unloading */
523 return elf_synchronize_module_list(pcs) || macho_synchronize_module_list(pcs);
524 }
525 #endif
526
527 /***********************************************************************
528 * SymLoadModule (DBGHELP.@)
529 */
530 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
531 PCSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
532 {
533 return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll,
534 SizeOfDll, NULL, 0);
535 }
536
537 /***********************************************************************
538 * SymLoadModuleEx (DBGHELP.@)
539 */
540 DWORD64 WINAPI SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
541 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
542 PMODLOAD_DATA Data, DWORD Flags)
543 {
544 PWSTR wImageName, wModuleName;
545 unsigned len;
546 DWORD64 ret;
547
548 TRACE("(%p %p %s %s %s %08x %p %08x)\n",
549 hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
550 wine_dbgstr_longlong(BaseOfDll), DllSize, Data, Flags);
551
552 if (ImageName)
553 {
554 len = MultiByteToWideChar(CP_ACP, 0, ImageName, -1, NULL, 0);
555 wImageName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
556 MultiByteToWideChar(CP_ACP, 0, ImageName, -1, wImageName, len);
557 }
558 else wImageName = NULL;
559 if (ModuleName)
560 {
561 len = MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, NULL, 0);
562 wModuleName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
563 MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, wModuleName, len);
564 }
565 else wModuleName = NULL;
566
567 ret = SymLoadModuleExW(hProcess, hFile, wImageName, wModuleName,
568 BaseOfDll, DllSize, Data, Flags);
569 HeapFree(GetProcessHeap(), 0, wImageName);
570 HeapFree(GetProcessHeap(), 0, wModuleName);
571 return ret;
572 }
573
574 /***********************************************************************
575 * SymLoadModuleExW (DBGHELP.@)
576 */
577 DWORD64 WINAPI SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageName,
578 PCWSTR wModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll,
579 PMODLOAD_DATA Data, DWORD Flags)
580 {
581 struct process* pcs;
582 struct module* module = NULL;
583
584 TRACE("(%p %p %s %s %s %08x %p %08x)\n",
585 hProcess, hFile, debugstr_w(wImageName), debugstr_w(wModuleName),
586 wine_dbgstr_longlong(BaseOfDll), SizeOfDll, Data, Flags);
587
588 if (Data)
589 FIXME("Unsupported load data parameter %p for %s\n",
590 Data, debugstr_w(wImageName));
591 if (!validate_addr64(BaseOfDll)) return FALSE;
592
593 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
594
595 if (Flags & SLMFLAG_VIRTUAL)
596 {
597 if (!wImageName) return FALSE;
598 module = module_new(pcs, wImageName, module_get_type_by_name(wImageName),
599 TRUE, BaseOfDll, SizeOfDll, 0, 0);
600 if (!module) return FALSE;
601 if (wModuleName) module_set_module(module, wModuleName);
602 module->module.SymType = SymVirtual;
603
604 return TRUE;
605 }
606 if (Flags & ~(SLMFLAG_VIRTUAL))
607 FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
608
609 #ifndef DBGHELP_STATIC_LIB
610 refresh_module_list(pcs);
611 #endif
612
613 /* this is a Wine extension to the API just to redo the synchronisation */
614 if (!wImageName && !hFile) return 0;
615
616 /* check if the module is already loaded, or if it's a builtin PE module with
617 * an containing ELF module
618 */
619 if (wImageName)
620 {
621 module = module_is_already_loaded(pcs, wImageName);
622 if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll))
623 {
624 /* force the loading of DLL as builtin */
625 module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
626 }
627 }
628 if (!module)
629 {
630 /* otherwise, try a regular PE module */
631 if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) &&
632 wImageName)
633 {
634 /* and finally an ELF or Mach-O module */
635 #ifndef DBGHELP_STATIC_LIB
636 switch (module_get_type_by_name(wImageName))
637 {
638 case DMT_ELF:
639 module = elf_load_module(pcs, wImageName, BaseOfDll);
640 break;
641 case DMT_MACHO:
642 module = macho_load_module(pcs, wImageName, BaseOfDll);
643 break;
644 default:
645 /* Ignored */
646 break;
647 }
648 #endif
649 }
650 }
651 if (!module)
652 {
653 WARN("Couldn't locate %s\n", debugstr_w(wImageName));
654 return 0;
655 }
656 module->module.NumSyms = module->ht_symbols.num_elts;
657 /* by default module_new fills module.ModuleName from a derivation
658 * of LoadedImageName. Overwrite it, if we have better information
659 */
660 if (wModuleName)
661 module_set_module(module, wModuleName);
662 if (wImageName)
663 lstrcpynW(module->module.ImageName, wImageName,
664 sizeof(module->module.ImageName) / sizeof(WCHAR));
665
666 return module->module.BaseOfImage;
667 }
668
669 /***********************************************************************
670 * SymLoadModule64 (DBGHELP.@)
671 */
672 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
673 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
674 {
675 return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll,
676 NULL, 0);
677 }
678
679 /******************************************************************
680 * module_remove
681 *
682 */
683 BOOL module_remove(struct process* pcs, struct module* module)
684 {
685 struct module_format*modfmt;
686 struct module** p;
687 unsigned i;
688
689 TRACE("%s (%p)\n", debugstr_w(module->module.ModuleName), module);
690
691 for (i = 0; i < DFI_LAST; i++)
692 {
693 if ((modfmt = module->format_info[i]) && modfmt->remove)
694 modfmt->remove(pcs, module->format_info[i]);
695 }
696 hash_table_destroy(&module->ht_symbols);
697 hash_table_destroy(&module->ht_types);
698 wine_rb_destroy(&module->sources_offsets_tree, NULL, NULL);
699 HeapFree(GetProcessHeap(), 0, module->sources);
700 HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
701 pool_destroy(&module->pool);
702 /* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here
703 * so do we
704 */
705 for (p = &pcs->lmodules; *p; p = &(*p)->next)
706 {
707 if (*p == module)
708 {
709 *p = module->next;
710 HeapFree(GetProcessHeap(), 0, module);
711 return TRUE;
712 }
713 }
714 FIXME("This shouldn't happen\n");
715 return FALSE;
716 }
717
718 /******************************************************************
719 * SymUnloadModule (DBGHELP.@)
720 *
721 */
722 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
723 {
724 struct process* pcs;
725 struct module* module;
726
727 pcs = process_find_by_handle(hProcess);
728 if (!pcs) return FALSE;
729 module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
730 if (!module) return FALSE;
731 return module_remove(pcs, module);
732 }
733
734 /******************************************************************
735 * SymUnloadModule64 (DBGHELP.@)
736 *
737 */
738 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
739 {
740 struct process* pcs;
741 struct module* module;
742
743 pcs = process_find_by_handle(hProcess);
744 if (!pcs) return FALSE;
745 if (!validate_addr64(BaseOfDll)) return FALSE;
746 module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
747 if (!module) return FALSE;
748 return module_remove(pcs, module);
749 }
750
751 /******************************************************************
752 * SymEnumerateModules (DBGHELP.@)
753 *
754 */
755 struct enum_modW64_32
756 {
757 PSYM_ENUMMODULES_CALLBACK cb;
758 PVOID user;
759 char module[MAX_PATH];
760 };
761
762 static BOOL CALLBACK enum_modW64_32(PCWSTR name, DWORD64 base, PVOID user)
763 {
764 struct enum_modW64_32* x = user;
765
766 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
767 return x->cb(x->module, (DWORD)base, x->user);
768 }
769
770 BOOL WINAPI SymEnumerateModules(HANDLE hProcess,
771 PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
772 PVOID UserContext)
773 {
774 struct enum_modW64_32 x;
775
776 x.cb = EnumModulesCallback;
777 x.user = UserContext;
778
779 return SymEnumerateModulesW64(hProcess, enum_modW64_32, &x);
780 }
781
782 /******************************************************************
783 * SymEnumerateModules64 (DBGHELP.@)
784 *
785 */
786 struct enum_modW64_64
787 {
788 PSYM_ENUMMODULES_CALLBACK64 cb;
789 PVOID user;
790 char module[MAX_PATH];
791 };
792
793 static BOOL CALLBACK enum_modW64_64(PCWSTR name, DWORD64 base, PVOID user)
794 {
795 struct enum_modW64_64* x = user;
796
797 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
798 return x->cb(x->module, base, x->user);
799 }
800
801 BOOL WINAPI SymEnumerateModules64(HANDLE hProcess,
802 PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
803 PVOID UserContext)
804 {
805 struct enum_modW64_64 x;
806
807 x.cb = EnumModulesCallback;
808 x.user = UserContext;
809
810 return SymEnumerateModulesW64(hProcess, enum_modW64_64, &x);
811 }
812
813 /******************************************************************
814 * SymEnumerateModulesW64 (DBGHELP.@)
815 *
816 */
817 BOOL WINAPI SymEnumerateModulesW64(HANDLE hProcess,
818 PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,
819 PVOID UserContext)
820 {
821 struct process* pcs = process_find_by_handle(hProcess);
822 struct module* module;
823
824 if (!pcs) return FALSE;
825
826 for (module = pcs->lmodules; module; module = module->next)
827 {
828 if (!(dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) &&
829 (module->type == DMT_ELF || module->type == DMT_MACHO))
830 continue;
831 if (!EnumModulesCallback(module->module.ModuleName,
832 module->module.BaseOfImage, UserContext))
833 break;
834 }
835 return TRUE;
836 }
837
838 #ifndef DBGHELP_STATIC_LIB
839 /******************************************************************
840 * EnumerateLoadedModules64 (DBGHELP.@)
841 *
842 */
843 struct enum_load_modW64_64
844 {
845 PENUMLOADED_MODULES_CALLBACK64 cb;
846 PVOID user;
847 char module[MAX_PATH];
848 };
849
850 static BOOL CALLBACK enum_load_modW64_64(PCWSTR name, DWORD64 base, ULONG size,
851 PVOID user)
852 {
853 struct enum_load_modW64_64* x = user;
854
855 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
856 return x->cb(x->module, base, size, x->user);
857 }
858
859 BOOL WINAPI EnumerateLoadedModules64(HANDLE hProcess,
860 PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,
861 PVOID UserContext)
862 {
863 struct enum_load_modW64_64 x;
864
865 x.cb = EnumLoadedModulesCallback;
866 x.user = UserContext;
867
868 return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_64, &x);
869 }
870
871 /******************************************************************
872 * EnumerateLoadedModules (DBGHELP.@)
873 *
874 */
875 struct enum_load_modW64_32
876 {
877 PENUMLOADED_MODULES_CALLBACK cb;
878 PVOID user;
879 char module[MAX_PATH];
880 };
881
882 static BOOL CALLBACK enum_load_modW64_32(PCWSTR name, DWORD64 base, ULONG size,
883 PVOID user)
884 {
885 struct enum_load_modW64_32* x = user;
886 WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
887 return x->cb(x->module, (DWORD)base, size, x->user);
888 }
889
890 BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess,
891 PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
892 PVOID UserContext)
893 {
894 struct enum_load_modW64_32 x;
895
896 x.cb = EnumLoadedModulesCallback;
897 x.user = UserContext;
898
899 return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x);
900 }
901
902 /******************************************************************
903 * EnumerateLoadedModulesW64 (DBGHELP.@)
904 *
905 */
906 BOOL WINAPI EnumerateLoadedModulesW64(HANDLE hProcess,
907 PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,
908 PVOID UserContext)
909 {
910 HMODULE* hMods;
911 WCHAR baseW[256], modW[256];
912 DWORD i, sz;
913 MODULEINFO mi;
914
915 hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
916 if (!hMods) return FALSE;
917
918 if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
919 {
920 /* hProcess should also be a valid process handle !! */
921 FIXME("If this happens, bump the number in mod\n");
922 HeapFree(GetProcessHeap(), 0, hMods);
923 return FALSE;
924 }
925 sz /= sizeof(HMODULE);
926 for (i = 0; i < sz; i++)
927 {
928 if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
929 !GetModuleBaseNameW(hProcess, hMods[i], baseW, sizeof(baseW) / sizeof(WCHAR)))
930 continue;
931 module_fill_module(baseW, modW, sizeof(modW) / sizeof(CHAR));
932 EnumLoadedModulesCallback(modW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage,
933 UserContext);
934 }
935 HeapFree(GetProcessHeap(), 0, hMods);
936
937 return sz != 0 && i == sz;
938 }
939 #endif /* DBGHELP_STATIC_LIB */
940
941 /******************************************************************
942 * SymGetModuleInfo (DBGHELP.@)
943 *
944 */
945 BOOL WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
946 PIMAGEHLP_MODULE ModuleInfo)
947 {
948 IMAGEHLP_MODULE mi;
949 IMAGEHLP_MODULEW64 miw64;
950
951 if (sizeof(mi) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
952
953 miw64.SizeOfStruct = sizeof(miw64);
954 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
955
956 mi.SizeOfStruct = miw64.SizeOfStruct;
957 mi.BaseOfImage = miw64.BaseOfImage;
958 mi.ImageSize = miw64.ImageSize;
959 mi.TimeDateStamp = miw64.TimeDateStamp;
960 mi.CheckSum = miw64.CheckSum;
961 mi.NumSyms = miw64.NumSyms;
962 mi.SymType = miw64.SymType;
963 WideCharToMultiByte(CP_ACP, 0, miw64.ModuleName, -1,
964 mi.ModuleName, sizeof(mi.ModuleName), NULL, NULL);
965 WideCharToMultiByte(CP_ACP, 0, miw64.ImageName, -1,
966 mi.ImageName, sizeof(mi.ImageName), NULL, NULL);
967 WideCharToMultiByte(CP_ACP, 0, miw64.LoadedImageName, -1,
968 mi.LoadedImageName, sizeof(mi.LoadedImageName), NULL, NULL);
969
970 memcpy(ModuleInfo, &mi, ModuleInfo->SizeOfStruct);
971
972 return TRUE;
973 }
974
975 /******************************************************************
976 * SymGetModuleInfoW (DBGHELP.@)
977 *
978 */
979 BOOL WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr,
980 PIMAGEHLP_MODULEW ModuleInfo)
981 {
982 IMAGEHLP_MODULEW64 miw64;
983 IMAGEHLP_MODULEW miw;
984
985 if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
986
987 miw64.SizeOfStruct = sizeof(miw64);
988 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
989
990 miw.SizeOfStruct = miw64.SizeOfStruct;
991 miw.BaseOfImage = miw64.BaseOfImage;
992 miw.ImageSize = miw64.ImageSize;
993 miw.TimeDateStamp = miw64.TimeDateStamp;
994 miw.CheckSum = miw64.CheckSum;
995 miw.NumSyms = miw64.NumSyms;
996 miw.SymType = miw64.SymType;
997 strcpyW(miw.ModuleName, miw64.ModuleName);
998 strcpyW(miw.ImageName, miw64.ImageName);
999 strcpyW(miw.LoadedImageName, miw64.LoadedImageName);
1000 memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
1001
1002 return TRUE;
1003 }
1004
1005 /******************************************************************
1006 * SymGetModuleInfo64 (DBGHELP.@)
1007 *
1008 */
1009 BOOL WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr,
1010 PIMAGEHLP_MODULE64 ModuleInfo)
1011 {
1012 IMAGEHLP_MODULE64 mi64;
1013 IMAGEHLP_MODULEW64 miw64;
1014
1015 if (sizeof(mi64) < ModuleInfo->SizeOfStruct)
1016 {
1017 SetLastError(ERROR_MOD_NOT_FOUND); /* NOTE: native returns this error */
1018 WARN("Wrong size %u\n", ModuleInfo->SizeOfStruct);
1019 return FALSE;
1020 }
1021
1022 miw64.SizeOfStruct = sizeof(miw64);
1023 if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1024
1025 mi64.SizeOfStruct = miw64.SizeOfStruct;
1026 mi64.BaseOfImage = miw64.BaseOfImage;
1027 mi64.ImageSize = miw64.ImageSize;
1028 mi64.TimeDateStamp = miw64.TimeDateStamp;
1029 mi64.CheckSum = miw64.CheckSum;
1030 mi64.NumSyms = miw64.NumSyms;
1031 mi64.SymType = miw64.SymType;
1032 WideCharToMultiByte(CP_ACP, 0, miw64.ModuleName, -1,
1033 mi64.ModuleName, sizeof(mi64.ModuleName), NULL, NULL);
1034 WideCharToMultiByte(CP_ACP, 0, miw64.ImageName, -1,
1035 mi64.ImageName, sizeof(mi64.ImageName), NULL, NULL);
1036 WideCharToMultiByte(CP_ACP, 0, miw64.LoadedImageName, -1,
1037 mi64.LoadedImageName, sizeof(mi64.LoadedImageName), NULL, NULL);
1038 WideCharToMultiByte(CP_ACP, 0, miw64.LoadedPdbName, -1,
1039 mi64.LoadedPdbName, sizeof(mi64.LoadedPdbName), NULL, NULL);
1040
1041 mi64.CVSig = miw64.CVSig;
1042 WideCharToMultiByte(CP_ACP, 0, miw64.CVData, -1,
1043 mi64.CVData, sizeof(mi64.CVData), NULL, NULL);
1044 mi64.PdbSig = miw64.PdbSig;
1045 mi64.PdbSig70 = miw64.PdbSig70;
1046 mi64.PdbAge = miw64.PdbAge;
1047 mi64.PdbUnmatched = miw64.PdbUnmatched;
1048 mi64.DbgUnmatched = miw64.DbgUnmatched;
1049 mi64.LineNumbers = miw64.LineNumbers;
1050 mi64.GlobalSymbols = miw64.GlobalSymbols;
1051 mi64.TypeInfo = miw64.TypeInfo;
1052 mi64.SourceIndexed = miw64.SourceIndexed;
1053 mi64.Publics = miw64.Publics;
1054
1055 memcpy(ModuleInfo, &mi64, ModuleInfo->SizeOfStruct);
1056
1057 return TRUE;
1058 }
1059
1060 /******************************************************************
1061 * SymGetModuleInfoW64 (DBGHELP.@)
1062 *
1063 */
1064 BOOL WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr,
1065 PIMAGEHLP_MODULEW64 ModuleInfo)
1066 {
1067 struct process* pcs = process_find_by_handle(hProcess);
1068 struct module* module;
1069 IMAGEHLP_MODULEW64 miw64;
1070
1071 TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
1072
1073 if (!pcs) return FALSE;
1074 if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
1075 module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1076 if (!module) return FALSE;
1077
1078 miw64 = module->module;
1079
1080 /* update debug information from container if any */
1081 if (module->module.SymType == SymNone)
1082 {
1083 module = module_get_container(pcs, module);
1084 if (module && module->module.SymType != SymNone)
1085 {
1086 miw64.SymType = module->module.SymType;
1087 miw64.NumSyms = module->module.NumSyms;
1088 }
1089 }
1090 memcpy(ModuleInfo, &miw64, ModuleInfo->SizeOfStruct);
1091 return TRUE;
1092 }
1093
1094 /***********************************************************************
1095 * SymGetModuleBase (DBGHELP.@)
1096 */
1097 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
1098 {
1099 DWORD64 ret;
1100
1101 ret = SymGetModuleBase64(hProcess, dwAddr);
1102 return validate_addr64(ret) ? ret : 0;
1103 }
1104
1105 /***********************************************************************
1106 * SymGetModuleBase64 (DBGHELP.@)
1107 */
1108 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
1109 {
1110 struct process* pcs = process_find_by_handle(hProcess);
1111 struct module* module;
1112
1113 if (!pcs) return 0;
1114 module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1115 if (!module) return 0;
1116 return module->module.BaseOfImage;
1117 }
1118
1119 /******************************************************************
1120 * module_reset_debug_info
1121 * Removes any debug information linked to a given module.
1122 */
1123 void module_reset_debug_info(struct module* module)
1124 {
1125 module->sortlist_valid = TRUE;
1126 module->sorttab_size = 0;
1127 module->addr_sorttab = NULL;
1128 module->num_sorttab = module->num_symbols = 0;
1129 hash_table_destroy(&module->ht_symbols);
1130 module->ht_symbols.num_buckets = 0;
1131 module->ht_symbols.buckets = NULL;
1132 hash_table_destroy(&module->ht_types);
1133 module->ht_types.num_buckets = 0;
1134 module->ht_types.buckets = NULL;
1135 module->vtypes.num_elts = 0;
1136 hash_table_destroy(&module->ht_symbols);
1137 module->sources_used = module->sources_alloc = 0;
1138 module->sources = NULL;
1139 }
1140
1141 /******************************************************************
1142 * SymRefreshModuleList (DBGHELP.@)
1143 */
1144 BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
1145 {
1146 struct process* pcs;
1147
1148 TRACE("(%p)\n", hProcess);
1149
1150 if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
1151
1152 #ifndef DBGHELP_STATIC_LIB
1153 return refresh_module_list(pcs);
1154 #else
1155 return TRUE;
1156 #endif
1157 }
1158
1159 /***********************************************************************
1160 * SymFunctionTableAccess (DBGHELP.@)
1161 */
1162 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
1163 {
1164 return SymFunctionTableAccess64(hProcess, AddrBase);
1165 }
1166
1167 /***********************************************************************
1168 * SymFunctionTableAccess64 (DBGHELP.@)
1169 */
1170 PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase)
1171 {
1172 struct process* pcs = process_find_by_handle(hProcess);
1173 struct module* module;
1174
1175 if (!pcs || !dbghelp_current_cpu->find_runtime_function) return NULL;
1176 module = module_find_by_addr(pcs, AddrBase, DMT_UNKNOWN);
1177 if (!module) return NULL;
1178
1179 return dbghelp_current_cpu->find_runtime_function(module, AddrBase);
1180 }