dbghelp: Always set the size to public symbols to 1 when we don't know the size
[wine] / dlls / dbghelp / module.c
1 /*
2  * File module.c - module handling for the wine debugger
3  *
4  * Copyright (C) 1993,      Eric Youngdale.
5  *               2000-2004, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "dbghelp_private.h"
29 #include "psapi.h"
30 #include "winreg.h"
31 #include "winternl.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
35
36 static const char* ext[] = {".acm", ".dll", ".drv", ".exe", ".ocx", ".vxd", NULL};
37
38 static int match_ext(const char* ptr, size_t len)
39 {
40     const char**e;
41     size_t      l;
42
43     for (e = ext; *e; e++)
44     {
45         l = strlen(*e);
46         if (l >= len) return FALSE;
47         if (strncasecmp(&ptr[len - l], *e, l)) continue;
48         return l;
49     }
50     return 0;
51 }
52         
53 static void module_fill_module(const char* in, char* out, size_t size)
54 {
55     const char  *ptr,*endptr;
56     size_t      len, l;
57
58     endptr = in + strlen(in);
59     for (ptr = endptr - 1;
60          ptr >= in && *ptr != '/' && *ptr != '\\';
61          ptr--);
62     ptr++;
63     len = min(endptr-ptr,size-1);
64     memcpy(out, ptr, len);
65     out[len] = '\0';
66     if (len > 4 && (l = match_ext(out, len)))
67         out[len - l] = '\0';
68     else if (len > 12 &&
69              (!strcasecmp(out + len - 12, "wine-pthread") || 
70               !strcasecmp(out + len - 12, "wine-kthread")))
71         lstrcpynA(out, "<wine-loader>", size);
72     else
73     {
74         if (len > 3 && !strcasecmp(&out[len - 3], ".so") &&
75             (l = match_ext(out, len - 3)))
76             strcpy(&out[len - l - 3], "<elf>");
77     }
78     while ((*out = tolower(*out))) out++;
79 }
80
81 static const char*      get_module_type(enum module_type type)
82 {
83     switch (type)
84     {
85     case DMT_ELF: return "ELF";
86     case DMT_PE: return "PE";
87     case DMT_VIRTUAL: return "Virtual";
88     default: return "---";
89     }
90 }
91
92 /***********************************************************************
93  * Creates and links a new module to a process 
94  */
95 struct module* module_new(struct process* pcs, const char* name, 
96                           enum module_type type, 
97                           unsigned long mod_addr, unsigned long size,
98                           unsigned long stamp, unsigned long checksum) 
99 {
100     struct module*      module;
101
102     assert(type == DMT_ELF || type == DMT_PE || type == DMT_VIRTUAL);
103     if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module))))
104         return NULL;
105
106     memset(module, 0, sizeof(*module));
107
108     module->next = pcs->lmodules;
109     pcs->lmodules = module;
110
111     TRACE("=> %s %08lx-%08lx %s\n", 
112           get_module_type(type), mod_addr, mod_addr + size, name);
113
114     pool_init(&module->pool, 65536);
115     
116     module->module.SizeOfStruct = sizeof(module->module);
117     module->module.BaseOfImage = mod_addr;
118     module->module.ImageSize = size;
119     module_fill_module(name, module->module.ModuleName,
120                        sizeof(module->module.ModuleName));
121     module->module.ImageName[0] = '\0';
122     lstrcpynA(module->module.LoadedImageName, name, sizeof(module->module.LoadedImageName));
123     module->module.SymType = SymNone;
124     module->module.NumSyms = 0;
125     module->module.TimeDateStamp = stamp;
126     module->module.CheckSum = checksum;
127
128     module->type              = type;
129     module->sortlist_valid    = FALSE;
130     module->addr_sorttab      = NULL;
131     /* FIXME: this seems a bit too high (on a per module basis)
132      * need some statistics about this
133      */
134     hash_table_init(&module->pool, &module->ht_symbols, 4096);
135     hash_table_init(&module->pool, &module->ht_types,   4096);
136     vector_init(&module->vtypes, sizeof(struct symt*),  32);
137
138     module->sources_used      = 0;
139     module->sources_alloc     = 0;
140     module->sources           = 0;
141
142     return module;
143 }
144
145 /***********************************************************************
146  *      module_find_by_name
147  *
148  */
149 struct module* module_find_by_name(const struct process* pcs, 
150                                    const char* name, enum module_type type)
151 {
152     struct module*      module;
153
154     if (type == DMT_UNKNOWN)
155     {
156         if ((module = module_find_by_name(pcs, name, DMT_PE)) ||
157             (module = module_find_by_name(pcs, name, DMT_ELF)) ||
158             (module = module_find_by_name(pcs, name, DMT_VIRTUAL)))
159             return module;
160     }
161     else
162     {
163         char                modname[MAX_PATH];
164
165         for (module = pcs->lmodules; module; module = module->next)
166         {
167             if (type == module->type &&
168                 !strcasecmp(name, module->module.LoadedImageName)) 
169                 return module;
170         }
171         module_fill_module(name, modname, sizeof(modname));
172         for (module = pcs->lmodules; module; module = module->next)
173         {
174             if (type == module->type &&
175                 !strcasecmp(modname, module->module.ModuleName)) 
176                 return module;
177         }
178     }
179     SetLastError(ERROR_INVALID_NAME);
180     return NULL;
181 }
182
183 /***********************************************************************
184  *           module_get_container
185  *
186  */
187 struct module* module_get_container(const struct process* pcs, 
188                                     const struct module* inner)
189 {
190     struct module*      module;
191      
192     for (module = pcs->lmodules; module; module = module->next)
193     {
194         if (module != inner &&
195             module->module.BaseOfImage <= inner->module.BaseOfImage &&
196             module->module.BaseOfImage + module->module.ImageSize >=
197             inner->module.BaseOfImage + inner->module.ImageSize)
198             return module;
199     }
200     return NULL;
201 }
202
203 /***********************************************************************
204  *           module_get_containee
205  *
206  */
207 struct module* module_get_containee(const struct process* pcs, 
208                                     const struct module* outter)
209 {
210     struct module*      module;
211      
212     for (module = pcs->lmodules; module; module = module->next)
213     {
214         if (module != outter &&
215             outter->module.BaseOfImage <= module->module.BaseOfImage &&
216             outter->module.BaseOfImage + outter->module.ImageSize >=
217             module->module.BaseOfImage + module->module.ImageSize)
218             return module;
219     }
220     return NULL;
221 }
222
223 /******************************************************************
224  *              module_get_debug
225  *
226  * get the debug information from a module:
227  * - if the module's type is deferred, then force loading of debug info (and return
228  *   the module itself)
229  * - if the module has no debug info and has an ELF container, then return the ELF
230  *   container (and also force the ELF container's debug info loading if deferred)
231  * - otherwise return the module itself if it has some debug info
232  */
233 struct module* module_get_debug(const struct process* pcs, struct module* module)
234 {
235     struct module*                      parent;
236     IMAGEHLP_DEFERRED_SYMBOL_LOAD64     idsl64;
237
238     if (!module) return NULL;
239     /* for a PE builtin, always get info from parent */
240     if ((parent = module_get_container(pcs, module)))
241         module = parent;
242     /* if deferred, force loading */
243     if (module->module.SymType == SymDeferred)
244     {
245         BOOL ret;
246
247         switch (module->type)
248         {
249         case DMT_ELF:
250             ret = elf_load_debug_info(module, NULL);
251             break;
252         case DMT_PE:
253             idsl64.SizeOfStruct = sizeof(idsl64);
254             idsl64.BaseOfImage = module->module.BaseOfImage;
255             idsl64.CheckSum = module->module.CheckSum;
256             idsl64.TimeDateStamp = module->module.TimeDateStamp;
257             strcpy(idsl64.FileName, module->module.ImageName);
258             idsl64.Reparse = FALSE;
259             idsl64.hFile = INVALID_HANDLE_VALUE;
260
261             pcs_callback(pcs, CBA_DEFERRED_SYMBOL_LOAD_START, &idsl64);
262             ret = pe_load_debug_info(pcs, module);
263             pcs_callback(pcs,
264                          ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
265                          &idsl64);
266             break;
267         case DMT_VIRTUAL: /* fall through */
268         default:
269             ret = FALSE;
270             break;
271         }
272         if (!ret) module->module.SymType = SymNone;
273         assert(module->module.SymType != SymDeferred);
274         module_compute_num_syms(module);
275     }
276     return (module && module->module.SymType != SymNone) ? module : NULL;
277 }
278
279 /***********************************************************************
280  *      module_find_by_addr
281  *
282  * either the addr where module is loaded, or any address inside the 
283  * module
284  */
285 struct module* module_find_by_addr(const struct process* pcs, unsigned long addr, 
286                                    enum module_type type)
287 {
288     struct module*      module;
289     
290     if (type == DMT_UNKNOWN)
291     {
292         if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
293             (module = module_find_by_addr(pcs, addr, DMT_ELF)) ||
294             (module = module_find_by_addr(pcs, addr, DMT_VIRTUAL)))
295             return module;
296     }
297     else
298     {
299         for (module = pcs->lmodules; module; module = module->next)
300         {
301             if (type == module->type && addr >= module->module.BaseOfImage &&
302                 addr < module->module.BaseOfImage + module->module.ImageSize) 
303                 return module;
304         }
305     }
306     SetLastError(ERROR_INVALID_ADDRESS);
307     return module;
308 }
309
310 static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName,
311                                            const char* ModuleName)
312 {
313     char                buffer[MAX_PATH];
314     size_t              len;
315     struct module*      module;
316
317     if (!ModuleName)
318     {
319         module_fill_module(ImageName, buffer, sizeof(buffer));
320         ModuleName = buffer;
321     }
322     len = strlen(ModuleName);
323     for (module = pcs->lmodules; module; module = module->next)
324     {
325         if (!strncasecmp(module->module.ModuleName, ModuleName, len) &&
326             module->type == DMT_ELF &&
327             !strcmp(module->module.ModuleName + len, "<elf>"))
328             return TRUE;
329     }
330     return FALSE;
331 }
332
333 /******************************************************************
334  *              module_get_type_by_name
335  *
336  * Guesses a filename type from its extension
337  */
338 enum module_type module_get_type_by_name(const char* name)
339 {
340     const char* ptr;
341     int         len = strlen(name);
342
343     /* check for terminating .so or .so.[digit] */
344     ptr = strrchr(name, '.');
345     if (ptr)
346     {
347         if (!strcmp(ptr, ".so") ||
348             (isdigit(ptr[1]) && !ptr[2] && ptr >= name + 3 && !memcmp(ptr - 3, ".so", 3)))
349             return DMT_ELF;
350         else if (!strcasecmp(ptr, ".pdb"))
351             return DMT_PDB;
352     }
353     /* wine-[kp]thread is also an ELF module */
354     else if (((len > 12 && name[len - 13] == '/') || len == 12) && 
355              (!strcasecmp(name + len - 12, "wine-pthread") || 
356               !strcasecmp(name + len - 12, "wine-kthread")))
357     {
358         return DMT_ELF;
359     }
360     return DMT_PE;
361 }
362
363 int module_compute_num_syms(struct module* module)
364 {
365     struct hash_table_iter      hti;
366     void*                       ptr;
367
368     module->module.NumSyms = 0;
369     hash_table_iter_init(&module->ht_symbols, &hti, NULL);
370     while ((ptr = hash_table_iter_up(&hti)))
371          module->module.NumSyms++;
372     return module->module.NumSyms;
373 }
374
375 /***********************************************************************
376  *                      SymLoadModule (DBGHELP.@)
377  */
378 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, const char* ImageName,
379                            const char* ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
380 {
381     struct process*     pcs;
382     struct module*      module = NULL;
383
384     TRACE("(%p %p %s %s %08lx %08lx)\n", 
385           hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName), 
386           BaseOfDll, SizeOfDll);
387
388     pcs = process_find_by_handle(hProcess);
389     if (!pcs) return FALSE;
390
391     /* force transparent ELF loading / unloading */
392     elf_synchronize_module_list(pcs);
393
394     /* this is a Wine extension to the API just to redo the synchronisation */
395     if (!ImageName && !hFile) return 0;
396
397     if (module_is_elf_container_loaded(pcs, ImageName, ModuleName))
398     {
399         /* force the loading of DLL as builtin */
400         if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName,
401                                               BaseOfDll, SizeOfDll)))
402             goto done;
403         WARN("Couldn't locate %s\n", ImageName);
404         return 0;
405     }
406     TRACE("Assuming %s as native DLL\n", ImageName);
407     if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
408     {
409         if (module_get_type_by_name(ImageName) == DMT_ELF &&
410             (module = elf_load_module(pcs, ImageName, BaseOfDll)))
411             goto done;
412         FIXME("Should have successfully loaded debug information for image %s\n",
413               ImageName);
414         if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName,
415                                               BaseOfDll, SizeOfDll)))
416             goto done;
417         WARN("Couldn't locate %s\n", ImageName);
418         return 0;
419     }
420     module_compute_num_syms(module);
421 done:
422     /* by default pe_load_module fills module.ModuleName from a derivation 
423      * of ImageName. Overwrite it, if we have better information
424      */
425     if (ModuleName)
426         lstrcpynA(module->module.ModuleName, ModuleName, sizeof(module->module.ModuleName));
427     lstrcpynA(module->module.ImageName, ImageName, sizeof(module->module.ImageName));
428
429     return module->module.BaseOfImage;
430 }
431
432 /***********************************************************************
433  *                      SymLoadModuleEx (DBGHELP.@)
434  */
435 DWORD64 WINAPI  SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
436                                 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
437                                 PMODLOAD_DATA Data, DWORD Flags)
438 {
439     if (Data)
440         FIXME("Unsupported load data parameter %p for %s\n", Data, ImageName);
441     if (!validate_addr64(BaseOfDll)) return FALSE;
442     if (Flags & SLMFLAG_VIRTUAL)
443     {
444         struct process* pcs = process_find_by_handle(hProcess);
445         struct module* module;
446         if (!pcs) return FALSE;
447
448         module = module_new(pcs, ImageName, DMT_VIRTUAL, (DWORD)BaseOfDll, DllSize, 0, 0);
449         if (!module) return FALSE;
450         if (ModuleName)
451             lstrcpynA(module->module.ModuleName, ModuleName, sizeof(module->module.ModuleName));
452         module->module.SymType = SymVirtual;
453
454         return TRUE;
455     }
456     if (Flags & ~(SLMFLAG_VIRTUAL))
457         FIXME("Unsupported Flags %08lx for %s\n", Flags, ImageName);
458
459     return SymLoadModule(hProcess, hFile, (char*)ImageName, (char*)ModuleName,
460                          (DWORD)BaseOfDll, DllSize);
461 }
462
463 /***********************************************************************
464  *                     SymLoadModule64 (DBGHELP.@)
465  */
466 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
467                                PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
468 {
469     if (!validate_addr64(BaseOfDll)) return FALSE;
470     return SymLoadModule(hProcess, hFile, ImageName, ModuleName, (DWORD)BaseOfDll, SizeOfDll);
471 }
472
473 /******************************************************************
474  *              module_remove
475  *
476  */
477 BOOL module_remove(struct process* pcs, struct module* module)
478 {
479     struct module**     p;
480
481     TRACE("%s (%p)\n", module->module.ModuleName, module);
482     hash_table_destroy(&module->ht_symbols);
483     hash_table_destroy(&module->ht_types);
484     HeapFree(GetProcessHeap(), 0, (char*)module->sources);
485     HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
486     pool_destroy(&module->pool);
487     if (module->module.SymType != SymNone)
488         pcs_callback(pcs, CBA_SYMBOLS_UNLOADED, NULL);
489
490     for (p = &pcs->lmodules; *p; p = &(*p)->next)
491     {
492         if (*p == module)
493         {
494             *p = module->next;
495             HeapFree(GetProcessHeap(), 0, module);
496             return TRUE;
497         }
498     }
499     FIXME("This shouldn't happen\n");
500     return FALSE;
501 }
502
503 /******************************************************************
504  *              SymUnloadModule (DBGHELP.@)
505  *
506  */
507 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
508 {
509     struct process*     pcs;
510     struct module*      module;
511
512     pcs = process_find_by_handle(hProcess);
513     if (!pcs) return FALSE;
514     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
515     if (!module) return FALSE;
516     return module_remove(pcs, module);
517 }
518
519 /******************************************************************
520  *              SymUnloadModule64 (DBGHELP.@)
521  *
522  */
523 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
524 {
525     struct process*     pcs;
526     struct module*      module;
527
528     pcs = process_find_by_handle(hProcess);
529     if (!pcs) return FALSE;
530     if (!validate_addr64(BaseOfDll)) return FALSE;
531     module = module_find_by_addr(pcs, (DWORD)BaseOfDll, DMT_UNKNOWN);
532     if (!module) return FALSE;
533     return module_remove(pcs, module);
534 }
535
536 /******************************************************************
537  *              SymEnumerateModules (DBGHELP.@)
538  *
539  */
540 BOOL  WINAPI SymEnumerateModules(HANDLE hProcess,
541                                  PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,  
542                                  PVOID UserContext)
543 {
544     struct process*     pcs = process_find_by_handle(hProcess);
545     struct module*      module;
546
547     if (!pcs) return FALSE;
548     
549     for (module = pcs->lmodules; module; module = module->next)
550     {
551         if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF)
552             continue;
553         if (!EnumModulesCallback(module->module.ModuleName, 
554                                  module->module.BaseOfImage, UserContext))
555             break;
556     }
557     return TRUE;
558 }
559
560 /******************************************************************
561  *              EnumerateLoadedModules (DBGHELP.@)
562  *
563  */
564 BOOL  WINAPI EnumerateLoadedModules(HANDLE hProcess,
565                                     PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
566                                     PVOID UserContext)
567 {
568     HMODULE*    hMods;
569     char        base[256], mod[256];
570     DWORD       i, sz;
571     MODULEINFO  mi;
572
573     hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
574     if (!hMods) return FALSE;
575
576     if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
577     {
578         /* hProcess should also be a valid process handle !! */
579         FIXME("If this happens, bump the number in mod\n");
580         HeapFree(GetProcessHeap(), 0, hMods);
581         return FALSE;
582     }
583     sz /= sizeof(HMODULE);
584     for (i = 0; i < sz; i++)
585     {
586         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
587             !GetModuleBaseNameA(hProcess, hMods[i], base, sizeof(base)))
588             continue;
589         module_fill_module(base, mod, sizeof(mod));
590         EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage, 
591                                   UserContext);
592     }
593     HeapFree(GetProcessHeap(), 0, hMods);
594
595     return sz != 0 && i == sz;
596 }
597
598 /******************************************************************
599  *              SymGetModuleInfo (DBGHELP.@)
600  *
601  */
602 BOOL  WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr, 
603                               PIMAGEHLP_MODULE ModuleInfo)
604 {
605     struct process*     pcs = process_find_by_handle(hProcess);
606     struct module*      module;
607
608     if (!pcs) return FALSE;
609     if (ModuleInfo->SizeOfStruct < sizeof(*ModuleInfo)) return FALSE;
610     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
611     if (!module) return FALSE;
612
613     *ModuleInfo = module->module;
614     if (module->module.SymType == SymNone)
615     {
616         module = module_get_container(pcs, module);
617         if (module && module->module.SymType != SymNone)
618         {
619             ModuleInfo->SymType = module->module.SymType;
620             ModuleInfo->NumSyms = module->module.NumSyms;
621         }
622     }
623
624     return TRUE;
625 }
626
627 /******************************************************************
628  *              SymGetModuleInfo64 (DBGHELP.@)
629  *
630  */
631 BOOL  WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr, 
632                                 PIMAGEHLP_MODULE64 ModuleInfo)
633 {
634     struct process*     pcs = process_find_by_handle(hProcess);
635     struct module*      module;
636     IMAGEHLP_MODULE64   mod;
637     char*               ptr;
638
639     TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
640
641     if (!pcs) return FALSE;
642     if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
643     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
644     if (!module) return FALSE;
645
646     mod.SizeOfStruct = ModuleInfo->SizeOfStruct;
647     mod.BaseOfImage = module->module.BaseOfImage;
648     mod.ImageSize = module->module.ImageSize;
649     mod.TimeDateStamp = module->module.TimeDateStamp;
650     mod.CheckSum = module->module.CheckSum;
651     mod.NumSyms = module->module.NumSyms;
652     mod.SymType = module->module.SymType;
653     strcpy(mod.ModuleName, module->module.ModuleName);
654     strcpy(mod.ImageName, module->module.ImageName);
655     strcpy(mod.LoadedImageName, module->module.LoadedImageName);
656     /* FIXME: for now, using some 'rather sane' value */
657     sprintf(mod.LoadedPdbName, ".\%s.pdb", module->module.ModuleName);
658     mod.CVSig = 0x53445352; /* RSDS */
659     memset(mod.CVData, 0, sizeof(mod.CVData));
660     strcpy(mod.CVData, module->module.LoadedImageName);
661     if ((ptr = strrchr(mod.CVData, '.')))
662         strcpy(ptr + 1, "pdb");
663     mod.PdbSig = 0;
664     memset(&mod.PdbSig70, 0, sizeof(mod.PdbSig70));
665     mod.PdbAge = 0;
666     mod.PdbUnmatched = FALSE;
667     mod.DbgUnmatched = FALSE;
668     mod.LineNumbers = TRUE;
669     mod.GlobalSymbols = TRUE;
670     mod.TypeInfo = TRUE;
671     mod.SourceIndexed = 0;
672     mod.Publics = 0;
673
674     if (module->module.SymType == SymNone)
675     {
676         module = module_get_container(pcs, module);
677         if (module && module->module.SymType != SymNone)
678         {
679             mod.SymType = module->module.SymType;
680             mod.NumSyms = module->module.NumSyms;
681         }
682     }
683     memcpy(ModuleInfo, &mod, mod.SizeOfStruct);
684     return TRUE;
685 }
686
687 /***********************************************************************
688  *              SymGetModuleBase (DBGHELP.@)
689  */
690 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
691 {
692     struct process*     pcs = process_find_by_handle(hProcess);
693     struct module*      module;
694
695     if (!pcs) return 0;
696     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
697     if (!module) return 0;
698     return module->module.BaseOfImage;
699 }
700
701 /***********************************************************************
702  *              SymGetModuleBase64 (DBGHELP.@)
703  */
704 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
705 {
706     if (!validate_addr64(dwAddr)) return 0;
707     return SymGetModuleBase(hProcess, (DWORD)dwAddr);
708 }
709
710 /******************************************************************
711  *              module_reset_debug_info
712  * Removes any debug information linked to a given module.
713  */
714 void module_reset_debug_info(struct module* module)
715 {
716     module->sortlist_valid = TRUE;
717     module->addr_sorttab = NULL;
718     hash_table_destroy(&module->ht_symbols);
719     module->ht_symbols.num_buckets = 0;
720     module->ht_symbols.buckets = NULL;
721     hash_table_destroy(&module->ht_types);
722     module->ht_types.num_buckets = 0;
723     module->ht_types.buckets = NULL;
724     module->vtypes.num_elts = 0;
725     hash_table_destroy(&module->ht_symbols);
726     module->sources_used = module->sources_alloc = 0;
727     module->sources = NULL;
728 }