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