diff --git a/dwarf.c b/dwarf.c index cd80675..60d3fbb 100644 --- a/dwarf.c +++ b/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; } diff --git a/dwarf.h b/dwarf.h index 17971c2..c418f3d 100644 --- a/dwarf.h +++ b/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); diff --git a/library.c b/library.c index 4ee399c..19585a2 100644 --- a/library.c +++ b/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; } diff --git a/library.h b/library.h index 682db3b..82e3929 100644 --- a/library.h +++ b/library.h @@ -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); diff --git a/mtelf.c b/mtelf.c index c5e8b6a..7c9e702 100644 --- a/mtelf.c +++ b/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; +} + diff --git a/mtelf.h b/mtelf.h index a4d14bf..bbf2f49 100644 --- a/mtelf.h +++ b/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 diff --git a/sysdeps/linux-gnu/ppc/arch.c b/sysdeps/linux-gnu/ppc/arch.c index 72329dc..6a019b4 100644 --- a/sysdeps/linux-gnu/ppc/arch.c +++ b/sysdeps/linux-gnu/ppc/arch.c @@ -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); } diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c index 8dca9ce..7daae8a 100644 --- a/sysdeps/linux-gnu/proc.c +++ b/sysdeps/linux-gnu/proc.c @@ -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); } diff --git a/sysdeps/linux-gnu/x86/arch.c b/sysdeps/linux-gnu/x86/arch.c index 92e6809..6e9c544 100644 --- a/sysdeps/linux-gnu/x86/arch.c +++ b/sysdeps/linux-gnu/x86/arch.c @@ -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)