📄 elf_module.c
字号:
* Loads the symbolic information from ELF module stored in 'file'
* the module has been loaded at 'load_offset' address, so symbols' address
* relocation is performed. crc optionally points to the CRC of the debug file
* to load.
* returns
* 0 if the file doesn't contain symbolic info (or this info cannot be
* read or parsed)
* 1 on success
*/
static BOOL elf_load_debug_info_from_file(
struct module* module, const char* file, struct pool* pool,
struct hash_table* ht_symtab, const DWORD *crc)
{
BOOL ret = FALSE;
char* addr = (char*)0xffffffff;
int fd = -1;
struct stat statbuf;
const Elf32_Ehdr* ehptr;
const Elf32_Shdr* spnt;
const char* shstrtab;
int i;
int symtab_sect, dynsym_sect, stab_sect, stabstr_sect, debug_sect, debuglink_sect;
struct thunk_area thunks[] =
{
{"__wine_spec_import_thunks", THUNK_ORDINAL_NOTYPE, 0, 0}, /* inter DLL calls */
{"__wine_spec_delayed_import_loaders", THUNK_ORDINAL_LOAD, 0, 0}, /* delayed inter DLL calls */
{"__wine_spec_delayed_import_thunks", THUNK_ORDINAL_LOAD, 0, 0}, /* delayed inter DLL calls */
{"__wine_delay_load", THUNK_ORDINAL_LOAD, 0, 0}, /* delayed inter DLL calls */
{"__wine_spec_thunk_text_16", -16, 0, 0}, /* 16 => 32 thunks */
{"__wine_spec_thunk_data_16", -16, 0, 0}, /* 16 => 32 thunks */
{"__wine_spec_thunk_text_32", -32, 0, 0}, /* 32 => 16 thunks */
{"__wine_spec_thunk_data_32", -32, 0, 0}, /* 32 => 16 thunks */
};
if (module->type != DMT_ELF || !module->elf_info)
{
ERR("Bad elf module '%s'\n", module->module.LoadedImageName);
return FALSE;
}
TRACE("%s\n", file);
/* check that the file exists, and that the module hasn't been loaded yet */
if (stat(file, &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(file, O_RDONLY)) == -1) goto leave;
/*
* Now mmap() the file.
*/
addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (addr == (char*)0xffffffff) goto leave;
if (crc && (*crc != calc_crc32(addr, statbuf.st_size)))
{
ERR("Bad CRC for file %s\n", file);
/* we don't tolerate mis-matched files */
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);
symtab_sect = dynsym_sect = stab_sect = stabstr_sect = debug_sect = debuglink_sect = -1;
for (i = 0; i < ehptr->e_shnum; i++)
{
if (strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0)
stab_sect = i;
if (strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0)
stabstr_sect = i;
if (strcmp(shstrtab + spnt[i].sh_name, ".debug_info") == 0)
debug_sect = i;
if (strcmp(shstrtab + spnt[i].sh_name, ".gnu_debuglink") == 0)
debuglink_sect = i;
if ((strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) &&
(spnt[i].sh_type == SHT_SYMTAB))
symtab_sect = i;
if ((strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) &&
(spnt[i].sh_type == SHT_DYNSYM))
dynsym_sect = i;
}
if (symtab_sect == -1)
{
/* if we don't have a symtab but a dynsym, process the dynsym
* section instead. It'll contain less (relevant) information,
* but it'll be better than nothing
*/
if (dynsym_sect == -1) goto leave;
symtab_sect = dynsym_sect;
}
module->module.SymType = SymExport;
/* create a hash table for the symtab */
elf_hash_symtab(module, pool, ht_symtab, addr,
spnt + symtab_sect, spnt + spnt[symtab_sect].sh_link,
sizeof(thunks) / sizeof(thunks[0]), thunks);
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
{
if (stab_sect != -1 && stabstr_sect != -1)
{
/* OK, now just parse all of the stabs. */
ret = stabs_parse(module, module->elf_info->elf_addr,
addr + spnt[stab_sect].sh_offset,
spnt[stab_sect].sh_size,
addr + spnt[stabstr_sect].sh_offset,
spnt[stabstr_sect].sh_size);
if (!ret)
{
WARN("Couldn't read correctly read stabs\n");
goto leave;
}
/* and fill in the missing information for stabs */
elf_finish_stabs_info(module, ht_symtab);
}
else if (debug_sect != -1)
{
/* Dwarf 2 debug information */
FIXME("Unsupported Dwarf2 information for %s\n", module->module.ModuleName);
}
else if (debuglink_sect != -1)
{
DWORD crc;
const char * file = (const char *)(addr + spnt[debuglink_sect].sh_offset);
/* crc is stored after the null terminated file string rounded
* up to the next 4 byte boundary */
crc = *(const DWORD *)(file + ((DWORD_PTR)(strlen(file) + 4) & ~3));
ret = elf_load_debug_info_from_file(module, file, pool, ht_symtab, &crc);
if (!ret)
WARN("Couldn't load linked debug file %s\n", file);
}
}
if (strstr(module->module.ModuleName, "<elf>") ||
!strcmp(module->module.ModuleName, "<wine-loader>"))
{
/* add the thunks for native libraries */
if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
elf_new_wine_thunks(module, ht_symtab,
sizeof(thunks) / sizeof(thunks[0]), thunks);
}
/* add all the public symbols from symtab */
if (elf_new_public_symbols(module, ht_symtab) && !ret) ret = TRUE;
leave:
if (addr != (char*)0xffffffff) munmap(addr, statbuf.st_size);
if (fd != -1) close(fd);
return ret;
}
/******************************************************************
* elf_load_debug_info
*
* Loads ELF debugging information from the module image file.
*/
BOOL elf_load_debug_info(struct module* module)
{
BOOL ret;
struct pool pool;
struct hash_table ht_symtab;
pool_init(&pool, 65536);
hash_table_init(&pool, &ht_symtab, 256);
ret = elf_load_debug_info_from_file(module,
module->module.LoadedImageName, &pool, &ht_symtab, NULL);
pool_destroy(&pool);
return ret;
}
/******************************************************************
* is_dt_flag_valid
* returns true iff the section tag is valid
*/
static unsigned is_dt_flag_valid(unsigned d_tag)
{
#ifndef DT_PROCNUM
#define DT_PROCNUM 0
#endif
#ifndef DT_EXTRANUM
#define DT_EXTRANUM 0
#endif
return (d_tag >= 0 && d_tag < DT_NUM + DT_PROCNUM + DT_EXTRANUM)
#if defined(DT_LOOS) && defined(DT_HIOS)
|| (d_tag >= DT_LOOS && d_tag < DT_HIOS)
#endif
#if defined(DT_LOPROC) && defined(DT_HIPROC)
|| (d_tag >= DT_LOPROC && d_tag < DT_HIPROC)
#endif
;
}
/******************************************************************
* elf_load_file
*
* 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 BOOL elf_load_file(struct process* pcs, const char* filename,
unsigned long load_offset, struct elf_info* elf_info)
{
static const BYTE elf_signature[4] = { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3 };
BOOL ret = FALSE;
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 size, start;
unsigned tmp, page_mask = getpagesize() - 1;
TRACE("Processing elf file '%s' at %08lx\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;
/* 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 = (const Elf32_Ehdr*)addr;
if (memcmp(ehptr->e_ident, elf_signature, sizeof(elf_signature))) goto leave;
spnt = (const Elf32_Shdr*)(addr + ehptr->e_shoff);
shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset);
/* grab size of module once loaded in memory */
ppnt = (const Elf32_Phdr*)(addr + ehptr->e_phoff);
size = 0; start = ~0L;
for (i = 0; i < ehptr->e_phnum; i++)
{
if (ppnt[i].p_type == PT_LOAD)
{
tmp = (ppnt[i].p_vaddr + ppnt[i].p_memsz + page_mask) & ~page_mask;
if (size < tmp) size = tmp;
if (ppnt[i].p_vaddr < start) start = ppnt[i].p_vaddr;
}
}
/* if non relocatable ELF, then remove fixed address from computation
* otherwise, all addresses are zero based and start has no effect
*/
size -= start;
if (!start && !load_offset)
ERR("Relocatable ELF %s, but no load address. Loading at 0x0000000\n",
filename);
if (start && load_offset)
{
WARN("Non-relocatable ELF %s, but load address of 0x%08lx supplied. "
"Assuming load address is corrupt\n", filename, load_offset);
load_offset = 0;
}
if (elf_info->flags & ELF_INFO_DEBUG_HEADER)
{
for (i = 0; i < ehptr->e_shnum; i++)
{
if (strcmp(shstrtab + spnt[i].sh_name, ".dynamic") == 0 &&
spnt[i].sh_type == SHT_DYNAMIC)
{
Elf32_Dyn dyn;
char* ptr = (char*)spnt[i].sh_addr;
unsigned long len;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -