Memory consumption optimization while loading ELF debug info:
[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 void module_fill_module(const char* in, char* out, unsigned size)
37 {
38     const char*         ptr;
39     unsigned            len;
40
41     for (ptr = in + strlen(in) - 1; 
42          *ptr != '/' && *ptr != '\\' && ptr >= in; 
43          ptr--);
44     if (ptr < in || *ptr == '/' || *ptr == '\\') ptr++;
45     strncpy(out, ptr, size);
46     out[size - 1] = '\0';
47     len = strlen(out);
48     if (len > 4 && 
49         (!strcasecmp(&out[len - 4], ".dll") || !strcasecmp(&out[len - 4], ".exe")))
50         out[len - 4] = '\0';
51     else if (((len > 12 && out[len - 13] == '/') || len == 12) && 
52              (!strcasecmp(out + len - 12, "wine-pthread") || 
53               !strcasecmp(out + len - 12, "wine-kthread")))
54         strcpy(out, "<wine-loader>");
55     else
56     {
57         if (len > 7 && 
58             (!strcasecmp(&out[len - 7], ".dll.so") || !strcasecmp(&out[len - 7], ".exe.so")))
59             strcpy(&out[len - 7], "<elf>");
60         else if (len > 7 &&
61                  out[len - 7] == '.' && !strcasecmp(&out[len - 3], ".so"))
62         {
63             if (len + 3 < size) strcpy(&out[len - 3], "<elf>");
64             else WARN("Buffer too short: %s\n", out);
65         }
66     }
67     while ((*out = tolower(*out))) out++;
68 }
69
70 /***********************************************************************
71  * Creates and links a new module to a process 
72  */
73 struct module* module_new(struct process* pcs, const char* name, 
74                           enum module_type type, 
75                           unsigned long mod_addr, unsigned long size,
76                           unsigned long stamp, unsigned long checksum) 
77 {
78     struct module*      module;
79
80     if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module))))
81         return NULL;
82
83     memset(module, 0, sizeof(*module));
84
85     module->next = pcs->lmodules;
86     pcs->lmodules = module;
87
88     TRACE("=> %s %08lx-%08lx %s\n", 
89           type == DMT_ELF ? "ELF" : (type == DMT_PE ? "PE" : "---"),
90           mod_addr, mod_addr + size, name);
91
92     pool_init(&module->pool, 65536);
93     
94     module->module.SizeOfStruct = sizeof(module->module);
95     module->module.BaseOfImage = mod_addr;
96     module->module.ImageSize = size;
97     module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName));
98     module->module.ImageName[0] = '\0';
99     strncpy(module->module.LoadedImageName, name, 
100             sizeof(module->module.LoadedImageName));
101     module->module.LoadedImageName[sizeof(module->module.LoadedImageName) - 1] = '\0';
102     module->module.SymType = SymNone;
103     module->module.NumSyms = 0;
104     module->module.TimeDateStamp = stamp;
105     module->module.CheckSum = checksum;
106
107     module->type              = type;
108     module->sortlist_valid    = FALSE;
109     module->addr_sorttab      = NULL;
110     /* FIXME: this seems a bit too high (on a per module basis)
111      * need some statistics about this
112      */
113     hash_table_init(&module->pool, &module->ht_symbols, 4096);
114     hash_table_init(&module->pool, &module->ht_types,   4096);
115     vector_init(&module->vtypes, sizeof(struct symt*),  32);
116
117     module->sources_used      = 0;
118     module->sources_alloc     = 0;
119     module->sources           = 0;
120
121     return module;
122 }
123
124 /***********************************************************************
125  *      module_find_by_name
126  *
127  */
128 struct module* module_find_by_name(const struct process* pcs, 
129                                    const char* name, enum module_type type)
130 {
131     struct module*      module;
132
133     if (type == DMT_UNKNOWN)
134     {
135         if ((module = module_find_by_name(pcs, name, DMT_PE)) ||
136             (module = module_find_by_name(pcs, name, DMT_ELF)))
137             return module;
138     }
139     else
140     {
141         char                modname[MAX_PATH];
142
143         for (module = pcs->lmodules; module; module = module->next)
144         {
145             if (type == module->type && !strcasecmp(name, module->module.LoadedImageName)) 
146                 return module;
147         }
148         module_fill_module(name, modname, sizeof(modname));
149         for (module = pcs->lmodules; module; module = module->next)
150         {
151             if (type == module->type && !strcasecmp(modname, module->module.ModuleName)) 
152                 return module;
153         }
154     }
155     SetLastError(ERROR_INVALID_NAME);
156     return NULL;
157 }
158
159 /***********************************************************************
160  *           module_get_container
161  *
162  */
163 struct module* module_get_container(const struct process* pcs, 
164                                     const struct module* inner)
165 {
166     struct module*      module;
167      
168     for (module = pcs->lmodules; module; module = module->next)
169     {
170         if (module != inner &&
171             module->module.BaseOfImage <= inner->module.BaseOfImage &&
172             module->module.BaseOfImage + module->module.ImageSize >=
173             inner->module.BaseOfImage + inner->module.ImageSize)
174             return module;
175     }
176     return NULL;
177 }
178
179 /***********************************************************************
180  *           module_get_containee
181  *
182  */
183 struct module* module_get_containee(const struct process* pcs, 
184                                     const struct module* outter)
185 {
186     struct module*      module;
187      
188     for (module = pcs->lmodules; module; module = module->next)
189     {
190         if (module != outter &&
191             outter->module.BaseOfImage <= module->module.BaseOfImage &&
192             outter->module.BaseOfImage + outter->module.ImageSize >=
193             module->module.BaseOfImage + module->module.ImageSize)
194             return module;
195     }
196     return NULL;
197 }
198
199 /******************************************************************
200  *              module_get_debug
201  *
202  * get the debug information from a module:
203  * - if the module's type is deferred, then force loading of debug info (and return
204  *   the module itself)
205  * - if the module has no debug info and has an ELF container, then return the ELF
206  *   container (and also force the ELF container's debug info loading if deferred)
207  * - otherwise return the module itself if it has some debug info
208  */
209 struct module* module_get_debug(const struct process* pcs, struct module* module)
210 {
211     struct module*      parent;
212
213     if (!module) return NULL;
214     /* for a PE builtin, always get info from parent */
215     if ((parent = module_get_container(pcs, module)))
216         module = parent;
217     /* if deferred, force loading */
218     if (module->module.SymType == SymDeferred)
219     {
220         BOOL ret;
221
222         switch (module->type)
223         {
224         case DMT_ELF: ret = elf_load_debug_info(module, NULL);  break;
225         case DMT_PE:  ret = pe_load_debug_info(pcs, module);    break;
226         default:      ret = FALSE;                              break;
227         }
228         if (!ret) module->module.SymType = SymNone;
229         assert(module->module.SymType != SymDeferred);
230     }
231     return (module && module->module.SymType != SymNone) ? module : NULL;
232 }
233
234 /***********************************************************************
235  *      module_find_by_addr
236  *
237  * either the addr where module is loaded, or any address inside the 
238  * module
239  */
240 struct module* module_find_by_addr(const struct process* pcs, unsigned long addr, 
241                                    enum module_type type)
242 {
243     struct module*      module;
244     
245     if (type == DMT_UNKNOWN)
246     {
247         if ((module = module_find_by_addr(pcs, addr, DMT_PE)) ||
248             (module = module_find_by_addr(pcs, addr, DMT_ELF)))
249             return module;
250     }
251     else
252     {
253         for (module = pcs->lmodules; module; module = module->next)
254         {
255             if (type == module->type && addr >= module->module.BaseOfImage &&
256                 addr < module->module.BaseOfImage + module->module.ImageSize) 
257                 return module;
258         }
259     }
260     SetLastError(ERROR_INVALID_ADDRESS);
261     return module;
262 }
263
264 static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName, 
265                                            const char* ModuleName)
266 {
267     char                buffer[MAX_PATH];
268     size_t              len;
269     struct module*      module;
270
271     if (!ModuleName)
272     {
273         module_fill_module(ImageName, buffer, sizeof(buffer));
274         ModuleName = buffer;
275     }
276     len = strlen(ModuleName);
277     for (module = pcs->lmodules; module; module = module->next)
278     {
279         if (!strncasecmp(module->module.ModuleName, ModuleName, len) &&
280             module->type == DMT_ELF &&
281             !strcmp(module->module.ModuleName + len, "<elf>"))
282             return TRUE;
283     }
284     return FALSE;
285 }
286
287 static BOOL elf_is_shared_by_name(const char* name)
288 {
289     const char* ptr;
290     int         len = strlen(name);
291
292     /* check for terminating .so or .so.[digit]+ */
293     while (len)
294     {
295         for (ptr = name + len - 1; ptr >= name; ptr--) if (*ptr == '.') break;
296         if (ptr < name) break;
297         if (ptr == name + len - 2 && isdigit(ptr[1]))
298         {
299             len -= 2;
300             continue;
301         }
302         if (ptr == name + len - 3 && ptr[1] == 's' && ptr[2] == 'o')
303             return TRUE;
304         break;
305     }
306     /* wine-[kp]thread is valid too */
307     if (((len > 12 && name[len - 13] == '/') || len == 12) && 
308              (!strcasecmp(name + len - 12, "wine-pthread") || 
309               !strcasecmp(name + len - 12, "wine-kthread")))
310         return TRUE;
311     return FALSE;
312 }
313
314 /***********************************************************************
315  *                      SymLoadModule (DBGHELP.@)
316  */
317 DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName,
318                            char* ModuleName, DWORD BaseOfDll, DWORD SizeOfDll)
319 {
320     struct process*     pcs;
321     struct module*      module = NULL;
322
323     TRACE("(%p %p %s %s %08lx %08lx)\n", 
324           hProcess, hFile, debugstr_a(ImageName), debugstr_a(ModuleName), 
325           BaseOfDll, SizeOfDll);
326
327     pcs = process_find_by_handle(hProcess);
328     if (!pcs) return FALSE;
329
330     /* force transparent ELF loading / unloading */
331     elf_synchronize_module_list(pcs);
332
333     /* this is a Wine extension to the API just to redo the synchronisation */
334     if (!ImageName && !hFile) return 0;
335
336     if (module_is_elf_container_loaded(pcs, ImageName, ModuleName))
337     {
338         /* force the loading of DLL as builtin */
339         if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
340             goto done;
341         WARN("Couldn't locate %s\n", ImageName);
342         return 0;
343     }
344     TRACE("Assuming %s as native DLL\n", ImageName);
345     if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll)))
346     {
347         if (elf_is_shared_by_name(ImageName) &&
348             (module = elf_load_module(pcs, ImageName, BaseOfDll)))
349             goto done;
350         FIXME("Should have successfully loaded debug information for image %s\n",
351               ImageName);
352         if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll)))
353             goto done;
354         WARN("Couldn't locate %s\n", ImageName);
355         return 0;
356     }
357
358 done:
359     /* by default pe_load_module fills module.ModuleName from a derivation 
360      * of ImageName. Overwrite it, if we have better information
361      */
362     if (ModuleName)
363     {
364         strncpy(module->module.ModuleName, ModuleName, 
365                 sizeof(module->module.ModuleName));
366         module->module.ModuleName[sizeof(module->module.ModuleName) - 1] = '\0';
367     }
368     strncpy(module->module.ImageName, ImageName, sizeof(module->module.ImageName));
369     module->module.ImageName[sizeof(module->module.ImageName) - 1] = '\0';
370
371     return module->module.BaseOfImage;
372 }
373
374 /******************************************************************
375  *              module_remove
376  *
377  */
378 BOOL module_remove(struct process* pcs, struct module* module)
379 {
380     struct module**     p;
381
382     TRACE("%s (%p)\n", module->module.ModuleName, module);
383     hash_table_destroy(&module->ht_symbols);
384     hash_table_destroy(&module->ht_types);
385     HeapFree(GetProcessHeap(), 0, (char*)module->sources);
386     HeapFree(GetProcessHeap(), 0, module->addr_sorttab);
387     pool_destroy(&module->pool);
388
389     for (p = &pcs->lmodules; *p; p = &(*p)->next)
390     {
391         if (*p == module)
392         {
393             *p = module->next;
394             HeapFree(GetProcessHeap(), 0, module);
395             return TRUE;
396         }
397     }
398     FIXME("This shouldn't happen\n");
399     return FALSE;
400 }
401
402 /******************************************************************
403  *              SymUnloadModule (DBGHELP.@)
404  *
405  */
406 BOOL WINAPI SymUnloadModule(HANDLE hProcess, DWORD BaseOfDll)
407 {
408     struct process*     pcs;
409     struct module*      module;
410
411     pcs = process_find_by_handle(hProcess);
412     if (!pcs) return FALSE;
413     module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
414     if (!module) return FALSE;
415     return module_remove(pcs, module);
416 }
417
418 /******************************************************************
419  *              SymEnumerateModules (DBGHELP.@)
420  *
421  */
422 BOOL  WINAPI SymEnumerateModules(HANDLE hProcess,
423                                  PSYM_ENUMMODULES_CALLBACK EnumModulesCallback,  
424                                  PVOID UserContext)
425 {
426     struct process*     pcs = process_find_by_handle(hProcess);
427     struct module*      module;
428
429     if (!pcs) return FALSE;
430     
431     for (module = pcs->lmodules; module; module = module->next)
432     {
433         if (!(dbghelp_options & SYMOPT_WINE_WITH_ELF_MODULES) && module->type != DMT_PE)
434             continue;
435         if (!EnumModulesCallback(module->module.ModuleName, 
436                                  module->module.BaseOfImage, UserContext))
437             break;
438     }
439     return TRUE;
440 }
441
442 /******************************************************************
443  *              EnumerateLoadedModules (DBGHELP.@)
444  *
445  */
446 BOOL  WINAPI EnumerateLoadedModules(HANDLE hProcess,
447                                     PENUMLOADED_MODULES_CALLBACK EnumLoadedModulesCallback,
448                                     PVOID UserContext)
449 {
450     HMODULE*    hMods;
451     char        base[256], mod[256];
452     DWORD       i, sz;
453     MODULEINFO  mi;
454
455     hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0]));
456     if (!hMods) return FALSE;
457
458     if (!EnumProcessModules(hProcess, hMods, 256 * sizeof(hMods[0]), &sz))
459     {
460         /* hProcess should also be a valid process handle !! */
461         FIXME("If this happens, bump the number in mod\n");
462         HeapFree(GetProcessHeap(), 0, hMods);
463         return FALSE;
464     }
465     sz /= sizeof(HMODULE);
466     for (i = 0; i < sz; i++)
467     {
468         if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) ||
469             !GetModuleBaseNameA(hProcess, hMods[i], base, sizeof(base)))
470             continue;
471         module_fill_module(base, mod, sizeof(mod));
472
473         EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage, 
474                                   UserContext);
475     }
476     HeapFree(GetProcessHeap(), 0, hMods);
477
478     return sz != 0 && i == sz;
479 }
480
481 /******************************************************************
482  *              SymGetModuleInfo (DBGHELP.@)
483  *
484  */
485 BOOL  WINAPI SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr, 
486                               PIMAGEHLP_MODULE ModuleInfo)
487 {
488     struct process*     pcs = process_find_by_handle(hProcess);
489     struct module*      module;
490
491     if (!pcs) return FALSE;
492     if (ModuleInfo->SizeOfStruct < sizeof(*ModuleInfo)) return FALSE;
493     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
494     if (!module) return FALSE;
495
496     *ModuleInfo = module->module;
497     if (module->module.SymType == SymNone)
498     {
499         module = module_get_container(pcs, module);
500         if (module && module->module.SymType != SymNone)
501             ModuleInfo->SymType = module->module.SymType;
502     }
503
504     return TRUE;
505 }
506
507 /***********************************************************************
508  *              SymGetModuleBase (IMAGEHLP.@)
509  */
510 DWORD WINAPI SymGetModuleBase(HANDLE hProcess, DWORD dwAddr)
511 {
512     struct process*     pcs = process_find_by_handle(hProcess);
513     struct module*      module;
514
515     if (!pcs) return 0;
516     module = module_find_by_addr(pcs, dwAddr, DMT_UNKNOWN);
517     if (!module) return 0;
518     return module->module.BaseOfImage;
519 }
520
521 /******************************************************************
522  *              module_reset_debug_info
523  * Removes any debug information linked to a given module.
524  */
525 void module_reset_debug_info(struct module* module)
526 {
527     module->sortlist_valid = TRUE;
528     module->addr_sorttab = NULL;
529     hash_table_destroy(&module->ht_symbols);
530     module->ht_symbols.num_buckets = 0;
531     module->ht_symbols.buckets = NULL;
532     hash_table_destroy(&module->ht_types);
533     module->ht_types.num_buckets = 0;
534     module->ht_types.buckets = NULL;
535     module->vtypes.num_elts = 0;
536     hash_table_destroy(&module->ht_symbols);
537     module->sources_used = module->sources_alloc = 0;
538     module->sources = NULL;
539 }