mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-08 01:36:43 +08:00
better dwarf address space handling
This commit is contained in:
parent
6bc375640c
commit
e7417cafe6
@ -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
41
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);
|
||||
|
||||
9
dwarf.h
9
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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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
16
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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user