xref: /reactos/dll/win32/dbghelp/module.c (revision 40462c92)
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     static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
546     static const WCHAR dotDebugW[] = {'.','d','e','b','u','g','/'};
547     const size_t globalDebugDirLen = ARRAY_SIZE(globalDebugDirW);
548     size_t filename_len, path_len;
549     WCHAR* p = NULL;
550     WCHAR* slash;
551     WCHAR* slash2;
552     struct image_file_map* fmap_link = NULL;
553 
554     fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
555     if (!fmap_link) return FALSE;
556 
557     filename_len = MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, NULL, 0);
558     path_len = lstrlenW(module->module.LoadedImageName);
559     if (module->real_path) path_len = max(path_len, lstrlenW(module->real_path));
560     p = HeapAlloc(GetProcessHeap(), 0,
561                   (globalDebugDirLen + path_len + 6 + 1 + filename_len + 1) * sizeof(WCHAR));
562     if (!p) goto found;
563 
564     /* we prebuild the string with "execdir" */
565     lstrcpyW(p, module->module.LoadedImageName);
566     slash = p;
567     if ((slash2 = wcsrchr(slash, '/'))) slash = slash2 + 1;
568     if ((slash2 = wcsrchr(slash, '\\'))) slash = slash2 + 1;
569 
570     /* testing execdir/filename */
571     MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
572     if (image_check_debug_link(p, fmap_link, crc)) goto found;
573 
574     /* testing execdir/.debug/filename */
575     memcpy(slash, dotDebugW, sizeof(dotDebugW));
576     MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash + ARRAY_SIZE(dotDebugW), filename_len);
577     if (image_check_debug_link(p, fmap_link, crc)) goto found;
578 
579     if (module->real_path)
580     {
581         lstrcpyW(p, module->real_path);
582         slash = p;
583         if ((slash2 = wcsrchr(slash, '/'))) slash = slash2 + 1;
584         if ((slash2 = wcsrchr(slash, '\\'))) slash = slash2 + 1;
585         MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
586         if (image_check_debug_link(p, fmap_link, crc)) goto found;
587     }
588 
589     /* testing globaldebugdir/execdir/filename */
590     memmove(p + globalDebugDirLen, p, (slash - p) * sizeof(WCHAR));
591     memcpy(p, globalDebugDirW, globalDebugDirLen * sizeof(WCHAR));
592     slash += globalDebugDirLen;
593     MultiByteToWideChar(CP_UNIXCP, 0, filename, -1, slash, filename_len);
594     if (image_check_debug_link(p, fmap_link, crc)) goto found;
595 
596     /* finally testing filename */
597     if (image_check_debug_link(slash, fmap_link, crc)) goto found;
598 
599 
600     WARN("Couldn't locate or map %s\n", filename);
601     HeapFree(GetProcessHeap(), 0, p);
602     HeapFree(GetProcessHeap(), 0, fmap_link);
603     return FALSE;
604 
605 found:
606     TRACE("Located debug information file %s at %s\n", filename, debugstr_w(p));
607     HeapFree(GetProcessHeap(), 0, p);
608     fmap->alternate = fmap_link;
609     return TRUE;
610 }
611 
612 /******************************************************************
613  *		image_locate_build_id_target
614  *
615  * Try to find the .so file containing the debug info out of the build-id note information
616  */
617 static BOOL image_locate_build_id_target(struct image_file_map* fmap, const BYTE* id, unsigned idlen)
618 {
619     static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
620     static const WCHAR buildidW[] = {'.','b','u','i','l','d','-','i','d','/'};
621     static const WCHAR dotDebug0W[] = {'.','d','e','b','u','g',0};
622     struct image_file_map* fmap_link = NULL;
623     WCHAR* p;
624     WCHAR* z;
625     const BYTE* idend = id + idlen;
626 
627     fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
628     if (!fmap_link) return FALSE;
629 
630     p = HeapAlloc(GetProcessHeap(), 0,
631                   sizeof(globalDebugDirW) + sizeof(buildidW) +
632                   (idlen * 2 + 1) * sizeof(WCHAR) + sizeof(dotDebug0W));
633     z = p;
634     memcpy(z, globalDebugDirW, sizeof(globalDebugDirW));
635     z += ARRAY_SIZE(globalDebugDirW);
636     memcpy(z, buildidW, sizeof(buildidW));
637     z += ARRAY_SIZE(buildidW);
638 
639     if (id < idend)
640     {
641         *z++ = "0123456789abcdef"[*id >> 4  ];
642         *z++ = "0123456789abcdef"[*id & 0x0F];
643         id++;
644     }
645     if (id < idend)
646         *z++ = '/';
647     while (id < idend)
648     {
649         *z++ = "0123456789abcdef"[*id >> 4  ];
650         *z++ = "0123456789abcdef"[*id & 0x0F];
651         id++;
652     }
653     memcpy(z, dotDebug0W, sizeof(dotDebug0W));
654     TRACE("checking %s\n", wine_dbgstr_w(p));
655 
656     if (image_check_debug_link(p, fmap_link, 0))
657     {
658         struct image_section_map buildid_sect;
659         if (image_find_section(fmap_link, ".note.gnu.build-id", &buildid_sect))
660         {
661             const UINT32* note;
662 
663             note = (const UINT32*)image_map_section(&buildid_sect);
664             if (note != IMAGE_NO_MAP)
665             {
666                 /* the usual ELF note structure: name-size desc-size type <name> <desc> */
667                 if (note[2] == NOTE_GNU_BUILD_ID)
668                 {
669                     if (note[1] == idlen &&
670                         !memcmp(note + 3 + ((note[0] + 3) >> 2), idend - idlen, idlen))
671                     {
672                         TRACE("Located debug information file at %s\n", debugstr_w(p));
673                         HeapFree(GetProcessHeap(), 0, p);
674                         fmap->alternate = fmap_link;
675                         return TRUE;
676                     }
677                     WARN("mismatch in buildid information for %s\n", wine_dbgstr_w(p));
678                 }
679             }
680             image_unmap_section(&buildid_sect);
681         }
682         image_unmap_file(fmap_link);
683     }
684 
685     TRACE("not found\n");
686     HeapFree(GetProcessHeap(), 0, p);
687     HeapFree(GetProcessHeap(), 0, fmap_link);
688     return FALSE;
689 }
690 
691 /******************************************************************
692  *		image_check_alternate
693  *
694  * Load alternate files for a given image file, looking at either .note.gnu_build-id
695  * or .gnu_debuglink sections.
696  */
697 BOOL image_check_alternate(struct image_file_map* fmap, const struct module* module)
698 {
699     BOOL ret = FALSE;
700     BOOL found = FALSE;
701     struct image_section_map buildid_sect, debuglink_sect;
702 
703     /* if present, add the .gnu_debuglink file as an alternate to current one */
704     if (image_find_section(fmap, ".note.gnu.build-id", &buildid_sect))
705     {
706         const UINT32* note;
707 
708         found = TRUE;
709         note = (const UINT32*)image_map_section(&buildid_sect);
710         if (note != IMAGE_NO_MAP)
711         {
712             /* the usual ELF note structure: name-size desc-size type <name> <desc> */
713             if (note[2] == NOTE_GNU_BUILD_ID)
714             {
715                 ret = image_locate_build_id_target(fmap, (const BYTE*)(note + 3 + ((note[0] + 3) >> 2)), note[1]);
716             }
717         }
718         image_unmap_section(&buildid_sect);
719     }
720     /* if present, add the .gnu_debuglink file as an alternate to current one */
721     if (!ret && image_find_section(fmap, ".gnu_debuglink", &debuglink_sect))
722     {
723         const char* dbg_link;
724 
725         found = TRUE;
726         dbg_link = (const char*)image_map_section(&debuglink_sect);
727         if (dbg_link != IMAGE_NO_MAP)
728         {
729             /* The content of a debug link section is:
730              * 1/ a NULL terminated string, containing the file name for the
731              *    debug info
732              * 2/ padding on 4 byte boundary
733              * 3/ CRC of the linked file
734              */
735             DWORD crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
736             ret = image_locate_debug_link(module, fmap, dbg_link, crc);
737             if (!ret)
738                 WARN("Couldn't load linked debug file for %s\n",
739                      debugstr_w(module->module.ModuleName));
740         }
741         image_unmap_section(&debuglink_sect);
742     }
743     return found ? ret : TRUE;
744 }
745 
746 /***********************************************************************
747  *			SymLoadModule (DBGHELP.@)
748  */
749 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
750                            PCSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
751 {
752     return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll,
753                            SizeOfDll, NULL, 0);
754 }
755 
756 /***********************************************************************
757  *			SymLoadModuleEx (DBGHELP.@)
758  */
759 DWORD64 WINAPI  SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
760                                 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
761                                 PMODLOAD_DATA Data, DWORD Flags)
762 {
763     PWSTR       wImageName, wModuleName;
764     unsigned    len;
765     DWORD64     ret;
766 
767     TRACE("(%p %p %s %s %s %08x %p %08x)\n",
768           hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
769           wine_dbgstr_longlong(BaseOfDll), DllSize, Data, Flags);
770 
771     if (ImageName)
772     {
773         len = MultiByteToWideChar(CP_ACP, 0, ImageName, -1, NULL, 0);
774         wImageName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
775         MultiByteToWideChar(CP_ACP, 0, ImageName, -1, wImageName, len);
776     }
777     else wImageName = NULL;
778     if (ModuleName)
779     {
780         len = MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, NULL, 0);
781         wModuleName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
782         MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, wModuleName, len);
783     }
784     else wModuleName = NULL;
785 
786     ret = SymLoadModuleExW(hProcess, hFile, wImageName, wModuleName,
787                           BaseOfDll, DllSize, Data, Flags);
788     HeapFree(GetProcessHeap(), 0, wImageName);
789     HeapFree(GetProcessHeap(), 0, wModuleName);
790     return ret;
791 }
792 
793 /***********************************************************************
794  *			SymLoadModuleExW (DBGHELP.@)
795  */
796 DWORD64 WINAPI  SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageName,
797                                  PCWSTR wModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll,
798                                  PMODLOAD_DATA Data, DWORD Flags)
799 {
800     struct process*     pcs;
801     struct module*	module = NULL;
802 
803     TRACE("(%p %p %s %s %s %08x %p %08x)\n",
804           hProcess, hFile, debugstr_w(wImageName), debugstr_w(wModuleName),
805           wine_dbgstr_longlong(BaseOfDll), SizeOfDll, Data, Flags);
806 
807     if (Data)
808         FIXME("Unsupported load data parameter %p for %s\n",
809               Data, debugstr_w(wImageName));
810     if (!validate_addr64(BaseOfDll)) return FALSE;
811 
812     if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
813 
814     if (Flags & SLMFLAG_VIRTUAL)
815     {
816         if (!wImageName) return FALSE;
817         module = module_new(pcs, wImageName, DMT_PE, TRUE, BaseOfDll, SizeOfDll, 0, 0);
818         if (!module) return FALSE;
819         if (wModuleName) module_set_module(module, wModuleName);
820         module->module.SymType = SymVirtual;
821 
822         return TRUE;
823     }
824     if (Flags & ~(SLMFLAG_VIRTUAL))
825         FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
826 
827     pcs->loader->synchronize_module_list(pcs);
828 
829     /* this is a Wine extension to the API just to redo the synchronisation */
830     if (!wImageName && !hFile) return 0;
831 
832     /* check if the module is already loaded, or if it's a builtin PE module with
833      * an containing ELF module
834      */
835     if (wImageName)
836     {
837         module = module_is_already_loaded(pcs, wImageName);
838         if (!module && module_is_container_loaded(pcs, wImageName, BaseOfDll))
839         {
840             /* force the loading of DLL as builtin */
841             module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
842         }
843     }
844     if (!module)
845     {
846         /* otherwise, try a regular PE module */
847         if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)) &&
848             wImageName)
849         {
850             /* and finally an ELF or Mach-O module */
851             module = pcs->loader->load_module(pcs, wImageName, BaseOfDll);
852         }
853     }
854     if (!module)
855     {
856         WARN("Couldn't locate %s\n", debugstr_w(wImageName));
857         return 0;
858     }
859     module->module.NumSyms = module->ht_symbols.num_elts;
860     /* by default module_new fills module.ModuleName from a derivation
861      * of LoadedImageName. Overwrite it, if we have better information
862      */
863     if (wModuleName)
864         module_set_module(module, wModuleName);
865     if (wImageName)
866         lstrcpynW(module->module.ImageName, wImageName, ARRAY_SIZE(module->module.ImageName));
867 
868     return module->module.BaseOfImage;
869 }
870 
871 /***********************************************************************
872  *                     SymLoadModule64 (DBGHELP.@)
873  */
874 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
875                                PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
876 {
877     return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll, SizeOfDll,
878                            NULL, 0);
879 }
880 
881 /******************************************************************
882  *		module_remove
883  *
884  */
885 BOOL module_remove(struct process* pcs, struct module* module)
886 {
887     struct module_format*modfmt;
888     struct module**     p;
889     unsigned            i;
890 
891     TRACE("%s (%p)\n", debugstr_w(module->module.ModuleName), module);
892 
893     for (i = 0; i < DFI_LAST; i++)
894     {
895         if ((modfmt = module->format_info[i]) && modfmt->remove)
896             modfmt->remove(pcs, module->format_info[i]);
897     }
898     hash_table_destroy(&module->ht_symbols);
899     hash_table_destroy(&module->ht_types);
900     HeapFree(GetProcessHeap(), 0, module->sources);
901     HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
902     HeapFree(GetProcessHeap(), 0, module->real_path);
903     pool_destroy(&module->pool);
904     /* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here
905      * so do we
906      */
907     for (p = &pcs->lmodules; *p; p = &(*p)->next)
908     {
909         if (*p == module)
910         {
911             *p = module->next;
912             HeapFree(GetProcessHeap(), 0, module);
913             return TRUE;
914         }
915     }
916     FIXME("This shouldn't happen\n");
917     return FALSE;
918 }
919 
920 /******************************************************************
921  *		SymUnloadModule (DBGHELP.@)
922  *
923  */
924 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
925 {
926     struct process*     pcs;
927     struct module*      module;
928 
929     pcs = process_find_by_handle(hProcess);
930     if (!pcs) return FALSE;
931     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
932     if (!module) return FALSE;
933     return module_remove(pcs, module);
934 }
935 
936 /******************************************************************
937  *		SymUnloadModule64 (DBGHELP.@)
938  *
939  */
940 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
941 {
942     struct process*     pcs;
943     struct module*      module;
944 
945     pcs = process_find_by_handle(hProcess);
946     if (!pcs) return FALSE;
947     if (!validate_addr64(BaseOfDll)) return FALSE;
948     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
949     if (!module) return FALSE;
950     return module_remove(pcs, module);
951 }
952 
953 /******************************************************************
954  *		SymEnumerateModules (DBGHELP.@)
955  *
956  */
957 struct enum_modW64_32
958 {
959     PSYM_ENUMMODULES_CALLBACK   cb;
960     PVOID                       user;
961     char                        module[MAX_PATH];
962 };
963 
964 static BOOL CALLBACK enum_modW64_32(PCWSTR name, DWORD64 base, PVOID user)
965 {
966     struct enum_modW64_32*      x = user;
967 
968     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
969     return x->cb(x->module, (DWORD)base, x->user);
970 }
971 
972 BOOL  WINAPI SymEnumerateModules(HANDLE hProcess,
973                                  PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,
974                                  PVOID UserContext)
975 {
976     struct enum_modW64_32       x;
977 
978     x.cb = EnumModulesCallback;
979     x.user = UserContext;
980 
981     return SymEnumerateModulesW64(hProcess, enum_modW64_32, &x);
982 }
983 
984 /******************************************************************
985  *		SymEnumerateModules64 (DBGHELP.@)
986  *
987  */
988 struct enum_modW64_64
989 {
990     PSYM_ENUMMODULES_CALLBACK64 cb;
991     PVOID                       user;
992     char                        module[MAX_PATH];
993 };
994 
995 static BOOL CALLBACK enum_modW64_64(PCWSTR name, DWORD64 base, PVOID user)
996 {
997     struct enum_modW64_64*      x = user;
998 
999     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1000     return x->cb(x->module, base, x->user);
1001 }
1002 
1003 BOOL  WINAPI SymEnumerateModules64(HANDLE hProcess,
1004                                    PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,
1005                                    PVOID UserContext)
1006 {
1007     struct enum_modW64_64       x;
1008 
1009     x.cb = EnumModulesCallback;
1010     x.user = UserContext;
1011 
1012     return SymEnumerateModulesW64(hProcess, enum_modW64_64, &x);
1013 }
1014 
1015 /******************************************************************
1016  *		SymEnumerateModulesW64 (DBGHELP.@)
1017  *
1018  */
1019 BOOL  WINAPI SymEnumerateModulesW64(HANDLE hProcess,
1020                                     PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,
1021                                     PVOID UserContext)
1022 {
1023     struct process*     pcs = process_find_by_handle(hProcess);
1024     struct module*      module;
1025 
1026     if (!pcs) return FALSE;
1027 
1028     for (module = pcs->lmodules; module; module = module->next)
1029     {
1030         if (!dbghelp_opt_native &&
1031             (module->type == DMT_ELF || module->type == DMT_MACHO))
1032             continue;
1033         if (!EnumModulesCallback(module->modulename,
1034                                  module->module.BaseOfImage, UserContext))
1035             break;
1036     }
1037     return TRUE;
1038 }
1039 
1040 #ifndef DBGHELP_STATIC_LIB
1041 /******************************************************************
1042  *		EnumerateLoadedModules64 (DBGHELP.@)
1043  *
1044  */
1045 struct enum_load_modW64_64
1046 {
1047     PENUMLOADED_MODULES_CALLBACK64      cb;
1048     PVOID                               user;
1049     char                                module[MAX_PATH];
1050 };
1051 
1052 static BOOL CALLBACK enum_load_modW64_64(PCWSTR name, DWORD64 base, ULONG size,
1053                                          PVOID user)
1054 {
1055     struct enum_load_modW64_64* x = user;
1056 
1057     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1058     return x->cb(x->module, base, size, x->user);
1059 }
1060 
1061 BOOL  WINAPI EnumerateLoadedModules64(HANDLE hProcess,
1062                                       PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,
1063                                       PVOID UserContext)
1064 {
1065     struct enum_load_modW64_64  x;
1066 
1067     x.cb = EnumLoadedModulesCallback;
1068     x.user = UserContext;
1069 
1070     return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_64, &x);
1071 }
1072 
1073 /******************************************************************
1074  *		EnumerateLoadedModules (DBGHELP.@)
1075  *
1076  */
1077 struct enum_load_modW64_32
1078 {
1079     PENUMLOADED_MODULES_CALLBACK        cb;
1080     PVOID                               user;
1081     char                                module[MAX_PATH];
1082 };
1083 
1084 static BOOL CALLBACK enum_load_modW64_32(PCWSTR name, DWORD64 base, ULONG size,
1085                                          PVOID user)
1086 {
1087     struct enum_load_modW64_32* x = user;
1088     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
1089     return x->cb(x->module, (DWORD)base, size, x->user);
1090 }
1091 
1092 BOOL  WINAPI EnumerateLoadedModules(HANDLE hProcess,
1093                                     PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
1094                                     PVOID UserContext)
1095 {
1096     struct enum_load_modW64_32  x;
1097 
1098     x.cb = EnumLoadedModulesCallback;
1099     x.user = UserContext;
1100 
1101     return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x);
1102 }
1103 
1104 /******************************************************************
1105  *		EnumerateLoadedModulesW64 (DBGHELP.@)
1106  *
1107  */
1108 BOOL  WINAPI EnumerateLoadedModulesW64(HANDLE hProcess,
1109                                        PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,
1110                                        PVOID UserContext)
1111 {
1112     HMODULE*    hMods;
1113     WCHAR       baseW[256], modW[256];
1114     DWORD       i, sz;
1115     MODULEINFO  mi;
1116 
1117     hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
1118     if (!hMods) return FALSE;
1119 
1120     if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
1121     {
1122         /* hProcess should also be a valid process handle !! */
1123         FIXME("If this happens, bump the number in mod\n");
1124         HeapFree(GetProcessHeap(), 0, hMods);
1125         return FALSE;
1126     }
1127     sz /= sizeof(HMODULE);
1128     for (i = 0; i < sz; i++)
1129     {
1130         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
1131             !GetModuleBaseNameW(hProcess, hMods[i], baseW, ARRAY_SIZE(baseW)))
1132             continue;
1133         module_fill_module(baseW, modW, ARRAY_SIZE(modW));
1134         EnumLoadedModulesCallback(modW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage,
1135                                   UserContext);
1136     }
1137     HeapFree(GetProcessHeap(), 0, hMods);
1138 
1139     return sz != 0 && i == sz;
1140 }
1141 
1142 #endif /* DBGHELP_STATIC_LIB */
1143 
1144 static void dbghelp_str_WtoA(const WCHAR *src, char *dst, int dst_len)
1145 {
1146     WideCharToMultiByte(CP_ACP, 0, src, -1, dst, dst_len - 1, NULL, NULL);
1147     dst[dst_len - 1] = 0;
1148 }
1149 
1150 /******************************************************************
1151  *		SymGetModuleInfo (DBGHELP.@)
1152  *
1153  */
1154 BOOL  WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
1155                               PIMAGEHLP_MODULE ModuleInfo)
1156 {
1157     IMAGEHLP_MODULE     mi;
1158     IMAGEHLP_MODULEW64  miw64;
1159 
1160     if (sizeof(mi) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
1161 
1162     miw64.SizeOfStruct = sizeof(miw64);
1163     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1164 
1165     mi.SizeOfStruct  = ModuleInfo->SizeOfStruct;
1166     mi.BaseOfImage   = miw64.BaseOfImage;
1167     mi.ImageSize     = miw64.ImageSize;
1168     mi.TimeDateStamp = miw64.TimeDateStamp;
1169     mi.CheckSum      = miw64.CheckSum;
1170     mi.NumSyms       = miw64.NumSyms;
1171     mi.SymType       = miw64.SymType;
1172     dbghelp_str_WtoA(miw64.ModuleName, mi.ModuleName, sizeof(mi.ModuleName));
1173     dbghelp_str_WtoA(miw64.ImageName, mi.ImageName, sizeof(mi.ImageName));
1174     dbghelp_str_WtoA(miw64.LoadedImageName, mi.LoadedImageName, sizeof(mi.LoadedImageName));
1175 
1176     memcpy(ModuleInfo, &mi, ModuleInfo->SizeOfStruct);
1177 
1178     return TRUE;
1179 }
1180 
1181 /******************************************************************
1182  *		SymGetModuleInfoW (DBGHELP.@)
1183  *
1184  */
1185 BOOL  WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr,
1186                                PIMAGEHLP_MODULEW ModuleInfo)
1187 {
1188     IMAGEHLP_MODULEW64  miw64;
1189     IMAGEHLP_MODULEW    miw;
1190 
1191     if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
1192 
1193     miw64.SizeOfStruct = sizeof(miw64);
1194     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1195 
1196     miw.SizeOfStruct  = ModuleInfo->SizeOfStruct;
1197     miw.BaseOfImage   = miw64.BaseOfImage;
1198     miw.ImageSize     = miw64.ImageSize;
1199     miw.TimeDateStamp = miw64.TimeDateStamp;
1200     miw.CheckSum      = miw64.CheckSum;
1201     miw.NumSyms       = miw64.NumSyms;
1202     miw.SymType       = miw64.SymType;
1203     lstrcpyW(miw.ModuleName, miw64.ModuleName);
1204     lstrcpyW(miw.ImageName, miw64.ImageName);
1205     lstrcpyW(miw.LoadedImageName, miw64.LoadedImageName);
1206     memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
1207 
1208     return TRUE;
1209 }
1210 
1211 /******************************************************************
1212  *		SymGetModuleInfo64 (DBGHELP.@)
1213  *
1214  */
1215 BOOL  WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr,
1216                                 PIMAGEHLP_MODULE64 ModuleInfo)
1217 {
1218     IMAGEHLP_MODULE64   mi64;
1219     IMAGEHLP_MODULEW64  miw64;
1220 
1221     if (sizeof(mi64) < ModuleInfo->SizeOfStruct)
1222     {
1223         SetLastError(ERROR_MOD_NOT_FOUND); /* NOTE: native returns this error */
1224         WARN("Wrong size %u\n", ModuleInfo->SizeOfStruct);
1225         return FALSE;
1226     }
1227 
1228     miw64.SizeOfStruct = sizeof(miw64);
1229     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
1230 
1231     mi64.SizeOfStruct  = ModuleInfo->SizeOfStruct;
1232     mi64.BaseOfImage   = miw64.BaseOfImage;
1233     mi64.ImageSize     = miw64.ImageSize;
1234     mi64.TimeDateStamp = miw64.TimeDateStamp;
1235     mi64.CheckSum      = miw64.CheckSum;
1236     mi64.NumSyms       = miw64.NumSyms;
1237     mi64.SymType       = miw64.SymType;
1238     dbghelp_str_WtoA(miw64.ModuleName, mi64.ModuleName, sizeof(mi64.ModuleName));
1239     dbghelp_str_WtoA(miw64.ImageName, mi64.ImageName, sizeof(mi64.ImageName));
1240     dbghelp_str_WtoA(miw64.LoadedImageName, mi64.LoadedImageName, sizeof(mi64.LoadedImageName));
1241     dbghelp_str_WtoA(miw64.LoadedPdbName, mi64.LoadedPdbName, sizeof(mi64.LoadedPdbName));
1242 
1243     mi64.CVSig         = miw64.CVSig;
1244     dbghelp_str_WtoA(miw64.CVData, mi64.CVData, sizeof(mi64.CVData));
1245     mi64.PdbSig        = miw64.PdbSig;
1246     mi64.PdbSig70      = miw64.PdbSig70;
1247     mi64.PdbAge        = miw64.PdbAge;
1248     mi64.PdbUnmatched  = miw64.PdbUnmatched;
1249     mi64.DbgUnmatched  = miw64.DbgUnmatched;
1250     mi64.LineNumbers   = miw64.LineNumbers;
1251     mi64.GlobalSymbols = miw64.GlobalSymbols;
1252     mi64.TypeInfo      = miw64.TypeInfo;
1253     mi64.SourceIndexed = miw64.SourceIndexed;
1254     mi64.Publics       = miw64.Publics;
1255 
1256     memcpy(ModuleInfo, &mi64, ModuleInfo->SizeOfStruct);
1257 
1258     return TRUE;
1259 }
1260 
1261 /******************************************************************
1262  *		SymGetModuleInfoW64 (DBGHELP.@)
1263  *
1264  */
1265 BOOL  WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr,
1266                                  PIMAGEHLP_MODULEW64 ModuleInfo)
1267 {
1268     struct process*     pcs = process_find_by_handle(hProcess);
1269     struct module*      module;
1270     IMAGEHLP_MODULEW64  miw64;
1271 
1272     TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
1273 
1274     if (!pcs) return FALSE;
1275     if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
1276     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1277     if (!module) return FALSE;
1278 
1279     miw64 = module->module;
1280 
1281     /* update debug information from container if any */
1282     if (module->module.SymType == SymNone)
1283     {
1284         module = module_get_container(pcs, module);
1285         if (module && module->module.SymType != SymNone)
1286         {
1287             miw64.SymType = module->module.SymType;
1288             miw64.NumSyms = module->module.NumSyms;
1289         }
1290     }
1291     memcpy(ModuleInfo, &miw64, ModuleInfo->SizeOfStruct);
1292     return TRUE;
1293 }
1294 
1295 /***********************************************************************
1296  *		SymGetModuleBase (DBGHELP.@)
1297  */
1298 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
1299 {
1300     DWORD64     ret;
1301 
1302     ret = SymGetModuleBase64(hProcess, dwAddr);
1303     return validate_addr64(ret) ? ret : 0;
1304 }
1305 
1306 /***********************************************************************
1307  *		SymGetModuleBase64 (DBGHELP.@)
1308  */
1309 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
1310 {
1311     struct process*     pcs = process_find_by_handle(hProcess);
1312     struct module*      module;
1313 
1314     if (!pcs) return 0;
1315     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
1316     if (!module) return 0;
1317     return module->module.BaseOfImage;
1318 }
1319 
1320 /******************************************************************
1321  *		module_reset_debug_info
1322  * Removes any debug information linked to a given module.
1323  */
1324 void module_reset_debug_info(struct module* module)
1325 {
1326     module->sortlist_valid = TRUE;
1327     module->sorttab_size = 0;
1328     module->addr_sorttab = NULL;
1329     module->num_sorttab = module->num_symbols = 0;
1330     hash_table_destroy(&module->ht_symbols);
1331     module->ht_symbols.num_buckets = 0;
1332     module->ht_symbols.buckets = NULL;
1333     hash_table_destroy(&module->ht_types);
1334     module->ht_types.num_buckets = 0;
1335     module->ht_types.buckets = NULL;
1336     module->vtypes.num_elts = 0;
1337     hash_table_destroy(&module->ht_symbols);
1338     module->sources_used = module->sources_alloc = 0;
1339     module->sources = NULL;
1340 }
1341 
1342 /******************************************************************
1343  *              SymRefreshModuleList (DBGHELP.@)
1344  */
1345 BOOL WINAPI SymRefreshModuleList(HANDLE hProcess)
1346 {
1347     struct process*     pcs;
1348 
1349     TRACE("(%p)\n", hProcess);
1350 
1351     if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
1352 
1353     return pcs->loader->synchronize_module_list(pcs);
1354 }
1355 
1356 /***********************************************************************
1357  *		SymFunctionTableAccess (DBGHELP.@)
1358  */
1359 PVOID WINAPI SymFunctionTableAccess(HANDLE hProcess, DWORD AddrBase)
1360 {
1361     return SymFunctionTableAccess64(hProcess, AddrBase);
1362 }
1363 
1364 /***********************************************************************
1365  *		SymFunctionTableAccess64 (DBGHELP.@)
1366  */
1367 PVOID WINAPI SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase)
1368 {
1369     struct process*     pcs = process_find_by_handle(hProcess);
1370     struct module*      module;
1371 
1372     if (!pcs || !dbghelp_current_cpu->find_runtime_function) return NULL;
1373     module = module_find_by_addr(pcs, AddrBase, DMT_UNKNOWN);
1374     if (!module) return NULL;
1375 
1376     return dbghelp_current_cpu->find_runtime_function(module, AddrBase);
1377 }
1378 
1379 static BOOL native_synchronize_module_list(struct process* pcs)
1380 {
1381     return FALSE;
1382 }
1383 
1384 static struct module* native_load_module(struct process* pcs, const WCHAR* name, ULONG_PTR addr)
1385 {
1386     return NULL;
1387 }
1388 
1389 static BOOL native_load_debug_info(struct process* process, struct module* module)
1390 {
1391     return FALSE;
1392 }
1393 
1394 static BOOL native_enum_modules(struct process *process, enum_modules_cb cb, void* user)
1395 {
1396     return FALSE;
1397 }
1398 
1399 static BOOL native_fetch_file_info(struct process* process, const WCHAR* name, ULONG_PTR load_addr, DWORD_PTR* base,
1400                                    DWORD* size, DWORD* checksum)
1401 {
1402     return FALSE;
1403 }
1404 
1405 const struct loader_ops no_loader_ops =
1406 {
1407     native_synchronize_module_list,
1408     native_load_module,
1409     native_load_debug_info,
1410     native_enum_modules,
1411     native_fetch_file_info,
1412 };
1413