diff --git a/backtrace.h b/backtrace.h index 49ffc98..bdbf9f0 100644 --- a/backtrace.h +++ b/backtrace.h @@ -25,10 +25,10 @@ #include "task.h" -/* init backtrace for given task */ +/* init backtrace for given leader task */ int backtrace_init(struct task *task); -/* destroy backtrace for given task */ +/* destroy backtrace for given leader task */ void backtrace_destroy(struct task *task); /* start backtrace for given task */ diff --git a/dwarf.c b/dwarf.c index fab854f..2280e4d 100644 --- a/dwarf.c +++ b/dwarf.c @@ -319,6 +319,8 @@ static const uint8_t dwarf_operands[256] = { static int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void *valp, size_t size) { + struct dwarf_cursor *c = &as->cursor; + if (!addr) { debug(DEBUG_DWARF, "invalid null memory access"); return -DWARF_EINVAL; @@ -337,8 +339,8 @@ static int dwarf_access_mem(struct dwarf_addr_space *as, arch_addr_t addr, void return 0; } - if (copy_from_proc(as->task, addr, &as->val, sizeof(as->val)) != sizeof(as->val)) { - debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", addr, as->task->pid); + if (copy_from_proc(c->task, addr, &as->val, sizeof(as->val)) != sizeof(as->val)) { + debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", addr, c->task->pid); return -DWARF_EINVAL; } @@ -469,7 +471,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.lib->gp; - int is_64bit = task_is_64bit(as->task); + int is_64bit = as->is_64bit; void *tmp_ptr; int ret; union { @@ -643,7 +645,7 @@ static int parse_cie(struct dwarf_addr_space *as, arch_addr_t addr, struct dwarf "address-unit sized constants". The `R' augmentation can be used to override this, but by default, we pick an address-sized unit for fde_encoding. */ - if (task_is_64bit(as->task)) + if (as->is_64bit) fde_encoding = DW_EH_PE_udata8; else fde_encoding = DW_EH_PE_udata4; @@ -882,6 +884,7 @@ static inline int lib_addr_match(struct library *lib, arch_addr_t ip) int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) { + struct dwarf_cursor *c = &as->cursor; struct task *leader; struct list_head *it; @@ -890,7 +893,7 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip) return 0; } - leader = as->task->leader; + leader = c->task->leader; as->cursor.lib = NULL; @@ -960,7 +963,7 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip dci->start_ip -= ARCH_ADDR_T(lib->image_addr) - lib->load_addr; - if (!task_is_64bit(as->task)) + if (!as->is_64bit) dci->start_ip &= 0xffffffff; if (ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range) { @@ -973,6 +976,8 @@ static int dwarf_search_unwind_table(struct dwarf_addr_space *as, arch_addr_t ip static int dwarf_access_reg(struct dwarf_addr_space *as, unsigned int reg, arch_addr_t *valp) { + struct dwarf_cursor *c = &as->cursor; + int map = dwarf_arch_map_reg(as, reg); if (map < 0) { @@ -981,7 +986,7 @@ static int dwarf_access_reg(struct dwarf_addr_space *as, unsigned int reg, arch_ return map; } - *valp = fetch_reg(as->task, map); + *valp = fetch_reg(c->task, map); return 0; } @@ -993,11 +998,11 @@ int dwarf_get(struct dwarf_addr_space *as, struct dwarf_loc loc, arch_addr_t *va if (DWARF_IS_REG_LOC(loc)) return dwarf_access_reg(as, val, valp); - if (!task_is_64bit(as->task)) + if (!as->is_64bit) val &= 0xffffffff; if (DWARF_IS_MEM_LOC(loc)) - return dwarf_readw(as, &val, valp, task_is_64bit(as->task)); + return dwarf_readw(as, &val, valp, as->is_64bit); *valp = val; return 0; @@ -1333,7 +1338,7 @@ static int parse_fde(struct dwarf_addr_space *as, arch_addr_t ip, struct dwarf_r static long sword(struct dwarf_addr_space *as, arch_addr_t val) { - if (task_is_64bit(as->task)) + if (as->is_64bit) return (int64_t)val; else return (int32_t)val; @@ -1350,7 +1355,7 @@ static arch_addr_t read_operand(struct dwarf_addr_space *as, arch_addr_t *addr, int ret; if (operand_type == ADDR) { - if (task_is_64bit(as->task)) + if (as->is_64bit) operand_type = VAL64; else operand_type = VAL32; @@ -1511,7 +1516,7 @@ do { \ break; case DW_OP_deref: tmp1 = pop(); - if ((ret = dwarf_readw(as, &tmp1, &tmp2, task_is_64bit(as->task))) < 0) + if ((ret = dwarf_readw(as, &tmp1, &tmp2, as->is_64bit)) < 0) return ret; push(tmp2); break; @@ -1832,7 +1837,7 @@ static int fetch_proc_info(struct dwarf_addr_space *as, arch_addr_t ip) return ret; } -int dwarf_init_unwind(struct dwarf_addr_space *as) +int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task) { struct dwarf_cursor *c = &as->cursor; @@ -1842,6 +1847,7 @@ int dwarf_init_unwind(struct dwarf_addr_space *as) c->use_prev_instr = 0; c->valid = 1; c->lib = NULL; + c->task = task; as->addr = 0; as->val = 0; @@ -1851,7 +1857,7 @@ int dwarf_init_unwind(struct dwarf_addr_space *as) return dwarf_arch_init_unwind(as); } -void *dwarf_init(struct task *task) +void *dwarf_init(int is_64bit) { struct dwarf_addr_space *as; int ret; @@ -1860,7 +1866,7 @@ void *dwarf_init(struct task *task) memset(as, 0, sizeof(*as)); - as->task = task; + as->is_64bit = is_64bit; as->addr = 0; as->val = 0; @@ -1947,7 +1953,7 @@ fail: unsigned int i; for(i = 0; i < 16; ++i) { - if (dwarf_readw(as, &cfa, &ip, task_is_64bit(as->task))) + if (dwarf_readw(as, &cfa, &ip, as->is_64bit)) break; if (!dwarf_locate_map(as, ip)) { @@ -1984,8 +1990,9 @@ int dwarf_get_unwind_table(struct task *task, struct library *lib, struct dwarf_ memset(&tmp_as, 0, sizeof(tmp_as)); - tmp_as.task = task; + tmp_as.is_64bit = task->is_64bit; tmp_as.cursor.lib = lib; + tmp_as.cursor.task = task; if (hdr->version != DW_EH_VERSION) { debug(DEBUG_DWARF, "exception table has unexpected version %d", hdr->version); diff --git a/dwarf.h b/dwarf.h index 600500e..b35a2e5 100644 --- a/dwarf.h +++ b/dwarf.h @@ -48,7 +48,7 @@ #define DWARF_IS_REG_LOC(l) ((l).type == DWARF_LOC_TYPE_REG) #define DWARF_IS_VAL_LOC(l) ((l).type == DWARF_LOC_TYPE_VAL) -#define DWARF_ADDR_SIZE(as) (task_is_64bit((as)->task) ? 8 : 4) +#define DWARF_ADDR_SIZE(as) ((as)->is_64bit ? 8 : 4) #define DWARF_ENOMEM 1 /* out of memory */ #define DWARF_EBADREG 2 /* bad register number */ @@ -83,6 +83,7 @@ struct dwarf_loc { }; struct dwarf_cursor { + struct task *task; arch_addr_t cfa; /* canonical frame address; aka frame-/stack-pointer */ arch_addr_t ip; /* instruction pointer */ arch_addr_t ret_addr_column; /* column for return-address */ @@ -94,7 +95,7 @@ struct dwarf_cursor { }; struct dwarf_addr_space { - struct task *task; + unsigned int is_64bit:1; arch_addr_t addr; union { long val; @@ -108,9 +109,9 @@ struct dwarf_addr_space { struct dwarf_eh_frame_hdr; -void *dwarf_init(struct task *task); +void *dwarf_init(int is_64bit); void dwarf_destroy(struct dwarf_addr_space *as); -int dwarf_init_unwind(struct dwarf_addr_space *as); +int dwarf_init_unwind(struct dwarf_addr_space *as, struct task *task); int dwarf_step(struct dwarf_addr_space *as); arch_addr_t dwarf_get_ip(struct dwarf_addr_space *as); diff --git a/options.c b/options.c index 8715d60..66e4887 100644 --- a/options.c +++ b/options.c @@ -3,6 +3,8 @@ * Copyright (C) 2015 Stefani Seibold * This file is based on the ltrace source * + * This work was sponsored by Rohde & Schwarz GmbH & Co. KG, Munich. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c index f03d08d..24d55a6 100644 --- a/sysdeps/linux-gnu/arm/regs.c +++ b/sysdeps/linux-gnu/arm/regs.c @@ -27,7 +27,6 @@ #include #include #include -//#include #include "backend.h" #include "task.h" diff --git a/sysdeps/linux-gnu/backtrace.c b/sysdeps/linux-gnu/backtrace.c index af889c7..5959386 100644 --- a/sysdeps/linux-gnu/backtrace.c +++ b/sysdeps/linux-gnu/backtrace.c @@ -27,15 +27,18 @@ int backtrace_init(struct task *task) { + assert(task->leader == task); assert(task->backtrace == NULL); - task->backtrace = dwarf_init(task); + task->backtrace = dwarf_init(task->is_64bit); return task->backtrace != NULL; } void backtrace_destroy(struct task *task) { + assert(task->leader == task); + if (task->backtrace) { dwarf_destroy(task->backtrace); @@ -45,22 +48,25 @@ void backtrace_destroy(struct task *task) int backtrace_init_unwind(struct task *task) { - assert(task->backtrace); + assert(task->leader); + assert(task->leader->backtrace); - return dwarf_init_unwind(task->backtrace); + return dwarf_init_unwind(task->leader->backtrace, task); } unsigned long backtrace_get_ip(struct task *task) { - assert(task->backtrace); + assert(task->leader); + assert(task->leader->backtrace); - return dwarf_get_ip(task->backtrace); + return dwarf_get_ip(task->leader->backtrace); } int backtrace_step(struct task *task) { - assert(task->backtrace); + assert(task->leader); + assert(task->leader->backtrace); - return dwarf_step(task->backtrace); + return dwarf_step(task->leader->backtrace); } diff --git a/sysdeps/linux-gnu/x86/dwarf-x86.c b/sysdeps/linux-gnu/x86/dwarf-x86.c index d56537b..0caa544 100644 --- a/sysdeps/linux-gnu/x86/dwarf-x86.c +++ b/sysdeps/linux-gnu/x86/dwarf-x86.c @@ -140,8 +140,8 @@ static int is_plt_entry(struct dwarf_addr_space *as) struct dwarf_cursor *c = &as->cursor; uint8_t data[12]; - if (copy_from_proc(as->task, c->ip, data, sizeof(data)) != sizeof(data)) { - debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", c->ip, as->task->pid); + if (copy_from_proc(c->task, c->ip, data, sizeof(data)) != sizeof(data)) { + debug(DEBUG_DWARF, "cannot access memory %#lx of pid %d", c->ip, c->task->pid); return 0; } @@ -154,7 +154,7 @@ static int is_plt_entry(struct dwarf_addr_space *as) int dwarf_arch_init(struct dwarf_addr_space *as) { #ifdef __x86_64__ - if (task_is_64bit(as->task)) { + if (as->is_64bit) { as->ip_reg = arch_reg64.ip; as->ret_reg = arch_reg64.sp; as->num_regs = ARRAY_SIZE(dwarf_to_regnum_map64); @@ -174,7 +174,7 @@ int dwarf_arch_init_unwind(struct dwarf_addr_space *as) struct dwarf_cursor *c = &as->cursor; #ifdef __x86_64__ - if (task_is_64bit(as->task)) { + if (as->is_64bit) { c->loc[DWARF_X86_RAX] = DWARF_REG_LOC(DWARF_X86_RAX); c->loc[DWARF_X86_RDX] = DWARF_REG_LOC(DWARF_X86_RDX); c->loc[DWARF_X86_RCX] = DWARF_REG_LOC(DWARF_X86_RCX); @@ -193,8 +193,8 @@ int dwarf_arch_init_unwind(struct dwarf_addr_space *as) c->loc[DWARF_X86_R15] = DWARF_REG_LOC(DWARF_X86_R15); c->loc[DWARF_X86_RIP] = DWARF_REG_LOC(DWARF_X86_RIP); - c->ip = fetch_reg(as->task, RIP); - c->cfa = fetch_reg(as->task, RSP); + c->ip = fetch_reg(c->task, RIP); + c->cfa = fetch_reg(c->task, RSP); } else #endif @@ -209,8 +209,8 @@ int dwarf_arch_init_unwind(struct dwarf_addr_space *as) c->loc[DWARF_X86_EDI] = DWARF_REG_LOC(DWARF_X86_EDI); c->loc[DWARF_X86_EIP] = DWARF_REG_LOC(DWARF_X86_EIP); - c->ip = fetch_reg(as->task, dwarf_to_regnum_map32[DWARF_X86_EIP]); - c->cfa = fetch_reg(as->task, dwarf_to_regnum_map32[DWARF_X86_ESP]); + c->ip = fetch_reg(c->task, dwarf_to_regnum_map32[DWARF_X86_EIP]); + c->cfa = fetch_reg(c->task, dwarf_to_regnum_map32[DWARF_X86_ESP]); } c->use_prev_instr = 0; @@ -227,7 +227,7 @@ int dwarf_arch_step(struct dwarf_addr_space *as) int ret; #ifdef __x86_64__ - arch_reg = task_is_64bit(as->task) ? &arch_reg64 : &arch_reg32; + arch_reg = as->is_64bit ? &arch_reg64 : &arch_reg32; #else arch_reg = &arch_reg32; #endif @@ -291,7 +291,7 @@ int dwarf_arch_step(struct dwarf_addr_space *as) int dwarf_arch_map_reg(struct dwarf_addr_space *as, unsigned int reg) { #ifdef __x86_64__ - if (task_is_64bit(as->task)) { + if (as->is_64bit) { if (reg >= ARRAY_SIZE(dwarf_to_regnum_map64)) return -DWARF_EBADREG; diff --git a/task.c b/task.c index adabc15..c43c28d 100644 --- a/task.c +++ b/task.c @@ -191,13 +191,13 @@ static void leader_cleanup(struct task *task) library_clear_all(task); breakpoint_clear_all(task); + backtrace_destroy(task); list_del(&task->leader_list); } static void task_destroy(struct task *task) { - backtrace_destroy(task); arch_task_destroy(task); os_task_destroy(task); detach_task(task); @@ -257,7 +257,6 @@ int process_exec(struct task *task) breakpoint_disable_all(leader); each_task(leader, &remove_task_cb, leader); - backtrace_destroy(leader); os_task_destroy(leader); arch_task_destroy(leader); leader_cleanup(leader); @@ -333,17 +332,9 @@ int task_clone(struct task *task, struct task *newtask) newtask->is_64bit = task->is_64bit; - if (backtrace_init(newtask) < 0) - goto fail; - breakpoint_hw_clone(newtask); return 0; -fail: - fprintf(stderr, "failed to clone process %d->%d : %s\n", task->pid, newtask->pid, strerror(errno)); - task_destroy(newtask); - - return -1; } int task_fork(struct task *task, struct task *newtask) @@ -482,11 +473,6 @@ void open_pid(pid_t pid) assert(task->leader == leader); task->is_64bit = leader->is_64bit; - - if (backtrace_init(task) < 0) { - fprintf(stderr, "Cannot init backtrace for pid %d: %s\n", pid, strerror(errno)); - goto fail1; - } }; if (options.verbose)