Merged the two serializer and unserializer functions into one, cleaned
[wine.git] / debugger / module.c
blob460e27b7aeb6988050ae98be10d7ab86ee525ea8
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * File module.c - module handling for the wine debugger
5 * Copyright (C) 1993, Eric Youngdale.
6 * 2000, Eric Pouech
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.
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.
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
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"
30 /***********************************************************************
31 * Creates and links a new module to the current process
34 DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
35 void* mod_addr, u_long size, HMODULE hmodule)
37 DBG_MODULE* wmod;
39 if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
40 return NULL;
42 memset(wmod, 0, sizeof(*wmod));
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);
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;
57 return wmod;
60 /***********************************************************************
61 * DEBUG_FindModuleByName
64 DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
66 int i;
67 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
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];
74 return NULL;
77 /***********************************************************************
78 * DEBUG_FindModuleByAddr
80 * either the addr where module is loaded, or any address inside the
81 * module
83 DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
85 int i;
86 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
87 DBG_MODULE* res = NULL;
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];
98 return res;
101 /***********************************************************************
102 * DEBUG_FindModuleByHandle
104 DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
106 int i;
107 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
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];
114 return NULL;
117 /***********************************************************************
118 * DEBUG_GetProcessMainModule
120 DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
122 if (!process || !process->num_modules) return NULL;
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];
130 /***********************************************************************
131 * DEBUG_RegisterELFModule
133 * ELF modules are also entered into the list - this is so that we
134 * can make 'info shared' types of displays possible.
136 DBG_MODULE* DEBUG_RegisterELFModule(u_long load_addr, u_long size, const char* name)
138 DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, (void*)load_addr, size, 0);
140 if (!wmod) return NULL;
142 DEBUG_CurrProcess->next_index++;
144 return wmod;
147 /***********************************************************************
148 * DEBUG_RegisterPEModule
151 DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, u_long load_addr, u_long size, const char *module_name)
153 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, (void*)load_addr, size, hModule);
155 if (!wmod) return NULL;
157 DEBUG_CurrProcess->next_index++;
159 return wmod;
162 /***********************************************************************
163 * DEBUG_RegisterNEModule
166 DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, u_long size, const char *module_name)
168 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
170 if (!wmod) return NULL;
172 DEBUG_CurrProcess->next_index++;
173 return wmod;
176 #if 0
177 /***********************************************************************
178 * DEBUG_GetEP16
180 * Helper function fo DEBUG_LoadModuleEPs16:
181 * finds the address of a given entry point from a given module
183 static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
184 WORD ordinal, DBG_ADDR* addr)
186 void* idx;
187 ET_ENTRY entry;
188 ET_BUNDLE bundle;
189 SEGTABLEENTRY ste;
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));
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;
205 addr->seg = entry.segnum;
206 addr->off = entry.offs;
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);
216 return TRUE;
219 /***********************************************************************
220 * DEBUG_LoadModule16
222 * Load the entry points of a Win16 module into the hash table.
224 static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
226 DBG_VALUE value;
227 BYTE buf[1 + 256 + 2];
228 char epname[512];
229 char* cpnt;
230 DBG_MODULE* wmod;
232 wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
234 value.type = NULL;
235 value.cookie = DV_TARGET;
236 value.addr.seg = 0;
237 value.addr.off = 0;
239 cpnt = moduleAddr + module->name_table;
241 /* First search the resident names */
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);
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);
253 cpnt += buf[0] + 1 + sizeof(WORD);
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);
264 cpnt += buf[0] + 1 + sizeof(WORD);
266 GlobalUnlock16(module->nrname_handle);
268 #endif
270 /***********************************************************************
271 * DEBUG_LoadModule32
273 void DEBUG_LoadModule32(const char* name, HANDLE hFile, DWORD base)
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;
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;
290 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
291 pe_header.FileHeader.SizeOfOptionalHeader;
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;
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;
311 DEBUG_ReportDIL(dil, "32bit DLL", name, base);
314 /***********************************************************************
315 * DEBUG_RegisterPEDebugInfo
317 enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
318 void* _nth, unsigned long nth_ofs)
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;
332 value.type = NULL;
333 value.cookie = DV_TARGET;
334 value.addr.seg = 0;
335 value.addr.off = 0;
337 /* Add start of DLL */
338 value.addr.off = base;
339 if ((prefix = strrchr(wmod->module_name, '\\' ))) prefix++;
340 else prefix = wmod->module_name;
342 DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
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);
349 /* Add start of sections */
350 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
351 nth->FileHeader.SizeOfOptionalHeader;
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);
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;
372 if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir.VirtualAddress),
373 &exports, sizeof(exports)) &&
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) &&
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) &&
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)) {
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);
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);
408 DBG_free(functions);
409 DBG_free(ordinals);
410 DBG_free(names);
412 /* no real debug info, only entry points */
413 return DIL_NOINFO;
416 /***********************************************************************
417 * DEBUG_LoadEntryPoints
419 * Load the entry points of all the modules into the hash table.
421 int DEBUG_LoadEntryPoints(const char* pfx)
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...
427 #if 0
428 MODULEENTRY entry;
429 NE_MODULE module;
430 void* moduleAddr;
431 int rowcount = 0;
432 int len;
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
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;
452 len = strlen(entry.szModule);
453 if ((rowcount + len) > 76) {
454 DEBUG_Printf(DBG_CHN_MESG, "\n ");
455 rowcount = 3;
457 DEBUG_Printf(DBG_CHN_MESG, " %s", entry.szModule);
458 rowcount += len + 1;
460 DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
461 } while (ModuleNext16(&entry));
462 #endif
464 if (first) DEBUG_Printf(DBG_CHN_MESG, "\n");
465 return first;
468 void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, DWORD load_addr)
470 const char* fmt;
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;
490 DEBUG_Printf(DBG_CHN_MESG, fmt, pfx, filename, load_addr);
493 static const char* DEBUG_GetModuleType(enum DbgModuleType type)
495 switch (type) {
496 case DMT_NE: return "NE";
497 case DMT_PE: return "PE";
498 case DMT_ELF: return "ELF";
499 default: return "???";
503 static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
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 "?";
514 /***********************************************************************
515 * DEBUG_ModuleCompare
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
520 static int DEBUG_ModuleCompare(const void* p1, const void* p2)
522 return (*((const DBG_MODULE**)p1))->load_addr -
523 (*((const DBG_MODULE**)p2))->load_addr;
526 /***********************************************************************
527 * DEBUG_IsContainer
529 * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
531 static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
532 const DBG_MODULE* wmod_child)
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;
539 static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
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);
548 /***********************************************************************
549 * DEBUG_InfoShare
551 * Display shared libarary information.
553 void DEBUG_InfoShare(void)
555 DBG_MODULE** ref;
556 int i, j;
558 ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
559 if (!ref) return;
561 DEBUG_Printf(DBG_CHN_MESG, "Module\tAddress\t\t\tName\t%d modules\n",
562 DEBUG_CurrProcess->num_modules);
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);
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;
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);
592 DBG_free(ref);
595 /***********************************************************************
596 * DEBUG_DumpModule
597 * Display information about a given module (DLL or EXE)
599 void DEBUG_DumpModule(DWORD mod)
601 DBG_MODULE* wmod;
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;
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));
615 /***********************************************************************
616 * DEBUG_WalkModules
618 * Display information about all modules (DLLs and EXEs)
620 void DEBUG_WalkModules(void)
622 DBG_MODULE** amod;
623 int i;
625 DEBUG_Printf(DBG_CHN_MESG, "Address\t\t\tModule\tName\n");
627 amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
628 if (!amod) return;
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;
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);
642 DBG_free(amod);