Eric Pouech ac11a68f3e improved exception handling
merged all module handling code in new module.c file
reenabled 'walk module' and 'info module' commands
added ability to drive break on thread startup
2000-03-26 13:37:39 +00:00

520 lines
15 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 "neexe.h"
#include "peexe.h"
#include "module.h"
#include "debugger.h"
#include "toolhelp.h"
/***********************************************************************
* Creates and links a new module to the current process
*
*/
DBG_MODULE* DEBUG_AddModule(const char* name, int type,
void* mod_addr, HMODULE hmodule)
{
DBG_MODULE* wmod;
if (!(wmod = (DBG_MODULE*)DBG_alloc(sizeof(*wmod))))
return NULL;
memset(wmod, 0, sizeof(*wmod));
wmod->next = DEBUG_CurrProcess->modules;
wmod->status = DM_STATUS_NEW;
wmod->type = type;
wmod->load_addr = mod_addr;
wmod->handle = hmodule;
wmod->dbg_index = DEBUG_CurrProcess->next_index;
wmod->module_name = DBG_strdup(name);
DEBUG_CurrProcess->modules = wmod;
return wmod;
}
/***********************************************************************
* DEBUG_FindModuleByName
*
*/
DBG_MODULE* DEBUG_FindModuleByName(const char* name, int type)
{
DBG_MODULE* wmod;
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
if ((type == DM_TYPE_UNKNOWN || type == wmod->type) &&
!strcasecmp(name, wmod->module_name)) break;
}
return wmod;
}
/***********************************************************************
* DEBUG_FindModuleByAddr
*
* either the addr where module is loaded, or any address inside the
* module
*/
DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, int type)
{
DBG_MODULE* wmod;
DBG_MODULE* res = NULL;
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
if ((type == DM_TYPE_UNKNOWN || type == wmod->type) &&
(u_long)addr >= (u_long)wmod->load_addr &&
(!res || res->load_addr < wmod->load_addr))
res = wmod;
}
return res;
}
/***********************************************************************
* DEBUG_FindModuleByHandle
*/
DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, int type)
{
DBG_MODULE* wmod;
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
if ((type == DM_TYPE_UNKNOWN || type == wmod->type) && handle == wmod->handle) break;
}
return wmod;
}
/***********************************************************************
* 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, const char* name)
{
DBG_MODULE* wmod = DEBUG_AddModule(name, DM_TYPE_ELF, (void*)load_addr, 0);
if (!wmod) return NULL;
wmod->status = DM_STATUS_LOADED;
DEBUG_CurrProcess->next_index++;
return wmod;
}
/***********************************************************************
* DEBUG_RegisterPEModule
*
*/
DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, u_long load_addr, const char *module_name)
{
DBG_MODULE* wmod = DEBUG_AddModule(module_name, DM_TYPE_PE, (void*)load_addr, hModule);
if (!wmod) return NULL;
DEBUG_CurrProcess->next_index++;
return wmod;
}
/***********************************************************************
* DEBUG_RegisterNEModule
*
*/
DBG_MODULE* DEBUG_RegisterNEModule(HMODULE hModule, void* load_addr, const char *module_name)
{
DBG_MODULE* wmod = DEBUG_AddModule(module_name, DM_TYPE_NE, load_addr, hModule);
if (!wmod) return NULL;
wmod->status = DM_STATUS_LOADED;
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]) {
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);
}
/***********************************************************************
* DEBUG_LoadModule32
*/
void DEBUG_LoadModule32(const char* name, DWORD base)
{
DBG_VALUE value;
char buffer[256];
char bufstr[256];
int i;
IMAGE_NT_HEADERS pe_header;
DWORD pe_header_ofs;
IMAGE_SECTION_HEADER pe_seg;
DWORD pe_seg_ofs;
IMAGE_DATA_DIRECTORY dir;
DWORD dir_ofs;
DBG_MODULE* wmod;
/* FIXME: we make the assumption that hModule == base */
wmod = DEBUG_RegisterPEModule((HMODULE)base, base, name);
fprintf(stderr, "Registring 32bit DLL '%s' at %08lx\n", name, base);
value.type = NULL;
value.cookie = DV_TARGET;
value.addr.seg = 0;
value.addr.off = 0;
/* grab PE Header */
if (!DEBUG_READ_MEM_VERBOSE((void*)(base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew)),
&pe_header_ofs, sizeof(pe_header_ofs)) ||
!DEBUG_READ_MEM_VERBOSE((void*)(base + pe_header_ofs),
&pe_header, sizeof(pe_header)))
return;
if (wmod) {
DEBUG_RegisterMSCDebugInfo(wmod, &pe_header, pe_header_ofs);
DEBUG_RegisterStabsDebugInfo(wmod, &pe_header, pe_header_ofs);
}
/* Add start of DLL */
value.addr.off = base;
DEBUG_AddSymbol(name, &value, NULL, SYM_WIN32 | SYM_FUNC);
/* Add entry point */
sprintf(buffer, "%s.EntryPoint", name);
value.addr.off = base + pe_header.OptionalHeader.AddressOfEntryPoint;
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
/* Add start of sections */
pe_seg_ofs = pe_header_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)) ||
!DEBUG_READ_MEM_VERBOSE((void*)pe_seg.Name, bufstr, sizeof(bufstr)))
continue;
bufstr[sizeof(bufstr) - 1] = 0;
sprintf(buffer, "%s.%s", name, bufstr);
value.addr.off = base + pe_seg.VirtualAddress;
DEBUG_AddSymbol(buffer, &value, NULL, SYM_WIN32 | SYM_FUNC);
}
/* Add exported functions */
dir_ofs = pe_header_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;
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;
sprintf(buffer, "%s.%s", name, 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;
sprintf(buffer, "%s.%ld", name, 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);
}
}
/***********************************************************************
* DEBUG_LoadEntryPoints
*
* Load the entry points of all the modules into the hash table.
*/
int DEBUG_LoadEntryPoints(const char* pfx)
{
MODULEENTRY entry;
NE_MODULE module;
void* moduleAddr;
int first = 0;
int rowcount = 0;
int len;
/* FIXME: we assume that a module is never removed from memory */
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) fprintf(stderr, pfx);
fprintf(stderr, " ");
rowcount = 3 + (pfx ? strlen(pfx) : 0);
first = 1;
}
len = strlen(entry.szModule);
if ((rowcount + len) > 76) {
fprintf(stderr, "\n ");
rowcount = 3;
}
fprintf(stderr, " %s", entry.szModule);
rowcount += len + 1;
DEBUG_LoadModule16(entry.hModule, &module, moduleAddr, entry.szModule);
} while (ModuleNext16(&entry));
if (first) fprintf(stderr, "\n");
return first;
}
/***********************************************************************
* DEBUG_ProcessDeferredDebug
*
*/
int DEBUG_ProcessDeferredDebug(void)
{
DBG_MODULE* wmod;
int sts;
int last_proc = -1;
int need_print = 0;
int rowcount = 0;
int len;
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
if (wmod->status != DM_STATUS_NEW) continue;
if (last_proc != wmod->dbg_index) {
if (!need_print) {
fprintf(stderr, "DeferredDebug for:");
rowcount = 18;
need_print = 1;
}
if (rowcount + (len = strlen(wmod->module_name)) > 76) {
rowcount = 0;
fprintf(stderr, "\n");
} else {
fprintf(stderr, " ");
rowcount++;
}
rowcount += len;
fprintf(stderr, wmod->module_name);
last_proc = wmod->dbg_index;
}
sts = (wmod->extra_info) ? DEBUG_ProcessMSCDebugInfo(wmod) : TRUE;
wmod->status = (sts) ? DM_STATUS_LOADED : DM_STATUS_ERROR;
}
if (need_print) fprintf(stderr, "\n");
return TRUE;
}
/***********************************************************************
* DEBUG_InfoShare
*
* Display shared libarary information.
*/
void DEBUG_InfoShare(void)
{
DBG_MODULE* wmod;
const char* xtype;
fprintf(stderr, "Address\t\tModule\tName\n");
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
switch (wmod->type) {
case DM_TYPE_NE: xtype = "NE"; break;
case DM_TYPE_PE: xtype = "PE"; break;
case DM_TYPE_ELF: xtype = "ELF"; break;
default: xtype = "???"; break;
}
fprintf(stderr, "0x%8.8x\t(%s)\t%s\n", (unsigned int)wmod->load_addr,
xtype, wmod->module_name);
}
}
static const char* DEBUG_GetModuleType(int type)
{
switch (type) {
case DM_TYPE_NE: return "NE";
case DM_TYPE_PE: return "PE";
case DM_TYPE_ELF: return "ELF";
default: return "???";;
}
}
static const char* DEBUG_GetModuleStatus(int status)
{
switch (status) {
case DM_STATUS_NEW: return "deferred";
case DM_STATUS_LOADED: return "ok";
case DM_STATUS_ERROR: return "error";
default: return "???";
}
}
/***********************************************************************
* DEBUG_
* Display information about a given module (DLL or EXE)
*/
void DEBUG_DumpModule(DWORD mod)
{
DBG_MODULE* wmod;
if (!(wmod = DEBUG_FindModuleByHandle(mod, DM_TYPE_UNKNOWN)) &&
!(wmod = DEBUG_FindModuleByAddr((void*)mod, DM_TYPE_UNKNOWN))) {
fprintf(stderr, "'0x%08lx' is not a valid module handle or address\n", mod);
return;
}
fprintf(stderr, "Module '%s' (handle=0x%08x) at 0x%8.8x (%s/%s)\n",
wmod->module_name, wmod->handle, (unsigned int)wmod->load_addr,
DEBUG_GetModuleType(wmod->type), DEBUG_GetModuleStatus(wmod->status));
}
/***********************************************************************
* DEBUG_WalkModules
*
* Display information about all modules (DLLs and EXEs)
*/
void DEBUG_WalkModules(void)
{
DBG_MODULE* wmod;
const char* xtype;
fprintf(stderr, "Address\t\tModule\tName\n");
for (wmod = DEBUG_CurrProcess->modules; wmod; wmod = wmod->next) {
switch (wmod->type) {
case DM_TYPE_NE: xtype = "NE"; break;
case DM_TYPE_PE: xtype = "PE"; break;
case DM_TYPE_ELF: continue;
default: xtype = "???"; break;
}
fprintf(stderr, "0x%8.8x\t(%s)\t%s\n",
(unsigned int)wmod->load_addr, DEBUG_GetModuleType(wmod->type),
wmod->module_name);
}
}