better dwarf address space handling

This commit is contained in:
Stefani Seibold 2015-05-04 12:32:45 +02:00
parent 6bc375640c
commit e7417cafe6
8 changed files with 57 additions and 56 deletions

View File

@ -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 */

41
dwarf.c
View File

@ -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);

View File

@ -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);

View File

@ -3,6 +3,8 @@
* Copyright (C) 2015 Stefani Seibold <stefani@seibold.net>
* 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

View File

@ -27,7 +27,6 @@
#include <string.h>
#include <sys/types.h>
#include <sys/ptrace.h>
//#include <sys/reg.h>
#include "backend.h"
#include "task.h"

View File

@ -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);
}

View File

@ -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;

16
task.c
View File

@ -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)