629 lines
19 KiB
C
629 lines
19 KiB
C
/* -*- 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 &&
|
|
(!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(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=0x%08x) 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);
|
|
}
|
|
|