fix address spaces

This commit is contained in:
Stefani Seibold 2018-04-16 16:24:19 +02:00
parent 87f73f3220
commit 73a4eca5ce
9 changed files with 98 additions and 80 deletions

13
dwarf.c
View File

@ -1996,13 +1996,14 @@ fail:
return ret;
}
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr)
int dwarf_get_unwind_table(struct task *task, struct libref *libref)
{
arch_addr_t addr;
arch_addr_t fde_count = 0;
arch_addr_t eh_frame = 0;
int ret;
struct dwarf_addr_space tmp_as;
struct dwarf_eh_frame_hdr *hdr = (struct dwarf_eh_frame_hdr *)(libref->mmap_addr + libref->eh_frame_hdr);
memset(&tmp_as, 0, sizeof(tmp_as));
@ -2012,21 +2013,27 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwar
if (hdr->version != DW_EH_VERSION) {
debug(DEBUG_DWARF, "exception table has unexpected version %d", hdr->version);
abort();
return -DWARF_ENOINFO;
}
addr = ARCH_ADDR_T(hdr + 1);
/* read eh_frame_ptr: */
if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->eh_frame_ptr_enc, &eh_frame, 0)) < 0)
if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->eh_frame_ptr_enc, &eh_frame, 0)) < 0) {
abort();
return -DWARF_ENOINFO;
}
/* (Optionally) read fde_count: */
if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->fde_count_enc, &fde_count, 0)) < 0)
if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->fde_count_enc, &fde_count, 0)) < 0) {
abort();
return -DWARF_ENOINFO;
}
if (hdr->table_enc != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
debug(DEBUG_DWARF, "unsupported unwind table encoding.");
abort();
return -DWARF_EINVAL;
}

View File

@ -115,7 +115,7 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip);
int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *valp);
int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr);
int dwarf_get_unwind_table(struct task *task, struct libref *libref);
int dwarf_arch_init(struct dwarf_addr_space *as);
int dwarf_arch_init_unwind(struct dwarf_addr_space *as);

View File

@ -149,14 +149,14 @@ struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t ad
return NULL;
}
struct library *library_find_with_key(struct list_head *list, arch_addr_t key)
struct library *library_find_by_dyn(struct list_head *list, arch_addr_t dyn)
{
struct list_head *it;
list_for_each(it, list) {
struct library *lib = container_of(it, struct library, list);
if (lib->libref->key == key)
if (lib->libref->dyn == dyn)
return lib;
}
return NULL;
@ -170,10 +170,10 @@ void library_delete_list(struct task *leader, struct list_head *list)
struct library *lib = container_of(it, struct library, list);
struct libref *libref = lib->libref;
debug(DEBUG_FUNCTION, "%s@%#lx pid=%d ", libref->filename, libref->key, leader->pid);
debug(DEBUG_FUNCTION, "%s@%#lx pid=%d ", libref->filename, libref->dyn, leader->pid);
if (unlikely(options.verbose > 1))
fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx\n", leader->pid, libref->filename, libref->key, libref->txt_vaddr, libref->txt_vaddr + libref->txt_size);
fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx\n", leader->pid, libref->filename, libref->dyn, libref->txt_vaddr, libref->txt_vaddr + libref->txt_size);
library_delete(leader, lib);
}
@ -258,7 +258,7 @@ static void insert_lib(struct task *leader, struct library *lib)
static struct library *_library_add(struct task *leader, struct libref *libref)
{
debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->key, leader->pid);
debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->dyn, leader->pid);
assert(leader->leader == leader);
@ -273,7 +273,7 @@ static struct library *_library_add(struct task *leader, struct libref *libref)
insert_lib(leader, lib);
if (unlikely(options.verbose > 1))
fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx\n", leader->pid, libref->filename, libref->key, libref->txt_vaddr, libref->txt_vaddr + libref->txt_size);
fprintf(stderr, "+++ library add pid=%d %s@%#lx %#lx-%#lx\n", leader->pid, libref->filename, libref->dyn, libref->txt_vaddr, libref->txt_vaddr + libref->txt_size);
return lib;
}

View File

@ -43,9 +43,8 @@ struct library_symbol {
};
struct libref {
/* Unique key. Two library objects are considered equal, if
* they have the same key. */
arch_addr_t key;
/* Unique dynamic entry address */
arch_addr_t dyn;
/* base address assign by the loader */
unsigned long bias;
@ -127,8 +126,8 @@ const char *library_execname(struct task *leader);
/* Iterate through list of symbols of library. */
struct library_symbol *library_find_symbol(struct libref *libref, arch_addr_t addr);
/* find a library with a given key */
struct library *library_find_with_key(struct list_head *list, arch_addr_t key);
/* find a library with a given dynamic entry address */
struct library *library_find_by_dyn(struct list_head *list, arch_addr_t dyn);
/* create a library reference. */
struct libref *libref_new(unsigned int type);

105
mtelf.c
View File

@ -50,6 +50,33 @@
#define PAGESIZE 4096
#define PAGEALIGN (PAGESIZE - 1)
struct mt_elf {
int fd;
const char *filename;
Elf *elf;
unsigned int loadsegs;
GElf_Phdr loadseg[4];
unsigned long loadbase;
unsigned long loadsize;
unsigned long vstart;
GElf_Ehdr ehdr;
Elf_Data *dynsym;
size_t dynsym_count;
const char *dynstr;
Elf_Data *symtab;
const char *strtab;
size_t symtab_count;
GElf_Addr bias;
GElf_Addr entry_addr;
GElf_Addr base_addr;
GElf_Addr interp;
GElf_Phdr txt_hdr;
GElf_Phdr eh_hdr;
GElf_Addr dyn;
GElf_Phdr exidx_hdr;
GElf_Addr pltgot;
};
static int open_elf(struct mt_elf *mte, struct task *task, const char *filename)
{
char *cwd;
@ -242,14 +269,13 @@ static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *li
libref->entry = ARCH_ADDR_T(mte->entry_addr);
libref->mmap_offset = mte->loadbase;
libref->mmap_size = mte->loadsize;
libref->txt_vaddr = mte->txt_hdr.p_vaddr + mte->bias;
libref->txt_vaddr = mte->txt_hdr.p_vaddr - mte->vstart + mte->bias;
libref->txt_size = mte->txt_hdr.p_filesz;
libref->txt_offset = mte->txt_hdr.p_offset;
libref->txt_offset = mte->txt_hdr.p_offset - mte->loadbase;
libref->bias = mte->bias;
libref->eh_frame_hdr = mte->eh_hdr.p_offset;
libref->eh_frame_hdr = mte->eh_hdr.p_offset - mte->loadbase;
libref->pltgot = mte->pltgot;
libref->key = mte->dyn;
libref->dyn = mte->dyn - mte->vstart + mte->bias;
libref->loadsegs = mte->loadsegs;
for(unsigned int i = 0; i < libref->loadsegs; ++i)
@ -257,13 +283,13 @@ static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *li
#ifdef __arm__
if (mte->exidx_hdr.p_filesz) {
libref->exidx_data = libref->mmap_addr + mte->exidx_hdr.p_offset;
libref->exidx_len = mte->exidx_hdr.p_memsz;
libref->exidx_data = libref->mmap_addr + mte->exidx_hdr.p_offset - mte->loadbase;
libref->exidx_len = mte->exidx_hdr.p_filesz;
}
#endif
if (mte->eh_hdr.p_filesz && mte->dyn) {
if (dwarf_get_unwind_table(task, libref, (struct dwarf_eh_frame_hdr *)(libref->mmap_addr - libref->txt_offset + mte->eh_hdr.p_offset)) < 0)
if (dwarf_get_unwind_table(task, libref) < 0)
return -1;
}
@ -278,13 +304,18 @@ static void close_elf(struct mt_elf *mte)
if (mte->fd != -1) {
elf_end(mte->elf);
close(mte->fd);
mte->fd = -1;
mte->filename = NULL;
}
}
static int elf_read(struct mt_elf *mte, struct task *task, const char *filename, GElf_Addr bias)
static int elf_read(struct mt_elf *mte, struct task *task, const char *filename)
{
unsigned long loadsize = 0;
unsigned long loadbase = ~0;
unsigned long align;
unsigned long vstart;
debug(DEBUG_FUNCTION, "filename=%s", filename);
@ -301,7 +332,6 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
mte->loadsegs = 0;
for (i = 0; gelf_getphdr(mte->elf, i, &phdr) != NULL; ++i) {
switch (phdr.p_type) {
case PT_LOAD:
if (mte->loadsegs >= ARRAY_SIZE(mte->loadseg)) {
@ -311,6 +341,15 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
mte->loadseg[mte->loadsegs++] = phdr;
align = phdr.p_align;
if (align)
align -= 1;
vstart = phdr.p_vaddr & ~align;
if (mte->vstart > vstart)
mte->vstart = vstart;
if (loadbase > phdr.p_offset)
loadbase = phdr.p_offset;
@ -330,10 +369,10 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
break;
#endif
case PT_INTERP:
mte->interp = phdr.p_vaddr + bias;
mte->interp = phdr.p_vaddr;
break;
case PT_DYNAMIC:
mte->dyn = phdr.p_vaddr + bias;
mte->dyn = phdr.p_vaddr;
break;
default:
break;
@ -348,12 +387,12 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
//fprintf(stderr, "%s:%d %s loadbase:%#lx loadsize:%#lx\n", __func__, __LINE__, filename, loadbase, loadsize);
mte->loadbase = loadbase & ~PAGEALIGN;
mte->loadsize = (loadsize + (loadbase - mte->loadbase) + PAGEALIGN) & ~PAGEALIGN;
//fprintf(stderr, "%s:%d loadbase:%#lx loadsize:%#lx\n", __func__, __LINE__, mte->loadbase, mte->loadsize);
fprintf(stderr, "%s:%d %s loadbase:%#lx loadsize:%#lx\n", __func__, __LINE__, mte->filename, mte->loadbase, mte->loadsize);
debug(DEBUG_FUNCTION, "filename=`%s' text offset=%#llx addr=%#llx size=%#llx",
filename,
(unsigned long long)mte->txt_hdr.p_offset,
(unsigned long long)mte->txt_hdr.p_vaddr + bias,
(unsigned long long)mte->txt_hdr.p_vaddr,
(unsigned long long)mte->txt_hdr.p_filesz);
for (i = 1; i < mte->ehdr.e_shnum; ++i) {
@ -394,16 +433,9 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
break;
}
}
mte->dyn_addr = shdr.sh_addr + bias;
}
}
if (!mte->dyn_addr) {
fprintf(stderr, "Couldn't find .dynamic section \"%s\"\n", filename);
return -1;
}
if (!mte->dynsym || !mte->dynstr) {
fprintf(stderr, "Couldn't find .dynsym or .dynstr in \"%s\"\n", filename);
return -1;
@ -419,11 +451,11 @@ int elf_read_library(struct task *task, struct libref *libref, const char *filen
libref_set_filename(libref, filename);
if (elf_read(&mte, task, filename, bias) == -1)
if (elf_read(&mte, task, filename) == -1)
return -1;
mte.bias = bias;
mte.entry_addr = mte.ehdr.e_entry + bias;
mte.entry_addr = mte.ehdr.e_entry - mte.vstart + bias;
ret = elf_lib_init(&mte, task, libref);
@ -522,9 +554,11 @@ struct libref *elf_read_main_binary(struct task *task, int was_attached)
fname[ret] = 0;
free(filename);
libref_set_filename(libref, fname);
if (elf_read(&mte, task, filename, 0) == -1)
if (elf_read(&mte, task, fname) == -1)
goto fail3;
task->is_64bit = is_64bit(&mte);
@ -534,10 +568,8 @@ struct libref *elf_read_main_binary(struct task *task, int was_attached)
goto fail3;
}
free(filename);
mte.bias = (GElf_Addr) (uintptr_t) entry - mte.ehdr.e_entry;
mte.entry_addr = (GElf_Addr) (uintptr_t) entry;
mte.bias = entry - mte.ehdr.e_entry - mte.vstart;
mte.entry_addr = entry;
if (elf_lib_init(&mte, task, libref))
goto fail3;
@ -553,12 +585,12 @@ struct libref *elf_read_main_binary(struct task *task, int was_attached)
struct mt_elf mte_ld = { };
if (copy_str_from_proc(task, ARCH_ADDR_T(mte.bias + mte.interp), fname, sizeof(fname)) == -1) {
if (copy_str_from_proc(task, ARCH_ADDR_T(mte.bias + mte.interp - mte.vstart), fname, sizeof(fname)) == -1) {
fprintf(stderr, "fatal error: cannot get loader name for pid=%d\n", task->pid);
abort();
}
if (!elf_read(&mte_ld, task, fname, (GElf_Addr)base)) {
if (!elf_read(&mte_ld, task, fname)) {
struct libref *libref;
libref = libref_new(LIBTYPE_LOADER);
@ -567,14 +599,14 @@ struct libref *elf_read_main_binary(struct task *task, int was_attached)
libref_set_filename(libref, fname);
mte_ld.bias = (GElf_Addr)base;
mte_ld.entry_addr = mte_ld.ehdr.e_entry + (GElf_Addr)base;
mte_ld.bias = base;
mte_ld.entry_addr = base + mte_ld.ehdr.e_entry - mte.vstart;
ret = elf_lib_init(&mte_ld, task, libref);
if (!ret) {
library_add(task, libref);
if (linkmap_init(task, ARCH_ADDR_T(mte.bias + mte.dyn))) {
if (linkmap_init(task, ARCH_ADDR_T(mte.bias + mte.dyn - mte.vstart))) {
arch_addr_t addr = find_solib_break(&mte_ld);
if (!addr)
addr = ARCH_ADDR_T(entry);
@ -589,7 +621,7 @@ struct libref *elf_read_main_binary(struct task *task, int was_attached)
else {
entry_bp->breakpoint.on_hit = entry_breakpoint_on_hit;
entry_bp->breakpoint.locked = 1;
entry_bp->dyn_addr = ARCH_ADDR_T(mte.bias + mte.dyn);
entry_bp->dyn_addr = ARCH_ADDR_T(mte.bias + mte.dyn - mte.vstart);
breakpoint_enable(task, &entry_bp->breakpoint);
}
@ -625,3 +657,8 @@ fail1:
return libref;
}
int mte_cmp_machine(struct mt_elf *mte, Elf64_Half type)
{
return mte->ehdr.e_machine == type;
}

29
mtelf.h
View File

@ -29,37 +29,12 @@
#include "forward.h"
#include "sysdep.h"
struct mt_elf {
int fd;
const char *filename;
Elf *elf;
unsigned int loadsegs;
GElf_Phdr loadseg[4];
unsigned long loadbase;
unsigned long loadsize;
GElf_Ehdr ehdr;
Elf_Data *dynsym;
size_t dynsym_count;
const char *dynstr;
Elf_Data *symtab;
const char *strtab;
size_t symtab_count;
GElf_Addr dyn_addr;
GElf_Addr bias;
GElf_Addr entry_addr;
GElf_Addr base_addr;
GElf_Addr interp;
GElf_Phdr txt_hdr;
GElf_Phdr eh_hdr;
GElf_Addr dyn;
GElf_Phdr exidx_hdr;
GElf_Addr pltgot;
};
int elf_read_library(struct task *task, struct libref *libref, const char *filename, GElf_Addr bias);
/* Create a library object representing the main binary. */
struct libref *elf_read_main_binary(struct task *task, int was_attached);
int mte_cmp_machine(struct mt_elf *mte, Elf64_Half type);
#endif

View File

@ -25,6 +25,6 @@
int is_64bit(struct mt_elf *mte)
{
return mte->ehdr.e_machine != EM_PPC;
return !mte_cmp_machine(mte, EM_PPC);
}

View File

@ -402,7 +402,7 @@ static void linkmap_add(struct task *task, struct lt_r_debug_64 *dbg)
}
/* Do we have that library already? */
lib = library_find_with_key(&task->libraries_list, ARCH_ADDR_T(rlm.l_ld));
lib = library_find_by_dyn(&task->libraries_list, ARCH_ADDR_T(rlm.l_ld));
if (lib)
continue;
@ -468,7 +468,7 @@ static void linkmap_del(struct task *task, struct lt_r_debug_64 *dbg)
addr = ARCH_ADDR_T(rlm.l_next);
lib = library_find_with_key(&tmp_list, ARCH_ADDR_T(rlm.l_ld));
lib = library_find_by_dyn(&tmp_list, ARCH_ADDR_T(rlm.l_ld));
if (lib)
list_move_tail(&lib->list, &task->libraries_list);
}

View File

@ -203,7 +203,7 @@ int reset_all_hw_bp(struct task *task)
int is_64bit(struct mt_elf *mte)
{
return mte->ehdr.e_machine != EM_386;
return !mte_cmp_machine(mte, EM_386);
}
int arch_task_init(struct task *task)