| /* -*- tab-width: 8; c-basic-offset: 4 -*- */ | |
| /* | |
| * File module.c - module handling for the wine debugger | |
| * | |
| * Copyright (C) 1993, Eric Youngdale. | |
| * 2000, Eric Pouech | |
| */ | |
| #include "config.h" | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "debugger.h" | |
| #include "toolhelp.h" | |
| #include "wingdi.h" | |
| #include "winuser.h" | |
| /*********************************************************************** | |
| * Creates and links a new module to the current process | |
| * | |
| */ | |
| DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type, | |
| void* mod_addr, u_long size, HMODULE hmodule) | |
| { | |
| DBG_MODULE* wmod; | |
| if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod)))) | |
| return NULL; | |
| memset(wmod, 0, sizeof(*wmod)); | |
| wmod->dil = DIL_DEFERRED; | |
| wmod->main = (DEBUG_CurrProcess->num_modules == 0); | |
| wmod->type = type; | |
| wmod->load_addr = mod_addr; | |
| wmod->size = size; | |
| wmod->handle = hmodule; | |
| wmod->dbg_index = DEBUG_CurrProcess->next_index; | |
| wmod->module_name = DBG_strdup(name); | |
| DEBUG_CurrProcess->modules = DBG_realloc(DEBUG_CurrProcess->modules, | |
| ++DEBUG_CurrProcess->num_modules * sizeof(DBG_MODULE*)); | |
| DEBUG_CurrProcess->modules[DEBUG_CurrProcess->num_modules - 1] = wmod; | |
| return wmod; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_FindModuleByName | |
| * | |
| */ | |
| DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type) | |
| { | |
| int i; | |
| DBG_MODULE** amod = DEBUG_CurrProcess->modules; | |
| for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) { | |
| if ((type == DMT_UNKNOWN || type == amod[i]->type) && | |
| !strcasecmp(name, amod[i]->module_name)) | |
| return amod[i]; | |
| } | |
| return NULL; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_FindModuleByAddr | |
| * | |
| * either the addr where module is loaded, or any address inside the | |
| * module | |
| */ | |
| DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type) | |
| { | |
| int i; | |
| DBG_MODULE** amod = DEBUG_CurrProcess->modules; | |
| DBG_MODULE* res = NULL; | |
| for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) { | |
| if ((type == DMT_UNKNOWN || type == amod[i]->type) && | |
| (u_long)addr >= (u_long)amod[i]->load_addr && | |
| (u_long)addr < (u_long)amod[i]->load_addr + (u_long)amod[i]->size) { | |
| /* amod[i] contains it... check against res now */ | |
| if (!res || res->load_addr < amod[i]->load_addr) | |
| res = amod[i]; | |
| } | |
| } | |
| return res; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_FindModuleByHandle | |
| */ | |
| DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type) | |
| { | |
| int i; | |
| DBG_MODULE** amod = DEBUG_CurrProcess->modules; | |
| for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) { | |
| if ((type == DMT_UNKNOWN || type == amod[i]->type) && | |
| handle == amod[i]->handle) | |
| return amod[i]; | |
| } | |
| return NULL; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_GetProcessMainModule | |
| */ | |
| DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process) | |
| { | |
| if (!process || !process->num_modules) return NULL; | |
| /* main module is the first to be loaded on a given process, so it's the first | |
| * in the array */ | |
| assert(process->modules[0]->main); | |
| return process->modules[0]; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_RegisterELFModule | |
| * | |
| * ELF modules are also entered into the list - this is so that we | |
| * can make 'info shared' types of displays possible. | |
| */ | |
| DBG_MODULE* DEBUG_RegisterELFModule(u_long load_addr, u_long size, const char* name) | |
| { | |
| DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, (void*)load_addr, size, 0); | |
| if (!wmod) return NULL; | |
| DEBUG_CurrProcess->next_index++; | |
| return wmod; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_RegisterPEModule | |
| * | |
| */ | |
| DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, u_long load_addr, u_long size, const char *module_name) | |
| { | |
| DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, (void*)load_addr, size, hModule); | |
| if (!wmod) return NULL; | |
| DEBUG_CurrProcess->next_index++; | |
| return wmod; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_RegisterNEModule | |
| * | |
| */ | |
| DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, u_long size, const char *module_name) | |
| { | |
| DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_NE, load_addr, size, hModule); | |
| if (!wmod) return NULL; | |
| DEBUG_CurrProcess->next_index++; | |
| return wmod; | |
| } | |
| #if 0 | |
| /*********************************************************************** | |
| * DEBUG_GetEP16 | |
| * | |
| * Helper function fo DEBUG_LoadModuleEPs16: | |
| * finds the address of a given entry point from a given module | |
| */ | |
| static BOOL DEBUG_GetEP16(char* moduleAddr, const NE_MODULE* module, | |
| WORD ordinal, DBG_ADDR* addr) | |
| { | |
| void* idx; | |
| ET_ENTRY entry; | |
| ET_BUNDLE bundle; | |
| SEGTABLEENTRY ste; | |
| bundle.next = module->entry_table; | |
| do { | |
| if (!bundle.next) | |
| return FALSE; | |
| idx = moduleAddr + bundle.next; | |
| if (!DEBUG_READ_MEM_VERBOSE(idx, &bundle, sizeof(bundle))) | |
| return FALSE; | |
| } while ((ordinal < bundle.first + 1) || (ordinal > bundle.last)); | |
| if (!DEBUG_READ_MEM_VERBOSE((char*)idx + sizeof(ET_BUNDLE) + | |
| (ordinal - bundle.first - 1) * sizeof(ET_ENTRY), | |
| &entry, sizeof(ET_ENTRY))) | |
| return FALSE; | |
| addr->seg = entry.segnum; | |
| addr->off = entry.offs; | |
| if (addr->seg == 0xfe) addr->seg = 0xffff; /* constant entry */ | |
| else { | |
| if (!DEBUG_READ_MEM_VERBOSE(moduleAddr + module->seg_table + | |
| sizeof(ste) * (addr->seg - 1), | |
| &ste, sizeof(ste))) | |
| return FALSE; | |
| addr->seg = GlobalHandleToSel16(ste.hSeg); | |
| } | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_LoadModule16 | |
| * | |
| * Load the entry points of a Win16 module into the hash table. | |
| */ | |
| static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleAddr, const char* name) | |
| { | |
| DBG_VALUE value; | |
| BYTE buf[1 + 256 + 2]; | |
| char epname[512]; | |
| char* cpnt; | |
| DBG_MODULE* wmod; | |
| wmod = DEBUG_RegisterNEModule(hModule, moduleAddr, name); | |
| value.type = NULL; | |
| value.cookie = DV_TARGET; | |
| value.addr.seg = 0; | |
| value.addr.off = 0; | |
| cpnt = moduleAddr + module->name_table; | |
| /* First search the resident names */ | |
| /* skip module name */ | |
| if (!DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) || !buf[0]) | |
| return; | |
| cpnt += 1 + buf[0] + sizeof(WORD); | |
| while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) { | |
| sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]); | |
| if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) { | |
| DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| } | |
| cpnt += buf[0] + 1 + sizeof(WORD); | |
| } | |
| /* Now search the non-resident names table */ | |
| if (!module->nrname_handle) return; /* No non-resident table */ | |
| cpnt = (char *)GlobalLock16(module->nrname_handle); | |
| while (DEBUG_READ_MEM_VERBOSE(cpnt, buf, sizeof(buf)) && buf[0]) { | |
| sprintf(epname, "%s.%.*s", name, buf[0], &buf[1]); | |
| if (DEBUG_GetEP16(moduleAddr, module, *(WORD*)&buf[1 + buf[0]], &value.addr)) { | |
| DEBUG_AddSymbol(epname, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| } | |
| cpnt += buf[0] + 1 + sizeof(WORD); | |
| } | |
| GlobalUnlock16(module->nrname_handle); | |
| } | |
| #endif | |
| /*********************************************************************** | |
| * DEBUG_LoadModule32 | |
| */ | |
| void DEBUG_LoadModule32(const char* name, HANDLE hFile, DWORD base) | |
| { | |
| IMAGE_NT_HEADERS pe_header; | |
| DWORD nth_ofs; | |
| DBG_MODULE* wmod = NULL; | |
| int i; | |
| IMAGE_SECTION_HEADER pe_seg; | |
| DWORD pe_seg_ofs; | |
| DWORD size = 0; | |
| enum DbgInfoLoad dil = DIL_ERROR; | |
| /* grab PE Header */ | |
| if (!DEBUG_READ_MEM_VERBOSE((void*)(base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew)), | |
| &nth_ofs, sizeof(nth_ofs)) || | |
| !DEBUG_READ_MEM_VERBOSE((void*)(base + nth_ofs), &pe_header, sizeof(pe_header))) | |
| return; | |
| pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + | |
| pe_header.FileHeader.SizeOfOptionalHeader; | |
| for (i = 0; i < pe_header.FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) { | |
| if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg))) | |
| continue; | |
| if (size < pe_seg.VirtualAddress + pe_seg.SizeOfRawData) | |
| size = pe_seg.VirtualAddress + pe_seg.SizeOfRawData; | |
| } | |
| /* FIXME: we make the assumption that hModule == base */ | |
| wmod = DEBUG_RegisterPEModule((HMODULE)base, base, size, name); | |
| if (wmod) { | |
| dil = DEBUG_RegisterStabsDebugInfo(wmod, hFile, &pe_header, nth_ofs); | |
| if (dil != DIL_LOADED) | |
| dil = DEBUG_RegisterMSCDebugInfo(wmod, hFile, &pe_header, nth_ofs); | |
| if (dil != DIL_LOADED) | |
| dil = DEBUG_RegisterPEDebugInfo(wmod, hFile, &pe_header, nth_ofs); | |
| } | |
| if (wmod) wmod->dil = dil; | |
| DEBUG_ReportDIL(dil, "32bit DLL", name, base); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_RegisterPEDebugInfo | |
| */ | |
| enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile, | |
| void* _nth, unsigned long nth_ofs) | |
| { | |
| DBG_VALUE value; | |
| char buffer[512]; | |
| char bufstr[256]; | |
| unsigned int i; | |
| IMAGE_SECTION_HEADER pe_seg; | |
| DWORD pe_seg_ofs; | |
| IMAGE_DATA_DIRECTORY dir; | |
| DWORD dir_ofs; | |
| const char* prefix; | |
| IMAGE_NT_HEADERS* nth = (PIMAGE_NT_HEADERS)_nth; | |
| DWORD base = (u_long)wmod->load_addr; | |
| value.type = NULL; | |
| value.cookie = DV_TARGET; | |
| value.addr.seg = 0; | |
| value.addr.off = 0; | |
| /* Add start of DLL */ | |
| value.addr.off = base; | |
| if ((prefix = strrchr(wmod->module_name, '\\' ))) prefix++; | |
| else prefix = wmod->module_name; | |
| DEBUG_AddSymbol(prefix, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| /* Add entry point */ | |
| snprintf(buffer, sizeof(buffer), "%s.EntryPoint", prefix); | |
| value.addr.off = base + nth->OptionalHeader.AddressOfEntryPoint; | |
| DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| /* Add start of sections */ | |
| pe_seg_ofs = nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) + | |
| nth->FileHeader.SizeOfOptionalHeader; | |
| for (i = 0; i < nth->FileHeader.NumberOfSections; i++, pe_seg_ofs += sizeof(pe_seg)) { | |
| if (!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_seg_ofs), &pe_seg, sizeof(pe_seg))) | |
| continue; | |
| snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name); | |
| value.addr.off = base + pe_seg.VirtualAddress; | |
| DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| } | |
| /* Add exported functions */ | |
| dir_ofs = nth_ofs + | |
| OFFSET_OF(IMAGE_NT_HEADERS, | |
| OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]); | |
| if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir_ofs), &dir, sizeof(dir)) && dir.Size) { | |
| IMAGE_EXPORT_DIRECTORY exports; | |
| WORD* ordinals = NULL; | |
| void** functions = NULL; | |
| DWORD* names = NULL; | |
| unsigned int j; | |
| if (DEBUG_READ_MEM_VERBOSE((void*)(base + dir.VirtualAddress), | |
| &exports, sizeof(exports)) && | |
| ((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) && | |
| DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfFunctions), | |
| functions, sizeof(functions[0]) * exports.NumberOfFunctions) && | |
| ((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) && | |
| DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNameOrdinals), | |
| ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) && | |
| ((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) && | |
| DEBUG_READ_MEM_VERBOSE((void*)(base + (DWORD)exports.AddressOfNames), | |
| names, sizeof(names[0]) * exports.NumberOfNames)) { | |
| for (i = 0; i < exports.NumberOfNames; i++) { | |
| if (!names[i] || | |
| !DEBUG_READ_MEM_VERBOSE((void*)(base + names[i]), bufstr, sizeof(bufstr))) | |
| continue; | |
| bufstr[sizeof(bufstr) - 1] = 0; | |
| snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr); | |
| value.addr.off = base + (DWORD)functions[ordinals[i]]; | |
| DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| } | |
| for (i = 0; i < exports.NumberOfFunctions; i++) { | |
| if (!functions[i]) continue; | |
| /* Check if we already added it with a name */ | |
| for (j = 0; j < exports.NumberOfNames; j++) | |
| if ((ordinals[j] == i) && names[j]) break; | |
| if (j < exports.NumberOfNames) continue; | |
| snprintf(buffer, sizeof(buffer), "%s.%ld", prefix, i + exports.Base); | |
| value.addr.off = base + (DWORD)functions[i]; | |
| DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC); | |
| } | |
| } | |
| DBG_free(functions); | |
| DBG_free(ordinals); | |
| DBG_free(names); | |
| } | |
| /* no real debug info, only entry points */ | |
| return DIL_NOINFO; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_LoadEntryPoints | |
| * | |
| * Load the entry points of all the modules into the hash table. | |
| */ | |
| int DEBUG_LoadEntryPoints(const char* pfx) | |
| { | |
| int first = 0; | |
| /* FIXME: with address space separation in space, this is plain wrong | |
| * it requires the 16 bit WOW debugging interface... | |
| */ | |
| #if 0 | |
| MODULEENTRY entry; | |
| NE_MODULE module; | |
| void* moduleAddr; | |
| int rowcount = 0; | |
| int len; | |
| /* FIXME: we assume that a module is never removed from memory */ | |
| /* FIXME: this is (currently plain wrong when debugger is started by | |
| * attaching to an existing program => the 16 bit modules will | |
| * not be shared... not much to do on debugger side... sigh | |
| */ | |
| if (ModuleFirst16(&entry)) do { | |
| if (DEBUG_FindModuleByName(entry.szModule, DM_TYPE_UNKNOWN) || | |
| !(moduleAddr = NE_GetPtr(entry.hModule)) || | |
| !DEBUG_READ_MEM_VERBOSE(moduleAddr, &module, sizeof(module)) || | |
| (module.flags & NE_FFLAGS_WIN32) /* NE module */) | |
| continue; | |
| if (!first) { | |
| if (pfx) DEBUG_Printf(DBG_CHN_MESG, pfx); | |
| DEBUG_Printf(DBG_CHN_MESG, " "); | |
| rowcount = 3 + (pfx ? strlen(pfx) : 0); | |
| first = 1; | |
| } | |
| len = strlen(entry.szModule); | |
| if ((rowcount + len) > 76) { | |
| DEBUG_Printf(DBG_CHN_MESG, "\n "); | |
| rowcount = 3; | |
| } | |
| DEBUG_Printf(DBG_CHN_MESG, " %s", entry.szModule); | |
| rowcount += len + 1; | |
| DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule); | |
| } while (ModuleNext16(&entry)); | |
| #endif | |
| if (first) DEBUG_Printf(DBG_CHN_MESG, "\n"); | |
| return first; | |
| } | |
| void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, DWORD load_addr) | |
| { | |
| const char* fmt; | |
| switch (dil) { | |
| case DIL_DEFERRED: | |
| fmt = "Deferring debug information loading for %s '%s' (0x%08x)\n"; | |
| break; | |
| case DIL_LOADED: | |
| fmt = "Loaded debug information from %s '%s' (0x%08x)\n"; | |
| break; | |
| case DIL_NOINFO: | |
| fmt = "No debug information in %s '%s' (0x%08x)\n"; | |
| break; | |
| case DIL_ERROR: | |
| fmt = "Can't find file for %s '%s' (0x%08x)\n"; | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_ERR, "Oooocch (%d)\n", dil); | |
| return; | |
| } | |
| DEBUG_Printf(DBG_CHN_MESG, fmt, pfx, filename, load_addr); | |
| } | |
| static const char* DEBUG_GetModuleType(enum DbgModuleType type) | |
| { | |
| switch (type) { | |
| case DMT_NE: return "NE"; | |
| case DMT_PE: return "PE"; | |
| case DMT_ELF: return "ELF"; | |
| default: return "???";; | |
| } | |
| } | |
| static const char* DEBUG_GetDbgInfo(enum DbgInfoLoad dil) | |
| { | |
| switch (dil) { | |
| case DIL_LOADED: return "loaded"; | |
| case DIL_DEFERRED: return "deferred"; | |
| case DIL_NOINFO: return "none"; | |
| case DIL_ERROR: return "error"; | |
| default: return "?"; | |
| } | |
| } | |
| /*********************************************************************** | |
| * DEBUG_ModuleCompare | |
| * | |
| * returns -1 is p1 < p2, 0 is p1 == p2, +1 if p1 > p2 | |
| * order used is order on load_addr of a module | |
| */ | |
| static int DEBUG_ModuleCompare(const void* p1, const void* p2) | |
| { | |
| return (*((const DBG_MODULE**)p1))->load_addr - | |
| (*((const DBG_MODULE**)p2))->load_addr; | |
| } | |
| /*********************************************************************** | |
| * DEBUG_IsContainer | |
| * | |
| * returns TRUE is wmod_child is contained (inside bounds) of wmod_cntnr | |
| */ | |
| static inline BOOL DEBUG_IsContainer(const DBG_MODULE* wmod_cntnr, | |
| const DBG_MODULE* wmod_child) | |
| { | |
| return wmod_cntnr->load_addr < wmod_child->load_addr && | |
| (DWORD)wmod_cntnr->load_addr + wmod_cntnr->size > | |
| (DWORD)wmod_child->load_addr + wmod_child->size; | |
| } | |
| static void DEBUG_InfoShareModule(const DBG_MODULE* module, int ident) | |
| { | |
| if (ident) DEBUG_Printf(DBG_CHN_MESG, " \\-"); | |
| DEBUG_Printf(DBG_CHN_MESG, "%s\t0x%08lx-%08lx\t%s\n", | |
| DEBUG_GetModuleType(module->type), | |
| (DWORD)module->load_addr, (DWORD)module->load_addr + module->size, | |
| module->module_name); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_InfoShare | |
| * | |
| * Display shared libarary information. | |
| */ | |
| void DEBUG_InfoShare(void) | |
| { | |
| DBG_MODULE** ref; | |
| int i, j; | |
| ref = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules); | |
| if (!ref) return; | |
| DEBUG_Printf(DBG_CHN_MESG, "Module\tAddress\t\t\tName\t%d modules\n", | |
| DEBUG_CurrProcess->num_modules); | |
| memcpy(ref, DEBUG_CurrProcess->modules, | |
| sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules); | |
| qsort(ref, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*), | |
| DEBUG_ModuleCompare); | |
| for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) { | |
| switch (ref[i]->type) { | |
| case DMT_ELF: | |
| DEBUG_InfoShareModule(ref[i], 0); | |
| for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) { | |
| if (ref[j]->type != DMT_ELF && DEBUG_IsContainer(ref[i], ref[j])) | |
| DEBUG_InfoShareModule(ref[j], 1); | |
| } | |
| break; | |
| case DMT_NE: | |
| case DMT_PE: | |
| /* check module is not in ELF */ | |
| for (j = 0; j < DEBUG_CurrProcess->num_modules; j++) { | |
| if (ref[j]->type == DMT_ELF && | |
| DEBUG_IsContainer(ref[j], ref[i])) | |
| break; | |
| } | |
| if (j >= DEBUG_CurrProcess->num_modules) | |
| DEBUG_InfoShareModule(ref[i], 0); | |
| break; | |
| default: | |
| DEBUG_Printf(DBG_CHN_ERR, "Unknown type (%d)\n", ref[i]->type); | |
| } | |
| } | |
| DBG_free(ref); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_DumpModule | |
| * Display information about a given module (DLL or EXE) | |
| */ | |
| void DEBUG_DumpModule(DWORD mod) | |
| { | |
| DBG_MODULE* wmod; | |
| if (!(wmod = DEBUG_FindModuleByHandle((HANDLE)mod, DMT_UNKNOWN)) && | |
| !(wmod = DEBUG_FindModuleByAddr((void*)mod, DMT_UNKNOWN))) { | |
| DEBUG_Printf(DBG_CHN_MESG, "'0x%08lx' is not a valid module handle or address\n", mod); | |
| return; | |
| } | |
| DEBUG_Printf(DBG_CHN_MESG, "Module '%s' (handle=%p) 0x%08lx-0x%08lx (%s, debug info %s)\n", | |
| wmod->module_name, wmod->handle, (DWORD)wmod->load_addr, | |
| (DWORD)wmod->load_addr + wmod->size, | |
| DEBUG_GetModuleType(wmod->type), DEBUG_GetDbgInfo(wmod->dil)); | |
| } | |
| /*********************************************************************** | |
| * DEBUG_WalkModules | |
| * | |
| * Display information about all modules (DLLs and EXEs) | |
| */ | |
| void DEBUG_WalkModules(void) | |
| { | |
| DBG_MODULE** amod; | |
| int i; | |
| DEBUG_Printf(DBG_CHN_MESG, "Address\t\t\tModule\tName\n"); | |
| amod = DBG_alloc(sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules); | |
| if (!amod) return; | |
| memcpy(amod, DEBUG_CurrProcess->modules, | |
| sizeof(DBG_MODULE*) * DEBUG_CurrProcess->num_modules); | |
| qsort(amod, DEBUG_CurrProcess->num_modules, sizeof(DBG_MODULE*), | |
| DEBUG_ModuleCompare); | |
| for (i = 0; i < DEBUG_CurrProcess->num_modules; i++) { | |
| if (amod[i]->type == DMT_ELF) continue; | |
| DEBUG_Printf(DBG_CHN_MESG, "0x%08lx-%08lx\t(%s)\t%s\n", | |
| (DWORD)amod[i]->load_addr, | |
| (DWORD)amod[i]->load_addr + amod[i]->size, | |
| DEBUG_GetModuleType(amod[i]->type), amod[i]->module_name); | |
| } | |
| DBG_free(amod); | |
| } | |