mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 08:46:41 +08:00
fix address spaces
This commit is contained in:
parent
87f73f3220
commit
73a4eca5ce
13
dwarf.c
13
dwarf.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
2
dwarf.h
2
dwarf.h
@ -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);
|
||||
|
||||
12
library.c
12
library.c
@ -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;
|
||||
}
|
||||
|
||||
@ -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
105
mtelf.c
@ -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
29
mtelf.h
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user