Skip to content

Commit

Permalink
fix dwarf unwinding
Browse files Browse the repository at this point in the history
  • Loading branch information
sstefani committed Apr 17, 2018
1 parent 73a4eca commit 495a9d5
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 68 deletions.
16 changes: 9 additions & 7 deletions client/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -1035,7 +1035,7 @@ static int sort_total(const struct rb_stack **p, const struct rb_stack **q)

static void _process_dump(struct process *process, int (*sortby)(const struct rb_stack **, const struct rb_stack **), int (*skipfunc)(struct rb_stack *), FILE *file, int lflag)
{
struct rb_stack **arr;
struct rb_stack **arr = NULL;
unsigned long i;
void *data;
unsigned long stack_trees = process->stack_trees;
Expand All @@ -1045,9 +1045,12 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
if (dump_init(file) == -1)
return;

if (!stack_trees)
goto skip;

arr = malloc(sizeof(struct rb_stack *) * stack_trees);
if (!arr)
return;
goto skip;

for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data)) {
struct rb_stack *stack_node = container_of(data, struct rb_stack, node);
Expand All @@ -1060,9 +1063,6 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb

dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : "<unknown>");

if (!stack_trees)
goto skip;

qsort(arr, stack_trees, sizeof(struct rb_stack *), (void *)sortby);

if (file == stderr) {
Expand Down Expand Up @@ -1245,8 +1245,10 @@ int process_scan(struct process *process, void *leaks, uint32_t payload_len)
for(i = 0; i < new; ++i) {
struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(new_leaks));

if (dump_printf(" leaked at 0x%08lx (%lu bytes)\n", (unsigned long)block->addr, (unsigned long)block->size) == -1)
break;
if (options.verbose > 1) {
if (dump_printf(" leaked at 0x%08lx (%lu bytes)\n", (unsigned long)block->addr, (unsigned long)block->size) == -1)
break;
}

new_leaks += process->ptr_size;
}
Expand Down
22 changes: 8 additions & 14 deletions dwarf.c
Original file line number Diff line number Diff line change
Expand Up @@ -871,20 +871,16 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
return 0;
}

static inline int lib_addr_match(struct libref *libref, arch_addr_t ip)
{
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)
{
struct dwarf_cursor *c = &as->cursor;
struct libref *libref = c->libref;

if (c->use_prev_instr)
ip -= 1;

if (likely(c->libref)) {
if (lib_addr_match(c->libref, ip))
if (ip >= libref->txt_vaddr && ip < libref->txt_vaddr + libref->txt_size)
return 0;
}

Expand Down Expand Up @@ -930,20 +926,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(fde_tab, fde_count, ip - libref->txt_vaddr - libref->eh_frame_hdr);
e = lookup(fde_tab, fde_count, ip - libref->eh_hdr_vaddr);
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->mmap_addr - (libref->txt_offset - libref->mmap_offset) + e->fde_offset + libref->eh_frame_hdr;
fde_addr = libref->mmap_addr + e->fde_offset + libref->eh_hdr_offset;

if (unlikely((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0))
return ret;

dci->start_ip -= ARCH_ADDR_T(libref->mmap_addr) - libref->txt_vaddr;

dci->start_ip = dci->start_ip - (arch_addr_t)libref->mmap_addr + libref->txt_vaddr;
if (!as->is_64bit)
dci->start_ip &= 0xffffffff;

Expand Down Expand Up @@ -1942,8 +1937,6 @@ int dwarf_step(struct dwarf_addr_space *as)
c->ip = ip;

if (ret == -DWARF_ENOINFO) {
debug(DEBUG_DWARF, "try arch specific step");

ret = dwarf_arch_step(as);
if (!ret) {
if (dwarf_locate_map(as, c->ip) < 0)
Expand Down Expand Up @@ -1988,7 +1981,8 @@ int dwarf_step(struct dwarf_addr_space *as)
break;
}
#endif
debug(DEBUG_DWARF, "error %d", ret);
if (ret != -DWARF_ENOINFO && ret != -DWARF_EBADFRAME)
debug(DEBUG_DWARF, "error %d", ret);

c->valid = 0;
}
Expand All @@ -2003,7 +1997,7 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref)
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);
struct dwarf_eh_frame_hdr *hdr = (struct dwarf_eh_frame_hdr *)(libref->mmap_addr + libref->eh_hdr_offset);

memset(&tmp_as, 0, sizeof(tmp_as));

Expand Down
1 change: 0 additions & 1 deletion dwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
#define DWARF_EINVAL 4 /* unsupported operation or bad value */
#define DWARF_EBADVERSION 5 /* unwind info has unsupported version */
#define DWARF_ENOINFO 6 /* no unwind info found */
#define DWARF_STOPUNWIND 7 /* no unwind info found */

struct dwarf_cie_info {
arch_addr_t start_ip; /* first IP covered by this procedure */
Expand Down
19 changes: 1 addition & 18 deletions library.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,6 @@ 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->txt_vaddr && addr < libref->txt_vaddr + libref->txt_size;
}

struct libref *addr2libref(struct task *leader, arch_addr_t addr)
{
struct rb_node **new = &(leader->libraries_tree.rb_node);
Expand All @@ -223,7 +218,7 @@ struct libref *addr2libref(struct task *leader, arch_addr_t addr)
while (*new) {
struct libref *this = container_of(*new, struct library, rb_node)->libref;

if (lib_addr_match(this, addr))
if (addr >= this->txt_vaddr && addr < this->txt_vaddr + this->txt_size)
return this;

if (this->txt_vaddr < addr)
Expand Down Expand Up @@ -321,15 +316,3 @@ 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;
}
11 changes: 2 additions & 9 deletions library.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,17 @@ struct libref {
unsigned long txt_size;
unsigned long txt_offset;

/* loadable segments */
unsigned int loadsegs;
GElf_Phdr loadseg[4];

/* mapped image */
void *mmap_addr;
unsigned long mmap_offset;
unsigned long mmap_size;

/* global-pointer */
arch_addr_t pltgot;
unsigned long eh_frame_hdr;
unsigned long eh_hdr_offset;
unsigned long eh_hdr_vaddr;
void *fde_tab;
unsigned long fde_count;
unsigned long eh_frame;
unsigned int type;

#ifdef __arm__
Expand Down Expand Up @@ -141,8 +137,5 @@ 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

25 changes: 6 additions & 19 deletions mtelf.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ 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;
Expand Down Expand Up @@ -273,13 +271,10 @@ static int elf_lib_init(struct mt_elf *mte, struct task *task, struct libref *li
libref->txt_size = mte->txt_hdr.p_filesz;
libref->txt_offset = mte->txt_hdr.p_offset - mte->loadbase;
libref->bias = mte->bias;
libref->eh_frame_hdr = mte->eh_hdr.p_offset - mte->loadbase;
libref->pltgot = mte->pltgot;
libref->eh_hdr_offset = mte->eh_hdr.p_offset - mte->loadbase;
libref->eh_hdr_vaddr = mte->eh_hdr.p_vaddr - mte->vstart + mte->bias;
libref->pltgot = mte->pltgot - mte->vstart + mte->bias;
libref->dyn = mte->dyn - mte->vstart + mte->bias;
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) {
Expand Down Expand Up @@ -316,6 +311,7 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename)
unsigned long loadbase = ~0;
unsigned long align;
unsigned long vstart;
unsigned int loadsegs = 0;

debug(DEBUG_FUNCTION, "filename=%s", filename);

Expand All @@ -329,17 +325,10 @@ 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->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;
loadsegs++;

align = phdr.p_align;
if (align)
Expand Down Expand Up @@ -379,15 +368,13 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename)
}
}

if (!mte->loadsegs) {
if (!loadsegs) {
fprintf(stderr, "No loadable segemnts in %s\n", filename);
return -1;
}

//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 %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,
Expand Down

0 comments on commit 495a9d5

Please sign in to comment.