dbghelp: Implemented SymGetLineFromAddrW64.
[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 #include "winnls.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
36
37 static const char* ext[] = {".acm", ".dll", ".drv", ".exe", ".ocx", ".vxd", NULL};
38
39 static int match_ext(const char* ptr, size_t len)
40 {
41     const char**e;
42     size_t      l;
43
44     for (e = ext; *e; e++)
45     {
46         l = strlen(*e);
47         if (l >= len) return FALSE;
48         if (strncasecmp(&ptr[len - l], *e, l)) continue;
49         return l;
50     }
51     return 0;
52 }
53         
54 static void module_fill_module(const char* in, char* out, size_t size)
55 {
56     const char  *ptr,*endptr;
57     size_t      len, l;
58
59     endptr = in + strlen(in);
60     for (ptr = endptr - 1;
61          ptr >= in && *ptr != '/' && *ptr != '\\';
62          ptr--);
63     ptr++;
64     len = min(endptr-ptr,size-1);
65     memcpy(out, ptr, len);
66     out[len] = '\0';
67     if (len > 4 && (l = match_ext(out, len)))
68         out[len - l] = '\0';
69     else if (len > 12 &&
70              (!strcasecmp(out + len - 12, "wine-pthread") || 
71               !strcasecmp(out + len - 12, "wine-kthread")))
72         lstrcpynA(out, "<wine-loader>", size);
73     else
74     {
75         if (len > 3 && !strcasecmp(&out[len - 3], ".so") &&
76             (l = match_ext(out, len - 3)))
77             strcpy(&out[len - l - 3], "<elf>");
78     }
79     while ((*out = tolower(*out))) out++;
80 }
81
82 static const char*      get_module_type(enum module_type type, BOOL virtual)
83 {
84     switch (type)
85     {
86     case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
87     case DMT_PE: return virtual ? "Virtual PE" : "PE";
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, BOOL virtual,
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);
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, virtual), 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->is_virtual        = virtual ? TRUE : FALSE;
130     module->sortlist_valid    = FALSE;
131     module->addr_sorttab      = NULL;
132     /* FIXME: this seems a bit too high (on a per module basis)
133      * need some statistics about this
134      */
135     hash_table_init(&module->pool, &module->ht_symbols, 4096);
136     hash_table_init(&module->pool, &module->ht_types,   4096);
137     vector_init(&module->vtypes, sizeof(struct symt*),  32);
138
139     module->sources_used      = 0;
140     module->sources_alloc     = 0;
141     module->sources           = 0;
142
143     return module;
144 }
145
146 /***********************************************************************
147  *      module_find_by_name
148  *
149  */
150 struct module* module_find_by_name(const struct process* pcs, 
151                                    const char* name, enum module_type type)
152 {
153     struct module*      module;
154
155     if (type == DMT_UNKNOWN)
156     {
157         if ((module = module_find_by_name(pcs, name, DMT_PE)) ||
158             (module = module_find_by_name(pcs, name, DMT_ELF)))
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 BOOL module_get_debug(const struct process* pcs, struct module_pair* pair)
234 {
235     IMAGEHLP_DEFERRED_SYMBOL_LOAD64     idsl64;
236
237     if (!pair->requested) return FALSE;
238     /* for a PE builtin, always get info from container */
239     if (!(pair->effective = module_get_container(pcs, pair->requested)))
240         pair->effective = pair->requested;
241     /* if deferred, force loading */
242     if (pair->effective->module.SymType == SymDeferred)
243     {
244         BOOL ret;
245         
246         if (pair->effective->is_virtual) ret = FALSE;
247         else switch (pair->effective->type)
248         {
249         case DMT_ELF:
250             ret = elf_load_debug_info(pair->effective, NULL);
251             break;
252         case DMT_PE:
253             idsl64.SizeOfStruct = sizeof(idsl64);
254             idsl64.BaseOfImage = pair->effective->module.BaseOfImage;
255             idsl64.CheckSum = pair->effective->module.CheckSum;
256             idsl64.TimeDateStamp = pair->effective->module.TimeDateStamp;
257             strcpy(idsl64.FileName, pair->effective->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, pair->effective);
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) pair->effective->module.SymType = SymNone;
272         assert(pair->effective->module.SymType != SymDeferred);
273         module_compute_num_syms(pair->effective);
274     }
275     return pair->effective->module.SymType != SymNone;
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  *                      SymLoadModuleExW (DBGHELP.@)
468  */
469 DWORD64 WINAPI  SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageName,
470                                  PCWSTR wModuleName, DWORD64 BaseOfDll, DWORD DllSize,
471                                  PMODLOAD_DATA Data, DWORD Flags)
472 {
473     LPSTR       ImageName, ModuleName;
474     unsigned    len;
475     BOOL        ret;
476
477     if (wImageName)
478     {
479         len = WideCharToMultiByte(CP_ACP,0, wImageName, -1, NULL, 0, NULL, NULL);
480         ImageName = HeapAlloc(GetProcessHeap(), 0, len);
481         WideCharToMultiByte(CP_ACP,0, wImageName, -1, ImageName, len, NULL, NULL);
482     }
483     else ImageName = NULL;
484     if (wModuleName)
485     {
486         len = WideCharToMultiByte(CP_ACP,0, wModuleName, -1, NULL, 0, NULL, NULL);
487         ModuleName = HeapAlloc(GetProcessHeap(), 0, len);
488         WideCharToMultiByte(CP_ACP,0, wModuleName, -1, ModuleName, len, NULL, NULL);
489     }
490     else ModuleName = NULL;
491
492     ret = SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName,
493                           BaseOfDll, DllSize, Data, Flags);
494     HeapFree(GetProcessHeap(), 0, ImageName);
495     HeapFree(GetProcessHeap(), 0, ModuleName);
496     return ret;
497 }
498
499 /***********************************************************************
500  *                     SymLoadModule64 (DBGHELP.@)
501  */
502 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
503                                PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
504 {
505     if (!validate_addr64(BaseOfDll)) return FALSE;
506     return SymLoadModule(hProcess, hFile, ImageName, ModuleName, (DWORD)BaseOfDll, SizeOfDll);
507 }
508
509 /******************************************************************
510  *              module_remove
511  *
512  */
513 BOOL module_remove(struct process* pcs, struct module* module)
514 {
515     struct module**     p;
516
517     TRACE("%s (%p)\n", module->module.ModuleName, module);
518     hash_table_destroy(&module->ht_symbols);
519     hash_table_destroy(&module->ht_types);
520     HeapFree(GetProcessHeap(), 0, (char*)module->sources);
521     HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
522     pool_destroy(&module->pool);
523     if (module->module.SymType != SymNone)
524         pcs_callback(pcs, CBA_SYMBOLS_UNLOADED, NULL);
525
526     for (p = &pcs->lmodules; *p; p = &(*p)->next)
527     {
528         if (*p == module)
529         {
530             *p = module->next;
531             HeapFree(GetProcessHeap(), 0, module);
532             return TRUE;
533         }
534     }
535     FIXME("This shouldn't happen\n");
536     return FALSE;
537 }
538
539 /******************************************************************
540  *              SymUnloadModule (DBGHELP.@)
541  *
542  */
543 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
544 {
545     struct process*     pcs;
546     struct module*      module;
547
548     pcs = process_find_by_handle(hProcess);
549     if (!pcs) return FALSE;
550     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
551     if (!module) return FALSE;
552     return module_remove(pcs, module);
553 }
554
555 /******************************************************************
556  *              SymUnloadModule64 (DBGHELP.@)
557  *
558  */
559 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
560 {
561     struct process*     pcs;
562     struct module*      module;
563
564     pcs = process_find_by_handle(hProcess);
565     if (!pcs) return FALSE;
566     if (!validate_addr64(BaseOfDll)) return FALSE;
567     module = module_find_by_addr(pcs, (DWORD)BaseOfDll, DMT_UNKNOWN);
568     if (!module) return FALSE;
569     return module_remove(pcs, module);
570 }
571
572 /******************************************************************
573  *              SymEnumerateModules (DBGHELP.@)
574  *
575  */
576 BOOL  WINAPI SymEnumerateModules(HANDLE hProcess,
577                                  PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,  
578                                  PVOID UserContext)
579 {
580     struct process*     pcs = process_find_by_handle(hProcess);
581     struct module*      module;
582
583     if (!pcs) return FALSE;
584     
585     for (module = pcs->lmodules; module; module = module->next)
586     {
587         if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF)
588             continue;
589         if (!EnumModulesCallback(module->module.ModuleName, 
590                                  module->module.BaseOfImage, UserContext))
591             break;
592     }
593     return TRUE;
594 }
595
596 /******************************************************************
597  *              EnumerateLoadedModules (DBGHELP.@)
598  *
599  */
600 BOOL  WINAPI EnumerateLoadedModules(HANDLE hProcess,
601                                     PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
602                                     PVOID UserContext)
603 {
604     HMODULE*    hMods;
605     char        base[256], mod[256];
606     DWORD       i, sz;
607     MODULEINFO  mi;
608
609     hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
610     if (!hMods) return FALSE;
611
612     if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
613     {
614         /* hProcess should also be a valid process handle !! */
615         FIXME("If this happens, bump the number in mod\n");
616         HeapFree(GetProcessHeap(), 0, hMods);
617         return FALSE;
618     }
619     sz /= sizeof(HMODULE);
620     for (i = 0; i < sz; i++)
621     {
622         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
623             !GetModuleBaseNameA(hProcess, hMods[i], base, sizeof(base)))
624             continue;
625         module_fill_module(base, mod, sizeof(mod));
626         EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage, 
627                                   UserContext);
628     }
629     HeapFree(GetProcessHeap(), 0, hMods);
630
631     return sz != 0 && i == sz;
632 }
633
634 /******************************************************************
635  *              SymGetModuleInfo (DBGHELP.@)
636  *
637  */
638 BOOL  WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr, 
639                               PIMAGEHLP_MODULE ModuleInfo)
640 {
641     struct process*     pcs = process_find_by_handle(hProcess);
642     struct module*      module;
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     *ModuleInfo = module->module;
650     if (module->module.SymType == SymNone)
651     {
652         module = module_get_container(pcs, module);
653         if (module && module->module.SymType != SymNone)
654         {
655             ModuleInfo->SymType = module->module.SymType;
656             ModuleInfo->NumSyms = module->module.NumSyms;
657         }
658     }
659
660     return TRUE;
661 }
662
663 /******************************************************************
664  *              SymGetModuleInfoW (DBGHELP.@)
665  *
666  */
667 BOOL  WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr, 
668                                PIMAGEHLP_MODULEW ModuleInfo)
669 {
670     IMAGEHLP_MODULE     mi;
671     IMAGEHLP_MODULEW    miw;
672
673     if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
674
675     mi.SizeOfStruct = sizeof(mi);
676     if (!SymGetModuleInfo(hProcess, dwAddr, &mi)) return FALSE;
677
678     miw.SizeOfStruct  = mi.SizeOfStruct;
679     miw.BaseOfImage   = mi.BaseOfImage;
680     miw.ImageSize     = mi.ImageSize;
681     miw.TimeDateStamp = mi.TimeDateStamp;
682     miw.CheckSum      = mi.CheckSum;
683     miw.NumSyms       = mi.NumSyms;
684     miw.SymType       = mi.SymType;
685     MultiByteToWideChar(CP_ACP, 0, mi.ModuleName, -1,   
686                         miw.ModuleName, sizeof(miw.ModuleName) / sizeof(WCHAR));
687     MultiByteToWideChar(CP_ACP, 0, mi.ImageName, -1,   
688                         miw.ImageName, sizeof(miw.ImageName) / sizeof(WCHAR));
689     MultiByteToWideChar(CP_ACP, 0, mi.LoadedImageName, -1,   
690                         miw.LoadedImageName, sizeof(miw.LoadedImageName) / sizeof(WCHAR));
691     memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
692
693     return TRUE;
694 }
695
696 /******************************************************************
697  *              SymGetModuleInfo64 (DBGHELP.@)
698  *
699  */
700 BOOL  WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr, 
701                                 PIMAGEHLP_MODULE64 ModuleInfo)
702 {
703     struct process*     pcs = process_find_by_handle(hProcess);
704     struct module*      module;
705     IMAGEHLP_MODULE64   mod;
706     char*               ptr;
707
708     TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
709
710     if (!pcs) return FALSE;
711     if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
712     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
713     if (!module) return FALSE;
714
715     mod.SizeOfStruct = ModuleInfo->SizeOfStruct;
716     mod.BaseOfImage = module->module.BaseOfImage;
717     mod.ImageSize = module->module.ImageSize;
718     mod.TimeDateStamp = module->module.TimeDateStamp;
719     mod.CheckSum = module->module.CheckSum;
720     mod.NumSyms = module->module.NumSyms;
721     mod.SymType = module->module.SymType;
722     strcpy(mod.ModuleName, module->module.ModuleName);
723     strcpy(mod.ImageName, module->module.ImageName);
724     strcpy(mod.LoadedImageName, module->module.LoadedImageName);
725     /* FIXME: for now, using some 'rather sane' value */
726     sprintf(mod.LoadedPdbName, ".\%s.pdb", module->module.ModuleName);
727     mod.CVSig = 0x53445352; /* RSDS */
728     memset(mod.CVData, 0, sizeof(mod.CVData));
729     strcpy(mod.CVData, module->module.LoadedImageName);
730     if ((ptr = strrchr(mod.CVData, '.')))
731         strcpy(ptr + 1, "pdb");
732     mod.PdbSig = 0;
733     memset(&mod.PdbSig70, 0, sizeof(mod.PdbSig70));
734     mod.PdbAge = 0;
735     mod.PdbUnmatched = FALSE;
736     mod.DbgUnmatched = FALSE;
737     mod.LineNumbers = TRUE;
738     mod.GlobalSymbols = TRUE;
739     mod.TypeInfo = TRUE;
740     mod.SourceIndexed = 0;
741     mod.Publics = 0;
742
743     if (module->module.SymType == SymNone)
744     {
745         module = module_get_container(pcs, module);
746         if (module && module->module.SymType != SymNone)
747         {
748             mod.SymType = module->module.SymType;
749             mod.NumSyms = module->module.NumSyms;
750         }
751     }
752     memcpy(ModuleInfo, &mod, mod.SizeOfStruct);
753     return TRUE;
754 }
755
756 /******************************************************************
757  *              SymGetModuleInfoW64 (DBGHELP.@)
758  *
759  */
760 BOOL  WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr, 
761                                  PIMAGEHLP_MODULEW64 ModuleInfo)
762 {
763     IMAGEHLP_MODULE64   mi;
764     IMAGEHLP_MODULEW64  miw;
765
766     if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
767
768     mi.SizeOfStruct = sizeof(mi);
769     if (!SymGetModuleInfo64(hProcess, dwAddr, &mi)) return FALSE;
770
771     miw.SizeOfStruct  = mi.SizeOfStruct;
772     miw.BaseOfImage   = mi.BaseOfImage;
773     miw.ImageSize     = mi.ImageSize;
774     miw.TimeDateStamp = mi.TimeDateStamp;
775     miw.CheckSum      = mi.CheckSum;
776     miw.NumSyms       = mi.NumSyms;
777     miw.SymType       = mi.SymType;
778     MultiByteToWideChar(CP_ACP, 0, mi.ModuleName, -1,   
779                         miw.ModuleName, sizeof(miw.ModuleName) / sizeof(WCHAR));
780     MultiByteToWideChar(CP_ACP, 0, mi.ImageName, -1,   
781                         miw.ImageName, sizeof(miw.ImageName) / sizeof(WCHAR));
782     MultiByteToWideChar(CP_ACP, 0, mi.LoadedImageName, -1,   
783                         miw.LoadedImageName, sizeof(miw.LoadedImageName) / sizeof(WCHAR));
784
785     miw.CVSig         = mi.CVSig;
786     MultiByteToWideChar(CP_ACP, 0, mi.CVData, -1,   
787                         miw.CVData, sizeof(miw.CVData) / sizeof(WCHAR));
788     miw.PdbSig        = mi.PdbSig;
789     miw.PdbSig70      = mi.PdbSig70;
790     miw.PdbAge        = mi.PdbAge;
791     miw.PdbUnmatched  = mi.PdbUnmatched;
792     miw.DbgUnmatched  = mi.DbgUnmatched;
793     miw.LineNumbers   = mi.LineNumbers;
794     miw.GlobalSymbols = mi.GlobalSymbols;
795     miw.TypeInfo      = mi.TypeInfo;
796     miw.SourceIndexed = mi.SourceIndexed;
797     miw.Publics       = mi.Publics;
798
799     memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
800
801     return TRUE;
802 }
803
804 /***********************************************************************
805  *              SymGetModuleBase (DBGHELP.@)
806  */
807 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
808 {
809     struct process*     pcs = process_find_by_handle(hProcess);
810     struct module*      module;
811
812     if (!pcs) return 0;
813     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
814     if (!module) return 0;
815     return module->module.BaseOfImage;
816 }
817
818 /***********************************************************************
819  *              SymGetModuleBase64 (DBGHELP.@)
820  */
821 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
822 {
823     if (!validate_addr64(dwAddr)) return 0;
824     return SymGetModuleBase(hProcess, (DWORD)dwAddr);
825 }
826
827 /******************************************************************
828  *              module_reset_debug_info
829  * Removes any debug information linked to a given module.
830  */
831 void module_reset_debug_info(struct module* module)
832 {
833     module->sortlist_valid = TRUE;
834     module->addr_sorttab = NULL;
835     hash_table_destroy(&module->ht_symbols);
836     module->ht_symbols.num_buckets = 0;
837     module->ht_symbols.buckets = NULL;
838     hash_table_destroy(&module->ht_types);
839     module->ht_types.num_buckets = 0;
840     module->ht_types.buckets = NULL;
841     module->vtypes.num_elts = 0;
842     hash_table_destroy(&module->ht_symbols);
843     module->sources_used = module->sources_alloc = 0;
844     module->sources = NULL;
845 }