mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 08:46:41 +08:00
fix dwarf unwinding
This commit is contained in:
parent
73a4eca5ce
commit
495a9d535d
@ -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)
|
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;
|
unsigned long i;
|
||||||
void *data;
|
void *data;
|
||||||
unsigned long stack_trees = process->stack_trees;
|
unsigned long stack_trees = process->stack_trees;
|
||||||
@ -1045,9 +1045,12 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
|
|||||||
if (dump_init(file) == -1)
|
if (dump_init(file) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!stack_trees)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
arr = malloc(sizeof(struct rb_stack *) * stack_trees);
|
arr = malloc(sizeof(struct rb_stack *) * stack_trees);
|
||||||
if (!arr)
|
if (!arr)
|
||||||
return;
|
goto skip;
|
||||||
|
|
||||||
for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data)) {
|
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);
|
struct rb_stack *stack_node = container_of(data, struct rb_stack, node);
|
||||||
@ -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>");
|
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);
|
qsort(arr, stack_trees, sizeof(struct rb_stack *), (void *)sortby);
|
||||||
|
|
||||||
if (file == stderr) {
|
if (file == stderr) {
|
||||||
@ -1245,8 +1245,10 @@ int process_scan(struct process *process, void *leaks, uint32_t payload_len)
|
|||||||
for(i = 0; i < new; ++i) {
|
for(i = 0; i < new; ++i) {
|
||||||
struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(new_leaks));
|
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)
|
if (options.verbose > 1) {
|
||||||
break;
|
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;
|
new_leaks += process->ptr_size;
|
||||||
}
|
}
|
||||||
|
|||||||
22
dwarf.c
22
dwarf.c
@ -871,20 +871,16 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
|
|||||||
return 0;
|
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)
|
int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip)
|
||||||
{
|
{
|
||||||
struct dwarf_cursor *c = &as->cursor;
|
struct dwarf_cursor *c = &as->cursor;
|
||||||
|
struct libref *libref = c->libref;
|
||||||
|
|
||||||
if (c->use_prev_instr)
|
if (c->use_prev_instr)
|
||||||
ip -= 1;
|
ip -= 1;
|
||||||
|
|
||||||
if (likely(c->libref)) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 dwarf_cie_info *dci = &as->cursor.dci;
|
||||||
struct libref *libref = as->cursor.libref;
|
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)) {
|
if (unlikely(!e)) {
|
||||||
/* IP is inside this table's range, but there is no explicit unwind info. */
|
/* 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);
|
debug(DEBUG_DWARF, "no unwind info found for IP %#lx", ip);
|
||||||
return -DWARF_ENOINFO;
|
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))
|
if (unlikely((ret = dwarf_extract_cfi_from_fde(as, fde_addr)) < 0))
|
||||||
return ret;
|
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)
|
if (!as->is_64bit)
|
||||||
dci->start_ip &= 0xffffffff;
|
dci->start_ip &= 0xffffffff;
|
||||||
|
|
||||||
@ -1942,8 +1937,6 @@ fail:
|
|||||||
c->ip = ip;
|
c->ip = ip;
|
||||||
|
|
||||||
if (ret == -DWARF_ENOINFO) {
|
if (ret == -DWARF_ENOINFO) {
|
||||||
debug(DEBUG_DWARF, "try arch specific step");
|
|
||||||
|
|
||||||
ret = dwarf_arch_step(as);
|
ret = dwarf_arch_step(as);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (dwarf_locate_map(as, c->ip) < 0)
|
if (dwarf_locate_map(as, c->ip) < 0)
|
||||||
@ -1988,7 +1981,8 @@ fail:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
debug(DEBUG_DWARF, "error %d", ret);
|
if (ret != -DWARF_ENOINFO && ret != -DWARF_EBADFRAME)
|
||||||
|
debug(DEBUG_DWARF, "error %d", ret);
|
||||||
|
|
||||||
c->valid = 0;
|
c->valid = 0;
|
||||||
}
|
}
|
||||||
@ -2003,7 +1997,7 @@ int dwarf_get_unwind_table(struct task *task, struct libref *libref)
|
|||||||
arch_addr_t eh_frame = 0;
|
arch_addr_t eh_frame = 0;
|
||||||
int ret;
|
int ret;
|
||||||
struct dwarf_addr_space tmp_as;
|
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));
|
memset(&tmp_as, 0, sizeof(tmp_as));
|
||||||
|
|
||||||
|
|||||||
1
dwarf.h
1
dwarf.h
@ -58,7 +58,6 @@
|
|||||||
#define DWARF_EINVAL 4 /* unsupported operation or bad value */
|
#define DWARF_EINVAL 4 /* unsupported operation or bad value */
|
||||||
#define DWARF_EBADVERSION 5 /* unwind info has unsupported version */
|
#define DWARF_EBADVERSION 5 /* unwind info has unsupported version */
|
||||||
#define DWARF_ENOINFO 6 /* no unwind info found */
|
#define DWARF_ENOINFO 6 /* no unwind info found */
|
||||||
#define DWARF_STOPUNWIND 7 /* no unwind info found */
|
|
||||||
|
|
||||||
struct dwarf_cie_info {
|
struct dwarf_cie_info {
|
||||||
arch_addr_t start_ip; /* first IP covered by this procedure */
|
arch_addr_t start_ip; /* first IP covered by this procedure */
|
||||||
|
|||||||
19
library.c
19
library.c
@ -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 libref *addr2libref(struct task *leader, arch_addr_t addr)
|
||||||
{
|
{
|
||||||
struct rb_node **new = &(leader->libraries_tree.rb_node);
|
struct rb_node **new = &(leader->libraries_tree.rb_node);
|
||||||
@ -223,7 +218,7 @@ struct libref *addr2libref(struct task *leader, arch_addr_t addr)
|
|||||||
while (*new) {
|
while (*new) {
|
||||||
struct libref *this = container_of(*new, struct library, rb_node)->libref;
|
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;
|
return this;
|
||||||
|
|
||||||
if (this->txt_vaddr < addr)
|
if (this->txt_vaddr < addr)
|
||||||
@ -321,15 +316,3 @@ const char *library_execname(struct task *leader)
|
|||||||
return container_of(leader->libraries_list.next, struct library, list)->libref->filename;
|
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
library.h
11
library.h
@ -62,10 +62,6 @@ struct libref {
|
|||||||
unsigned long txt_size;
|
unsigned long txt_size;
|
||||||
unsigned long txt_offset;
|
unsigned long txt_offset;
|
||||||
|
|
||||||
/* loadable segments */
|
|
||||||
unsigned int loadsegs;
|
|
||||||
GElf_Phdr loadseg[4];
|
|
||||||
|
|
||||||
/* mapped image */
|
/* mapped image */
|
||||||
void *mmap_addr;
|
void *mmap_addr;
|
||||||
unsigned long mmap_offset;
|
unsigned long mmap_offset;
|
||||||
@ -73,10 +69,10 @@ struct libref {
|
|||||||
|
|
||||||
/* global-pointer */
|
/* global-pointer */
|
||||||
arch_addr_t pltgot;
|
arch_addr_t pltgot;
|
||||||
unsigned long eh_frame_hdr;
|
unsigned long eh_hdr_offset;
|
||||||
|
unsigned long eh_hdr_vaddr;
|
||||||
void *fde_tab;
|
void *fde_tab;
|
||||||
unsigned long fde_count;
|
unsigned long fde_count;
|
||||||
unsigned long eh_frame;
|
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
|
|
||||||
#ifdef __arm__
|
#ifdef __arm__
|
||||||
@ -141,8 +137,5 @@ void libref_set_filename(struct libref *libref, const char *new_name);
|
|||||||
/* find library by address */
|
/* find library by address */
|
||||||
struct libref *addr2libref(struct task *leader, arch_addr_t addr);
|
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
|
#endif
|
||||||
|
|
||||||
|
|||||||
25
mtelf.c
25
mtelf.c
@ -54,8 +54,6 @@ struct mt_elf {
|
|||||||
int fd;
|
int fd;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
Elf *elf;
|
Elf *elf;
|
||||||
unsigned int loadsegs;
|
|
||||||
GElf_Phdr loadseg[4];
|
|
||||||
unsigned long loadbase;
|
unsigned long loadbase;
|
||||||
unsigned long loadsize;
|
unsigned long loadsize;
|
||||||
unsigned long vstart;
|
unsigned long vstart;
|
||||||
@ -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_size = mte->txt_hdr.p_filesz;
|
||||||
libref->txt_offset = mte->txt_hdr.p_offset - mte->loadbase;
|
libref->txt_offset = mte->txt_hdr.p_offset - mte->loadbase;
|
||||||
libref->bias = mte->bias;
|
libref->bias = mte->bias;
|
||||||
libref->eh_frame_hdr = mte->eh_hdr.p_offset - mte->loadbase;
|
libref->eh_hdr_offset = mte->eh_hdr.p_offset - mte->loadbase;
|
||||||
libref->pltgot = mte->pltgot;
|
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->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__
|
#ifdef __arm__
|
||||||
if (mte->exidx_hdr.p_filesz) {
|
if (mte->exidx_hdr.p_filesz) {
|
||||||
@ -316,6 +311,7 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename)
|
|||||||
unsigned long loadbase = ~0;
|
unsigned long loadbase = ~0;
|
||||||
unsigned long align;
|
unsigned long align;
|
||||||
unsigned long vstart;
|
unsigned long vstart;
|
||||||
|
unsigned int loadsegs = 0;
|
||||||
|
|
||||||
debug(DEBUG_FUNCTION, "filename=%s", filename);
|
debug(DEBUG_FUNCTION, "filename=%s", filename);
|
||||||
|
|
||||||
@ -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->eh_hdr, 0, sizeof(mte->eh_hdr));
|
||||||
memset(&mte->exidx_hdr, 0, sizeof(mte->exidx_hdr));
|
memset(&mte->exidx_hdr, 0, sizeof(mte->exidx_hdr));
|
||||||
|
|
||||||
mte->loadsegs = 0;
|
|
||||||
|
|
||||||
for (i = 0; gelf_getphdr(mte->elf, i, &phdr) != NULL; ++i) {
|
for (i = 0; gelf_getphdr(mte->elf, i, &phdr) != NULL; ++i) {
|
||||||
switch (phdr.p_type) {
|
switch (phdr.p_type) {
|
||||||
case PT_LOAD:
|
case PT_LOAD:
|
||||||
if (mte->loadsegs >= ARRAY_SIZE(mte->loadseg)) {
|
loadsegs++;
|
||||||
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;
|
|
||||||
|
|
||||||
align = phdr.p_align;
|
align = phdr.p_align;
|
||||||
if (align)
|
if (align)
|
||||||
@ -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);
|
fprintf(stderr, "No loadable segemnts in %s\n", filename);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//fprintf(stderr, "%s:%d %s loadbase:%#lx loadsize:%#lx\n", __func__, __LINE__, filename, loadbase, loadsize);
|
|
||||||
mte->loadbase = loadbase & ~PAGEALIGN;
|
mte->loadbase = loadbase & ~PAGEALIGN;
|
||||||
mte->loadsize = (loadsize + (loadbase - mte->loadbase) + PAGEALIGN) & ~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",
|
debug(DEBUG_FUNCTION, "filename=`%s' text offset=%#llx addr=%#llx size=%#llx",
|
||||||
filename,
|
filename,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user