Don't create the WINEPREFIX directory if it doesn't exist.
[wine/multimedia.git] / debugger / module.c
blobcce20da63509743f315a908423c84658a2118a81
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
7 */
8 #include "config.h"
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "debugger.h"
13 #include "wingdi.h"
14 #include "winuser.h"
16 /***********************************************************************
17 * Creates and links a new module to the current process
20 DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
21 void* mod_addr, u_long size, HMODULE hmodule)
23 DBG_MODULE* wmod;
25 if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
26 return NULL;
28 memset(wmod, 0, sizeof(*wmod));
30 wmod->dil = DIL_DEFERRED;
31 wmod->main = (DEBUG_CurrProcess->num_modules == 0);
32 wmod->type = type;
33 wmod->load_addr = mod_addr;
34 wmod->size = size;
35 wmod->handle = hmodule;
36 wmod->dbg_index = DEBUG_CurrProcess->next_index;
37 wmod->module_name = DBG_strdup(name);
39 DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules,
40 ++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*));
41 DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod;
43 return wmod;
46 /***********************************************************************
47 * DEBUG_FindModuleByName
50 DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
52 int i;
53 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
55 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
56 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
57 !strcasecmp(name, amod[i]->module_name))
58 return amod[i];
60 return NULL;
63 /***********************************************************************
64 * DEBUG_FindModuleByAddr
66 * either the addr where module is loaded, or any address inside the
67 * module
69 DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
71 int i;
72 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
73 DBG_MODULE* res = NULL;
75 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
76 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
77 (u_long)addr >= (u_long)amod[i]->load_addr &&
78 (u_long)addr < (u_long)amod[i]->load_addr + (u_long)amod[i]->size) {
79 /* amod[i] contains it... check against res now */
80 if (!res || res->load_addr < amod[i]->load_addr)
81 res = amod[i];
84 return res;
87 /***********************************************************************
88 * DEBUG_FindModuleByHandle
90 DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
92 int i;
93 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
95 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
96 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
97 handle == amod[i]->handle)
98 return amod[i];
100 return NULL;
103 /***********************************************************************
104 * DEBUG_GetProcessMainModule
106 DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
108 if (!process || !process->num_modules) return NULL;
110 /* main module is the first to be loaded on a given process, so it's the first
111 * in the array */
112 assert(process->modules[0]->main);
113 return process->modules[0];
116 /***********************************************************************
117 * DEBUG_RegisterELFModule
119 * ELF modules are also entered into the list - this is so that we
120 * can make 'info shared' types of displays possible.
122 DBG_MODULE* DEBUG_RegisterELFModule(u_long load_addr, u_long size, const char* name)
124 DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, (void*)load_addr, size, 0);
126 if (!wmod) return NULL;
128 DEBUG_CurrProcess->next_index++;
130 return wmod;
133 /***********************************************************************
134 * DEBUG_RegisterPEModule
137 DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, u_long load_addr, u_long size, const char *module_name)
139 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, (void*)load_addr, size, hModule);
141 if (!wmod) return NULL;
143 DEBUG_CurrProcess->next_index++;
145 return wmod;
148 /***********************************************************************
149 * DEBUG_RegisterNEModule
152 DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, u_long size, const char *module_name)
154 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
156 if (!wmod) return NULL;
158 DEBUG_CurrProcess->next_index++;
159 return wmod;
162 #if 0
163 /***********************************************************************
164 * DEBUG_GetEP16
166 * Helper function fo DEBUG_LoadModuleEPs16:
167 * finds the address of a given entry point from a given module
169 static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
170 WORD ordinal, DBG_ADDR* addr)
172 void* idx;
173 ET_ENTRY entry;
174 ET_BUNDLE bundle;
175 SEGTABLEENTRY ste;
177 bundle.next = module->entry_table;
178 do {
179 if (!bundle.next)
180 return FALSE;
181 idx = moduleAddr + bundle.next;
182 if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle)))
183 return FALSE;
184 } while ((ordinal < bundle.first + 1) || (ordinal > bundle.last));
186 if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) +
187 (ordinal - bundle.first - 1) * sizeof(ET_ENTRY),
188 &entry, sizeof(ET_ENTRY)))
189 return FALSE;
191 addr->seg = entry.segnum;
192 addr->off = entry.offs;
194 if (addr->seg == 0xfe) addr->seg = 0xffff; /* constant entry */
195 else {
196 if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table +
197 sizeof(ste) * (addr->seg - 1),
198 &ste, sizeof(ste)))
199 return FALSE;
200 addr->seg = GlobalHandleToSel16(ste.hSeg);
202 return TRUE;
205 /***********************************************************************
206 * DEBUG_LoadModule16
208 * Load the entry points of a Win16 module into the hash table.
210 static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
212 DBG_VALUE value;
213 BYTE buf[1 + 256 + 2];
214 char epname[512];
215 char* cpnt;
216 DBG_MODULE* wmod;
218 wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
220 value.type = NULL;
221 value.cookie = DV_TARGET;
222 value.addr.seg = 0;
223 value.addr.off = 0;
225 cpnt = moduleAddr + module->name_table;
227 /* First search the resident names */
229 /* skip module name */
230 if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0])
231 return;
232 cpnt += 1 + buf[0] + sizeof(WORD);
234 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
235 sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]);
236 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
237 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
239 cpnt += buf[0] + 1 + sizeof(WORD);
242 /* Now search the non-resident names table */
243 if (!module->nrname_handle) return; /* No non-resident table */
244 cpnt = (char *)GlobalLock16(module->nrname_handle);
245 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
246 sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]);
247 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
248 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
250 cpnt += buf[0] + 1 + sizeof(WORD);
252 GlobalUnlock16(module->nrname_handle);
254 #endif
256 /***********************************************************************
257 * DEBUG_LoadModule32
259 void DEBUG_LoadModule32(const char* name, HANDLE hFile, DWORD base)
261 IMAGE_NT_HEADERS pe_header;
262 DWORD nth_ofs;
263 DBG_MODULE* wmod = NULL;
264 int i;
265 IMAGE_SECTION_HEADER pe_seg;
266 DWORD pe_seg_ofs;
267 DWORD size = 0;
268 enum DbgInfoLoad dil = DIL_ERROR;
270 /* grab PE Header */
271 if (!DEBUG_READ_MEM_VERBOSE((void*)(base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew)),
272 &nth_ofs, sizeof(nth_ofs)) ||
273 !DEBUG_READ_MEM_VERBOSE((void*)(base + nth_ofs), &pe_header, sizeof(pe_header)))
274 return;
276 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
277 pe_header.FileHeader.SizeOfOptionalHeader;
279 for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
280 if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg)))
281 continue;
282 if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData)
283 size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData;
286 /* FIXME: we make the assumption that hModule == base */
287 wmod = DEBUG_RegisterPEModule((HMODULE)base, base, size, name);
288 if (wmod) {
289 dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs);
290 if (dil != DIL_LOADED)
291 dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs);
292 if (dil != DIL_LOADED)
293 dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs);
296 if (wmod) wmod->dil = dil;
297 DEBUG_ReportDIL(dil, "32bit DLL", name, base);
300 /***********************************************************************
301 * DEBUG_RegisterPEDebugInfo
303 enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
304 void* _nth, unsigned long nth_ofs)
306 DBG_VALUE value;
307 char buffer[512];
308 char bufstr[256];
309 unsigned int i;
310 IMAGE_SECTION_HEADER pe_seg;
311 DWORD pe_seg_ofs;
312 IMAGE_DATA_DIRECTORY dir;
313 DWORD dir_ofs;
314 const char* prefix;
315 IMAGE_NT_HEADERS* nth = (PIMAGE_NT_HEADERS)_nth;
316 DWORD base = (u_long)wmod->load_addr;
318 value.type = NULL;
319 value.cookie = DV_TARGET;
320 value.addr.seg = 0;
321 value.addr.off = 0;
323 /* Add start of DLL */
324 value.addr.off = base;
325 if ((prefix = strrchr(wmod->module_name, '\\' ))) prefix++;
326 else prefix = wmod->module_name;
328 DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
330 /* Add entry point */
331 snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix);
332 value.addr.off = base + nth->OptionalHeader.AddressOfEntryPoint;
333 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
335 /* Add start of sections */
336 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
337 nth->FileHeader.SizeOfOptionalHeader;
339 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
340 if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg)))
341 continue;
342 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
343 value.addr.off = base + pe_seg.VirtualAddress;
344 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
347 /* Add exported functions */
348 dir_ofs = nth_ofs +
349 OFFSET_OF(IMAGE_NT_HEADERS,
350 OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
351 if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir_ofs), &dir, sizeof(dir)) && dir.Size) {
352 IMAGE_EXPORT_DIRECTORY exports;
353 WORD* ordinals = NULL;
354 void** functions = NULL;
355 DWORD* names = NULL;
356 unsigned int j;
358 if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir.VirtualAddress),
359 &exports, sizeof(exports)) &&
361 ((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
362 DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfFunctions),
363 functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
365 ((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
366 DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNameOrdinals),
367 ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
369 ((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
370 DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNames),
371 names, sizeof(names[0]) * exports.NumberOfNames)) {
373 for (i = 0; i < exports.NumberOfNames; i++) {
374 if (!names[i] ||
375 !DEBUG_READ_MEM_VERBOSE((void*)(base + names[i]), bufstr, sizeof(bufstr)))
376 continue;
377 bufstr[sizeof(bufstr) - 1] = 0;
378 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
379 value.addr.off = base + (DWORD)functions[ordinals[i]];
380 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
383 for (i = 0; i < exports.NumberOfFunctions; i++) {
384 if (!functions[i]) continue;
385 /* Check if we already added it with a name */
386 for (j = 0; j < exports.NumberOfNames; j++)
387 if ((ordinals[j] == i) && names[j]) break;
388 if (j < exports.NumberOfNames) continue;
389 snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base);
390 value.addr.off = base + (DWORD)functions[i];
391 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
394 DBG_free(functions);
395 DBG_free(ordinals);
396 DBG_free(names);
398 /* no real debug info, only entry points */
399 return DIL_NOINFO;
402 /***********************************************************************
403 * DEBUG_LoadEntryPoints
405 * Load the entry points of all the modules into the hash table.
407 int DEBUG_LoadEntryPoints(const char* pfx)
409 int first = 0;
410 /* FIXME: with address space separation in space, this is plain wrong
411 * it requires the 16 bit WOW debugging interface...
413 #if 0
414 MODULEENTRY entry;
415 NE_MODULE module;
416 void* moduleAddr;
417 int rowcount = 0;
418 int len;
420 /* FIXME: we assume that a module is never removed from memory */
421 /* FIXME: this is (currently plain wrong when debugger is started by
422 * attaching to an existing program => the 16 bit modules will
423 * not be shared... not much to do on debugger side... sigh
425 if (ModuleFirst16(&entry)) do {
426 if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) ||
427 !(moduleAddr = NE_GetPtr(entry.hModule)) ||
428 !DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) ||
429 (module.flags & NE_FFLAGS_WIN32) /* NE module */)
430 continue;
431 if (!first) {
432 if (pfx) DEBUG_Printf(DBG_CHN_MESG, pfx);
433 DEBUG_Printf(DBG_CHN_MESG, " ");
434 rowcount = 3 + (pfx ? strlen(pfx) : 0);
435 first = 1;
438 len = strlen(entry.szModule);
439 if ((rowcount + len) > 76) {
440 DEBUG_Printf(DBG_CHN_MESG, "\n ");
441 rowcount = 3;
443 DEBUG_Printf(DBG_CHN_MESG, " %s", entry.szModule);
444 rowcount += len + 1;
446 DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
447 } while (ModuleNext16(&entry));
448 #endif
450 if (first) DEBUG_Printf(DBG_CHN_MESG, "\n");
451 return first;
454 void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, DWORD load_addr)
456 const char* fmt;
458 switch (dil) {
459 case DIL_DEFERRED:
460 fmt = "Deferring debug information loading for %s '%s' (0x%08x)\n";
461 break;
462 case DIL_LOADED:
463 fmt = "Loaded debug information from %s '%s' (0x%08x)\n";
464 break;
465 case DIL_NOINFO:
466 fmt = "No debug information in %s '%s' (0x%08x)\n";
467 break;
468 case DIL_ERROR:
469 fmt = "Can't find file for %s '%s' (0x%08x)\n";
470 break;
471 default:
472 DEBUG_Printf(DBG_CHN_ERR, "Oooocch (%d)\n", dil);
473 return;
476 DEBUG_Printf(DBG_CHN_MESG, fmt, pfx, filename, load_addr);
479 static const char* DEBUG_GetModuleType(enum DbgModuleType type)
481 switch (type) {
482 case DMT_NE: return "NE";
483 case DMT_PE: return "PE";
484 case DMT_ELF: return "ELF";
485 default: return "???";;
489 static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
491 switch (dil) {
492 case DIL_LOADED: return "loaded";
493 case DIL_DEFERRED: return "deferred";
494 case DIL_NOINFO: return "none";
495 case DIL_ERROR: return "error";
496 default: return "?";
500 /***********************************************************************
501 * DEBUG_ModuleCompare
503 * returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2
504 * order used is order on load_addr of a module
506 static int DEBUG_ModuleCompare(const void* p1, const void* p2)
508 return (*((const DBG_MODULE**)p1))->load_addr -
509 (*((const DBG_MODULE**)p2))->load_addr;
512 /***********************************************************************
513 * DEBUG_IsContainer
515 * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
517 static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
518 const DBG_MODULE* wmod_child)
520 return wmod_cntnr->load_addr < wmod_child->load_addr &&
521 (DWORD)wmod_cntnr->load_addr + wmod_cntnr->size >
522 (DWORD)wmod_child->load_addr + wmod_child->size;
525 static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
527 if (ident) DEBUG_Printf(DBG_CHN_MESG, " \\-");
528 DEBUG_Printf(DBG_CHN_MESG, "%s\t0x%08lx-%08lx\t%s\n",
529 DEBUG_GetModuleType(module->type),
530 (DWORD)module->load_addr, (DWORD)module->load_addr + module->size,
531 module->module_name);
534 /***********************************************************************
535 * DEBUG_InfoShare
537 * Display shared libarary information.
539 void DEBUG_InfoShare(void)
541 DBG_MODULE** ref;
542 int i, j;
544 ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
545 if (!ref) return;
547 DEBUG_Printf(DBG_CHN_MESG, "Module\tAddress\t\t\tName\t%d modules\n",
548 DEBUG_CurrProcess->num_modules);
550 memcpy(ref, DEBUG_CurrProcess->modules,
551 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
552 qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
553 DEBUG_ModuleCompare);
554 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
555 switch (ref[i]->type) {
556 case DMT_ELF:
557 DEBUG_InfoShareModule(ref[i], 0);
558 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
559 if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j]))
560 DEBUG_InfoShareModule(ref[j], 1);
562 break;
563 case DMT_NE:
564 case DMT_PE:
565 /* check module is not in ELF */
566 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
567 if (ref[j]->type == DMT_ELF &&
568 DEBUG_IsContainer(ref[j], ref[i]))
569 break;
571 if (j >= DEBUG_CurrProcess->num_modules)
572 DEBUG_InfoShareModule(ref[i], 0);
573 break;
574 default:
575 DEBUG_Printf(DBG_CHN_ERR, "Unknown type (%d)\n", ref[i]->type);
578 DBG_free(ref);
581 /***********************************************************************
582 * DEBUG_DumpModule
583 * Display information about a given module (DLL or EXE)
585 void DEBUG_DumpModule(DWORD mod)
587 DBG_MODULE* wmod;
589 if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) &&
590 !(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) {
591 DEBUG_Printf(DBG_CHN_MESG, "'0x%08lx' is not a valid module handle or address\n", mod);
592 return;
595 DEBUG_Printf(DBG_CHN_MESG, "Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n",
596 wmod->module_name, wmod->handle, (DWORD)wmod->load_addr,
597 (DWORD)wmod->load_addr + wmod->size,
598 DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil));
601 /***********************************************************************
602 * DEBUG_WalkModules
604 * Display information about all modules (DLLs and EXEs)
606 void DEBUG_WalkModules(void)
608 DBG_MODULE** amod;
609 int i;
611 DEBUG_Printf(DBG_CHN_MESG, "Address\t\t\tModule\tName\n");
613 amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
614 if (!amod) return;
616 memcpy(amod, DEBUG_CurrProcess->modules,
617 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
618 qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
619 DEBUG_ModuleCompare);
620 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
621 if (amod[i]->type == DMT_ELF) continue;
623 DEBUG_Printf(DBG_CHN_MESG, "0x%08lx-%08lx\t(%s)\t%s\n",
624 (DWORD)amod[i]->load_addr,
625 (DWORD)amod[i]->load_addr + amod[i]->size,
626 DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name);
628 DBG_free(amod);