From a6c7ba8fcc1977c9e9001b2a3e566614d3cd9773 Mon Sep 17 00:00:00 2001 From: Stefani Seibold Date: Thu, 12 Apr 2018 13:03:16 +0200 Subject: [PATCH] code cleanup --- CMakeLists.txt | 2 +- dwarf.c | 40 ++++++++++--------- library.c | 30 +++++++++----- library.h | 30 ++++++++------ mtelf.c | 66 +++++++++++++++++++++---------- mtelf.h | 4 ++ report.c | 6 +-- sysdeps/linux-gnu/x86/dwarf-x86.c | 4 +- 8 files changed, 116 insertions(+), 66 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94f620e..e11023d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.9) set(MT "mtrace-ng") project(${MT} C) -set(MT_VERSION_STRING "0.8") +set(MT_VERSION_STRING "0.8.1") option(DISABLE_CLIENT "whether to disable client support" OFF) diff --git a/dwarf.c b/dwarf.c index 688ae16..52504a6 100644 --- a/dwarf.c +++ b/dwarf.c @@ -463,7 +463,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, { struct dwarf_addr_space *indirect_as = as; arch_addr_t val, initial_addr = *addr; - arch_addr_t gp = as->cursor.libref->gp; + arch_addr_t gp = as->cursor.libref->pltgot; int is_64bit = as->is_64bit; void *tmp_ptr; int ret; @@ -481,10 +481,10 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local, struct dwarf_cursor *c = &as->cursor; struct libref *libref = c->libref; - if (*addr < ARCH_ADDR_T(libref->image_addr)) - fatal("invalid access mem: addr %#lx < %p", *addr, libref->image_addr); - if (*addr >= ARCH_ADDR_T(libref->image_addr + libref->load_size)) - fatal("invalid access mem: addr %#lx >= %p", *addr, libref->image_addr + libref->load_size); + if (*addr < ARCH_ADDR_T(libref->mmap_addr)) + fatal("invalid access mem: addr %#lx < %p", *addr, libref->mmap_addr); + if (*addr >= ARCH_ADDR_T(libref->mmap_addr + libref->txt_size)) + fatal("invalid access mem: addr %#lx >= %p", *addr, libref->mmap_addr + libref->txt_size); #endif memset(&tmp, 0, sizeof(tmp)); @@ -873,7 +873,7 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp) static inline int lib_addr_match(struct libref *libref, arch_addr_t ip) { - return ip >= libref->load_addr && ip < libref->load_addr + libref->load_size; + return ip >= libref->txt_vaddr && ip < libref->txt_vaddr + libref->txt_size; } int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) @@ -895,16 +895,16 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) return 0; } -static const struct table_entry *lookup(const struct table_entry *table, size_t table_len, int32_t rel_ip) +static const struct table_entry *lookup(const struct table_entry *table, size_t fde_count, int32_t rel_ip) { const struct table_entry *e, *f; unsigned long lo, hi; - if (!table_len) + if (!fde_count) return NULL; lo = 0; - hi = table_len; + hi = fde_count; f = NULL; do { unsigned long mid = (lo + hi) / 2; @@ -922,7 +922,7 @@ static const struct table_entry *lookup(const struct table_entry *table, size_t return f; } -static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip, void *table_data, unsigned long table_len) +static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip, void *fde_tab, unsigned long fde_count) { const struct table_entry *e; void *fde_addr; @@ -930,19 +930,19 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip struct dwarf_cie_info *dci = &as->cursor.dci; struct libref *libref = as->cursor.libref; - e = lookup(table_data, table_len, ip - libref->load_addr - libref->seg_offset); + e = lookup(fde_tab, fde_count, ip - libref->txt_vaddr - libref->eh_frame_hdr); if (unlikely(!e)) { /* IP is inside this table's range, but there is no explicit unwind info. */ debug(DEBUG_DWARF, "no unwind info found for IP %#lx", ip); return -DWARF_ENOINFO; } - fde_addr = libref->image_addr - libref->load_offset + e->fde_offset + libref->seg_offset; + fde_addr = libref->mmap_addr - libref->mmap_offset + e->fde_offset + libref->eh_frame_hdr; if (unlikely((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0)) return ret; - dci->start_ip -= ARCH_ADDR_T(libref->image_addr) - libref->load_addr; + dci->start_ip -= ARCH_ADDR_T(libref->mmap_addr) - libref->txt_vaddr; if (!as->is_64bit) dci->start_ip &= 0xffffffff; @@ -1808,7 +1808,7 @@ static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip) struct libref *libref = c->libref; int ret; - ret = dwarf_search_unwind_table(as, ip, libref->table_data, libref->table_len); + ret = dwarf_search_unwind_table(as, ip, libref->fde_tab, libref->fde_count); if (ret < 0) return ret; @@ -1998,7 +1998,9 @@ fail: int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwarf_eh_frame_hdr *hdr) { - arch_addr_t addr, fde_count; + arch_addr_t addr; + arch_addr_t fde_count = 0; + arch_addr_t eh_frame = 0; int ret; struct dwarf_addr_space tmp_as; @@ -2015,8 +2017,8 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwar addr = ARCH_ADDR_T(hdr + 1); - /* (Optionally) read eh_frame_ptr: */ - if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->eh_frame_ptr_enc, NULL, 0)) < 0) + /* read eh_frame_ptr: */ + if ((ret = dwarf_read_encoded_pointer_local(&tmp_as, &addr, hdr->eh_frame_ptr_enc, &eh_frame, 0)) < 0) return -DWARF_ENOINFO; /* (Optionally) read fde_count: */ @@ -2028,8 +2030,8 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref, struct dwar return -DWARF_EINVAL; } - libref->table_data = (void *)addr; - libref->table_len = fde_count; + libref->fde_tab = (void *)addr; + libref->fde_count = fde_count; return 0; } diff --git a/library.c b/library.c index 80a9fdc..4ee399c 100644 --- a/library.c +++ b/library.c @@ -66,8 +66,8 @@ void libref_delete(struct libref *libref) free(sym); } - if (libref->image_addr) - munmap(libref->image_addr, libref->load_size); + if (libref->mmap_addr) + munmap(libref->mmap_addr, libref->txt_size); free((void *)libref->filename); free(libref); @@ -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->base, leader->pid); + debug(DEBUG_FUNCTION, "%s@%#lx pid=%d ", libref->filename, libref->key, leader->pid); if (unlikely(options.verbose > 1)) - fprintf(stderr, "+++ library del pid=%d %s@%#lx %#lx-%#lx\n", leader->pid, libref->filename, libref->base, libref->load_addr, libref->load_addr + libref->load_size); + 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); library_delete(leader, lib); } @@ -212,7 +212,7 @@ static void library_each_symbol(struct libref *libref, void (*cb)(struct library static inline int lib_addr_match(struct libref *libref, arch_addr_t addr) { - return addr >= libref->load_addr && addr < libref->load_addr + libref->load_size; + return addr >= libref->txt_vaddr && addr < libref->txt_vaddr + libref->txt_size; } struct libref *addr2libref(struct task *leader, arch_addr_t addr) @@ -226,7 +226,7 @@ struct libref *addr2libref(struct task *leader, arch_addr_t addr) if (lib_addr_match(this, addr)) return this; - if (this->load_addr < addr) + if (this->txt_vaddr < addr) new = &((*new)->rb_left); else new = &((*new)->rb_right); @@ -245,7 +245,7 @@ static void insert_lib(struct task *leader, struct library *lib) parent = *new; - if (this->libref->load_addr < lib->libref->load_addr) + if (this->libref->txt_vaddr < lib->libref->txt_vaddr) new = &((*new)->rb_left); else new = &((*new)->rb_right); @@ -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->base, leader->pid); + debug(DEBUG_PROCESS, "%s@%#lx to pid=%d", libref->filename, libref->key, 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->base, libref->load_addr, libref->load_addr + libref->load_size); + 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); return lib; } @@ -321,3 +321,15 @@ const char *library_execname(struct task *leader) return container_of(leader->libraries_list.next, struct library, list)->libref->filename; } +arch_addr_t vaddr_to_off(struct libref *libref, arch_addr_t addr) +{ + for(unsigned int i = 0; i < libref->loadsegs; ++i) { + GElf_Phdr *phdr = &libref->loadseg[i]; + + if (phdr->p_vaddr >= addr && phdr->p_vaddr + phdr->p_filesz < addr) + return phdr->p_offset + addr - phdr->p_vaddr; + } + +fprintf(stderr, "%s:%d\n", __func__, __LINE__); + return ~0LU; +} diff --git a/library.h b/library.h index 7eb8208..f38173b 100644 --- a/library.h +++ b/library.h @@ -47,8 +47,8 @@ struct libref { * they have the same key. */ arch_addr_t key; - /* Address where the library is mapped. */ - arch_addr_t base; + /* base address assign by the loader */ + unsigned long bias; /* Absolute address of the entry point. Useful for main * binary, though I suppose the value might be useful for the @@ -59,19 +59,24 @@ struct libref { const char *filename; /* executable segment */ - unsigned long load_offset; - unsigned long load_addr; - unsigned long load_size; - unsigned long bias; + unsigned long txt_vaddr; + unsigned long txt_size; + + /* loadable segments */ + unsigned int loadsegs; + GElf_Phdr loadseg[4]; /* mapped image */ - void *image_addr; + void *mmap_addr; + unsigned long mmap_offset; + unsigned long mmap_size; /* global-pointer */ - arch_addr_t gp; - unsigned long seg_offset; - void *table_data; - unsigned long table_len; + arch_addr_t pltgot; + unsigned long eh_frame_hdr; + void *fde_tab; + unsigned long fde_count; + unsigned long eh_frame; unsigned int type; #ifdef __arm__ @@ -136,5 +141,8 @@ void libref_set_filename(struct libref *libref, const char *new_name); /* find library by address */ struct libref *addr2libref(struct task *leader, arch_addr_t addr); +/* return offset for virtual address */ +arch_addr_t vaddr_to_off(struct libref *libref, arch_addr_t addr); + #endif diff --git a/mtelf.c b/mtelf.c index 419b818..434f46c 100644 --- a/mtelf.c +++ b/mtelf.c @@ -47,6 +47,9 @@ #include "common.h" #include "report.h" +#define PAGESIZE 4096 +#define PAGEALIGN (PAGESIZE - 1) + static int open_elf(struct mt_elf *mte, struct task *task, const char *filename) { char *cwd; @@ -216,10 +219,9 @@ static int populate_symtab(struct mt_elf *mte, struct libref *libref) return populate_this_symtab(mte, libref, mte->dynsym, mte->dynstr, mte->dynsym_count); } -static inline int elf_map_image(struct mt_elf *mte, void **image_addr) +static inline int elf_map_image(struct mt_elf *mte, void **mmap_addr) { void *addr; - volatile char *p; addr = mmap(NULL, mte->txt_hdr.p_filesz, PROT_READ, MAP_PRIVATE, mte->fd, mte->txt_hdr.p_offset); if (addr == MAP_FAILED) { @@ -227,39 +229,40 @@ static inline int elf_map_image(struct mt_elf *mte, void **image_addr) return -1; } - *image_addr = addr; - - /* prefetch */ - for(p = addr; (void *)p <= addr + mte->txt_hdr.p_filesz; p += PAGE_SIZE) - *p; + *mmap_addr = addr; return 0; } static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *libref) { - if (elf_map_image(mte, &libref->image_addr)) + if (elf_map_image(mte, &libref->mmap_addr)) return -1; - libref->base = ARCH_ADDR_T(mte->base_addr); libref->entry = ARCH_ADDR_T(mte->entry_addr); - libref->load_offset = mte->txt_hdr.p_offset; - libref->load_addr = mte->txt_hdr.p_vaddr + mte->bias; - libref->load_size = mte->txt_hdr.p_filesz; + libref->mmap_offset = mte->txt_hdr.p_offset; + libref->mmap_size = mte->loadsize; + libref->txt_vaddr = mte->txt_hdr.p_vaddr + mte->bias; + libref->txt_size = mte->txt_hdr.p_filesz; libref->bias = mte->bias; - libref->seg_offset = mte->eh_hdr.p_offset; - libref->gp = mte->pltgot; + libref->eh_frame_hdr = mte->eh_hdr.p_offset; + libref->pltgot = mte->pltgot; libref->key = mte->dyn; + libref->loadsegs = mte->loadsegs; + + for(unsigned int i = 0; i < libref->loadsegs; ++i) + libref->loadseg[i] = mte->loadseg[i]; + #ifdef __arm__ if (mte->exidx_hdr.p_filesz) { - libref->exidx_data = libref->image_addr + mte->exidx_hdr.p_offset; + libref->exidx_data = libref->mmap_addr + mte->exidx_hdr.p_offset; libref->exidx_len = mte->exidx_hdr.p_memsz; } #endif if (mte->eh_hdr.p_filesz && mte->dyn) { - if (dwarf_get_unwind_table(task, libref, (struct dwarf_eh_frame_hdr *)(libref->image_addr - libref->load_offset + mte->eh_hdr.p_offset)) < 0) + if (dwarf_get_unwind_table(task, libref, (struct dwarf_eh_frame_hdr *)(libref->mmap_addr - libref->mmap_offset + mte->eh_hdr.p_offset)) < 0) return -1; } @@ -279,6 +282,9 @@ static void close_elf(struct mt_elf *mte) static int elf_read(struct mt_elf *mte, struct task *task, const char *filename, GElf_Addr bias) { + unsigned long loadsize = 0; + unsigned long loadbase = ~0; + debug(DEBUG_FUNCTION, "filename=%s", filename); if (open_elf(mte, task, filename) < 0) @@ -291,15 +297,28 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename, memset(&mte->eh_hdr, 0, sizeof(mte->eh_hdr)); memset(&mte->exidx_hdr, 0, sizeof(mte->exidx_hdr)); + mte->loadsegs = 0; + for (i = 0; gelf_getphdr(mte->elf, i, &phdr) != NULL; ++i) { switch (phdr.p_type) { case PT_LOAD: - if (!mte->base_addr || mte->base_addr > phdr.p_vaddr + bias) - mte->base_addr = phdr.p_vaddr + bias; + if (mte->loadsegs >= ARRAY_SIZE(mte->loadseg)) { + fprintf(stderr, "Unable to handle more than %lu loadable segments in %s\n", ARRAY_SIZE(mte->loadseg), filename); + return -1; + } + + mte->loadseg[mte->loadsegs++] = phdr; + + if (loadbase > phdr.p_vaddr) + loadbase = phdr.p_vaddr; + + if (loadsize < phdr.p_offset + phdr.p_filesz) + loadsize = phdr.p_offset + phdr.p_filesz; if ((phdr.p_flags & (PF_X | PF_W)) == PF_X) mte->txt_hdr = phdr; + break; case PT_GNU_EH_FRAME: mte->eh_hdr = phdr; @@ -320,12 +339,17 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename, } } - if (!mte->base_addr) { - fprintf(stderr, "Couldn't determine base address of %s\n", filename); + if (!mte->loadsegs) { + fprintf(stderr, "No loadable segemnts in %s\n", filename); return -1; } - debug(DEBUG_FUNCTION, "filename=`%s' load_offset=%#llx addr=%#llx size=%#llx", +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); + + debug(DEBUG_FUNCTION, "filename=`%s' mmap_offset=%#llx addr=%#llx size=%#llx", filename, (unsigned long long)mte->txt_hdr.p_offset, (unsigned long long)mte->txt_hdr.p_vaddr + bias, diff --git a/mtelf.h b/mtelf.h index 0949c7d..a4d14bf 100644 --- a/mtelf.h +++ b/mtelf.h @@ -33,6 +33,10 @@ 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; diff --git a/report.c b/report.c index 59a822a..baad854 100644 --- a/report.c +++ b/report.c @@ -439,9 +439,9 @@ int _report_map(struct task *task, struct library *lib, enum mt_operation op) size_t len = strlen(libref->filename) + 1; struct mt_map_payload *payload = alloca(sizeof(struct mt_map_payload) + len); - payload->addr = libref->load_addr; - payload->offset = libref->load_offset; - payload->size = libref->load_size; + payload->addr = libref->txt_vaddr; + payload->offset = libref->mmap_offset; + payload->size = libref->txt_size; payload->bias = libref->bias; memcpy(payload->filename, libref->filename, len); diff --git a/sysdeps/linux-gnu/x86/dwarf-x86.c b/sysdeps/linux-gnu/x86/dwarf-x86.c index 132abe9..b787ec5 100644 --- a/sysdeps/linux-gnu/x86/dwarf-x86.c +++ b/sysdeps/linux-gnu/x86/dwarf-x86.c @@ -330,9 +330,9 @@ int dwarf_arch_check_call(struct dwarf_addr_space *as, arch_addr_t ip) struct libref *libref = c->libref; for(p = call_op; p->len; ++p) { - if (likely(ip - ARCH_ADDR_T(libref->load_addr) >= p->off)) { + if (likely(ip - ARCH_ADDR_T(libref->txt_vaddr) >= p->off)) { unsigned int i; - unsigned char *addr = libref->image_addr + ip - p->off - libref->load_addr; + unsigned char *addr = libref->mmap_addr + ip - p->off - libref->txt_vaddr; for(i = 0; i < p->len; ++i) { if (unlikely((addr[i] & p->mask[i]) != p->op[i]))