- now detecting Dwarf debug information in ELF modules (but don't load
it) - separated module management (pe.c, elf.c) from debug information management (stabs.c, msc.c) - worked around new wine-pthread and wine-kthread loaders (no longer use "wine" as default loader) - better convergence of gdb-proxy and winedbg for ELF handling - fixed ELF link-map walking - now using all loaded shared libs - (with the help of Robert Shearman) - added a bit of const correctness
This commit is contained in:
parent
d329f1beb2
commit
62bf6ecc85
|
@ -11,6 +11,7 @@ C_SRCS = \
|
|||
break.c \
|
||||
db_disasm.c \
|
||||
display.c \
|
||||
elf.c \
|
||||
expr.c \
|
||||
ext_debugger.c \
|
||||
gdbproxy.c \
|
||||
|
@ -19,6 +20,7 @@ C_SRCS = \
|
|||
memory.c \
|
||||
module.c \
|
||||
msc.c \
|
||||
pe.c \
|
||||
registers.c \
|
||||
source.c \
|
||||
stabs.c \
|
||||
|
|
|
@ -267,20 +267,20 @@ extern HANDLE DEBUG_hParserOutput;
|
|||
#define DEBUG_WRITE_MEM_VERBOSE(addr, buf, len) \
|
||||
(DEBUG_WRITE_MEM((addr), (buf), (len)) || (DEBUG_InvalLinAddr( addr ),0))
|
||||
|
||||
enum DbgInfoLoad {DIL_DEFERRED, DIL_LOADED, DIL_NOINFO, DIL_ERROR};
|
||||
enum DbgInfoLoad {DIL_DEFERRED, DIL_LOADED, DIL_NOINFO, DIL_NOT_SUPPORTED, DIL_ERROR};
|
||||
enum DbgModuleType {DMT_UNKNOWN, DMT_ELF, DMT_NE, DMT_PE};
|
||||
|
||||
typedef struct tagDBG_MODULE {
|
||||
void* load_addr;
|
||||
unsigned long size;
|
||||
char* module_name;
|
||||
const char* module_name;
|
||||
enum DbgInfoLoad dil;
|
||||
enum DbgModuleType type;
|
||||
unsigned short main : 1;
|
||||
short int dbg_index;
|
||||
HMODULE handle;
|
||||
struct tagMSC_DBG_INFO* msc_info;
|
||||
struct tagELF_DBG_INFO* elf_info;
|
||||
struct tagMSC_DBG_INFO* msc_dbg_info;
|
||||
struct tagELF_DBG_INFO* elf_dbg_info;
|
||||
} DBG_MODULE;
|
||||
|
||||
typedef struct {
|
||||
|
@ -335,6 +335,26 @@ extern int DEBUG_DelDisplay(int displaynum);
|
|||
extern int DEBUG_InfoDisplay(void);
|
||||
extern int DEBUG_EnableDisplay(int displaynum, int enable);
|
||||
|
||||
/* debugger/elf.c */
|
||||
#define ELF_INFO_PATH 0x0001
|
||||
#define ELF_INFO_DEBUG_HEADER 0x0002
|
||||
#define ELF_INFO_SEGMENTS 0x0004
|
||||
#define ELF_INFO_MODULE 0x0008
|
||||
|
||||
struct elf_info
|
||||
{
|
||||
unsigned flags;
|
||||
char* elf_path; /* path to unix elf path, if ELF_INFO_PATH is set */
|
||||
size_t elf_path_len;
|
||||
void* load_addr; /* 32 bit linear addr, where ELF module is loaded */
|
||||
unsigned long size; /* size of elf module (guessed) */
|
||||
unsigned long dbg_hdr_addr; /* address of debug header (if ELF_INFO_DEBUG_HEADER is set) */
|
||||
unsigned long segments[3]; /* addresses of .text, .data and .bss segments (not filled yet) */
|
||||
};
|
||||
|
||||
extern enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info);
|
||||
extern BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info);
|
||||
|
||||
/* debugger/expr.c */
|
||||
extern void DEBUG_FreeExprMem(void);
|
||||
struct expr * DEBUG_IntVarExpr(const char* name);
|
||||
|
@ -432,27 +452,34 @@ extern int DEBUG_PrintStringA(const DBG_ADDR* address, int len);
|
|||
extern int DEBUG_PrintStringW(const DBG_ADDR* address, int len);
|
||||
|
||||
/* debugger/module.c */
|
||||
extern DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
|
||||
void* mod_addr, unsigned long size, HMODULE hmodule);
|
||||
extern int DEBUG_LoadEntryPoints( const char * prefix );
|
||||
extern void DEBUG_LoadModule32( const char* name, HANDLE hFile, void *base );
|
||||
extern DBG_MODULE* DEBUG_FindModuleByName(const char* name, enum DbgModuleType type);
|
||||
extern DBG_MODULE* DEBUG_FindModuleByHandle(HANDLE handle, enum DbgModuleType type);
|
||||
extern DBG_MODULE* DEBUG_FindModuleByAddr(void* addr, enum DbgModuleType type);
|
||||
extern DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process);
|
||||
extern DBG_MODULE* DEBUG_RegisterELFModule(void *load_addr, unsigned long size,
|
||||
const char* name);
|
||||
extern enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
|
||||
void* _nth, unsigned long nth_ofs);
|
||||
extern void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx,
|
||||
const char* filename, void *load_addr);
|
||||
extern void DEBUG_InfoShare(void);
|
||||
|
||||
/* debugger/msc.c */
|
||||
extern void DEBUG_InitCVDataTypes(void);
|
||||
extern enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module, const BYTE* file_map,
|
||||
PIMAGE_DEBUG_DIRECTORY dbg, int nDbg );
|
||||
|
||||
/* debugger/pe.c */
|
||||
extern void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
|
||||
HANDLE* hFile, HANDLE* hMap);
|
||||
extern void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr);
|
||||
extern void DEBUG_LoadPEModule( const char* name, HANDLE hFile, void *base );
|
||||
extern enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
|
||||
void* nth, unsigned long nth_ofs);
|
||||
extern enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module,
|
||||
HANDLE hFile, void* nth,
|
||||
unsigned long nth_ofs);
|
||||
extern void DEBUG_InitCVDataTypes(void);
|
||||
extern enum DbgInfoLoad DEBUG_RegisterPEDebugInfo(DBG_MODULE* wmod, HANDLE hFile,
|
||||
void* _nth, unsigned long nth_ofs);
|
||||
|
||||
/* debugger/registers.c */
|
||||
extern void DEBUG_InfoRegisters(const CONTEXT* ctx);
|
||||
|
@ -477,8 +504,7 @@ extern int DEBUG_GetCurrentFrame(struct name_hash ** name,
|
|||
unsigned int * ebp);
|
||||
|
||||
/* debugger/stabs.c */
|
||||
extern enum DbgInfoLoad DEBUG_ReadExecutableDbgInfo(const char* exe_name);
|
||||
extern enum DbgInfoLoad DEBUG_ParseStabs(char * addr, void *load_offset,
|
||||
extern enum DbgInfoLoad DEBUG_ParseStabs(const char* addr, void *load_offset,
|
||||
unsigned int staboff, int stablen,
|
||||
unsigned int strtaboff, int strtablen);
|
||||
|
||||
|
|
|
@ -0,0 +1,591 @@
|
|||
/*
|
||||
* File elf.c - processing of ELF files
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* 1999-2004 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
#if defined(__svr4__) || defined(__sun)
|
||||
#define __ELF__
|
||||
#endif
|
||||
|
||||
#ifdef __ELF__
|
||||
#ifdef HAVE_ELF_H
|
||||
# include <elf.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINK_H
|
||||
# include <link.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_LINK_H
|
||||
# include <sys/link.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
|
||||
typedef struct tagELF_DBG_INFO
|
||||
{
|
||||
void *elf_addr;
|
||||
} ELF_DBG_INFO;
|
||||
|
||||
#ifdef __ELF__
|
||||
|
||||
/*
|
||||
* Walk through the entire symbol table and add any symbols we find there.
|
||||
* This can be used in cases where we have stripped ELF shared libraries,
|
||||
* or it can be used in cases where we have data symbols for which the address
|
||||
* isn't encoded in the stabs.
|
||||
*
|
||||
* This is all really quite easy, since we don't have to worry about line
|
||||
* numbers or local data variables.
|
||||
*/
|
||||
static int DEBUG_ProcessElfSymtab(DBG_MODULE* module, const char* addr,
|
||||
void *load_addr, const Elf32_Shdr* symtab,
|
||||
const Elf32_Shdr* strtab)
|
||||
{
|
||||
const char* curfile = NULL;
|
||||
struct name_hash* curr_sym = NULL;
|
||||
int flags;
|
||||
int i;
|
||||
DBG_VALUE new_value;
|
||||
int nsym;
|
||||
const char* strp;
|
||||
const char* symname;
|
||||
const Elf32_Sym* symp;
|
||||
|
||||
symp = (Elf32_Sym *)(addr + symtab->sh_offset);
|
||||
nsym = symtab->sh_size / sizeof(*symp);
|
||||
strp = (char *)(addr + strtab->sh_offset);
|
||||
|
||||
for (i = 0; i < nsym; i++, symp++)
|
||||
{
|
||||
/*
|
||||
* Ignore certain types of entries which really aren't of that much
|
||||
* interest.
|
||||
*/
|
||||
if (ELF32_ST_TYPE(symp->st_info) == STT_SECTION ||
|
||||
symp->st_shndx == STN_UNDEF)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
symname = strp + symp->st_name;
|
||||
|
||||
/*
|
||||
* Save the name of the current file, so we have a way of tracking
|
||||
* static functions/data.
|
||||
*/
|
||||
if (ELF32_ST_TYPE(symp->st_info) == STT_FILE)
|
||||
{
|
||||
curfile = symname;
|
||||
continue;
|
||||
}
|
||||
|
||||
new_value.type = NULL;
|
||||
new_value.addr.seg = 0;
|
||||
new_value.addr.off = (unsigned long)load_addr + symp->st_value;
|
||||
new_value.cookie = DV_TARGET;
|
||||
flags = SYM_WINE | ((ELF32_ST_TYPE(symp->st_info) == STT_FUNC)
|
||||
? SYM_FUNC : SYM_DATA);
|
||||
if (ELF32_ST_BIND(symp->st_info) == STB_GLOBAL)
|
||||
curr_sym = DEBUG_AddSymbol(symname, &new_value, NULL, flags);
|
||||
else
|
||||
curr_sym = DEBUG_AddSymbol(symname, &new_value, curfile, flags);
|
||||
|
||||
/*
|
||||
* Record the size of the symbol. This can come in handy in
|
||||
* some cases. Not really used yet, however.
|
||||
*/
|
||||
if (symp->st_size != 0)
|
||||
DEBUG_SetSymbolSize(curr_sym, symp->st_size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the symbolic information from ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address, so symbols' address
|
||||
* relocation is performed
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_LoadElfStabs(DBG_MODULE* module)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
const Elf32_Ehdr* ehptr;
|
||||
const Elf32_Shdr* spnt;
|
||||
const char* shstrtab;
|
||||
int i;
|
||||
int stabsect, stabstrsect, debugsect;
|
||||
|
||||
if (module->type != DMT_ELF || !module->elf_dbg_info)
|
||||
{
|
||||
WINE_ERR("Bad elf module '%s'\n", module->module_name);
|
||||
return DIL_ERROR;
|
||||
}
|
||||
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(module->module_name, &statbuf) == -1) goto leave;
|
||||
if (S_ISDIR(statbuf.st_mode)) goto leave;
|
||||
|
||||
/*
|
||||
* Now open the file, so that we can mmap() it.
|
||||
*/
|
||||
if ((fd = open(module->module_name, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
dil = DIL_NOINFO;
|
||||
/*
|
||||
* Now mmap() the file.
|
||||
*/
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)0xffffffff) goto leave;
|
||||
|
||||
/*
|
||||
* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*)addr;
|
||||
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
stabsect = stabstrsect = debugsect = -1;
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
|
||||
stabsect = i;
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
|
||||
stabstrsect = i;
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".debug_info") == 0)
|
||||
debugsect = i;
|
||||
}
|
||||
|
||||
if (stabsect != -1 && stabstrsect != -1)
|
||||
{
|
||||
/*
|
||||
* OK, now just parse all of the stabs.
|
||||
*/
|
||||
if (DEBUG_ParseStabs(addr,
|
||||
module->elf_dbg_info->elf_addr,
|
||||
spnt[stabsect].sh_offset,
|
||||
spnt[stabsect].sh_size,
|
||||
spnt[stabstrsect].sh_offset,
|
||||
spnt[stabstrsect].sh_size))
|
||||
{
|
||||
dil = DIL_LOADED;
|
||||
}
|
||||
else
|
||||
{
|
||||
dil = DIL_ERROR;
|
||||
WINE_WARN("Couldn't read correctly read stabs\n");
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (debugsect != -1)
|
||||
{
|
||||
/* Dwarf 2 debug information */
|
||||
dil = DIL_NOT_SUPPORTED;
|
||||
}
|
||||
/* now load dynamic symbol info */
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
|
||||
(spnt[i].sh_type == SHT_SYMTAB))
|
||||
DEBUG_ProcessElfSymtab(module, addr, module->elf_dbg_info->elf_addr,
|
||||
spnt + i, spnt + spnt[i].sh_link);
|
||||
|
||||
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
|
||||
(spnt[i].sh_type == SHT_DYNSYM))
|
||||
DEBUG_ProcessElfSymtab(module, addr, module->elf_dbg_info->elf_addr,
|
||||
spnt + i, spnt + spnt[i].sh_link);
|
||||
}
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the information for ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfFile(HANDLE hProcess,
|
||||
const char* filename,
|
||||
void *load_offset,
|
||||
struct elf_info* elf_info)
|
||||
{
|
||||
static const unsigned char elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
const char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
const Elf32_Ehdr* ehptr;
|
||||
const Elf32_Shdr* spnt;
|
||||
const Elf32_Phdr* ppnt;
|
||||
const char* shstrtab;
|
||||
int i;
|
||||
DWORD delta;
|
||||
|
||||
WINE_TRACE("Processing elf file '%s' at %p\n", filename, load_offset);
|
||||
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(filename, &statbuf) == -1) goto leave;
|
||||
|
||||
/*
|
||||
* Now open the file, so that we can mmap() it.
|
||||
*/
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
/*
|
||||
* Now mmap() the file.
|
||||
*/
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)-1) goto leave;
|
||||
|
||||
dil = DIL_NOINFO;
|
||||
|
||||
/*
|
||||
* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*)addr;
|
||||
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
|
||||
|
||||
spnt = (Elf32_Shdr*)(addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
/* if non relocatable ELF, then remove fixed address from computation
|
||||
* otherwise, all addresses are zero based
|
||||
*/
|
||||
delta = (load_offset == 0) ? ehptr->e_entry : 0;
|
||||
|
||||
/* grab size of module once loaded in memory */
|
||||
ppnt = (Elf32_Phdr*)(addr + ehptr->e_phoff);
|
||||
elf_info->size = 0;
|
||||
for (i = 0; i < ehptr->e_phnum; i++)
|
||||
{
|
||||
if (ppnt[i].p_type != PT_LOAD) continue;
|
||||
if (elf_info->size < ppnt[i].p_vaddr - delta + ppnt[i].p_memsz)
|
||||
elf_info->size = ppnt[i].p_vaddr - delta + ppnt[i].p_memsz;
|
||||
}
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".bss") == 0 &&
|
||||
spnt[i].sh_type == SHT_NOBITS)
|
||||
{
|
||||
if (elf_info->size < spnt[i].sh_addr - delta + spnt[i].sh_size)
|
||||
elf_info->size = spnt[i].sh_addr - delta + spnt[i].sh_size;
|
||||
}
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
|
||||
spnt[i].sh_type == SHT_DYNAMIC)
|
||||
{
|
||||
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
|
||||
{
|
||||
Elf32_Dyn dyn;
|
||||
char* ptr = (char*)spnt[i].sh_addr;
|
||||
unsigned long len;
|
||||
|
||||
do
|
||||
{
|
||||
if (!ReadProcessMemory(hProcess, ptr, &dyn, sizeof(dyn), &len) ||
|
||||
len != sizeof(dyn) ||
|
||||
!((dyn.d_tag >= 0 &&
|
||||
dyn.d_tag < DT_NUM+DT_PROCNUM+DT_EXTRANUM) ||
|
||||
(dyn.d_tag >= DT_LOOS && dyn.d_tag < DT_HIOS) ||
|
||||
(dyn.d_tag >= DT_LOPROC && dyn.d_tag < DT_HIPROC))
|
||||
)
|
||||
dyn.d_tag = DT_NULL;
|
||||
ptr += sizeof(dyn);
|
||||
} while (dyn.d_tag != DT_DEBUG && dyn.d_tag != DT_NULL);
|
||||
if (dyn.d_tag == DT_NULL)
|
||||
{
|
||||
dil = DIL_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
elf_info->dbg_hdr_addr = dyn.d_un.d_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elf_info->segments[0] = elf_info->segments[1] = elf_info->segments[2] = 0;
|
||||
if (elf_info->flags & ELF_INFO_PATH)
|
||||
{
|
||||
strncpy(elf_info->elf_path, filename, elf_info->elf_path_len);
|
||||
elf_info->elf_path[elf_info->elf_path_len - 1] = '\0';
|
||||
}
|
||||
|
||||
elf_info->load_addr = (load_offset == 0) ? (void *)ehptr->e_entry : load_offset;
|
||||
|
||||
if (elf_info->flags & ELF_INFO_MODULE)
|
||||
{
|
||||
DBG_MODULE* module;
|
||||
|
||||
module = DEBUG_AddModule(filename, DMT_ELF, elf_info->load_addr, elf_info->size, 0);
|
||||
if (module)
|
||||
{
|
||||
if ((module->elf_dbg_info = DBG_alloc(sizeof(ELF_DBG_INFO))) == NULL)
|
||||
{
|
||||
WINE_ERR("OOM\n");
|
||||
exit(0);
|
||||
}
|
||||
module->elf_dbg_info->elf_addr = load_offset;
|
||||
module->dil = dil = DEBUG_LoadElfStabs(module);
|
||||
}
|
||||
else dil = DIL_ERROR;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap((void*)addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfFileFromPath(HANDLE hProcess,
|
||||
const char * filename,
|
||||
void *load_offset,
|
||||
const char* path,
|
||||
struct elf_info* elf_info)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
char *s, *t, *fn;
|
||||
char* paths = NULL;
|
||||
|
||||
if (!path) return -1;
|
||||
|
||||
for (s = paths = DBG_strdup(path); s && *s; s = (t) ? (t+1) : NULL)
|
||||
{
|
||||
t = strchr(s, ':');
|
||||
if (t) *t = '\0';
|
||||
fn = (char*)DBG_alloc(strlen(filename) + 1 + strlen(s) + 1);
|
||||
if (!fn) break;
|
||||
strcpy(fn, s );
|
||||
strcat(fn, "/");
|
||||
strcat(fn, filename);
|
||||
dil = DEBUG_ProcessElfFile(hProcess, fn, load_offset, elf_info);
|
||||
DBG_free(fn);
|
||||
if (dil != DIL_ERROR) break;
|
||||
s = (t) ? (t+1) : NULL;
|
||||
}
|
||||
|
||||
DBG_free(paths);
|
||||
return dil;
|
||||
}
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfObject(HANDLE hProcess,
|
||||
const char* filename,
|
||||
void *load_offset,
|
||||
struct elf_info* elf_info)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
|
||||
if (filename == NULL) return DIL_ERROR;
|
||||
if (DEBUG_FindModuleByName(filename, DMT_ELF))
|
||||
{
|
||||
assert(!(elf_info->flags & ELF_INFO_PATH));
|
||||
return DIL_LOADED;
|
||||
}
|
||||
|
||||
if (strstr(filename, "libstdc++")) return DIL_ERROR; /* We know we can't do it */
|
||||
dil = DEBUG_ProcessElfFile(hProcess, filename, load_offset, elf_info);
|
||||
/* if relative pathname, try some absolute base dirs */
|
||||
if (dil == DIL_ERROR && !strchr(filename, '/'))
|
||||
{
|
||||
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
|
||||
getenv("PATH"), elf_info);
|
||||
if (dil == DIL_ERROR)
|
||||
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
|
||||
getenv("LD_LIBRARY_PATH"), elf_info);
|
||||
if (dil == DIL_ERROR)
|
||||
dil = DEBUG_ProcessElfFileFromPath(hProcess, filename, load_offset,
|
||||
getenv("WINEDLLPATH"), elf_info);
|
||||
}
|
||||
|
||||
DEBUG_ReportDIL(dil, "ELF", filename, load_offset);
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_WalkList(const struct r_debug* dbg_hdr)
|
||||
{
|
||||
void* lm_addr;
|
||||
struct link_map lm;
|
||||
char bufstr[256];
|
||||
struct elf_info elf_info;
|
||||
|
||||
elf_info.flags = ELF_INFO_MODULE;
|
||||
/*
|
||||
* Now walk the linked list. In all known ELF implementations,
|
||||
* the dynamic loader maintains this linked list for us. In some
|
||||
* cases the first entry doesn't appear with a name, in other cases it
|
||||
* does.
|
||||
*/
|
||||
for (lm_addr = (void *)dbg_hdr->r_map; lm_addr; lm_addr = (void *)lm.l_next)
|
||||
{
|
||||
if (!DEBUG_READ_MEM_VERBOSE(lm_addr, &lm, sizeof(lm)))
|
||||
return FALSE;
|
||||
|
||||
if (lm.l_prev != NULL && /* skip first entry, normally debuggee itself */
|
||||
lm.l_name != NULL &&
|
||||
DEBUG_READ_MEM_VERBOSE((void*)lm.l_name, bufstr, sizeof(bufstr)))
|
||||
{
|
||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
||||
DEBUG_ProcessElfObject(DEBUG_CurrProcess->handle, bufstr,
|
||||
(void *)lm.l_addr, &elf_info);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_RescanElf(void)
|
||||
{
|
||||
struct r_debug dbg_hdr;
|
||||
|
||||
if (DEBUG_CurrProcess &&
|
||||
DEBUG_READ_MEM_VERBOSE((void*)DEBUG_CurrProcess->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
|
||||
{
|
||||
switch (dbg_hdr.r_state)
|
||||
{
|
||||
case RT_CONSISTENT:
|
||||
DEBUG_WalkList(&dbg_hdr);
|
||||
DEBUG_CheckDelayedBP();
|
||||
break;
|
||||
case RT_ADD:
|
||||
break;
|
||||
case RT_DELETE:
|
||||
/* FIXME: this is not currently handled */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DEBUG_ReadWineLoaderDbgInfo
|
||||
*
|
||||
* Try to find a decent wine executable which could have loader the debuggee
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info)
|
||||
{
|
||||
const char* ptr;
|
||||
enum DbgInfoLoad dil;
|
||||
|
||||
/* All binaries are loaded with WINELOADER (if run from tree) or by the
|
||||
* main executable (either wine-kthread or wine-pthread)
|
||||
* Note: the heuristic use to know wether we need to load wine-pthread or
|
||||
* wine-kthread is not 100% safe
|
||||
*/
|
||||
elf_info->flags |= ELF_INFO_DEBUG_HEADER;
|
||||
if ((ptr = getenv("WINELOADER")))
|
||||
dil = DEBUG_ProcessElfObject(hProcess, ptr, 0, elf_info);
|
||||
else
|
||||
{
|
||||
if ((dil = DEBUG_ProcessElfObject(hProcess, "wine-kthread", 0, elf_info)) == DIL_ERROR)
|
||||
dil = DEBUG_ProcessElfObject(hProcess, "wine-pthread", 0, elf_info);
|
||||
}
|
||||
return dil;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DEBUG_SetElfSoLoadBreakpoint
|
||||
*
|
||||
* Sets a breakpoint to handle .so loading events, so we can add debug info
|
||||
* on the fly
|
||||
*/
|
||||
BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info)
|
||||
{
|
||||
struct r_debug dbg_hdr;
|
||||
|
||||
/*
|
||||
* OK, now dig into the actual tables themselves.
|
||||
*/
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)elf_info->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
|
||||
return FALSE;
|
||||
|
||||
assert(!DEBUG_CurrProcess->dbg_hdr_addr);
|
||||
DEBUG_CurrProcess->dbg_hdr_addr = elf_info->dbg_hdr_addr;
|
||||
|
||||
if (dbg_hdr.r_brk)
|
||||
{
|
||||
DBG_VALUE value;
|
||||
|
||||
WINE_TRACE("Setting up a breakpoint on r_brk(%lx)\n",
|
||||
(unsigned long)dbg_hdr.r_brk);
|
||||
|
||||
DEBUG_SetBreakpoints(FALSE);
|
||||
value.type = NULL;
|
||||
value.cookie = DV_TARGET;
|
||||
value.addr.seg = 0;
|
||||
value.addr.off = (DWORD)dbg_hdr.r_brk;
|
||||
DEBUG_AddBreakpoint(&value, DEBUG_RescanElf, TRUE);
|
||||
DEBUG_SetBreakpoints(TRUE);
|
||||
}
|
||||
|
||||
return DEBUG_WalkList(&dbg_hdr);
|
||||
}
|
||||
|
||||
#else /* !__ELF__ */
|
||||
|
||||
enum DbgInfoLoad DEBUG_ReadWineLoaderDbgInfo(HANDLE hProcess, struct elf_info* elf_info)
|
||||
{
|
||||
return DIL_ERROR;
|
||||
}
|
||||
|
||||
BOOL DEBUG_SetElfSoLoadBreakpoint(const struct elf_info* elf_info)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* __ELF__ */
|
|
@ -102,8 +102,6 @@ struct gdb_context
|
|||
unsigned long wine_segs[3]; /* load addresses of the ELF wine exec segments (text, bss and data) */
|
||||
};
|
||||
|
||||
extern int read_elf_info(const char* filename, unsigned long tab[]);
|
||||
|
||||
/* =============================================== *
|
||||
* B A S I C M A N I P U L A T I O N S *
|
||||
* =============================================== *
|
||||
|
@ -620,29 +618,6 @@ static void handle_debug_event(struct gdb_context* gdbctx, DEBUG_EVENT* de)
|
|||
de->u.CreateProcessInfo.hThread,
|
||||
de->u.CreateProcessInfo.lpStartAddress,
|
||||
de->u.CreateProcessInfo.lpThreadLocalBase);
|
||||
#if 0
|
||||
DEBUG_LoadModule32(DEBUG_CurrProcess->imageName, de->u.CreateProcessInfo.hFile,
|
||||
de->u.CreateProcessInfo.lpBaseOfImage);
|
||||
|
||||
if (buffer[0]) /* we got a process name */
|
||||
{
|
||||
DWORD type;
|
||||
if (!GetBinaryTypeA( buffer, &type ))
|
||||
{
|
||||
/* not a Windows binary, assume it's a Unix executable then */
|
||||
char unixname[MAX_PATH];
|
||||
/* HACK!! should fix DEBUG_ReadExecutableDbgInfo to accept DOS filenames */
|
||||
if (wine_get_unix_file_name( buffer, unixname, sizeof(unixname) ))
|
||||
{
|
||||
DEBUG_ReadExecutableDbgInfo( unixname );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if it is a Windows binary, or an invalid or missing file name,
|
||||
* we use wine itself as the main executable */
|
||||
DEBUG_ReadExecutableDbgInfo( "wine" );
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LOAD_DLL_DEBUG_EVENT:
|
||||
|
@ -1980,7 +1955,7 @@ static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned fl
|
|||
int s_len = sizeof(s_addrs);
|
||||
struct pollfd pollfd;
|
||||
char wine_path[MAX_PATH];
|
||||
char* ptr;
|
||||
struct elf_info elf_info;
|
||||
|
||||
/* step 1: create socket for gdb connection request */
|
||||
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
|
@ -1995,11 +1970,16 @@ static BOOL gdb_startup(struct gdb_context* gdbctx, DEBUG_EVENT* de, unsigned fl
|
|||
return FALSE;
|
||||
|
||||
/* step 2: find out wine executable location (as a Unix filename) */
|
||||
ptr = getenv("WINELOADER");
|
||||
strcpy(wine_path, ptr ? ptr : "wine");
|
||||
elf_info.flags = ELF_INFO_PATH | ELF_INFO_SEGMENTS;
|
||||
elf_info.elf_path = wine_path;
|
||||
elf_info.elf_path_len = sizeof(wine_path);
|
||||
if (DEBUG_ReadWineLoaderDbgInfo(de->u.CreateProcessInfo.hProcess, &elf_info) == DIL_ERROR)
|
||||
return FALSE;
|
||||
gdbctx->wine_segs[0] = elf_info.segments[0];
|
||||
gdbctx->wine_segs[1] = elf_info.segments[1];
|
||||
gdbctx->wine_segs[2] = elf_info.segments[2];
|
||||
|
||||
fprintf(stderr, "Using wine_path: %s\n", wine_path);
|
||||
read_elf_info(wine_path, gdbctx->wine_segs);
|
||||
|
||||
/* step 3: fire up gdb (if requested) */
|
||||
if (flags & 1)
|
||||
|
|
|
@ -704,7 +704,7 @@ const char * DEBUG_FindNearestSymbol( const DBG_ADDR *addr, int flag,
|
|||
|
||||
module = DEBUG_FindModuleByAddr((void*)DEBUG_ToLinear(addr), DMT_UNKNOWN);
|
||||
if (module) {
|
||||
char *p, *name = module->module_name;
|
||||
const char *p, *name = module->module_name;
|
||||
if ((p = strrchr(name, '/'))) name = p + 1;
|
||||
if ((p = strrchr(name, '\\'))) name = p + 1;
|
||||
snprintf( modbuf, sizeof(modbuf), " in %s", name);
|
||||
|
|
|
@ -140,7 +140,7 @@ void DEBUG_GetCurrentAddress( DBG_ADDR *addr )
|
|||
void DEBUG_InvalAddr( const DBG_ADDR* addr )
|
||||
{
|
||||
DEBUG_Printf("*** Invalid address ");
|
||||
DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, FALSE);
|
||||
DEBUG_PrintAddress(addr, DEBUG_CurrThread ? DEBUG_CurrThread->dbg_mode : MODE_32, FALSE);
|
||||
DEBUG_Printf("\n");
|
||||
if (DBG_IVAR(ExtDbgOnInvalidAddress)) DEBUG_ExternalDebugger();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* -*- tab-width: 8; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* File module.c - module handling for the wine debugger
|
||||
*
|
||||
|
@ -34,8 +33,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
|||
* Creates and links a new module to the current process
|
||||
*
|
||||
*/
|
||||
static DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
|
||||
void* mod_addr, unsigned long size, HMODULE hmodule)
|
||||
DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
|
||||
void* mod_addr, unsigned long size, HMODULE hmodule)
|
||||
{
|
||||
DBG_MODULE* wmod;
|
||||
|
||||
|
@ -52,6 +51,7 @@ static DBG_MODULE* DEBUG_AddModule(const char* name, enum DbgModuleType type,
|
|||
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*));
|
||||
|
@ -130,39 +130,6 @@ DBG_MODULE* DEBUG_GetProcessMainModule(DBG_PROCESS* process)
|
|||
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(void *load_addr, unsigned long size, const char* name)
|
||||
{
|
||||
DBG_MODULE* wmod = DEBUG_AddModule(name, DMT_ELF, load_addr, size, 0);
|
||||
|
||||
if (!wmod) return NULL;
|
||||
|
||||
DEBUG_CurrProcess->next_index++;
|
||||
|
||||
return wmod;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_RegisterPEModule
|
||||
*
|
||||
*/
|
||||
static DBG_MODULE* DEBUG_RegisterPEModule(HMODULE hModule, void *load_addr,
|
||||
unsigned long size, const char *module_name)
|
||||
{
|
||||
DBG_MODULE* wmod = DEBUG_AddModule(module_name, DMT_PE, load_addr, size, hModule);
|
||||
|
||||
if (!wmod) return NULL;
|
||||
|
||||
DEBUG_CurrProcess->next_index++;
|
||||
|
||||
return wmod;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/***********************************************************************
|
||||
* DEBUG_RegisterNEModule
|
||||
|
@ -272,152 +239,6 @@ static void DEBUG_LoadModule16(HMODULE hModule, NE_MODULE* module, char* moduleA
|
|||
}
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_LoadModule32
|
||||
*/
|
||||
void DEBUG_LoadModule32(const char* name, HANDLE hFile, void *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( (char *)base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew),
|
||||
&nth_ofs, sizeof(nth_ofs)) ||
|
||||
!DEBUG_READ_MEM_VERBOSE( (char *)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( (char *)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);
|
||||
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;
|
||||
void * base = 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 = (unsigned long)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 = (unsigned long)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( (char *)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
|
||||
continue;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
|
||||
value.addr.off = (unsigned long)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( (char *)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( (char *)base + dir.VirtualAddress,
|
||||
&exports, sizeof(exports)) &&
|
||||
|
||||
((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
|
||||
DEBUG_READ_MEM_VERBOSE( (char *)base + exports.AddressOfFunctions,
|
||||
functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
|
||||
|
||||
((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
|
||||
DEBUG_READ_MEM_VERBOSE( (char *)base + (DWORD)exports.AddressOfNameOrdinals,
|
||||
ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
|
||||
|
||||
((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
|
||||
DEBUG_READ_MEM_VERBOSE( (char *)base + (DWORD)exports.AddressOfNames,
|
||||
names, sizeof(names[0]) * exports.NumberOfNames)) {
|
||||
|
||||
for (i = 0; i < exports.NumberOfNames; i++) {
|
||||
if (!names[i] ||
|
||||
!DEBUG_READ_MEM_VERBOSE( (char *)base + names[i], bufstr, sizeof(bufstr)))
|
||||
continue;
|
||||
bufstr[sizeof(bufstr) - 1] = 0;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
|
||||
value.addr.off = (unsigned long)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 = (unsigned long)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
|
||||
*
|
||||
|
@ -484,6 +305,9 @@ void DEBUG_ReportDIL(enum DbgInfoLoad dil, const char* pfx, const char* filename
|
|||
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;
|
||||
|
@ -508,11 +332,12 @@ static const char* DEBUG_GetModuleType(enum DbgModuleType type)
|
|||
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 "?";
|
||||
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 "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,83 +79,6 @@ static WINE_EXCEPTION_FILTER(page_fault)
|
|||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_LocateDebugInfoFile
|
||||
*
|
||||
* NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size
|
||||
*/
|
||||
static void DEBUG_LocateDebugInfoFile(const char *filename, char *dbg_filename)
|
||||
{
|
||||
char *str1 = DBG_alloc(MAX_PATHNAME_LEN);
|
||||
char *str2 = DBG_alloc(MAX_PATHNAME_LEN*10);
|
||||
const char *file;
|
||||
char *name_part;
|
||||
|
||||
file = strrchr(filename, '\\');
|
||||
if( file == NULL ) file = filename; else file++;
|
||||
|
||||
if ((GetEnvironmentVariable("_NT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
|
||||
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
|
||||
(GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
|
||||
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
|
||||
(SearchPath(NULL, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part)))
|
||||
lstrcpyn(dbg_filename, str2, MAX_PATHNAME_LEN);
|
||||
else
|
||||
lstrcpyn(dbg_filename, filename, MAX_PATHNAME_LEN);
|
||||
DBG_free(str1);
|
||||
DBG_free(str2);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_MapDebugInfoFile
|
||||
*/
|
||||
static void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
|
||||
HANDLE* hFile, HANDLE* hMap)
|
||||
{
|
||||
DWORD g_offset; /* offset aligned on map granuality */
|
||||
DWORD g_size; /* size to map, with offset aligned */
|
||||
char* ret;
|
||||
|
||||
*hMap = 0;
|
||||
|
||||
if (name != NULL) {
|
||||
char filename[MAX_PATHNAME_LEN];
|
||||
|
||||
DEBUG_LocateDebugInfoFile(name, filename);
|
||||
if ((*hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
DWORD file_size = GetFileSize(*hFile, NULL);
|
||||
if (file_size == (DWORD)-1) return NULL;
|
||||
size = file_size - offset;
|
||||
}
|
||||
|
||||
g_offset = offset & ~0xFFFF; /* FIXME: is granularity portable ? */
|
||||
g_size = offset + size - g_offset;
|
||||
|
||||
if ((*hMap = CreateFileMapping(*hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == 0)
|
||||
return NULL;
|
||||
|
||||
if ((ret = MapViewOfFile(*hMap, FILE_MAP_READ, 0, g_offset, g_size)) != NULL)
|
||||
ret += offset - g_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_UnmapDebugInfoFile
|
||||
*/
|
||||
static void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, void* addr)
|
||||
{
|
||||
if (addr) UnmapViewOfFile(addr);
|
||||
if (hMap) CloseHandle(hMap);
|
||||
if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Process COFF debug information.
|
||||
*/
|
||||
|
@ -234,7 +157,7 @@ static void DEBUG_AddCoffSymbol( struct CoffFile* coff_file, struct name_hash* s
|
|||
coff_file->entries[coff_file->neps++] = sym;
|
||||
}
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root )
|
||||
static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, const BYTE* root )
|
||||
{
|
||||
PIMAGE_AUX_SYMBOL aux;
|
||||
PIMAGE_COFF_SYMBOLS_HEADER coff;
|
||||
|
@ -369,7 +292,7 @@ static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root )
|
|||
&& (naux == 0)
|
||||
&& (coff_sym->SectionNumber == 1) )
|
||||
{
|
||||
DWORD base = module->msc_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
/*
|
||||
* This is a normal static function when naux == 0.
|
||||
* Just register it. The current file is the correct
|
||||
|
@ -396,7 +319,7 @@ static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root )
|
|||
&& (coff_sym->SectionNumber > 0) )
|
||||
{
|
||||
const char* this_file = NULL;
|
||||
DWORD base = module->msc_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
nampnt = DEBUG_GetCoffName( coff_sym, coff_strtab );
|
||||
|
||||
new_value.addr.seg = 0;
|
||||
|
@ -405,7 +328,7 @@ static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root )
|
|||
WINE_TRACE_(winedbg_msc)("%d: %lx %s\n", i, new_value.addr.off, nampnt);
|
||||
WINE_TRACE_(winedbg_msc)(
|
||||
"\tAdding global symbol %s (sect=%s)\n",
|
||||
nampnt, module->msc_info->sectp[coff_sym->SectionNumber - 1].Name);
|
||||
nampnt, module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].Name);
|
||||
|
||||
/*
|
||||
* Now we need to figure out which file this guy belongs to.
|
||||
|
@ -432,7 +355,7 @@ static enum DbgInfoLoad DEBUG_ProcessCoff( DBG_MODULE *module, LPBYTE root )
|
|||
if( (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL)
|
||||
&& (coff_sym->SectionNumber > 0) )
|
||||
{
|
||||
DWORD base = module->msc_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
DWORD base = module->msc_dbg_info->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
|
||||
/*
|
||||
* Similar to above, but for the case of data symbols.
|
||||
* These aren't treated as entrypoints.
|
||||
|
@ -1760,10 +1683,10 @@ DEBUG_ParseTypeTable( char *table, int len )
|
|||
|
||||
union any_size
|
||||
{
|
||||
char * c;
|
||||
short * s;
|
||||
int * i;
|
||||
unsigned int * ui;
|
||||
const char* c;
|
||||
const short* s;
|
||||
const int* i;
|
||||
const unsigned int* ui;
|
||||
};
|
||||
|
||||
struct startend
|
||||
|
@ -1778,18 +1701,18 @@ struct codeview_linetab_hdr
|
|||
unsigned int segno;
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
char * sourcefile;
|
||||
unsigned short * linetab;
|
||||
unsigned int * offtab;
|
||||
const char * sourcefile;
|
||||
const unsigned short * linetab;
|
||||
const unsigned int * offtab;
|
||||
};
|
||||
|
||||
static struct codeview_linetab_hdr *
|
||||
DEBUG_SnarfLinetab(char * linetab,
|
||||
DEBUG_SnarfLinetab(const char * linetab,
|
||||
int size)
|
||||
{
|
||||
int file_segcount;
|
||||
char filename[PATH_MAX];
|
||||
unsigned int * filetab;
|
||||
const unsigned int * filetab;
|
||||
char * fn;
|
||||
int i;
|
||||
int k;
|
||||
|
@ -1809,7 +1732,7 @@ DEBUG_SnarfLinetab(char * linetab,
|
|||
nfile = *pnt.s++;
|
||||
nseg = *pnt.s++;
|
||||
|
||||
filetab = (unsigned int *) pnt.c;
|
||||
filetab = (const unsigned int *) pnt.c;
|
||||
|
||||
/*
|
||||
* Now count up the number of segments in the file.
|
||||
|
@ -2049,8 +1972,8 @@ union codeview_symbol
|
|||
static unsigned int
|
||||
DEBUG_MapCVOffset( DBG_MODULE *module, unsigned int offset )
|
||||
{
|
||||
int nomap = module->msc_info->nomap;
|
||||
OMAP_DATA *omapp = module->msc_info->omapp;
|
||||
int nomap = module->msc_dbg_info->nomap;
|
||||
OMAP_DATA *omapp = module->msc_dbg_info->omapp;
|
||||
int i;
|
||||
|
||||
if ( !nomap || !omapp )
|
||||
|
@ -2070,8 +1993,8 @@ DEBUG_AddCVSymbol( DBG_MODULE *module, char *name, int namelen,
|
|||
int size, int cookie, int flags,
|
||||
struct codeview_linetab_hdr *linetab )
|
||||
{
|
||||
int nsect = module->msc_info->nsect;
|
||||
PIMAGE_SECTION_HEADER sectp = module->msc_info->sectp;
|
||||
int nsect = module->msc_dbg_info->nsect;
|
||||
PIMAGE_SECTION_HEADER sectp = module->msc_dbg_info->sectp;
|
||||
|
||||
struct name_hash *symbol;
|
||||
char symname[PATH_MAX];
|
||||
|
@ -2162,7 +2085,7 @@ DEBUG_AddCVLocal( struct name_hash *func, char *name, int namelen,
|
|||
}
|
||||
|
||||
static int
|
||||
DEBUG_SnarfCodeView( DBG_MODULE *module, LPBYTE root, int offset, int size,
|
||||
DEBUG_SnarfCodeView( DBG_MODULE *module, const BYTE* root, int offset, int size,
|
||||
struct codeview_linetab_hdr *linetab )
|
||||
{
|
||||
struct name_hash *curr_func = NULL;
|
||||
|
@ -2788,7 +2711,7 @@ typedef struct _CV_DIRECTORY_ENTRY
|
|||
#define sstSrcModule 0x127
|
||||
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessCodeView( DBG_MODULE *module, LPBYTE root )
|
||||
static enum DbgInfoLoad DEBUG_ProcessCodeView( DBG_MODULE *module, const BYTE* root )
|
||||
{
|
||||
PCODEVIEW_HEADER cv = (PCODEVIEW_HEADER)root;
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
|
@ -2860,10 +2783,8 @@ static enum DbgInfoLoad DEBUG_ProcessCodeView( DBG_MODULE *module, LPBYTE root )
|
|||
/*========================================================================
|
||||
* Process debug directory.
|
||||
*/
|
||||
static enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module,
|
||||
LPBYTE file_map,
|
||||
PIMAGE_DEBUG_DIRECTORY dbg,
|
||||
int nDbg )
|
||||
enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module, const BYTE* file_map,
|
||||
PIMAGE_DEBUG_DIRECTORY dbg, int nDbg )
|
||||
{
|
||||
enum DbgInfoLoad dil;
|
||||
int i;
|
||||
|
@ -2874,8 +2795,8 @@ static enum DbgInfoLoad DEBUG_ProcessDebugDirectory( DBG_MODULE *module,
|
|||
{
|
||||
if ( dbg[i].Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC )
|
||||
{
|
||||
module->msc_info->nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA);
|
||||
module->msc_info->omapp = (OMAP_DATA *)(file_map + dbg[i].PointerToRawData);
|
||||
module->msc_dbg_info->nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA);
|
||||
module->msc_dbg_info->omapp = (OMAP_DATA *)(file_map + dbg[i].PointerToRawData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2932,214 +2853,3 @@ typedef struct _FPO_DATA {
|
|||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Process DBG file.
|
||||
*/
|
||||
static enum DbgInfoLoad DEBUG_ProcessDBGFile( DBG_MODULE *module,
|
||||
const char *filename, DWORD timestamp )
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
|
||||
LPBYTE file_map = NULL;
|
||||
PIMAGE_SEPARATE_DEBUG_HEADER hdr;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg;
|
||||
int nDbg;
|
||||
|
||||
WINE_TRACE("Processing DBG file %s\n", filename);
|
||||
|
||||
file_map = DEBUG_MapDebugInfoFile( filename, 0, 0, &hFile, &hMap );
|
||||
if ( !file_map )
|
||||
{
|
||||
WINE_ERR("-Unable to peruse .DBG file %s\n", filename);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map;
|
||||
|
||||
if ( hdr->TimeDateStamp != timestamp )
|
||||
{
|
||||
WINE_ERR("Warning - %s has incorrect internal timestamp\n", filename);
|
||||
/*
|
||||
* Well, sometimes this happens to DBG files which ARE REALLY the right .DBG
|
||||
* files but nonetheless this check fails. Anyway, WINDBG (debugger for
|
||||
* Windows by Microsoft) loads debug symbols which have incorrect timestamps.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY) ( file_map + sizeof(*hdr)
|
||||
+ hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
|
||||
+ hdr->ExportedNamesSize );
|
||||
|
||||
nDbg = hdr->DebugDirectorySize / sizeof(*dbg);
|
||||
|
||||
dil = DEBUG_ProcessDebugDirectory( module, file_map, dbg, nDbg );
|
||||
|
||||
|
||||
leave:
|
||||
DEBUG_UnmapDebugInfoFile( hFile, hMap, file_map );
|
||||
return dil;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Process MSC debug information in PE file.
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo( DBG_MODULE *module, HANDLE hFile,
|
||||
void *_nth, unsigned long nth_ofs )
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
|
||||
PIMAGE_DATA_DIRECTORY dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg = NULL;
|
||||
int nDbg;
|
||||
MSC_DBG_INFO extra_info = { 0, NULL, 0, NULL };
|
||||
HANDLE hMap = 0;
|
||||
LPBYTE file_map = NULL;
|
||||
|
||||
|
||||
/* Read in section data */
|
||||
|
||||
module->msc_info = &extra_info;
|
||||
extra_info.nsect = nth->FileHeader.NumberOfSections;
|
||||
extra_info.sectp = DBG_alloc( extra_info.nsect * sizeof(IMAGE_SECTION_HEADER) );
|
||||
if ( !extra_info.sectp )
|
||||
goto leave;
|
||||
|
||||
if ( !DEBUG_READ_MEM_VERBOSE( (char *)module->load_addr +
|
||||
nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
|
||||
nth->FileHeader.SizeOfOptionalHeader,
|
||||
extra_info.sectp,
|
||||
extra_info.nsect * sizeof(IMAGE_SECTION_HEADER) ) )
|
||||
goto leave;
|
||||
|
||||
/* Read in debug directory */
|
||||
|
||||
nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
|
||||
if ( !nDbg )
|
||||
goto leave;
|
||||
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc( nDbg * sizeof(IMAGE_DEBUG_DIRECTORY) );
|
||||
if ( !dbg )
|
||||
goto leave;
|
||||
|
||||
if ( !DEBUG_READ_MEM_VERBOSE( (char *)module->load_addr + dir->VirtualAddress,
|
||||
dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY) ) )
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Map in PE file */
|
||||
file_map = DEBUG_MapDebugInfoFile( NULL, 0, 0, &hFile, &hMap );
|
||||
if ( !file_map )
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Parse debug directory */
|
||||
|
||||
if ( nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED )
|
||||
{
|
||||
/* Debug info is stripped to .DBG file */
|
||||
|
||||
PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData);
|
||||
|
||||
if ( nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC
|
||||
|| misc->DataType != IMAGE_DEBUG_MISC_EXENAME )
|
||||
{
|
||||
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
|
||||
module->module_name );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
dil = DEBUG_ProcessDBGFile( module, misc->Data, nth->FileHeader.TimeDateStamp );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Debug info is embedded into PE module */
|
||||
/* FIXME: the nDBG information we're manipulating comes from the debuggee
|
||||
* address space. However, the following code will be made against the
|
||||
* version mapped in the debugger address space. There are cases (for example
|
||||
* when the PE sections are compressed in the file and become decompressed
|
||||
* in the debuggee address space) where the two don't match.
|
||||
* Therefore, redo the DBG information lookup with the mapped data
|
||||
*/
|
||||
PIMAGE_NT_HEADERS mpd_nth = (PIMAGE_NT_HEADERS)(file_map + nth_ofs);
|
||||
PIMAGE_DATA_DIRECTORY mpd_dir;
|
||||
PIMAGE_DEBUG_DIRECTORY mpd_dbg = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if ( mpd_nth->Signature != IMAGE_NT_SIGNATURE ||
|
||||
mpd_nth->FileHeader.NumberOfSections != nth->FileHeader.NumberOfSections ||
|
||||
(mpd_nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) != 0)
|
||||
goto leave;
|
||||
mpd_dir = mpd_nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
|
||||
|
||||
if ((mpd_dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY)) != nDbg)
|
||||
goto leave;
|
||||
|
||||
mpd_dbg = (PIMAGE_DEBUG_DIRECTORY)(file_map + mpd_dir->VirtualAddress);
|
||||
|
||||
dil = DEBUG_ProcessDebugDirectory( module, file_map, mpd_dbg, nDbg );
|
||||
}
|
||||
|
||||
|
||||
leave:
|
||||
module->msc_info = NULL;
|
||||
|
||||
DEBUG_UnmapDebugInfoFile( 0, hMap, file_map );
|
||||
if ( extra_info.sectp ) DBG_free( extra_info.sectp );
|
||||
if ( dbg ) DBG_free( dbg );
|
||||
return dil;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* look for stabs information in PE header (it's how mingw compiler provides its
|
||||
* debugging information), and also wine PE <-> ELF linking through .wsolnk sections
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile,
|
||||
void* _nth, unsigned long nth_ofs)
|
||||
{
|
||||
IMAGE_SECTION_HEADER pe_seg;
|
||||
unsigned long pe_seg_ofs;
|
||||
int i, stabsize = 0, stabstrsize = 0;
|
||||
unsigned int stabs = 0, stabstr = 0;
|
||||
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
|
||||
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*)((char *)module->load_addr + pe_seg_ofs),
|
||||
&pe_seg, sizeof(pe_seg)))
|
||||
continue;
|
||||
|
||||
if (!strcasecmp(pe_seg.Name, ".stab")) {
|
||||
stabs = pe_seg.VirtualAddress;
|
||||
stabsize = pe_seg.SizeOfRawData;
|
||||
} else if (!strncasecmp(pe_seg.Name, ".stabstr", 8)) {
|
||||
stabstr = pe_seg.VirtualAddress;
|
||||
stabstrsize = pe_seg.SizeOfRawData;
|
||||
}
|
||||
}
|
||||
|
||||
if (stabstrsize && stabsize) {
|
||||
char* s1 = DBG_alloc(stabsize+stabstrsize);
|
||||
|
||||
if (s1) {
|
||||
if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) &&
|
||||
DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr,
|
||||
s1 + stabsize, stabstrsize)) {
|
||||
dil = DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize);
|
||||
} else {
|
||||
DEBUG_Printf("couldn't read data block\n");
|
||||
}
|
||||
DBG_free(s1);
|
||||
} else {
|
||||
DEBUG_Printf("couldn't alloc %d bytes\n", stabsize + stabstrsize);
|
||||
}
|
||||
} else {
|
||||
dil = DIL_NOINFO;
|
||||
}
|
||||
return dil;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,513 @@
|
|||
/*
|
||||
* File pe.c - handle PE module information
|
||||
*
|
||||
* Copyright (C) 1996, Eric Youngdale.
|
||||
* Copyright (C) 1999, 2000, Ulrich Weigand.
|
||||
*
|
||||
* 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 "wine/port.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX MAX_PATH
|
||||
#endif
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
#include "excpt.h"
|
||||
#include "debugger.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
|
||||
#define MAX_PATHNAME_LEN 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD from;
|
||||
DWORD to;
|
||||
|
||||
} OMAP_DATA;
|
||||
|
||||
typedef struct tagMSC_DBG_INFO
|
||||
{
|
||||
int nsect;
|
||||
PIMAGE_SECTION_HEADER sectp;
|
||||
int nomap;
|
||||
OMAP_DATA* omapp;
|
||||
|
||||
} MSC_DBG_INFO;
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_LocateDebugInfoFile
|
||||
*
|
||||
* NOTE: dbg_filename must be at least MAX_PATHNAME_LEN bytes in size
|
||||
*/
|
||||
static void DEBUG_LocateDebugInfoFile(const char* filename, char* dbg_filename)
|
||||
{
|
||||
char* str1 = DBG_alloc(MAX_PATHNAME_LEN);
|
||||
char* str2 = DBG_alloc(MAX_PATHNAME_LEN*10);
|
||||
const char* file;
|
||||
char* name_part;
|
||||
|
||||
file = strrchr(filename, '\\');
|
||||
if (file == NULL) file = filename; else file++;
|
||||
|
||||
if ((GetEnvironmentVariable("_NT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
|
||||
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
|
||||
(GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", str1, MAX_PATHNAME_LEN) &&
|
||||
(SearchPath(str1, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part))) ||
|
||||
(SearchPath(NULL, file, NULL, MAX_PATHNAME_LEN*10, str2, &name_part)))
|
||||
lstrcpyn(dbg_filename, str2, MAX_PATHNAME_LEN);
|
||||
else
|
||||
lstrcpyn(dbg_filename, filename, MAX_PATHNAME_LEN);
|
||||
DBG_free(str1);
|
||||
DBG_free(str2);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_MapDebugInfoFile
|
||||
*/
|
||||
void* DEBUG_MapDebugInfoFile(const char* name, DWORD offset, DWORD size,
|
||||
HANDLE* hFile, HANDLE* hMap)
|
||||
{
|
||||
DWORD g_offset; /* offset aligned on map granuality */
|
||||
DWORD g_size; /* size to map, with offset aligned */
|
||||
char* ret;
|
||||
|
||||
*hMap = 0;
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
char filename[MAX_PATHNAME_LEN];
|
||||
|
||||
DEBUG_LocateDebugInfoFile(name, filename);
|
||||
if ((*hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!size)
|
||||
{
|
||||
DWORD file_size = GetFileSize(*hFile, NULL);
|
||||
if (file_size == (DWORD)-1) return NULL;
|
||||
size = file_size - offset;
|
||||
}
|
||||
|
||||
g_offset = offset & ~0xFFFF; /* FIXME: is granularity portable ? */
|
||||
g_size = offset + size - g_offset;
|
||||
|
||||
if ((*hMap = CreateFileMapping(*hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == 0)
|
||||
return NULL;
|
||||
|
||||
if ((ret = MapViewOfFile(*hMap, FILE_MAP_READ, 0, g_offset, g_size)) != NULL)
|
||||
ret += offset - g_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* DEBUG_UnmapDebugInfoFile
|
||||
*/
|
||||
void DEBUG_UnmapDebugInfoFile(HANDLE hFile, HANDLE hMap, const void* addr)
|
||||
{
|
||||
if (addr) UnmapViewOfFile((void*)addr);
|
||||
if (hMap) CloseHandle(hMap);
|
||||
if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
|
||||
}
|
||||
|
||||
/*========================================================================
|
||||
* Process DBG file.
|
||||
*/
|
||||
static enum DbgInfoLoad DEBUG_ProcessDBGFile(DBG_MODULE* module,
|
||||
const char* filename, DWORD timestamp)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = 0;
|
||||
const BYTE* file_map = NULL;
|
||||
PIMAGE_SEPARATE_DEBUG_HEADER hdr;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg;
|
||||
int nDbg;
|
||||
|
||||
WINE_TRACE("Processing DBG file %s\n", filename);
|
||||
|
||||
file_map = DEBUG_MapDebugInfoFile(filename, 0, 0, &hFile, &hMap);
|
||||
if (!file_map)
|
||||
{
|
||||
WINE_ERR("-Unable to peruse .DBG file %s\n", filename);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
hdr = (PIMAGE_SEPARATE_DEBUG_HEADER) file_map;
|
||||
|
||||
if (hdr->TimeDateStamp != timestamp)
|
||||
{
|
||||
WINE_ERR("Warning - %s has incorrect internal timestamp\n", filename);
|
||||
/*
|
||||
* Well, sometimes this happens to DBG files which ARE REALLY the right .DBG
|
||||
* files but nonetheless this check fails. Anyway, WINDBG (debugger for
|
||||
* Windows by Microsoft) loads debug symbols which have incorrect timestamps.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY)
|
||||
(file_map + sizeof(*hdr) + hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
|
||||
+ hdr->ExportedNamesSize);
|
||||
|
||||
nDbg = hdr->DebugDirectorySize / sizeof(*dbg);
|
||||
|
||||
dil = DEBUG_ProcessDebugDirectory(module, file_map, dbg, nDbg);
|
||||
|
||||
leave:
|
||||
DEBUG_UnmapDebugInfoFile(hFile, hMap, file_map);
|
||||
return dil;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* Process MSC debug information in PE file.
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_RegisterMSCDebugInfo(DBG_MODULE* module, HANDLE hFile,
|
||||
void* _nth, unsigned long nth_ofs)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
|
||||
PIMAGE_DATA_DIRECTORY dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
|
||||
PIMAGE_DEBUG_DIRECTORY dbg = NULL;
|
||||
int nDbg;
|
||||
MSC_DBG_INFO extra_info = { 0, NULL, 0, NULL };
|
||||
HANDLE hMap = 0;
|
||||
const BYTE* file_map = NULL;
|
||||
|
||||
/* Read in section data */
|
||||
|
||||
module->msc_dbg_info = &extra_info;
|
||||
extra_info.nsect = nth->FileHeader.NumberOfSections;
|
||||
extra_info.sectp = DBG_alloc(extra_info.nsect * sizeof(IMAGE_SECTION_HEADER));
|
||||
if (!extra_info.sectp)
|
||||
goto leave;
|
||||
|
||||
if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr +
|
||||
nth_ofs + OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader) +
|
||||
nth->FileHeader.SizeOfOptionalHeader,
|
||||
extra_info.sectp,
|
||||
extra_info.nsect * sizeof(IMAGE_SECTION_HEADER)))
|
||||
goto leave;
|
||||
|
||||
/* Read in debug directory */
|
||||
|
||||
nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
|
||||
if (!nDbg)
|
||||
goto leave;
|
||||
|
||||
dbg = (PIMAGE_DEBUG_DIRECTORY) DBG_alloc(nDbg * sizeof(IMAGE_DEBUG_DIRECTORY));
|
||||
if (!dbg)
|
||||
goto leave;
|
||||
|
||||
if (!DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + dir->VirtualAddress,
|
||||
dbg, nDbg * sizeof(IMAGE_DEBUG_DIRECTORY)))
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Map in PE file */
|
||||
file_map = DEBUG_MapDebugInfoFile(NULL, 0, 0, &hFile, &hMap);
|
||||
if (!file_map)
|
||||
goto leave;
|
||||
|
||||
|
||||
/* Parse debug directory */
|
||||
|
||||
if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
|
||||
{
|
||||
/* Debug info is stripped to .DBG file */
|
||||
|
||||
PIMAGE_DEBUG_MISC misc = (PIMAGE_DEBUG_MISC)(file_map + dbg->PointerToRawData);
|
||||
|
||||
if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC
|
||||
|| misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
|
||||
{
|
||||
WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
|
||||
module->module_name);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
dil = DEBUG_ProcessDBGFile(module, misc->Data, nth->FileHeader.TimeDateStamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Debug info is embedded into PE module */
|
||||
/* FIXME: the nDBG information we're manipulating comes from the debuggee
|
||||
* address space. However, the following code will be made against the
|
||||
* version mapped in the debugger address space. There are cases (for example
|
||||
* when the PE sections are compressed in the file and become decompressed
|
||||
* in the debuggee address space) where the two don't match.
|
||||
* Therefore, redo the DBG information lookup with the mapped data
|
||||
*/
|
||||
PIMAGE_NT_HEADERS mpd_nth = (PIMAGE_NT_HEADERS)(file_map + nth_ofs);
|
||||
PIMAGE_DATA_DIRECTORY mpd_dir;
|
||||
PIMAGE_DEBUG_DIRECTORY mpd_dbg = NULL;
|
||||
|
||||
/* sanity checks */
|
||||
if (mpd_nth->Signature != IMAGE_NT_SIGNATURE ||
|
||||
mpd_nth->FileHeader.NumberOfSections != nth->FileHeader.NumberOfSections ||
|
||||
(mpd_nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) != 0)
|
||||
goto leave;
|
||||
mpd_dir = mpd_nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
|
||||
|
||||
if ((mpd_dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY)) != nDbg)
|
||||
goto leave;
|
||||
|
||||
mpd_dbg = (PIMAGE_DEBUG_DIRECTORY)(file_map + mpd_dir->VirtualAddress);
|
||||
|
||||
dil = DEBUG_ProcessDebugDirectory(module, file_map, mpd_dbg, nDbg);
|
||||
}
|
||||
|
||||
|
||||
leave:
|
||||
module->msc_dbg_info = NULL;
|
||||
|
||||
DEBUG_UnmapDebugInfoFile(0, hMap, file_map);
|
||||
if (extra_info.sectp) DBG_free(extra_info.sectp);
|
||||
if (dbg) DBG_free(dbg);
|
||||
return dil;
|
||||
}
|
||||
|
||||
|
||||
/*========================================================================
|
||||
* look for stabs information in PE header (it's how mingw compiler provides its
|
||||
* debugging information), and also wine PE <-> ELF linking through .wsolnk sections
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_RegisterStabsDebugInfo(DBG_MODULE* module, HANDLE hFile,
|
||||
void* _nth, unsigned long nth_ofs)
|
||||
{
|
||||
IMAGE_SECTION_HEADER pe_seg;
|
||||
unsigned long pe_seg_ofs;
|
||||
int i, stabsize = 0, stabstrsize = 0;
|
||||
unsigned int stabs = 0, stabstr = 0;
|
||||
PIMAGE_NT_HEADERS nth = (PIMAGE_NT_HEADERS)_nth;
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
|
||||
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*)((char*)module->load_addr + pe_seg_ofs),
|
||||
&pe_seg, sizeof(pe_seg)))
|
||||
continue;
|
||||
|
||||
if (!strcasecmp(pe_seg.Name, ".stab"))
|
||||
{
|
||||
stabs = pe_seg.VirtualAddress;
|
||||
stabsize = pe_seg.SizeOfRawData;
|
||||
}
|
||||
else if (!strncasecmp(pe_seg.Name, ".stabstr", 8))
|
||||
{
|
||||
stabstr = pe_seg.VirtualAddress;
|
||||
stabstrsize = pe_seg.SizeOfRawData;
|
||||
}
|
||||
}
|
||||
|
||||
if (stabstrsize && stabsize)
|
||||
{
|
||||
char* s1 = DBG_alloc(stabsize+stabstrsize);
|
||||
|
||||
if (s1)
|
||||
{
|
||||
if (DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabs, s1, stabsize) &&
|
||||
DEBUG_READ_MEM_VERBOSE((char*)module->load_addr + stabstr,
|
||||
s1 + stabsize, stabstrsize))
|
||||
{
|
||||
dil = DEBUG_ParseStabs(s1, 0, 0, stabsize, stabsize, stabstrsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_Printf("couldn't read data block\n");
|
||||
}
|
||||
DBG_free(s1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_Printf("couldn't alloc %d bytes\n", stabsize + stabstrsize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dil = DIL_NOINFO;
|
||||
}
|
||||
return dil;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 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;
|
||||
void* base = 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 = (unsigned long)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 = (unsigned long)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((char*)base + pe_seg_ofs, &pe_seg, sizeof(pe_seg)))
|
||||
continue;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, pe_seg.Name);
|
||||
value.addr.off = (unsigned long)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((char*)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((char*)base + dir.VirtualAddress,
|
||||
&exports, sizeof(exports)) &&
|
||||
|
||||
((functions = DBG_alloc(sizeof(functions[0]) * exports.NumberOfFunctions))) &&
|
||||
DEBUG_READ_MEM_VERBOSE((char*)base + exports.AddressOfFunctions,
|
||||
functions, sizeof(functions[0]) * exports.NumberOfFunctions) &&
|
||||
|
||||
((ordinals = DBG_alloc(sizeof(ordinals[0]) * exports.NumberOfNames))) &&
|
||||
DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNameOrdinals,
|
||||
ordinals, sizeof(ordinals[0]) * exports.NumberOfNames) &&
|
||||
|
||||
((names = DBG_alloc(sizeof(names[0]) * exports.NumberOfNames))) &&
|
||||
DEBUG_READ_MEM_VERBOSE((char*)base + (DWORD)exports.AddressOfNames,
|
||||
names, sizeof(names[0]) * exports.NumberOfNames))
|
||||
{
|
||||
|
||||
for (i = 0; i < exports.NumberOfNames; i++)
|
||||
{
|
||||
if (!names[i] ||
|
||||
!DEBUG_READ_MEM_VERBOSE((char*)base + names[i], bufstr, sizeof(bufstr)))
|
||||
continue;
|
||||
bufstr[sizeof(bufstr) - 1] = 0;
|
||||
snprintf(buffer, sizeof(buffer), "%s.%s", prefix, bufstr);
|
||||
value.addr.off = (unsigned long)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 = (unsigned long)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_LoadPEModule
|
||||
*/
|
||||
void DEBUG_LoadPEModule(const char* name, HANDLE hFile, void* 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((char*)base + OFFSET_OF(IMAGE_DOS_HEADER, e_lfanew),
|
||||
&nth_ofs, sizeof(nth_ofs)) ||
|
||||
!DEBUG_READ_MEM_VERBOSE((char*)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((char*)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_AddModule(name, DMT_PE, base, size, (HMODULE)base);
|
||||
|
||||
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);
|
||||
wmod->dil = dil;
|
||||
}
|
||||
|
||||
DEBUG_ReportDIL(dil, "32bit DLL", name, base);
|
||||
}
|
|
@ -56,22 +56,9 @@
|
|||
#define __ELF__
|
||||
#endif
|
||||
|
||||
#ifdef __ELF__
|
||||
#ifdef HAVE_ELF_H
|
||||
# include <elf.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINK_H
|
||||
# include <link.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_LINK_H
|
||||
# include <sys/link.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(winedbg_stabs);
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg_stabs);
|
||||
|
||||
#ifndef N_UNDF
|
||||
#define N_UNDF 0x00
|
||||
|
@ -100,11 +87,6 @@ WINE_DECLARE_DEBUG_CHANNEL(winedbg_stabs);
|
|||
#define N_EXCL 0xc2
|
||||
#define N_RBRAC 0xe0
|
||||
|
||||
typedef struct tagELF_DBG_INFO
|
||||
{
|
||||
void *elf_addr;
|
||||
} ELF_DBG_INFO;
|
||||
|
||||
struct stab_nlist {
|
||||
union {
|
||||
char *n_name;
|
||||
|
@ -235,7 +217,7 @@ DEBUG_FileSubNr2StabEnum(int filenr, int subnr)
|
|||
{
|
||||
struct datatype** ret;
|
||||
|
||||
WINE_TRACE_(winedbg_stabs)("creating type id for (%d,%d)\n", filenr, subnr);
|
||||
WINE_TRACE("creating type id for (%d,%d)\n", filenr, subnr);
|
||||
|
||||
/* FIXME: I could perhaps create a dummy include_def for each compilation
|
||||
* unit which would allow not to handle those two cases separately
|
||||
|
@ -266,24 +248,25 @@ DEBUG_FileSubNr2StabEnum(int filenr, int subnr)
|
|||
}
|
||||
ret = &idef->vector[subnr];
|
||||
}
|
||||
WINE_TRACE_(winedbg_stabs)("(%d,%d) is %p\n",filenr,subnr,ret);
|
||||
WINE_TRACE("(%d,%d) is %p\n",filenr,subnr,ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
struct datatype**
|
||||
DEBUG_ReadTypeEnum(char **x) {
|
||||
DEBUG_ReadTypeEnum(LPCSTR *x)
|
||||
{
|
||||
int filenr,subnr;
|
||||
|
||||
if (**x=='(') {
|
||||
(*x)++; /* '(' */
|
||||
filenr=strtol(*x,x,10); /* <int> */
|
||||
filenr=strtol(*x,(char**)x,10); /* <int> */
|
||||
(*x)++; /* ',' */
|
||||
subnr=strtol(*x,x,10); /* <int> */
|
||||
subnr=strtol(*x,(char**)x,10); /* <int> */
|
||||
(*x)++; /* ')' */
|
||||
} else {
|
||||
filenr = 0;
|
||||
subnr = strtol(*x,x,10); /* <int> */
|
||||
subnr = strtol(*x,(char**)x,10); /* <int> */
|
||||
}
|
||||
return DEBUG_FileSubNr2StabEnum(filenr,subnr);
|
||||
}
|
||||
|
@ -291,7 +274,7 @@ DEBUG_ReadTypeEnum(char **x) {
|
|||
/*#define PTS_DEBUG*/
|
||||
struct ParseTypedefData
|
||||
{
|
||||
char* ptr;
|
||||
const char* ptr;
|
||||
char buf[1024];
|
||||
int idx;
|
||||
#ifdef PTS_DEBUG
|
||||
|
@ -322,7 +305,7 @@ static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typen
|
|||
|
||||
static int DEBUG_PTS_ReadID(struct ParseTypedefData* ptd)
|
||||
{
|
||||
char* first = ptd->ptr;
|
||||
const char* first = ptd->ptr;
|
||||
unsigned int len;
|
||||
|
||||
PTS_ABORTIF(ptd, (ptd->ptr = strchr(ptd->ptr, ':')) == NULL);
|
||||
|
@ -611,7 +594,7 @@ static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typen
|
|||
if (*++ptd->ptr == 's') {
|
||||
ptd->ptr++;
|
||||
if (DEBUG_PTS_ReadNum(ptd, &sz) == -1) {
|
||||
WINE_ERR_(winedbg_stabs)("Not an attribute... NIY\n");
|
||||
WINE_ERR("Not an attribute... NIY\n");
|
||||
ptd->ptr -= 2;
|
||||
return -1;
|
||||
}
|
||||
|
@ -669,7 +652,7 @@ static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typen
|
|||
*DEBUG_FileSubNr2StabEnum(filenr1, subnr1) = new_dt;
|
||||
} else {
|
||||
if (DEBUG_GetType(dt1) != DT_STRUCT) {
|
||||
WINE_ERR_(winedbg_stabs)("Forward declaration is not an aggregate\n");
|
||||
WINE_ERR("Forward declaration is not an aggregate\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -784,7 +767,7 @@ static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typen
|
|||
}
|
||||
break;
|
||||
default:
|
||||
WINE_ERR_(winedbg_stabs)("Unknown type '%c'\n", ptd->ptr[-1]);
|
||||
WINE_ERR("Unknown type '%c'\n", ptd->ptr[-1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -809,7 +792,7 @@ static int DEBUG_PTS_ReadTypedef(struct ParseTypedefData* ptd, const char* typen
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int DEBUG_ParseTypedefStab(char* ptr, const char* typename)
|
||||
static int DEBUG_ParseTypedefStab(const char* ptr, const char* typename)
|
||||
{
|
||||
struct ParseTypedefData ptd;
|
||||
struct datatype* dt;
|
||||
|
@ -838,20 +821,20 @@ static int DEBUG_ParseTypedefStab(char* ptr, const char* typename)
|
|||
if (ret == -1 || *ptd.ptr) {
|
||||
#ifdef PTS_DEBUG
|
||||
int i;
|
||||
WINE_TRACE_(winedbg_stabs)("Failure on %s\n", ptr);
|
||||
WINE_TRACE("Failure on %s\n", ptr);
|
||||
if (ret == -1)
|
||||
{
|
||||
for (i = 0; i < ptd.err_idx; i++)
|
||||
{
|
||||
WINE_TRACE_(winedbg_stabs)("[%d]: line %d => %s\n",
|
||||
i, ptd.errors[i].line, ptd.errors[i].ptr);
|
||||
WINE_TRACE("[%d]: line %d => %s\n",
|
||||
i, ptd.errors[i].line, ptd.errors[i].ptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
WINE_TRACE_(winedbg_stabs)("[0]: => %s\n", ptd.ptr);
|
||||
WINE_TRACE("[0]: => %s\n", ptd.ptr);
|
||||
|
||||
#else
|
||||
WINE_ERR_(winedbg_stabs)("Failure on %s at %s\n", ptr, ptd.ptr);
|
||||
WINE_ERR("Failure on %s at %s\n", ptr, ptd.ptr);
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -859,8 +842,8 @@ static int DEBUG_ParseTypedefStab(char* ptr, const char* typename)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static struct datatype *
|
||||
DEBUG_ParseStabType(const char * stab)
|
||||
static struct datatype*
|
||||
DEBUG_ParseStabType(const char* stab)
|
||||
{
|
||||
const char* c = stab - 1;
|
||||
|
||||
|
@ -888,31 +871,31 @@ DEBUG_ParseStabType(const char * stab)
|
|||
* The next is either an integer or a (integer,integer).
|
||||
* The DEBUG_ReadTypeEnum takes care that stab_types is large enough.
|
||||
*/
|
||||
return *DEBUG_ReadTypeEnum((char**)&c);
|
||||
return *DEBUG_ReadTypeEnum(&c);
|
||||
}
|
||||
|
||||
enum DbgInfoLoad DEBUG_ParseStabs(char * addr, void *load_offset,
|
||||
enum DbgInfoLoad DEBUG_ParseStabs(const char* addr, void* load_offset,
|
||||
unsigned int staboff, int stablen,
|
||||
unsigned int strtaboff, int strtablen)
|
||||
{
|
||||
struct name_hash * curr_func = NULL;
|
||||
struct wine_locals * curr_loc = NULL;
|
||||
struct name_hash * curr_sym = NULL;
|
||||
char currpath[PATH_MAX];
|
||||
int i;
|
||||
int in_external_file = FALSE;
|
||||
int last_nso = -1;
|
||||
unsigned int len;
|
||||
DBG_VALUE new_value;
|
||||
int nstab;
|
||||
char * ptr;
|
||||
char * stabbuff;
|
||||
unsigned int stabbufflen;
|
||||
struct stab_nlist * stab_ptr;
|
||||
char * strs;
|
||||
int strtabinc;
|
||||
char * subpath = NULL;
|
||||
char symname[4096];
|
||||
struct name_hash* curr_func = NULL;
|
||||
struct wine_locals* curr_loc = NULL;
|
||||
struct name_hash* curr_sym = NULL;
|
||||
char currpath[PATH_MAX];
|
||||
int i;
|
||||
int in_external_file = FALSE;
|
||||
int last_nso = -1;
|
||||
unsigned int len;
|
||||
DBG_VALUE new_value;
|
||||
int nstab;
|
||||
const char* ptr;
|
||||
char* stabbuff;
|
||||
unsigned int stabbufflen;
|
||||
const struct stab_nlist* stab_ptr;
|
||||
const char* strs;
|
||||
int strtabinc;
|
||||
const char* subpath = NULL;
|
||||
char symname[4096];
|
||||
|
||||
nstab = stablen / sizeof(struct stab_nlist);
|
||||
stab_ptr = (struct stab_nlist *) (addr + staboff);
|
||||
|
@ -1200,15 +1183,15 @@ enum DbgInfoLoad DEBUG_ParseStabs(char * addr, void *load_offset,
|
|||
*/
|
||||
break;
|
||||
default:
|
||||
WINE_ERR_(winedbg_stabs)("Unknown stab type 0x%02x\n", stab_ptr->n_type);
|
||||
WINE_ERR("Unknown stab type 0x%02x\n", stab_ptr->n_type);
|
||||
break;
|
||||
}
|
||||
|
||||
stabbuff[0] = '\0';
|
||||
|
||||
WINE_TRACE_(winedbg_stabs)("0x%02x %x %s\n", stab_ptr->n_type,
|
||||
(unsigned int) stab_ptr->n_value,
|
||||
strs + (unsigned int) stab_ptr->n_un.n_name);
|
||||
WINE_TRACE("0x%02x %x %s\n", stab_ptr->n_type,
|
||||
(unsigned int) stab_ptr->n_value,
|
||||
strs + (unsigned int) stab_ptr->n_un.n_name);
|
||||
}
|
||||
|
||||
DEBUG_FreeIncludes();
|
||||
|
@ -1216,498 +1199,3 @@ enum DbgInfoLoad DEBUG_ParseStabs(char * addr, void *load_offset,
|
|||
return DIL_LOADED;
|
||||
}
|
||||
|
||||
#ifdef __ELF__
|
||||
|
||||
/*
|
||||
* Walk through the entire symbol table and add any symbols we find there.
|
||||
* This can be used in cases where we have stripped ELF shared libraries,
|
||||
* or it can be used in cases where we have data symbols for which the address
|
||||
* isn't encoded in the stabs.
|
||||
*
|
||||
* This is all really quite easy, since we don't have to worry about line
|
||||
* numbers or local data variables.
|
||||
*/
|
||||
static int DEBUG_ProcessElfSymtab(DBG_MODULE* module, char* addr,
|
||||
void *load_addr, Elf32_Shdr* symtab,
|
||||
Elf32_Shdr* strtab)
|
||||
{
|
||||
char * curfile = NULL;
|
||||
struct name_hash * curr_sym = NULL;
|
||||
int flags;
|
||||
int i;
|
||||
DBG_VALUE new_value;
|
||||
int nsym;
|
||||
char * strp;
|
||||
char * symname;
|
||||
Elf32_Sym * symp;
|
||||
|
||||
symp = (Elf32_Sym *) (addr + symtab->sh_offset);
|
||||
nsym = symtab->sh_size / sizeof(*symp);
|
||||
strp = (char *) (addr + strtab->sh_offset);
|
||||
|
||||
for (i = 0; i < nsym; i++, symp++)
|
||||
{
|
||||
/*
|
||||
* Ignore certain types of entries which really aren't of that much
|
||||
* interest.
|
||||
*/
|
||||
if( ELF32_ST_TYPE(symp->st_info) == STT_SECTION ||
|
||||
symp->st_shndx == STN_UNDEF )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
symname = strp + symp->st_name;
|
||||
|
||||
/*
|
||||
* Save the name of the current file, so we have a way of tracking
|
||||
* static functions/data.
|
||||
*/
|
||||
if( ELF32_ST_TYPE(symp->st_info) == STT_FILE )
|
||||
{
|
||||
curfile = symname;
|
||||
continue;
|
||||
}
|
||||
|
||||
new_value.type = NULL;
|
||||
new_value.addr.seg = 0;
|
||||
new_value.addr.off = (unsigned long)load_addr + symp->st_value;
|
||||
new_value.cookie = DV_TARGET;
|
||||
flags = SYM_WINE | ((ELF32_ST_TYPE(symp->st_info) == STT_FUNC)
|
||||
? SYM_FUNC : SYM_DATA);
|
||||
if( ELF32_ST_BIND(symp->st_info) == STB_GLOBAL )
|
||||
curr_sym = DEBUG_AddSymbol( symname, &new_value, NULL, flags );
|
||||
else
|
||||
curr_sym = DEBUG_AddSymbol( symname, &new_value, curfile, flags );
|
||||
|
||||
/*
|
||||
* Record the size of the symbol. This can come in handy in
|
||||
* some cases. Not really used yet, however.
|
||||
*/
|
||||
if( symp->st_size != 0 )
|
||||
DEBUG_SetSymbolSize(curr_sym, symp->st_size);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the symbolic information from ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address, so symbols' address
|
||||
* relocation is performed
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
enum DbgInfoLoad DEBUG_LoadElfStabs(DBG_MODULE* module)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
Elf32_Ehdr* ehptr;
|
||||
Elf32_Shdr* spnt;
|
||||
char* shstrtab;
|
||||
int i;
|
||||
int stabsect;
|
||||
int stabstrsect;
|
||||
|
||||
if (module->type != DMT_ELF || !module->elf_info) {
|
||||
WINE_ERR("Bad elf module '%s'\n", module->module_name);
|
||||
return DIL_ERROR;
|
||||
}
|
||||
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(module->module_name, &statbuf) == -1) goto leave;
|
||||
if (S_ISDIR(statbuf.st_mode)) goto leave;
|
||||
|
||||
/*
|
||||
* Now open the file, so that we can mmap() it.
|
||||
*/
|
||||
if ((fd = open(module->module_name, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
dil = DIL_NOINFO;
|
||||
/*
|
||||
* Now mmap() the file.
|
||||
*/
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)0xffffffff) goto leave;
|
||||
|
||||
/*
|
||||
* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*) addr;
|
||||
spnt = (Elf32_Shdr*) (addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
stabsect = stabstrsect = -1;
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++) {
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
|
||||
stabsect = i;
|
||||
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
|
||||
stabstrsect = i;
|
||||
}
|
||||
|
||||
if (stabsect == -1 || stabstrsect == -1) {
|
||||
WINE_WARN("No .stab section\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, now just parse all of the stabs.
|
||||
*/
|
||||
if (DEBUG_ParseStabs(addr,
|
||||
module->elf_info->elf_addr,
|
||||
spnt[stabsect].sh_offset,
|
||||
spnt[stabsect].sh_size,
|
||||
spnt[stabstrsect].sh_offset,
|
||||
spnt[stabstrsect].sh_size)) {
|
||||
dil = DIL_LOADED;
|
||||
} else {
|
||||
dil = DIL_ERROR;
|
||||
WINE_WARN("Couldn't read correctly read stabs\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++) {
|
||||
if ( (strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0)
|
||||
&& (spnt[i].sh_type == SHT_SYMTAB))
|
||||
DEBUG_ProcessElfSymtab(module, addr, module->elf_info->elf_addr,
|
||||
spnt + i, spnt + spnt[i].sh_link);
|
||||
|
||||
if ( (strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0)
|
||||
&& (spnt[i].sh_type == SHT_DYNSYM))
|
||||
DEBUG_ProcessElfSymtab(module, addr, module->elf_info->elf_addr,
|
||||
spnt + i, spnt + spnt[i].sh_link);
|
||||
}
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads the information for ELF module stored in 'filename'
|
||||
* the module has been loaded at 'load_offset' address
|
||||
* returns
|
||||
* -1 if the file cannot be found/opened
|
||||
* 0 if the file doesn't contain symbolic info (or this info cannot be
|
||||
* read or parsed)
|
||||
* 1 on success
|
||||
*/
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfFile(const char* filename,
|
||||
void *load_offset,
|
||||
unsigned int* dyn_addr)
|
||||
{
|
||||
static const unsigned char elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
char* addr = (char*)0xffffffff;
|
||||
int fd = -1;
|
||||
struct stat statbuf;
|
||||
Elf32_Ehdr* ehptr;
|
||||
Elf32_Shdr* spnt;
|
||||
Elf32_Phdr* ppnt;
|
||||
char * shstrtab;
|
||||
int i;
|
||||
DBG_MODULE* module = NULL;
|
||||
DWORD size;
|
||||
DWORD delta;
|
||||
|
||||
WINE_TRACE("Processing elf file '%s'\n", filename);
|
||||
|
||||
/* check that the file exists, and that the module hasn't been loaded yet */
|
||||
if (stat(filename, &statbuf) == -1) goto leave;
|
||||
|
||||
/*
|
||||
* Now open the file, so that we can mmap() it.
|
||||
*/
|
||||
if ((fd = open(filename, O_RDONLY)) == -1) goto leave;
|
||||
|
||||
/*
|
||||
* Now mmap() the file.
|
||||
*/
|
||||
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (addr == (char*)-1) goto leave;
|
||||
|
||||
dil = DIL_NOINFO;
|
||||
|
||||
/*
|
||||
* Next, we need to find a few of the internal ELF headers within
|
||||
* this thing. We need the main executable header, and the section
|
||||
* table.
|
||||
*/
|
||||
ehptr = (Elf32_Ehdr*) addr;
|
||||
if (memcmp( ehptr->e_ident, elf_signature, sizeof(elf_signature) )) goto leave;
|
||||
|
||||
spnt = (Elf32_Shdr*) (addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
/* if non relocatable ELF, then remove fixed address from computation
|
||||
* otherwise, all addresses are zero based
|
||||
*/
|
||||
delta = (load_offset == 0) ? ehptr->e_entry : 0;
|
||||
|
||||
/* grab size of module once loaded in memory */
|
||||
ppnt = (Elf32_Phdr*) (addr + ehptr->e_phoff);
|
||||
size = 0;
|
||||
for (i = 0; i < ehptr->e_phnum; i++) {
|
||||
if (ppnt[i].p_type != PT_LOAD) continue;
|
||||
if (size < ppnt[i].p_vaddr - delta + ppnt[i].p_memsz)
|
||||
size = ppnt[i].p_vaddr - delta + ppnt[i].p_memsz;
|
||||
}
|
||||
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".bss") == 0 &&
|
||||
spnt[i].sh_type == SHT_NOBITS)
|
||||
{
|
||||
if (size < spnt[i].sh_addr - delta + spnt[i].sh_size)
|
||||
size = spnt[i].sh_addr - delta + spnt[i].sh_size;
|
||||
}
|
||||
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
|
||||
spnt[i].sh_type == SHT_DYNAMIC)
|
||||
{
|
||||
if (dyn_addr) *dyn_addr = spnt[i].sh_addr;
|
||||
}
|
||||
}
|
||||
|
||||
module = DEBUG_RegisterELFModule((load_offset == 0) ? (void *)ehptr->e_entry : load_offset,
|
||||
size, filename);
|
||||
if (!module) {
|
||||
dil = DIL_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if ((module->elf_info = DBG_alloc(sizeof(ELF_DBG_INFO))) == NULL) {
|
||||
WINE_ERR("OOM\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
module->elf_info->elf_addr = load_offset;
|
||||
dil = DEBUG_LoadElfStabs(module);
|
||||
|
||||
leave:
|
||||
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
|
||||
if (fd != -1) close(fd);
|
||||
if (module) module->dil = dil;
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfFileFromPath(const char * filename,
|
||||
void *load_offset,
|
||||
unsigned int* dyn_addr,
|
||||
const char* path)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
char *s, *t, *fn;
|
||||
char* paths = NULL;
|
||||
|
||||
if (!path) return -1;
|
||||
|
||||
for (s = paths = DBG_strdup(path); s && *s; s = (t) ? (t+1) : NULL) {
|
||||
t = strchr(s, ':');
|
||||
if (t) *t = '\0';
|
||||
fn = (char*)DBG_alloc(strlen(filename) + 1 + strlen(s) + 1);
|
||||
if (!fn) break;
|
||||
strcpy(fn, s );
|
||||
strcat(fn, "/");
|
||||
strcat(fn, filename);
|
||||
dil = DEBUG_ProcessElfFile(fn, load_offset, dyn_addr);
|
||||
DBG_free(fn);
|
||||
if (dil != DIL_ERROR) break;
|
||||
s = (t) ? (t+1) : NULL;
|
||||
}
|
||||
|
||||
DBG_free(paths);
|
||||
return dil;
|
||||
}
|
||||
|
||||
static enum DbgInfoLoad DEBUG_ProcessElfObject(const char* filename,
|
||||
void *load_offset,
|
||||
unsigned int* dyn_addr)
|
||||
{
|
||||
enum DbgInfoLoad dil = DIL_ERROR;
|
||||
|
||||
if (filename == NULL) return DIL_ERROR;
|
||||
if (DEBUG_FindModuleByName(filename, DMT_ELF)) return DIL_LOADED;
|
||||
|
||||
if (strstr (filename, "libstdc++")) return DIL_ERROR; /* We know we can't do it */
|
||||
dil = DEBUG_ProcessElfFile(filename, load_offset, dyn_addr);
|
||||
|
||||
/* if relative pathname, try some absolute base dirs */
|
||||
if (dil == DIL_ERROR && !strchr(filename, '/')) {
|
||||
dil = DEBUG_ProcessElfFileFromPath(filename, load_offset, dyn_addr, getenv("PATH"));
|
||||
if (dil == DIL_ERROR)
|
||||
dil = DEBUG_ProcessElfFileFromPath(filename, load_offset, dyn_addr, getenv("LD_LIBRARY_PATH"));
|
||||
if (dil == DIL_ERROR)
|
||||
dil = DEBUG_ProcessElfFileFromPath(filename, load_offset, dyn_addr, getenv("WINEDLLPATH"));
|
||||
}
|
||||
|
||||
DEBUG_ReportDIL(dil, "ELF", filename, load_offset);
|
||||
|
||||
return dil;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_WalkList(struct r_debug* dbg_hdr)
|
||||
{
|
||||
void *lm_addr;
|
||||
struct link_map lm;
|
||||
Elf32_Ehdr ehdr;
|
||||
char bufstr[256];
|
||||
|
||||
/*
|
||||
* Now walk the linked list. In all known ELF implementations,
|
||||
* the dynamic loader maintains this linked list for us. In some
|
||||
* cases the first entry doesn't appear with a name, in other cases it
|
||||
* does.
|
||||
*/
|
||||
for (lm_addr = (void *)dbg_hdr->r_map; lm_addr; lm_addr = (void *)lm.l_next) {
|
||||
if (!DEBUG_READ_MEM_VERBOSE(lm_addr, &lm, sizeof(lm)))
|
||||
return FALSE;
|
||||
|
||||
if (lm.l_addr != 0 &&
|
||||
DEBUG_READ_MEM_VERBOSE((void*)lm.l_addr, &ehdr, sizeof(ehdr)) &&
|
||||
ehdr.e_type == ET_DYN && /* only look at dynamic modules */
|
||||
lm.l_name != NULL &&
|
||||
DEBUG_READ_MEM_VERBOSE((void*)lm.l_name, bufstr, sizeof(bufstr))) {
|
||||
bufstr[sizeof(bufstr) - 1] = '\0';
|
||||
DEBUG_ProcessElfObject(bufstr, (void *)lm.l_addr, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL DEBUG_RescanElf(void)
|
||||
{
|
||||
struct r_debug dbg_hdr;
|
||||
|
||||
if (!DEBUG_CurrProcess ||
|
||||
!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_CurrProcess->dbg_hdr_addr, &dbg_hdr, sizeof(dbg_hdr)))
|
||||
return FALSE;
|
||||
|
||||
switch (dbg_hdr.r_state) {
|
||||
case RT_CONSISTENT:
|
||||
DEBUG_WalkList(&dbg_hdr);
|
||||
DEBUG_CheckDelayedBP();
|
||||
break;
|
||||
case RT_ADD:
|
||||
break;
|
||||
case RT_DELETE:
|
||||
/* FIXME: this is not currently handled, would need some kind of mark&sweep algo */
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
enum DbgInfoLoad DEBUG_ReadExecutableDbgInfo(const char* exe_name)
|
||||
{
|
||||
Elf32_Dyn dyn;
|
||||
struct r_debug dbg_hdr;
|
||||
enum DbgInfoLoad dil = DIL_NOINFO;
|
||||
unsigned int dyn_addr;
|
||||
|
||||
/*
|
||||
* Make sure we can stat and open this file.
|
||||
*/
|
||||
if (exe_name == NULL) goto leave;
|
||||
DEBUG_ProcessElfObject(exe_name, 0, &dyn_addr);
|
||||
|
||||
do {
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)dyn_addr, &dyn, sizeof(dyn)))
|
||||
goto leave;
|
||||
dyn_addr += sizeof(dyn);
|
||||
} while (dyn.d_tag != DT_DEBUG && dyn.d_tag != DT_NULL);
|
||||
if (dyn.d_tag == DT_NULL) goto leave;
|
||||
|
||||
/*
|
||||
* OK, now dig into the actual tables themselves.
|
||||
*/
|
||||
if (!DEBUG_READ_MEM_VERBOSE((void*)dyn.d_un.d_ptr, &dbg_hdr, sizeof(dbg_hdr)))
|
||||
goto leave;
|
||||
|
||||
assert(!DEBUG_CurrProcess->dbg_hdr_addr);
|
||||
DEBUG_CurrProcess->dbg_hdr_addr = (unsigned long)dyn.d_un.d_ptr;
|
||||
|
||||
if (dbg_hdr.r_brk) {
|
||||
DBG_VALUE value;
|
||||
|
||||
WINE_TRACE("Setting up a breakpoint on r_brk(%lx)\n", (unsigned long)dbg_hdr.r_brk);
|
||||
|
||||
DEBUG_SetBreakpoints(FALSE);
|
||||
value.type = NULL;
|
||||
value.cookie = DV_TARGET;
|
||||
value.addr.seg = 0;
|
||||
value.addr.off = (DWORD)dbg_hdr.r_brk;
|
||||
DEBUG_AddBreakpoint(&value, DEBUG_RescanElf, TRUE);
|
||||
DEBUG_SetBreakpoints(TRUE);
|
||||
}
|
||||
|
||||
dil = DEBUG_WalkList(&dbg_hdr);
|
||||
|
||||
leave:
|
||||
return dil;
|
||||
}
|
||||
|
||||
/* FIXME: merge with some of the routines above */
|
||||
int read_elf_info(const char* filename, unsigned long tab[])
|
||||
{
|
||||
static const unsigned char elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
|
||||
char* addr;
|
||||
Elf32_Ehdr* ehptr;
|
||||
Elf32_Shdr* spnt;
|
||||
char* shstrtab;
|
||||
int i;
|
||||
int ret = 0;
|
||||
HANDLE hFile;
|
||||
HANDLE hMap = 0;
|
||||
|
||||
addr = NULL;
|
||||
hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) goto leave;
|
||||
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMap == 0) goto leave;
|
||||
addr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
|
||||
if (addr == NULL) goto leave;
|
||||
|
||||
ehptr = (Elf32_Ehdr*) addr;
|
||||
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
|
||||
|
||||
spnt = (Elf32_Shdr*) (addr + ehptr->e_shoff);
|
||||
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
|
||||
|
||||
tab[0] = tab[1] = tab[2] = 0;
|
||||
for (i = 0; i < ehptr->e_shnum; i++)
|
||||
{
|
||||
}
|
||||
ret = 1;
|
||||
leave:
|
||||
if (addr != NULL) UnmapViewOfFile(addr);
|
||||
if (hMap != 0) CloseHandle(hMap);
|
||||
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* !__ELF__ */
|
||||
|
||||
enum DbgInfoLoad DEBUG_ReadExecutableDbgInfo(const char* exe_name)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int read_elf_info(const char* filename, unsigned long tab[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __ELF__ */
|
||||
|
|
|
@ -674,8 +674,8 @@ static DWORD DEBUG_HandleException(EXCEPTION_RECORD *rec, BOOL first_chance, BOO
|
|||
|
||||
static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de)
|
||||
{
|
||||
char buffer[256];
|
||||
DWORD cont = DBG_CONTINUE;
|
||||
char buffer[256];
|
||||
DWORD cont = DBG_CONTINUE;
|
||||
|
||||
DEBUG_CurrPid = de->dwProcessId;
|
||||
DEBUG_CurrTid = de->dwThreadId;
|
||||
|
@ -782,24 +782,30 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de)
|
|||
WINE_ERR("Couldn't create thread\n");
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_InitCurrProcess();
|
||||
DEBUG_InitCurrThread();
|
||||
|
||||
/* module is either PE, NE or ELF module (for WineLib), but all
|
||||
* are loaded with wine, so load its symbols, then the main module
|
||||
*/
|
||||
do
|
||||
else
|
||||
{
|
||||
char* ptr = getenv("WINELOADER");
|
||||
struct elf_info elf_info;
|
||||
|
||||
if (!ptr || DEBUG_ReadExecutableDbgInfo( ptr ) == DIL_ERROR)
|
||||
DEBUG_ReadExecutableDbgInfo( "wine" );
|
||||
} while (0);
|
||||
DEBUG_InitCurrProcess();
|
||||
DEBUG_InitCurrThread();
|
||||
|
||||
DEBUG_LoadModule32(DEBUG_CurrProcess->imageName, de->u.CreateProcessInfo.hFile,
|
||||
de->u.CreateProcessInfo.lpBaseOfImage);
|
||||
elf_info.flags = ELF_INFO_MODULE;
|
||||
|
||||
if (DEBUG_ReadWineLoaderDbgInfo(DEBUG_CurrProcess->handle, &elf_info) != DIL_ERROR &&
|
||||
DEBUG_SetElfSoLoadBreakpoint(&elf_info))
|
||||
{
|
||||
/* then load the main module's symbols */
|
||||
DEBUG_LoadPEModule(DEBUG_CurrProcess->imageName,
|
||||
de->u.CreateProcessInfo.hFile,
|
||||
de->u.CreateProcessInfo.lpBaseOfImage);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_DelThread(DEBUG_CurrProcess->threads);
|
||||
DEBUG_DelProcess(DEBUG_CurrProcess);
|
||||
DEBUG_Printf("Couldn't load process\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EXIT_THREAD_DEBUG_EVENT:
|
||||
|
@ -850,7 +856,7 @@ static BOOL DEBUG_HandleDebugEvent(DEBUG_EVENT* de)
|
|||
de->u.LoadDll.dwDebugInfoFileOffset,
|
||||
de->u.LoadDll.nDebugInfoSize);
|
||||
_strupr(buffer);
|
||||
DEBUG_LoadModule32(buffer, de->u.LoadDll.hFile, de->u.LoadDll.lpBaseOfDll);
|
||||
DEBUG_LoadPEModule(buffer, de->u.LoadDll.hFile, de->u.LoadDll.lpBaseOfDll);
|
||||
DEBUG_CheckDelayedBP();
|
||||
if (DBG_IVAR(BreakOnDllLoad))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue