Translate msrle32 and oledlg resources.
[wine.git] / programs / winedbg / module.c
blobe387be6a4352e39376a259ca2e48e5ffed26933e
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"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
33 /***********************************************************************
34 * Creates and links a new module to the current process
37 static DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
38 void* mod_addr, unsigned long size, HMODULE hmodule)
40 DBG_MODULE* wmod;
42 if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
43 return NULL;
45 memset(wmod, 0, sizeof(*wmod));
47 wmod->dil = DIL_DEFERRED;
48 wmod->main = (DEBUG_CurrProcess->num_modules == 0);
49 wmod->type = type;
50 wmod->load_addr = mod_addr;
51 wmod->size = size;
52 wmod->handle = hmodule;
53 wmod->dbg_index = DEBUG_CurrProcess->next_index;
54 wmod->module_name = DBG_strdup(name);
56 DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules,
57 ++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*));
58 DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod;
60 return wmod;
63 /***********************************************************************
64 * DEBUG_FindModuleByName
67 DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type)
69 int i;
70 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
72 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
73 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
74 !strcasecmp(name, amod[i]->module_name))
75 return amod[i];
77 return NULL;
80 /***********************************************************************
81 * DEBUG_FindModuleByAddr
83 * either the addr where module is loaded, or any address inside the
84 * module
86 DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type)
88 int i;
89 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
90 DBG_MODULE* res = NULL;
92 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
93 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
94 (char *)addr >= (char *)amod[i]->load_addr &&
95 (char *)addr < (char *)amod[i]->load_addr + amod[i]->size) {
96 /* amod[i] contains it... check against res now */
97 if (!res || res->load_addr < amod[i]->load_addr)
98 res = amod[i];
101 return res;
104 /***********************************************************************
105 * DEBUG_FindModuleByHandle
107 DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type)
109 int i;
110 DBG_MODULE** amod = DEBUG_CurrProcess->modules;
112 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
113 if ((type == DMT_UNKNOWN || type == amod[i]->type) &&
114 handle == amod[i]->handle)
115 return amod[i];
117 return NULL;
120 /***********************************************************************
121 * DEBUG_GetProcessMainModule
123 DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
125 if (!process || !process->num_modules) return NULL;
127 /* main module is the first to be loaded on a given process, so it's the first
128 * in the array */
129 assert(process->modules[0]->main);
130 return process->modules[0];
133 /***********************************************************************
134 * DEBUG_RegisterELFModule
136 * ELF modules are also entered into the list - this is so that we
137 * can make 'info shared' types of displays possible.
139 DBG_MODULE* DEBUG_RegisterELFModule(void *load_addr, unsigned long size, const char* name)
141 DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, load_addr, size, 0);
143 if (!wmod) return NULL;
145 DEBUG_CurrProcess->next_index++;
147 return wmod;
150 /***********************************************************************
151 * DEBUG_RegisterPEModule
154 static DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, void *load_addr,
155 unsigned long size, const char *module_name)
157 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, load_addr, size, hModule);
159 if (!wmod) return NULL;
161 DEBUG_CurrProcess->next_index++;
163 return wmod;
166 #if 0
167 /***********************************************************************
168 * DEBUG_RegisterNEModule
171 static DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr,
172 unsigned long size, const char *module_name)
174 DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule);
176 if (!wmod) return NULL;
178 DEBUG_CurrProcess->next_index++;
179 return wmod;
182 /***********************************************************************
183 * DEBUG_GetEP16
185 * Helper function fo DEBUG_LoadModuleEPs16:
186 * finds the address of a given entry point from a given module
188 static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module,
189 WORD ordinal, DBG_ADDR* addr)
191 void* idx;
192 ET_ENTRY entry;
193 ET_BUNDLE bundle;
194 SEGTABLEENTRY ste;
196 bundle.next = module->entry_table;
197 do {
198 if (!bundle.next)
199 return FALSE;
200 idx = moduleAddr + bundle.next;
201 if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle)))
202 return FALSE;
203 } while ((ordinal < bundle.first + 1) || (ordinal > bundle.last));
205 if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) +
206 (ordinal - bundle.first - 1) * sizeof(ET_ENTRY),
207 &entry, sizeof(ET_ENTRY)))
208 return FALSE;
210 addr->seg = entry.segnum;
211 addr->off = entry.offs;
213 if (addr->seg == 0xfe) addr->seg = 0xffff; /* constant entry */
214 else {
215 if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table +
216 sizeof(ste) * (addr->seg - 1),
217 &ste, sizeof(ste)))
218 return FALSE;
219 addr->seg = GlobalHandleToSel16(ste.hSeg);
221 return TRUE;
224 /***********************************************************************
225 * DEBUG_LoadModule16
227 * Load the entry points of a Win16 module into the hash table.
229 static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name)
231 DBG_VALUE value;
232 BYTE buf[1 + 256 + 2];
233 char epname[512];
234 char* cpnt;
235 DBG_MODULE* wmod;
237 wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name);
239 value.type = NULL;
240 value.cookie = DV_TARGET;
241 value.addr.seg = 0;
242 value.addr.off = 0;
244 cpnt = moduleAddr + module->name_table;
246 /* First search the resident names */
248 /* skip module name */
249 if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0])
250 return;
251 cpnt += 1 + buf[0] + sizeof(WORD);
253 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
254 snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
255 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
256 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
258 cpnt += buf[0] + 1 + sizeof(WORD);
261 /* Now search the non-resident names table */
262 if (!module->nrname_handle) return; /* No non-resident table */
263 cpnt = (char *)GlobalLock16(module->nrname_handle);
264 while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) {
265 snprintf(epname, sizeof(epname), "%s.%.*s", name, buf[0], &buf[1]);
266 if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) {
267 DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC);
269 cpnt += buf[0] + 1 + sizeof(WORD);
271 GlobalUnlock16(module->nrname_handle);
273 #endif
275 /***********************************************************************
276 * DEBUG_LoadModule32
278 void DEBUG_LoadModule32(const char* name, HANDLE hFile, void *base)
280 IMAGE_NT_HEADERS pe_header;
281 DWORD nth_ofs;
282 DBG_MODULE* wmod = NULL;
283 int i;
284 IMAGE_SECTION_HEADER pe_seg;
285 DWORD pe_seg_ofs;
286 DWORD size = 0;
287 enum DbgInfoLoad dil = DIL_ERROR;
289 /* grab PE Header */
290 if (!DEBUG_READ_MEM_VERBOSE( (char *)base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew),
291 &nth_ofs, sizeof(nth_ofs)) ||
292 !DEBUG_READ_MEM_VERBOSE( (char *)base + nth_ofs, &pe_header, sizeof(pe_header)))
293 return;
295 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
296 pe_header.FileHeader.SizeOfOptionalHeader;
298 for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
299 if (!DEBUG_READ_MEM_VERBOSE( (char *)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
300 continue;
301 if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData)
302 size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData;
305 /* FIXME: we make the assumption that hModule == base */
306 wmod = DEBUG_RegisterPEModule((HMODULE)base, base, size, name);
307 if (wmod) {
308 dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs);
309 if (dil != DIL_LOADED)
310 dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs);
311 if (dil != DIL_LOADED)
312 dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs);
313 wmod->dil = dil;
316 DEBUG_ReportDIL(dil, "32bit DLL", name, base);
319 /***********************************************************************
320 * DEBUG_RegisterPEDebugInfo
322 enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
323 void* _nth, unsigned long nth_ofs)
325 DBG_VALUE value;
326 char buffer[512];
327 char bufstr[256];
328 unsigned int i;
329 IMAGE_SECTION_HEADER pe_seg;
330 DWORD pe_seg_ofs;
331 IMAGE_DATA_DIRECTORY dir;
332 DWORD dir_ofs;
333 const char* prefix;
334 IMAGE_NT_HEADERS* nth = (PIMAGE_NT_HEADERS)_nth;
335 void * base = wmod->load_addr;
337 value.type = NULL;
338 value.cookie = DV_TARGET;
339 value.addr.seg = 0;
340 value.addr.off = 0;
342 /* Add start of DLL */
343 value.addr.off = (unsigned long)base;
344 if ((prefix = strrchr(wmod->module_name, '\\' ))) prefix++;
345 else prefix = wmod->module_name;
347 DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC);
349 /* Add entry point */
350 snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix);
351 value.addr.off = (unsigned long)base + nth->OptionalHeader.AddressOfEntryPoint;
352 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
354 /* Add start of sections */
355 pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
356 nth->FileHeader.SizeOfOptionalHeader;
358 for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) {
359 if (!DEBUG_READ_MEM_VERBOSE( (char *)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
360 continue;
361 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
362 value.addr.off = (unsigned long)base + pe_seg.VirtualAddress;
363 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
366 /* Add exported functions */
367 dir_ofs = nth_ofs +
368 OFFSET_OF(IMAGE_NT_HEADERS,
369 OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
370 if (DEBUG_READ_MEM_VERBOSE( (char *)base + dir_ofs, &dir, sizeof(dir)) && dir.Size) {
371 IMAGE_EXPORT_DIRECTORY exports;
372 WORD* ordinals = NULL;
373 void** functions = NULL;
374 DWORD* names = NULL;
375 unsigned int j;
377 if (DEBUG_READ_MEM_VERBOSE( (char *)base + dir.VirtualAddress,
378 &exports, sizeof(exports)) &&
380 ((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
381 DEBUG_READ_MEM_VERBOSE( (char *)base + exports.AddressOfFunctions,
382 functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
384 ((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
385 DEBUG_READ_MEM_VERBOSE( (char *)base + (DWORD)exports.AddressOfNameOrdinals,
386 ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
388 ((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
389 DEBUG_READ_MEM_VERBOSE( (char *)base + (DWORD)exports.AddressOfNames,
390 names, sizeof(names[0]) * exports.NumberOfNames)) {
392 for (i = 0; i < exports.NumberOfNames; i++) {
393 if (!names[i] ||
394 !DEBUG_READ_MEM_VERBOSE( (char *)base + names[i], bufstr, sizeof(bufstr)))
395 continue;
396 bufstr[sizeof(bufstr) - 1] = 0;
397 snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
398 value.addr.off = (unsigned long)base + (DWORD)functions[ordinals[i]];
399 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
402 for (i = 0; i < exports.NumberOfFunctions; i++) {
403 if (!functions[i]) continue;
404 /* Check if we already added it with a name */
405 for (j = 0; j < exports.NumberOfNames; j++)
406 if ((ordinals[j] == i) && names[j]) break;
407 if (j < exports.NumberOfNames) continue;
408 snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base);
409 value.addr.off = (unsigned long)base + (DWORD)functions[i];
410 DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
413 DBG_free(functions);
414 DBG_free(ordinals);
415 DBG_free(names);
417 /* no real debug info, only entry points */
418 return DIL_NOINFO;
421 /***********************************************************************
422 * DEBUG_LoadEntryPoints
424 * Load the entry points of all the modules into the hash table.
426 int DEBUG_LoadEntryPoints(const char* pfx)
428 int first = 0;
429 /* FIXME: with address space separation in space, this is plain wrong
430 * it requires the 16 bit WOW debugging interface...
432 #if 0
433 MODULEENTRY entry;
434 NE_MODULE module;
435 void* moduleAddr;
436 int rowcount = 0;
437 int len;
439 /* FIXME: we assume that a module is never removed from memory */
440 /* FIXME: this is (currently plain wrong when debugger is started by
441 * attaching to an existing program => the 16 bit modules will
442 * not be shared... not much to do on debugger side... sigh
444 if (ModuleFirst16(&entry)) do {
445 if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) ||
446 !(moduleAddr = NE_GetPtr(entry.hModule)) ||
447 !DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) ||
448 (module.flags & NE_FFLAGS_WIN32) /* NE module */)
449 continue;
450 if (!first) {
451 if (pfx) DEBUG_Printf(pfx);
452 DEBUG_Printf(" ");
453 rowcount = 3 + (pfx ? strlen(pfx) : 0);
454 first = 1;
457 len = strlen(entry.szModule);
458 if ((rowcount + len) > 76) {
459 DEBUG_Printf("\n ");
460 rowcount = 3;
462 DEBUG_Printf(" %s", entry.szModule);
463 rowcount += len + 1;
465 DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
466 } while (ModuleNext16(&entry));
467 #endif
469 if (first) DEBUG_Printf("\n");
470 return first;
473 void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, void *load_addr)
475 const char* fmt;
477 switch (dil) {
478 case DIL_DEFERRED:
479 fmt = "Deferring debug information loading for %s '%s' (%p)\n";
480 break;
481 case DIL_LOADED:
482 fmt = "Loaded debug information from %s '%s' (%p)\n";
483 break;
484 case DIL_NOINFO:
485 fmt = "No debug information in %s '%s' (%p)\n";
486 break;
487 case DIL_ERROR:
488 fmt = "Can't find file for %s '%s' (%p)\n";
489 break;
490 default:
491 WINE_ERR("Oooocch (%d)\n", dil);
492 return;
495 DEBUG_Printf(fmt, pfx, filename, load_addr);
498 static const char* DEBUG_GetModuleType(enum DbgModuleType type)
500 switch (type) {
501 case DMT_NE: return "NE";
502 case DMT_PE: return "PE";
503 case DMT_ELF: return "ELF";
504 default: return "???";
508 static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil)
510 switch (dil) {
511 case DIL_LOADED: return "loaded";
512 case DIL_DEFERRED: return "deferred";
513 case DIL_NOINFO: return "none";
514 case DIL_ERROR: return "error";
515 default: return "?";
519 /***********************************************************************
520 * DEBUG_ModuleCompare
522 * returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2
523 * order used is order on load_addr of a module
525 static int DEBUG_ModuleCompare(const void* p1, const void* p2)
527 return (char*)(*((const DBG_MODULE**)p1))->load_addr -
528 (char*)(*((const DBG_MODULE**)p2))->load_addr;
531 /***********************************************************************
532 * DEBUG_IsContainer
534 * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr
536 static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr,
537 const DBG_MODULE* wmod_child)
539 return wmod_cntnr->load_addr < wmod_child->load_addr &&
540 (DWORD)wmod_cntnr->load_addr + wmod_cntnr->size >
541 (DWORD)wmod_child->load_addr + wmod_child->size;
544 static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident)
546 if (ident) DEBUG_Printf(" \\-");
547 DEBUG_Printf("%s\t0x%08lx-%08lx\t%s\n",
548 DEBUG_GetModuleType(module->type),
549 (DWORD)module->load_addr, (DWORD)module->load_addr + module->size,
550 module->module_name);
553 /***********************************************************************
554 * DEBUG_InfoShare
556 * Display shared libarary information.
558 void DEBUG_InfoShare(void)
560 DBG_MODULE** ref;
561 int i, j;
563 ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
564 if (!ref) return;
566 DEBUG_Printf("Module\tAddress\t\t\tName\t%d modules\n",
567 DEBUG_CurrProcess->num_modules);
569 memcpy(ref, DEBUG_CurrProcess->modules,
570 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
571 qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
572 DEBUG_ModuleCompare);
573 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
574 switch (ref[i]->type) {
575 case DMT_ELF:
576 DEBUG_InfoShareModule(ref[i], 0);
577 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
578 if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j]))
579 DEBUG_InfoShareModule(ref[j], 1);
581 break;
582 case DMT_NE:
583 case DMT_PE:
584 /* check module is not in ELF */
585 for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) {
586 if (ref[j]->type == DMT_ELF &&
587 DEBUG_IsContainer(ref[j], ref[i]))
588 break;
590 if (j >= DEBUG_CurrProcess->num_modules)
591 DEBUG_InfoShareModule(ref[i], 0);
592 break;
593 default:
594 WINE_ERR("Unknown type (%d)\n", ref[i]->type);
597 DBG_free(ref);
600 /***********************************************************************
601 * DEBUG_DumpModule
602 * Display information about a given module (DLL or EXE)
604 void DEBUG_DumpModule(DWORD mod)
606 DBG_MODULE* wmod;
608 if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) &&
609 !(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) {
610 DEBUG_Printf("'0x%08lx' is not a valid module handle or address\n", mod);
611 return;
614 DEBUG_Printf("Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n",
615 wmod->module_name, wmod->handle, (DWORD)wmod->load_addr,
616 (DWORD)wmod->load_addr + wmod->size,
617 DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil));
620 /***********************************************************************
621 * DEBUG_WalkModules
623 * Display information about all modules (DLLs and EXEs)
625 void DEBUG_WalkModules(void)
627 DBG_MODULE** amod;
628 int i;
630 if (!DEBUG_CurrProcess)
632 DEBUG_Printf("Cannot walk classes while no process is loaded\n");
633 return;
636 DEBUG_Printf("Address\t\t\tModule\tName\n");
638 amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
639 if (!amod) return;
641 memcpy(amod, DEBUG_CurrProcess->modules,
642 sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules);
643 qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*),
644 DEBUG_ModuleCompare);
645 for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) {
646 if (amod[i]->type == DMT_ELF) continue;
648 DEBUG_Printf("0x%08lx-%08lx\t(%s)\t%s\n",
649 (DWORD)amod[i]->load_addr,
650 (DWORD)amod[i]->load_addr + amod[i]->size,
651 DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name);
653 DBG_free(amod);