Sweden-Number/programs/winedbg/module.c

480 lines
14 KiB
C

/*
* File module.c - module handling for the wine debugger
*
* Copyright (C) 1993, Eric Youngdale.
* 2000, Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "debugger.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
/***********************************************************************
* Creates and links a new module to the current process
*
*/
DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
void* mod_addr, unsigned 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->next_index++;
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) &&
(char *)addr >= (char *)amod[i]->load_addr &&
(char *)addr < (char *)amod[i]->load_addr + 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];
}
#if 0
/***********************************************************************
* DEBUG_RegisterNEModule
*
*/
static DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr,
unsigned 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;
}
/***********************************************************************
* 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]) {
snprintf(epname, sizeof(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]) {
snprintf(epname, sizeof(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_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(pfx);
DEBUG_Printf(" ");
rowcount = 3 + (pfx ? strlen(pfx) : 0);
first = 1;
}
len = strlen(entry.szModule);
if ((rowcount + len) > 76) {
DEBUG_Printf("\n ");
rowcount = 3;
}
DEBUG_Printf(" %s", entry.szModule);
rowcount += len + 1;
DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
} while (ModuleNext16(&entry));
#endif
if (first) DEBUG_Printf("\n");
return first;
}
void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename, void *load_addr)
{
const char* fmt;
switch (dil) {
case DIL_DEFERRED:
fmt = "Deferring debug information loading for %s '%s' (%p)\n";
break;
case DIL_LOADED:
fmt = "Loaded debug information from %s '%s' (%p)\n";
break;
case DIL_NOINFO:
fmt = "No debug information in %s '%s' (%p)\n";
break;
case DIL_NOT_SUPPORTED:
fmt = "Unsupported debug information in %s '%s' (%p)\n";
break;
case DIL_ERROR:
fmt = "Can't find file for %s '%s' (%p)\n";
break;
default:
WINE_ERR("Oooocch (%d)\n", dil);
return;
}
DEBUG_Printf(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_NOT_SUPPORTED: return "not supported";
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 (char*)(*((const DBG_MODULE**)p1))->load_addr -
(char*)(*((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(" \\-");
DEBUG_Printf("%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("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:
WINE_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("'0x%08lx' is not a valid module handle or address\n", mod);
return;
}
DEBUG_Printf("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;
if (!DEBUG_CurrProcess)
{
DEBUG_Printf("Cannot walk classes while no process is loaded\n");
return;
}
DEBUG_Printf("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("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);
}