Added y.tab.[ch] pseudo-dependencies to fix parallel makes.
[wine] / programs / winedbg / module.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3  * File module.c - module handling for the wine debugger
4  *
5  * Copyright (C) 1993, Eric Youngdale.
6  *               2000, Eric Pouech
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include "debugger.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29
30 /***********************************************************************
31  * Creates and links a new module to the current process
32  *
33  */
34 DBG_MODULE*     DEBUG_AddModule(const char* name, enum DbgModuleType type,
35                                 void* mod_addr, u_long size, HMODULE hmodule)
36 {
37     DBG_MODULE* wmod;
38
39     if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
40         return NULL;
41
42     memset(wmod, 0, sizeof(*wmod));
43
44     wmod->dil = DIL_DEFERRED;
45     wmod->main = (DEBUG_CurrProcess->num_modules == 0);
46     wmod->type = type;
47     wmod->load_addr = mod_addr;
48     wmod->size = size;
49     wmod->handle = hmodule;
50     wmod->dbg_index = DEBUG_CurrProcess->next_index;
51     wmod->module_name = DBG_strdup(name);
52
53     DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules,
54                                              ++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*));
55     DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod;
56
57     return wmod;
58 }
59
60 /***********************************************************************
61  *      DEBUG_FindModuleByName
62  *
63  */
64 DBG_MODULE*     DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
65 {
66      int                i;
67      DBG_MODULE**       amod = DEBUG_CurrProcess->modules;
68
69      for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
70          if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
71              !strcasecmp(name, amod[i]->module_name))
72              return amod[i];
73      }
74      return NULL;
75 }
76
77 /***********************************************************************
78  *      DEBUG_FindModuleByAddr
79  *
80  * either the addr where module is loaded, or any address inside the
81  * module
82  */
83 DBG_MODULE*     DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
84 {
85      int                i;
86      DBG_MODULE**       amod = DEBUG_CurrProcess->modules;
87      DBG_MODULE*        res = NULL;
88
89      for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
90          if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
91              (u_long)addr >= (u_long)amod[i]->load_addr &&
92              (u_long)addr < (u_long)amod[i]->load_addr + (u_long)amod[i]->size) {
93              /* amod[i] contains it... check against res now */
94              if (!res || res->load_addr < amod[i]->load_addr)
95                  res = amod[i];
96          }
97      }
98      return res;
99 }
100
101 /***********************************************************************
102  *              DEBUG_FindModuleByHandle
103  */
104 DBG_MODULE*     DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
105 {
106      int                i;
107      DBG_MODULE**       amod = DEBUG_CurrProcess->modules;
108
109      for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
110          if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
111              handle == amod[i]->handle)
112              return amod[i];
113      }
114      return NULL;
115 }
116
117 /***********************************************************************
118  *              DEBUG_GetProcessMainModule
119  */
120 DBG_MODULE*     DEBUG_GetProcessMainModule(DBG_PROCESS* process)
121 {
122     if (!process || !process->num_modules)      return NULL;
123
124     /* main module is the first to be loaded on a given process, so it's the first
125      * in the array */
126     assert(process->modules[0]->main);
127     return process->modules[0];
128 }
129
130 /***********************************************************************
131  *                      DEBUG_RegisterELFModule
132  *
133  * ELF modules are also entered into the list - this is so that we
134  * can make 'info shared' types of displays possible.
135  */
136 DBG_MODULE* DEBUG_RegisterELFModule(u_long load_addr, u_long size, const char* name)
137 {
138     DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, (void*)load_addr, size, 0);
139
140     if (!wmod) return NULL;
141
142     DEBUG_CurrProcess->next_index++;
143
144     return wmod;
145 }
146
147 /***********************************************************************
148  *                      DEBUG_RegisterPEModule
149  *
150  */
151 DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, u_long load_addr, u_long size, const char *module_name)
152 {
153     DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, (void*)load_addr, size, hModule);
154
155     if (!wmod) return NULL;
156
157     DEBUG_CurrProcess->next_index++;
158
159     return wmod;
160 }
161
162 /***********************************************************************
163  *                      DEBUG_RegisterNEModule
164  *
165  */
166 DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, u_long size, const char *module_name)
167 {
168     DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
169
170     if (!wmod) return NULL;
171
172     DEBUG_CurrProcess->next_index++;
173     return wmod;
174 }
175
176 #if 0
177 /***********************************************************************
178  *           DEBUG_GetEP16
179  *
180  * Helper function fo DEBUG_LoadModuleEPs16:
181  *      finds the address of a given entry point from a given module
182  */
183 static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
184                           WORD ordinal, DBG_ADDR* addr)
185 {
186     void*               idx;
187     ET_ENTRY            entry;
188     ET_BUNDLE           bundle;
189     SEGTABLEENTRY       ste;
190
191     bundle.next = module->entry_table;
192     do {
193         if (!bundle.next)
194             return FALSE;
195         idx = moduleAddr + bundle.next;
196         if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle)))
197             return FALSE;
198     } while ((ordinal < bundle.first + 1) || (ordinal > bundle.last));
199
200     if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) +
201                                 (ordinal - bundle.first - 1) * sizeof(ET_ENTRY),
202                                 &entry, sizeof(ET_ENTRY)))
203         return FALSE;
204
205     addr->seg = entry.segnum;
206     addr->off = entry.offs;
207
208     if (addr->seg == 0xfe) addr->seg = 0xffff;  /* constant entry */
209     else {
210         if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table +
211                                     sizeof(ste) * (addr->seg - 1),
212                                     &ste, sizeof(ste)))
213             return FALSE;
214         addr->seg = GlobalHandleToSel16(ste.hSeg);
215     }
216     return TRUE;
217 }
218
219 /***********************************************************************
220  *           DEBUG_LoadModule16
221  *
222  * Load the entry points of a Win16 module into the hash table.
223  */
224 static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
225 {
226     DBG_VALUE   value;
227     BYTE        buf[1 + 256 + 2];
228     char        epname[512];
229     char*       cpnt;
230     DBG_MODULE* wmod;
231
232     wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
233
234     value.type = NULL;
235     value.cookie = DV_TARGET;
236     value.addr.seg = 0;
237     value.addr.off = 0;
238
239     cpnt = moduleAddr + module->name_table;
240
241     /* First search the resident names */
242
243     /* skip module name */
244     if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0])
245         return;
246     cpnt += 1 + buf[0] + sizeof(WORD);
247
248     while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
249         sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]);
250         if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
251             DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
252         }
253         cpnt += buf[0] + 1 + sizeof(WORD);
254     }
255
256     /* Now search the non-resident names table */
257     if (!module->nrname_handle) return;  /* No non-resident table */
258     cpnt = (char *)GlobalLock16(module->nrname_handle);
259     while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
260         sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]);
261         if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
262             DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
263         }
264         cpnt += buf[0] + 1 + sizeof(WORD);
265     }
266     GlobalUnlock16(module->nrname_handle);
267 }
268 #endif
269
270 /***********************************************************************
271  *                      DEBUG_LoadModule32
272  */
273 void    DEBUG_LoadModule32(const char* name, HANDLE hFile, DWORD base)
274 {
275      IMAGE_NT_HEADERS           pe_header;
276      DWORD                      nth_ofs;
277      DBG_MODULE*                wmod = NULL;
278      int                        i;
279      IMAGE_SECTION_HEADER       pe_seg;
280      DWORD                      pe_seg_ofs;
281      DWORD                      size = 0;
282      enum DbgInfoLoad           dil = DIL_ERROR;
283
284      /* grab PE Header */
285      if (!DEBUG_READ_MEM_VERBOSE((void*)(base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew)),
286                                  &nth_ofs, sizeof(nth_ofs)) ||
287          !DEBUG_READ_MEM_VERBOSE((void*)(base + nth_ofs), &pe_header, sizeof(pe_header)))
288          return;
289
290      pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
291          pe_header.FileHeader.SizeOfOptionalHeader;
292
293      for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
294          if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg)))
295              continue;
296          if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData)
297              size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData;
298      }
299
300      /* FIXME: we make the assumption that hModule == base */
301      wmod = DEBUG_RegisterPEModule((HMODULE)base, base, size, name);
302      if (wmod) {
303          dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs);
304          if (dil != DIL_LOADED)
305              dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs);
306          if (dil != DIL_LOADED)
307              dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs);
308          wmod->dil = dil;
309      }
310
311      DEBUG_ReportDIL(dil, "32bit DLL", name, base);
312 }
313
314 /***********************************************************************
315  *                      DEBUG_RegisterPEDebugInfo
316  */
317 enum DbgInfoLoad        DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
318                                                   void* _nth, unsigned long nth_ofs)
319 {
320     DBG_VALUE                   value;
321     char                        buffer[512];
322     char                        bufstr[256];
323     unsigned int                i;
324     IMAGE_SECTION_HEADER        pe_seg;
325     DWORD                       pe_seg_ofs;
326     IMAGE_DATA_DIRECTORY        dir;
327     DWORD                       dir_ofs;
328     const char*                 prefix;
329     IMAGE_NT_HEADERS*           nth = (PIMAGE_NT_HEADERS)_nth;
330     DWORD                       base = (u_long)wmod->load_addr;
331
332     value.type = NULL;
333     value.cookie = DV_TARGET;
334     value.addr.seg = 0;
335     value.addr.off = 0;
336
337     /* Add start of DLL */
338     value.addr.off = base;
339     if ((prefix = strrchr(wmod->module_name, '\\' ))) prefix++;
340     else prefix = wmod->module_name;
341
342     DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
343
344     /* Add entry point */
345     snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix);
346     value.addr.off = base + nth->OptionalHeader.AddressOfEntryPoint;
347     DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
348
349     /* Add start of sections */
350     pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
351         nth->FileHeader.SizeOfOptionalHeader;
352
353     for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
354         if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg)))
355             continue;
356         snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
357         value.addr.off = base + pe_seg.VirtualAddress;
358         DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
359     }
360
361     /* Add exported functions */
362     dir_ofs = nth_ofs +
363         OFFSET_OF(IMAGE_NT_HEADERS,
364                   OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
365     if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir_ofs), &dir, sizeof(dir)) && dir.Size) {
366         IMAGE_EXPORT_DIRECTORY  exports;
367         WORD*                   ordinals = NULL;
368         void**                  functions = NULL;
369         DWORD*                  names = NULL;
370         unsigned int            j;
371
372         if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir.VirtualAddress),
373                                    &exports, sizeof(exports)) &&
374
375             ((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
376             DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfFunctions),
377                                    functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
378
379             ((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
380             DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNameOrdinals),
381                                    ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
382
383             ((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
384             DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNames),
385                                    names, sizeof(names[0]) * exports.NumberOfNames)) {
386
387             for (i = 0; i < exports.NumberOfNames; i++) {
388                 if (!names[i] ||
389                     !DEBUG_READ_MEM_VERBOSE((void*)(base + names[i]), bufstr, sizeof(bufstr)))
390                     continue;
391                 bufstr[sizeof(bufstr) - 1] = 0;
392                 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
393                 value.addr.off = base + (DWORD)functions[ordinals[i]];
394                 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
395             }
396
397             for (i = 0; i < exports.NumberOfFunctions; i++) {
398                 if (!functions[i]) continue;
399                 /* Check if we already added it with a name */
400                 for (j = 0; j < exports.NumberOfNames; j++)
401                     if ((ordinals[j] == i) && names[j]) break;
402                 if (j < exports.NumberOfNames) continue;
403                 snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base);
404                 value.addr.off = base + (DWORD)functions[i];
405                 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
406             }
407         }
408         DBG_free(functions);
409         DBG_free(ordinals);
410         DBG_free(names);
411     }
412     /* no real debug info, only entry points */
413     return DIL_NOINFO;
414 }
415
416 /***********************************************************************
417  *              DEBUG_LoadEntryPoints
418  *
419  * Load the entry points of all the modules into the hash table.
420  */
421 int DEBUG_LoadEntryPoints(const char* pfx)
422 {
423     int         first = 0;
424     /* FIXME: with address space separation in space, this is plain wrong
425      *        it requires the 16 bit WOW debugging interface...
426      */
427 #if 0
428     MODULEENTRY entry;
429     NE_MODULE   module;
430     void*       moduleAddr;
431     int         rowcount = 0;
432     int         len;
433
434     /* FIXME: we assume that a module is never removed from memory */
435     /* FIXME: this is (currently plain wrong when debugger is started by
436      *        attaching to an existing program => the 16 bit modules will
437      *        not be shared... not much to do on debugger side... sigh
438      */
439     if (ModuleFirst16(&entry)) do {
440         if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) ||
441             !(moduleAddr = NE_GetPtr(entry.hModule)) ||
442             !DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) ||
443             (module.flags & NE_FFLAGS_WIN32) /* NE module */)
444             continue;
445         if (!first) {
446             if (pfx) DEBUG_Printf(DBG_CHN_MESG, pfx);
447             DEBUG_Printf(DBG_CHN_MESG, "   ");
448             rowcount = 3 + (pfx ? strlen(pfx) : 0);
449             first = 1;
450         }
451
452         len = strlen(entry.szModule);
453         if ((rowcount + len) > 76) {
454             DEBUG_Printf(DBG_CHN_MESG, "\n   ");
455             rowcount = 3;
456         }
457         DEBUG_Printf(DBG_CHN_MESG, " %s", entry.szModule);
458         rowcount += len + 1;
459
460         DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
461     } while (ModuleNext16(&entry));
462 #endif
463
464     if (first) DEBUG_Printf(DBG_CHN_MESG, "\n");
465     return first;
466 }
467
468 void    DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, DWORD load_addr)
469 {
470     const char* fmt;
471
472     switch (dil) {
473     case DIL_DEFERRED:
474         fmt = "Deferring debug information loading for %s '%s' (0x%08x)\n";
475         break;
476     case DIL_LOADED:
477         fmt = "Loaded debug information from %s '%s' (0x%08x)\n";
478         break;
479     case DIL_NOINFO:
480         fmt = "No debug information in %s '%s' (0x%08x)\n";
481         break;
482     case DIL_ERROR:
483         fmt = "Can't find file for %s '%s' (0x%08x)\n";
484         break;
485     default:
486         DEBUG_Printf(DBG_CHN_ERR, "Oooocch (%d)\n", dil);
487         return;
488     }
489
490     DEBUG_Printf(DBG_CHN_MESG, fmt, pfx, filename, load_addr);
491 }
492
493 static const char*      DEBUG_GetModuleType(enum DbgModuleType type)
494 {
495     switch (type) {
496     case DMT_NE:    return "NE";
497     case DMT_PE:    return "PE";
498     case DMT_ELF:   return "ELF";
499     default:        return "???";
500     }
501 }
502
503 static const char*      DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
504 {
505     switch (dil) {
506     case DIL_LOADED:    return "loaded";
507     case DIL_DEFERRED:  return "deferred";
508     case DIL_NOINFO:    return "none";
509     case DIL_ERROR:     return "error";
510     default:            return "?";
511     }
512 }
513
514 /***********************************************************************
515  *           DEBUG_ModuleCompare
516  *
517  * returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2
518  * order used is order on load_addr of a module
519  */
520 static int      DEBUG_ModuleCompare(const void* p1, const void* p2)
521 {
522     return (char*)(*((const DBG_MODULE**)p1))->load_addr -
523            (char*)(*((const DBG_MODULE**)p2))->load_addr;
524 }
525
526 /***********************************************************************
527  *           DEBUG_IsContainer
528  *
529  * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
530  */
531 static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
532                                      const DBG_MODULE* wmod_child)
533 {
534     return wmod_cntnr->load_addr < wmod_child->load_addr &&
535         (DWORD)wmod_cntnr->load_addr + wmod_cntnr->size >
536         (DWORD)wmod_child->load_addr + wmod_child->size;
537 }
538
539 static void     DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
540 {
541     if (ident) DEBUG_Printf(DBG_CHN_MESG, "  \\-");
542     DEBUG_Printf(DBG_CHN_MESG, "%s\t0x%08lx-%08lx\t%s\n",
543                  DEBUG_GetModuleType(module->type),
544                  (DWORD)module->load_addr, (DWORD)module->load_addr + module->size,
545                  module->module_name);
546 }
547
548 /***********************************************************************
549  *           DEBUG_InfoShare
550  *
551  * Display shared libarary information.
552  */
553 void DEBUG_InfoShare(void)
554 {
555     DBG_MODULE**        ref;
556     int                 i, j;
557
558     ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
559     if (!ref) return;
560
561     DEBUG_Printf(DBG_CHN_MESG, "Module\tAddress\t\t\tName\t%d modules\n",
562                  DEBUG_CurrProcess->num_modules);
563
564     memcpy(ref, DEBUG_CurrProcess->modules,
565            sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
566     qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
567           DEBUG_ModuleCompare);
568     for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
569         switch (ref[i]->type) {
570         case DMT_ELF:
571             DEBUG_InfoShareModule(ref[i], 0);
572             for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
573                 if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j]))
574                     DEBUG_InfoShareModule(ref[j], 1);
575             }
576             break;
577         case DMT_NE:
578         case DMT_PE:
579             /* check module is not in ELF */
580             for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
581                 if (ref[j]->type == DMT_ELF &&
582                     DEBUG_IsContainer(ref[j], ref[i]))
583                     break;
584             }
585             if (j >= DEBUG_CurrProcess->num_modules)
586                 DEBUG_InfoShareModule(ref[i], 0);
587             break;
588         default:
589             DEBUG_Printf(DBG_CHN_ERR, "Unknown type (%d)\n", ref[i]->type);
590         }
591     }
592     DBG_free(ref);
593 }
594
595 /***********************************************************************
596  *           DEBUG_DumpModule
597  * Display information about a given module (DLL or EXE)
598  */
599 void DEBUG_DumpModule(DWORD mod)
600 {
601     DBG_MODULE* wmod;
602
603     if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) &&
604         !(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) {
605         DEBUG_Printf(DBG_CHN_MESG, "'0x%08lx' is not a valid module handle or address\n", mod);
606         return;
607     }
608
609     DEBUG_Printf(DBG_CHN_MESG, "Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n",
610                  wmod->module_name, wmod->handle, (DWORD)wmod->load_addr,
611                  (DWORD)wmod->load_addr + wmod->size,
612                  DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil));
613 }
614
615 /***********************************************************************
616  *           DEBUG_WalkModules
617  *
618  * Display information about all modules (DLLs and EXEs)
619  */
620 void DEBUG_WalkModules(void)
621 {
622     DBG_MODULE**        amod;
623     int                 i;
624
625     DEBUG_Printf(DBG_CHN_MESG, "Address\t\t\tModule\tName\n");
626
627     amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
628     if (!amod) return;
629
630     memcpy(amod, DEBUG_CurrProcess->modules,
631            sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
632     qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
633           DEBUG_ModuleCompare);
634     for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
635         if (amod[i]->type == DMT_ELF)   continue;
636
637         DEBUG_Printf(DBG_CHN_MESG, "0x%08lx-%08lx\t(%s)\t%s\n",
638                      (DWORD)amod[i]->load_addr,
639                      (DWORD)amod[i]->load_addr + amod[i]->size,
640                      DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name);
641     }
642     DBG_free(amod);
643 }