xref: /reactos/dll/win32/dbghelp/module.c (revision 1734f297)
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 
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 
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__
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 
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 
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 */
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 
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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 
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 
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 
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  */
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 
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 
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 
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 
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  */
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
1363 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
1364 {
1365     return SymFunctionTableAccess64(hProcess, AddrBase);
1366 }
1367 
1368 /***********************************************************************
1369  *		SymFunctionTableAccess64 (DBGHELP.@)
1370  */
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 
1383 static BOOL native_synchronize_module_list(struct process* pcs)
1384 {
1385     return FALSE;
1386 }
1387 
1388 static struct module* native_load_module(struct process* pcs, const WCHAR* name, ULONG_PTR addr)
1389 {
1390     return NULL;
1391 }
1392 
1393 static BOOL native_load_debug_info(struct process* process, struct module* module)
1394 {
1395     return FALSE;
1396 }
1397 
1398 static BOOL native_enum_modules(struct process *process, enum_modules_cb cb, void* user)
1399 {
1400     return FALSE;
1401 }
1402 
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