ntdll: Check buffer for access in NtRead/WriteVirtualMemory.
[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-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 "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 "winternl.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
34
35 const WCHAR        S_ElfW[]         = {'<','e','l','f','>','\0'};
36 const WCHAR        S_WineLoaderW[]  = {'<','w','i','n','e','-','l','o','a','d','e','r','>','\0'};
37 static const WCHAR S_DotSoW[]       = {'.','s','o','\0'};
38 static const WCHAR S_DotPdbW[]      = {'.','p','d','b','\0'};
39 static const WCHAR S_DotDbgW[]      = {'.','d','b','g','\0'};
40 const WCHAR        S_WinePThreadW[] = {'w','i','n','e','-','p','t','h','r','e','a','d','\0'};
41 const WCHAR        S_WineKThreadW[] = {'w','i','n','e','-','k','t','h','r','e','a','d','\0'};
42 const WCHAR        S_SlashW[]       = {'/','\0'};
43
44 static const WCHAR S_AcmW[] = {'.','a','c','m','\0'};
45 static const WCHAR S_DllW[] = {'.','d','l','l','\0'};
46 static const WCHAR S_DrvW[] = {'.','d','r','v','\0'};
47 static const WCHAR S_ExeW[] = {'.','e','x','e','\0'};
48 static const WCHAR S_OcxW[] = {'.','o','c','x','\0'};
49 static const WCHAR S_VxdW[] = {'.','v','x','d','\0'};
50 static const WCHAR * const ext[] = {S_AcmW, S_DllW, S_DrvW, S_ExeW, S_OcxW, S_VxdW, NULL};
51
52 static int match_ext(const WCHAR* ptr, size_t len)
53 {
54     const WCHAR* const *e;
55     size_t      l;
56
57     for (e = ext; *e; e++)
58     {
59         l = strlenW(*e);
60         if (l >= len) return FALSE;
61         if (strncmpiW(&ptr[len - l], *e, l)) continue;
62         return l;
63     }
64     return 0;
65 }
66
67 static const WCHAR* get_filename(const WCHAR* name, const WCHAR* endptr)
68 {
69     const WCHAR*        ptr;
70
71     if (!endptr) endptr = name + strlenW(name);
72     for (ptr = endptr - 1; ptr >= name; ptr--)
73     {
74         if (*ptr == '/' || *ptr == '\\') break;
75     }
76     return ++ptr;
77 }
78
79 static void module_fill_module(const WCHAR* in, WCHAR* out, size_t size)
80 {
81     const WCHAR *ptr, *endptr;
82     size_t      len, l;
83
84     ptr = get_filename(in, endptr = in + strlenW(in));
85     len = min(endptr - ptr, size - 1);
86     memcpy(out, ptr, len * sizeof(WCHAR));
87     out[len] = '\0';
88     if (len > 4 && (l = match_ext(out, len)))
89         out[len - l] = '\0';
90     else if (len > 12 &&
91              (!strcmpiW(out + len - 12, S_WinePThreadW) ||
92               !strcmpiW(out + len - 12, S_WineKThreadW)))
93         lstrcpynW(out, S_WineLoaderW, size);
94     else
95     {
96         if (len > 3 && !strcmpiW(&out[len - 3], S_DotSoW) &&
97             (l = match_ext(out, len - 3)))
98             strcpyW(&out[len - l - 3], S_ElfW);
99     }
100     while ((*out = tolowerW(*out))) out++;
101 }
102
103 void module_set_module(struct module* module, const WCHAR* name)
104 {
105     module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName));
106     WideCharToMultiByte(CP_ACP, 0, module->module.ModuleName, -1,
107                         module->module_name, sizeof(module->module_name),
108                         NULL, NULL);
109 }
110
111 static const char*      get_module_type(enum module_type type, BOOL virtual)
112 {
113     switch (type)
114     {
115     case DMT_ELF: return virtual ? "Virtual ELF" : "ELF";
116     case DMT_PE: return virtual ? "Virtual PE" : "PE";
117     default: return "---";
118     }
119 }
120
121 /***********************************************************************
122  * Creates and links a new module to a process
123  */
124 struct module* module_new(struct process* pcs, const WCHAR* name,
125                           enum module_type type, BOOL virtual,
126                           unsigned long mod_addr, unsigned long size,
127                           unsigned long stamp, unsigned long checksum)
128 {
129     struct module*      module;
130
131     assert(type == DMT_ELF || type == DMT_PE);
132     if (!(module = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*module))))
133         return NULL;
134
135     module->next = pcs->lmodules;
136     pcs->lmodules = module;
137
138     TRACE("=> %s %08lx-%08lx %s\n",
139           get_module_type(type, virtual), mod_addr, mod_addr + size,
140           debugstr_w(name));
141
142     pool_init(&module->pool, 65536);
143
144     module->module.SizeOfStruct = sizeof(module->module);
145     module->module.BaseOfImage = mod_addr;
146     module->module.ImageSize = size;
147     module_set_module(module, name);
148     module->module.ImageName[0] = '\0';
149     lstrcpynW(module->module.LoadedImageName, name, sizeof(module->module.LoadedImageName) / sizeof(WCHAR));
150     module->module.SymType = SymNone;
151     module->module.NumSyms = 0;
152     module->module.TimeDateStamp = stamp;
153     module->module.CheckSum = checksum;
154
155     memset(module->module.LoadedPdbName, 0, sizeof(module->module.CVData));
156     module->module.CVSig = 0;
157     memset(module->module.CVData, 0, sizeof(module->module.CVData));
158     module->module.PdbSig = 0;
159     memset(&module->module.PdbSig70, 0, sizeof(module->module.PdbSig70));
160     module->module.PdbAge = 0;
161     module->module.PdbUnmatched = FALSE;
162     module->module.DbgUnmatched = FALSE;
163     module->module.LineNumbers = FALSE;
164     module->module.GlobalSymbols = FALSE;
165     module->module.TypeInfo = FALSE;
166     module->module.SourceIndexed = FALSE;
167     module->module.Publics = FALSE;
168
169     module->type              = type;
170     module->is_virtual        = virtual ? TRUE : FALSE;
171     module->sortlist_valid    = FALSE;
172     module->addr_sorttab      = NULL;
173     /* FIXME: this seems a bit too high (on a per module basis)
174      * need some statistics about this
175      */
176     hash_table_init(&module->pool, &module->ht_symbols, 4096);
177     hash_table_init(&module->pool, &module->ht_types,   4096);
178     vector_init(&module->vtypes, sizeof(struct symt*),  32);
179
180     module->sources_used      = 0;
181     module->sources_alloc     = 0;
182     module->sources           = 0;
183
184     return module;
185 }
186
187 /***********************************************************************
188  *      module_find_by_name
189  *
190  */
191 static struct module* module_find_by_name(const struct process* pcs, const WCHAR* name)
192 {
193     struct module*      module;
194
195     for (module = pcs->lmodules; module; module = module->next)
196     {
197         if (!strcmpiW(name, module->module.ModuleName)) return module;
198     }
199     SetLastError(ERROR_INVALID_NAME);
200     return NULL;
201 }
202
203 struct module* module_find_by_nameA(const struct process* pcs, const char* name)
204 {
205     WCHAR wname[MAX_PATH];
206
207     MultiByteToWideChar(CP_ACP, 0, name, -1, wname, sizeof(wname) / sizeof(WCHAR));
208     return module_find_by_name(pcs, wname);
209 }
210
211 /***********************************************************************
212  *      module_is_already_loaded
213  *
214  */
215 struct module* module_is_already_loaded(const struct process* pcs, const WCHAR* name)
216 {
217     struct module*      module;
218     const WCHAR*        filename;
219
220     /* first compare the loaded image name... */
221     for (module = pcs->lmodules; module; module = module->next)
222     {
223         if (!strcmpiW(name, module->module.LoadedImageName))
224             return module;
225     }
226     /* then compare the standard filenames (without the path) ... */
227     filename = get_filename(name, NULL);
228     for (module = pcs->lmodules; module; module = module->next)
229     {
230         if (!strcmpiW(filename, get_filename(module->module.LoadedImageName, NULL)))
231             return module;
232     }
233     SetLastError(ERROR_INVALID_NAME);
234     return NULL;
235 }
236
237 /***********************************************************************
238  *           module_get_container
239  *
240  */
241 static struct module* module_get_container(const struct process* pcs,
242                                     const struct module* inner)
243 {
244     struct module*      module;
245      
246     for (module = pcs->lmodules; module; module = module->next)
247     {
248         if (module != inner &&
249             module->module.BaseOfImage <= inner->module.BaseOfImage &&
250             module->module.BaseOfImage + module->module.ImageSize >=
251             inner->module.BaseOfImage + inner->module.ImageSize)
252             return module;
253     }
254     return NULL;
255 }
256
257 /***********************************************************************
258  *           module_get_containee
259  *
260  */
261 struct module* module_get_containee(const struct process* pcs, 
262                                     const struct module* outter)
263 {
264     struct module*      module;
265      
266     for (module = pcs->lmodules; module; module = module->next)
267     {
268         if (module != outter &&
269             outter->module.BaseOfImage <= module->module.BaseOfImage &&
270             outter->module.BaseOfImage + outter->module.ImageSize >=
271             module->module.BaseOfImage + module->module.ImageSize)
272             return module;
273     }
274     return NULL;
275 }
276
277 /******************************************************************
278  *              module_get_debug
279  *
280  * get the debug information from a module:
281  * - if the module's type is deferred, then force loading of debug info (and return
282  *   the module itself)
283  * - if the module has no debug info and has an ELF container, then return the ELF
284  *   container (and also force the ELF container's debug info loading if deferred)
285  * - otherwise return the module itself if it has some debug info
286  */
287 BOOL module_get_debug(struct module_pair* pair)
288 {
289     IMAGEHLP_DEFERRED_SYMBOL_LOADW64    idslW64;
290
291     if (!pair->requested) return FALSE;
292     /* for a PE builtin, always get info from container */
293     if (!(pair->effective = module_get_container(pair->pcs, pair->requested)))
294         pair->effective = pair->requested;
295     /* if deferred, force loading */
296     if (pair->effective->module.SymType == SymDeferred)
297     {
298         BOOL ret;
299         
300         if (pair->effective->is_virtual) ret = FALSE;
301         else switch (pair->effective->type)
302         {
303         case DMT_ELF:
304             ret = elf_load_debug_info(pair->effective, NULL);
305             break;
306         case DMT_PE:
307             idslW64.SizeOfStruct = sizeof(idslW64);
308             idslW64.BaseOfImage = pair->effective->module.BaseOfImage;
309             idslW64.CheckSum = pair->effective->module.CheckSum;
310             idslW64.TimeDateStamp = pair->effective->module.TimeDateStamp;
311             memcpy(idslW64.FileName, pair->effective->module.ImageName,
312                    sizeof(pair->effective->module.ImageName));
313             idslW64.Reparse = FALSE;
314             idslW64.hFile = INVALID_HANDLE_VALUE;
315
316             pcs_callback(pair->pcs, CBA_DEFERRED_SYMBOL_LOAD_START, &idslW64);
317             ret = pe_load_debug_info(pair->pcs, pair->effective);
318             pcs_callback(pair->pcs,
319                          ret ? CBA_DEFERRED_SYMBOL_LOAD_COMPLETE : CBA_DEFERRED_SYMBOL_LOAD_FAILURE,
320                          &idslW64);
321             break;
322         default:
323             ret = FALSE;
324             break;
325         }
326         if (!ret) pair->effective->module.SymType = SymNone;
327         assert(pair->effective->module.SymType != SymDeferred);
328         pair->effective->module.NumSyms = pair->effective->ht_symbols.num_elts;
329     }
330     return pair->effective->module.SymType != SymNone;
331 }
332
333 /***********************************************************************
334  *      module_find_by_addr
335  *
336  * either the addr where module is loaded, or any address inside the 
337  * module
338  */
339 struct module* module_find_by_addr(const struct process* pcs, unsigned long addr, 
340                                    enum module_type type)
341 {
342     struct module*      module;
343     
344     if (type == DMT_UNKNOWN)
345     {
346         if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
347             (module = module_find_by_addr(pcs, addr, DMT_ELF)))
348             return module;
349     }
350     else
351     {
352         for (module = pcs->lmodules; module; module = module->next)
353         {
354             if (type == module->type && addr >= module->module.BaseOfImage &&
355                 addr < module->module.BaseOfImage + module->module.ImageSize) 
356                 return module;
357         }
358     }
359     SetLastError(ERROR_INVALID_ADDRESS);
360     return module;
361 }
362
363 /******************************************************************
364  *              module_is_elf_container_loaded
365  *
366  * checks whether the ELF container, for a (supposed) PE builtin is
367  * already loaded
368  */
369 static BOOL module_is_elf_container_loaded(const struct process* pcs,
370                                            const WCHAR* ImageName, DWORD base)
371 {
372     size_t              len;
373     struct module*      module;
374     PCWSTR              filename, modname;
375
376     if (!base) return FALSE;
377     filename = get_filename(ImageName, NULL);
378     len = strlenW(filename);
379
380     for (module = pcs->lmodules; module; module = module->next)
381     {
382         if (module->type == DMT_ELF &&
383             base >= module->module.BaseOfImage &&
384             base < module->module.BaseOfImage + module->module.ImageSize)
385         {
386             modname = get_filename(module->module.LoadedImageName, NULL);
387             if (!strncmpiW(modname, filename, len) &&
388                 !memcmp(modname + len, S_DotSoW, 3 * sizeof(WCHAR)))
389             {
390                 return TRUE;
391             }
392         }
393     }
394     /* likely a native PE module */
395     WARN("Couldn't find container for %s\n", debugstr_w(ImageName));
396     return FALSE;
397 }
398
399 /******************************************************************
400  *              module_get_type_by_name
401  *
402  * Guesses a filename type from its extension
403  */
404 enum module_type module_get_type_by_name(const WCHAR* name)
405 {
406     int len = strlenW(name);
407
408     /* Skip all version extensions (.[digits]) regex: "(\.\d+)*$" */
409     do
410     {
411         int i = len;
412
413         while (i && isdigit(name[i - 1])) i--;
414
415         if (i && name[i - 1] == '.')
416             len = i - 1;
417         else
418             break;
419     } while (len);
420
421     /* check for terminating .so or .so.[digit] */
422     if (len > 3 && !memcmp(name + len - 3, S_DotSoW, 3))
423         return DMT_ELF;
424
425     if (len > 4 && !strncmpiW(name + len - 4, S_DotPdbW, 4))
426         return DMT_PDB;
427
428     if (len > 4 && !strncmpiW(name + len - 4, S_DotDbgW, 4))
429         return DMT_DBG;
430
431     /* wine-[kp]thread is also an ELF module */
432     if (((len > 12 && name[len - 13] == '/') || len == 12) &&
433         (!strncmpiW(name + len - 12, S_WinePThreadW, 12) ||
434          !strncmpiW(name + len - 12, S_WineKThreadW, 12)))
435     {
436         return DMT_ELF;
437     }
438     return DMT_PE;
439 }
440
441 /***********************************************************************
442  *                      SymLoadModule (DBGHELP.@)
443  */
444 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
445                            PCSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
446 {
447     return SymLoadModuleEx(hProcess, hFile, ImageName, ModuleName, BaseOfDll,
448                            SizeOfDll, NULL, 0);
449 }
450
451 /***********************************************************************
452  *                      SymLoadModuleEx (DBGHELP.@)
453  */
454 DWORD64 WINAPI  SymLoadModuleEx(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
455                                 PCSTR ModuleName, DWORD64 BaseOfDll, DWORD DllSize,
456                                 PMODLOAD_DATA Data, DWORD Flags)
457 {
458     PWSTR       wImageName, wModuleName;
459     unsigned    len;
460     DWORD64     ret;
461
462     TRACE("(%p %p %s %s %s %08x %p %08x)\n",
463           hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName),
464           wine_dbgstr_longlong(BaseOfDll), DllSize, Data, Flags);
465
466     if (ImageName)
467     {
468         len = MultiByteToWideChar(CP_ACP, 0, ImageName, -1, NULL, 0);
469         wImageName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
470         MultiByteToWideChar(CP_ACP, 0, ImageName, -1, wImageName, len);
471     }
472     else wImageName = NULL;
473     if (ModuleName)
474     {
475         len = MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, NULL, 0);
476         wModuleName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
477         MultiByteToWideChar(CP_ACP, 0, ModuleName, -1, wModuleName, len);
478     }
479     else wModuleName = NULL;
480
481     ret = SymLoadModuleExW(hProcess, hFile, wImageName, wModuleName,
482                           BaseOfDll, DllSize, Data, Flags);
483     HeapFree(GetProcessHeap(), 0, wImageName);
484     HeapFree(GetProcessHeap(), 0, wModuleName);
485     return ret;
486 }
487
488 /***********************************************************************
489  *                      SymLoadModuleExW (DBGHELP.@)
490  */
491 DWORD64 WINAPI  SymLoadModuleExW(HANDLE hProcess, HANDLE hFile, PCWSTR wImageName,
492                                  PCWSTR wModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll,
493                                  PMODLOAD_DATA Data, DWORD Flags)
494 {
495     struct process*     pcs;
496     struct module*      module = NULL;
497
498     TRACE("(%p %p %s %s %s %08x %p %08x)\n",
499           hProcess, hFile, debugstr_w(wImageName), debugstr_w(wModuleName),
500           wine_dbgstr_longlong(BaseOfDll), SizeOfDll, Data, Flags);
501
502     if (Data)
503         FIXME("Unsupported load data parameter %p for %s\n",
504               Data, debugstr_w(wImageName));
505     if (!validate_addr64(BaseOfDll)) return FALSE;
506
507     if (!(pcs = process_find_by_handle(hProcess))) return FALSE;
508
509     if (Flags & SLMFLAG_VIRTUAL)
510     {
511         module = module_new(pcs, wImageName, module_get_type_by_name(wImageName),
512                             TRUE, (DWORD)BaseOfDll, SizeOfDll, 0, 0);
513         if (!module) return FALSE;
514         if (wModuleName) module_set_module(module, wModuleName);
515         module->module.SymType = SymVirtual;
516
517         return TRUE;
518     }
519     if (Flags & ~(SLMFLAG_VIRTUAL))
520         FIXME("Unsupported Flags %08x for %s\n", Flags, debugstr_w(wImageName));
521
522     /* force transparent ELF loading / unloading */
523     elf_synchronize_module_list(pcs);
524
525     /* this is a Wine extension to the API just to redo the synchronisation */
526     if (!wImageName && !hFile) return 0;
527
528     /* check if the module is already loaded, or if it's a builtin PE module with
529      * an containing ELF module
530      */
531     if (wImageName)
532     {
533         module = module_is_already_loaded(pcs, wImageName);
534         if (!module && module_is_elf_container_loaded(pcs, wImageName, BaseOfDll))
535         {
536             /* force the loading of DLL as builtin */
537             module = pe_load_builtin_module(pcs, wImageName, BaseOfDll, SizeOfDll);
538         }
539     }
540     if (!module)
541     {
542         /* otherwise, try a regular PE module */
543         if (!(module = pe_load_native_module(pcs, wImageName, hFile, BaseOfDll, SizeOfDll)))
544         {
545             /* and finally and ELF module */
546             if (module_get_type_by_name(wImageName) == DMT_ELF)
547                 module = elf_load_module(pcs, wImageName, BaseOfDll);
548         }
549     }
550     if (!module)
551     {
552         WARN("Couldn't locate %s\n", debugstr_w(wImageName));
553         return 0;
554     }
555     module->module.NumSyms = module->ht_symbols.num_elts;
556     /* by default module_new fills module.ModuleName from a derivation
557      * of LoadedImageName. Overwrite it, if we have better information
558      */
559     if (wModuleName)
560         module_set_module(module, wModuleName);
561     lstrcpynW(module->module.ImageName, wImageName,
562               sizeof(module->module.ImageName) / sizeof(WCHAR));
563
564     return module->module.BaseOfImage;
565 }
566
567 /***********************************************************************
568  *                     SymLoadModule64 (DBGHELP.@)
569  */
570 DWORD64 WINAPI SymLoadModule64(HANDLE hProcess, HANDLE hFile, PCSTR ImageName,
571                                PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll)
572 {
573     if (!validate_addr64(BaseOfDll)) return FALSE;
574     return SymLoadModule(hProcess, hFile, ImageName, ModuleName, (DWORD)BaseOfDll, SizeOfDll);
575 }
576
577 /******************************************************************
578  *              module_remove
579  *
580  */
581 BOOL module_remove(struct process* pcs, struct module* module)
582 {
583     struct module**     p;
584
585     TRACE("%s (%p)\n", debugstr_w(module->module.ModuleName), module);
586     hash_table_destroy(&module->ht_symbols);
587     hash_table_destroy(&module->ht_types);
588     HeapFree(GetProcessHeap(), 0, module->sources);
589     HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
590     HeapFree(GetProcessHeap(), 0, module->dwarf2_info);
591     pool_destroy(&module->pool);
592     /* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here
593      * so do we
594      */
595     for (p = &pcs->lmodules; *p; p = &(*p)->next)
596     {
597         if (*p == module)
598         {
599             *p = module->next;
600             HeapFree(GetProcessHeap(), 0, module);
601             return TRUE;
602         }
603     }
604     FIXME("This shouldn't happen\n");
605     return FALSE;
606 }
607
608 /******************************************************************
609  *              SymUnloadModule (DBGHELP.@)
610  *
611  */
612 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
613 {
614     struct process*     pcs;
615     struct module*      module;
616
617     pcs = process_find_by_handle(hProcess);
618     if (!pcs) return FALSE;
619     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
620     if (!module) return FALSE;
621     return module_remove(pcs, module);
622 }
623
624 /******************************************************************
625  *              SymUnloadModule64 (DBGHELP.@)
626  *
627  */
628 BOOL WINAPI SymUnloadModule64(HANDLE hProcess, DWORD64 BaseOfDll)
629 {
630     struct process*     pcs;
631     struct module*      module;
632
633     pcs = process_find_by_handle(hProcess);
634     if (!pcs) return FALSE;
635     if (!validate_addr64(BaseOfDll)) return FALSE;
636     module = module_find_by_addr(pcs, (DWORD)BaseOfDll, DMT_UNKNOWN);
637     if (!module) return FALSE;
638     return module_remove(pcs, module);
639 }
640
641 /******************************************************************
642  *              SymEnumerateModules (DBGHELP.@)
643  *
644  */
645 struct enum_modW64_32
646 {
647     PSYM_ENUMMODULES_CALLBACK   cb;
648     PVOID                       user;
649     char                        module[MAX_PATH];
650 };
651
652 static BOOL CALLBACK enum_modW64_32(PCWSTR name, DWORD64 base, PVOID user)
653 {
654     struct enum_modW64_32*      x = user;
655
656     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
657     return x->cb(x->module, (DWORD)base, x->user);
658 }
659
660 BOOL  WINAPI SymEnumerateModules(HANDLE hProcess,
661                                  PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,  
662                                  PVOID UserContext)
663 {
664     struct enum_modW64_32       x;
665
666     x.cb = EnumModulesCallback;
667     x.user = UserContext;
668
669     return SymEnumerateModulesW64(hProcess, enum_modW64_32, &x);
670 }
671
672 /******************************************************************
673  *              SymEnumerateModules64 (DBGHELP.@)
674  *
675  */
676 struct enum_modW64_64
677 {
678     PSYM_ENUMMODULES_CALLBACK64 cb;
679     PVOID                       user;
680     char                        module[MAX_PATH];
681 };
682
683 static BOOL CALLBACK enum_modW64_64(PCWSTR name, DWORD64 base, PVOID user)
684 {
685     struct enum_modW64_64*      x = user;
686
687     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
688     return x->cb(x->module, base, x->user);
689 }
690
691 BOOL  WINAPI SymEnumerateModules64(HANDLE hProcess,
692                                    PSYM_ENUMMODULES_CALLBACK64 EnumModulesCallback,  
693                                    PVOID UserContext)
694 {
695     struct enum_modW64_64       x;
696
697     x.cb = EnumModulesCallback;
698     x.user = UserContext;
699
700     return SymEnumerateModulesW64(hProcess, enum_modW64_64, &x);
701 }
702
703 /******************************************************************
704  *              SymEnumerateModulesW64 (DBGHELP.@)
705  *
706  */
707 BOOL  WINAPI SymEnumerateModulesW64(HANDLE hProcess,
708                                     PSYM_ENUMMODULES_CALLBACKW64 EnumModulesCallback,
709                                     PVOID UserContext)
710 {
711     struct process*     pcs = process_find_by_handle(hProcess);
712     struct module*      module;
713
714     if (!pcs) return FALSE;
715     
716     for (module = pcs->lmodules; module; module = module->next)
717     {
718         if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type == DMT_ELF)
719             continue;
720         if (!EnumModulesCallback(module->module.ModuleName,
721                                  module->module.BaseOfImage, UserContext))
722             break;
723     }
724     return TRUE;
725 }
726
727 /******************************************************************
728  *              EnumerateLoadedModules64 (DBGHELP.@)
729  *
730  */
731 struct enum_load_modW64_64
732 {
733     PENUMLOADED_MODULES_CALLBACK64      cb;
734     PVOID                               user;
735     char                                module[MAX_PATH];
736 };
737
738 static BOOL CALLBACK enum_load_modW64_64(PCWSTR name, DWORD64 base, ULONG size,
739                                          PVOID user)
740 {
741     struct enum_load_modW64_64* x = user;
742
743     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
744     return x->cb(x->module, base, size, x->user);
745 }
746
747 BOOL  WINAPI EnumerateLoadedModules64(HANDLE hProcess,
748                                       PENUMLOADED_MODULES_CALLBACK64 EnumLoadedModulesCallback,
749                                       PVOID UserContext)
750 {
751     struct enum_load_modW64_64  x;
752
753     x.cb = EnumLoadedModulesCallback;
754     x.user = UserContext;
755
756     return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_64, &x);
757 }
758
759 /******************************************************************
760  *              EnumerateLoadedModules (DBGHELP.@)
761  *
762  */
763 struct enum_load_modW64_32
764 {
765     PENUMLOADED_MODULES_CALLBACK        cb;
766     PVOID                               user;
767     char                                module[MAX_PATH];
768 };
769
770 static BOOL CALLBACK enum_load_modW64_32(PCWSTR name, DWORD64 base, ULONG size,
771                                          PVOID user)
772 {
773     struct enum_load_modW64_32* x = user;
774     WideCharToMultiByte(CP_ACP, 0, name, -1, x->module, sizeof(x->module), NULL, NULL);
775     return x->cb(x->module, (DWORD)base, size, x->user);
776 }
777
778 BOOL  WINAPI EnumerateLoadedModules(HANDLE hProcess,
779                                     PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
780                                     PVOID UserContext)
781 {
782     struct enum_load_modW64_32  x;
783
784     x.cb = EnumLoadedModulesCallback;
785     x.user = UserContext;
786
787     return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x);
788 }
789
790 /******************************************************************
791  *              EnumerateLoadedModulesW64 (DBGHELP.@)
792  *
793  */
794 BOOL  WINAPI EnumerateLoadedModulesW64(HANDLE hProcess,
795                                        PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback,
796                                        PVOID UserContext)
797 {
798     HMODULE*    hMods;
799     WCHAR       baseW[256], modW[256];
800     DWORD       i, sz;
801     MODULEINFO  mi;
802
803     hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
804     if (!hMods) return FALSE;
805
806     if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
807     {
808         /* hProcess should also be a valid process handle !! */
809         FIXME("If this happens, bump the number in mod\n");
810         HeapFree(GetProcessHeap(), 0, hMods);
811         return FALSE;
812     }
813     sz /= sizeof(HMODULE);
814     for (i = 0; i < sz; i++)
815     {
816         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
817             !GetModuleBaseNameW(hProcess, hMods[i], baseW, sizeof(baseW) / sizeof(WCHAR)))
818             continue;
819         module_fill_module(baseW, modW, sizeof(modW) / sizeof(CHAR));
820         EnumLoadedModulesCallback(modW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage,
821                                   UserContext);
822     }
823     HeapFree(GetProcessHeap(), 0, hMods);
824
825     return sz != 0 && i == sz;
826 }
827
828 /******************************************************************
829  *              SymGetModuleInfo (DBGHELP.@)
830  *
831  */
832 BOOL  WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr,
833                               PIMAGEHLP_MODULE ModuleInfo)
834 {
835     IMAGEHLP_MODULE     mi;
836     IMAGEHLP_MODULEW64  miw64;
837
838     if (sizeof(mi) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
839
840     miw64.SizeOfStruct = sizeof(miw64);
841     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
842
843     mi.SizeOfStruct  = miw64.SizeOfStruct;
844     mi.BaseOfImage   = miw64.BaseOfImage;
845     mi.ImageSize     = miw64.ImageSize;
846     mi.TimeDateStamp = miw64.TimeDateStamp;
847     mi.CheckSum      = miw64.CheckSum;
848     mi.NumSyms       = miw64.NumSyms;
849     mi.SymType       = miw64.SymType;
850     WideCharToMultiByte(CP_ACP, 0, miw64.ModuleName, -1,
851                         mi.ModuleName, sizeof(mi.ModuleName), NULL, NULL);
852     WideCharToMultiByte(CP_ACP, 0, miw64.ImageName, -1,
853                         mi.ImageName, sizeof(mi.ImageName), NULL, NULL);
854     WideCharToMultiByte(CP_ACP, 0, miw64.LoadedImageName, -1,
855                         mi.LoadedImageName, sizeof(mi.LoadedImageName), NULL, NULL);
856
857     memcpy(ModuleInfo, &mi, ModuleInfo->SizeOfStruct);
858
859     return TRUE;
860 }
861
862 /******************************************************************
863  *              SymGetModuleInfoW (DBGHELP.@)
864  *
865  */
866 BOOL  WINAPI SymGetModuleInfoW(HANDLE hProcess, DWORD dwAddr,
867                                PIMAGEHLP_MODULEW ModuleInfo)
868 {
869     IMAGEHLP_MODULEW64  miw64;
870     IMAGEHLP_MODULEW    miw;
871
872     if (sizeof(miw) < ModuleInfo->SizeOfStruct) FIXME("Wrong size\n");
873
874     miw64.SizeOfStruct = sizeof(miw64);
875     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
876
877     miw.SizeOfStruct  = miw64.SizeOfStruct;
878     miw.BaseOfImage   = miw64.BaseOfImage;
879     miw.ImageSize     = miw64.ImageSize;
880     miw.TimeDateStamp = miw64.TimeDateStamp;
881     miw.CheckSum      = miw64.CheckSum;
882     miw.NumSyms       = miw64.NumSyms;
883     miw.SymType       = miw64.SymType;
884     strcpyW(miw.ModuleName, miw64.ModuleName);
885     strcpyW(miw.ImageName, miw64.ImageName);
886     strcpyW(miw.LoadedImageName, miw64.LoadedImageName);
887     memcpy(ModuleInfo, &miw, ModuleInfo->SizeOfStruct);
888
889     return TRUE;
890 }
891
892 /******************************************************************
893  *              SymGetModuleInfo64 (DBGHELP.@)
894  *
895  */
896 BOOL  WINAPI SymGetModuleInfo64(HANDLE hProcess, DWORD64 dwAddr,
897                                 PIMAGEHLP_MODULE64 ModuleInfo)
898 {
899     IMAGEHLP_MODULE64   mi64;
900     IMAGEHLP_MODULEW64  miw64;
901
902     if (sizeof(mi64) < ModuleInfo->SizeOfStruct)
903     {
904         SetLastError(ERROR_MOD_NOT_FOUND); /* NOTE: native returns this error */
905         WARN("Wrong size %u\n", ModuleInfo->SizeOfStruct);
906         return FALSE;
907     }
908
909     miw64.SizeOfStruct = sizeof(miw64);
910     if (!SymGetModuleInfoW64(hProcess, dwAddr, &miw64)) return FALSE;
911
912     mi64.SizeOfStruct  = miw64.SizeOfStruct;
913     mi64.BaseOfImage   = miw64.BaseOfImage;
914     mi64.ImageSize     = miw64.ImageSize;
915     mi64.TimeDateStamp = miw64.TimeDateStamp;
916     mi64.CheckSum      = miw64.CheckSum;
917     mi64.NumSyms       = miw64.NumSyms;
918     mi64.SymType       = miw64.SymType;
919     WideCharToMultiByte(CP_ACP, 0, miw64.ModuleName, -1,
920                         mi64.ModuleName, sizeof(mi64.ModuleName), NULL, NULL);
921     WideCharToMultiByte(CP_ACP, 0, miw64.ImageName, -1,
922                         mi64.ImageName, sizeof(mi64.ImageName), NULL, NULL);
923     WideCharToMultiByte(CP_ACP, 0, miw64.LoadedImageName, -1,
924                         mi64.LoadedImageName, sizeof(mi64.LoadedImageName), NULL, NULL);
925     WideCharToMultiByte(CP_ACP, 0, miw64.LoadedPdbName, -1,
926                         mi64.LoadedPdbName, sizeof(mi64.LoadedPdbName), NULL, NULL);
927
928     mi64.CVSig         = miw64.CVSig;
929     WideCharToMultiByte(CP_ACP, 0, miw64.CVData, -1,
930                         mi64.CVData, sizeof(mi64.CVData), NULL, NULL);
931     mi64.PdbSig        = miw64.PdbSig;
932     mi64.PdbSig70      = miw64.PdbSig70;
933     mi64.PdbAge        = miw64.PdbAge;
934     mi64.PdbUnmatched  = miw64.PdbUnmatched;
935     mi64.DbgUnmatched  = miw64.DbgUnmatched;
936     mi64.LineNumbers   = miw64.LineNumbers;
937     mi64.GlobalSymbols = miw64.GlobalSymbols;
938     mi64.TypeInfo      = miw64.TypeInfo;
939     mi64.SourceIndexed = miw64.SourceIndexed;
940     mi64.Publics       = miw64.Publics;
941
942     memcpy(ModuleInfo, &mi64, ModuleInfo->SizeOfStruct);
943
944     return TRUE;
945 }
946
947 /******************************************************************
948  *              SymGetModuleInfoW64 (DBGHELP.@)
949  *
950  */
951 BOOL  WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr,
952                                  PIMAGEHLP_MODULEW64 ModuleInfo)
953 {
954     struct process*     pcs = process_find_by_handle(hProcess);
955     struct module*      module;
956     IMAGEHLP_MODULEW64  miw64;
957
958     TRACE("%p %s %p\n", hProcess, wine_dbgstr_longlong(dwAddr), ModuleInfo);
959
960     if (!pcs) return FALSE;
961     if (ModuleInfo->SizeOfStruct > sizeof(*ModuleInfo)) return FALSE;
962     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
963     if (!module) return FALSE;
964
965     miw64 = module->module;
966
967     /* update debug information from container if any */
968     if (module->module.SymType == SymNone)
969     {
970         module = module_get_container(pcs, module);
971         if (module && module->module.SymType != SymNone)
972         {
973             miw64.SymType = module->module.SymType;
974             miw64.NumSyms = module->module.NumSyms;
975         }
976     }
977     memcpy(ModuleInfo, &miw64, ModuleInfo->SizeOfStruct);
978     return TRUE;
979 }
980
981 /***********************************************************************
982  *              SymGetModuleBase (DBGHELP.@)
983  */
984 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
985 {
986     struct process*     pcs = process_find_by_handle(hProcess);
987     struct module*      module;
988
989     if (!pcs) return 0;
990     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
991     if (!module) return 0;
992     return module->module.BaseOfImage;
993 }
994
995 /***********************************************************************
996  *              SymGetModuleBase64 (DBGHELP.@)
997  */
998 DWORD64 WINAPI SymGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr)
999 {
1000     if (!validate_addr64(dwAddr)) return 0;
1001     return SymGetModuleBase(hProcess, (DWORD)dwAddr);
1002 }
1003
1004 /******************************************************************
1005  *              module_reset_debug_info
1006  * Removes any debug information linked to a given module.
1007  */
1008 void module_reset_debug_info(struct module* module)
1009 {
1010     module->sortlist_valid = TRUE;
1011     module->addr_sorttab = NULL;
1012     hash_table_destroy(&module->ht_symbols);
1013     module->ht_symbols.num_buckets = 0;
1014     module->ht_symbols.buckets = NULL;
1015     hash_table_destroy(&module->ht_types);
1016     module->ht_types.num_buckets = 0;
1017     module->ht_types.buckets = NULL;
1018     module->vtypes.num_elts = 0;
1019     hash_table_destroy(&module->ht_symbols);
1020     module->sources_used = module->sources_alloc = 0;
1021     module->sources = NULL;
1022 }