fix attach for 64 bit processes

init the backtrace for the cloned threads after the leader is
initialized
This commit is contained in:
Stefani Seibold 2015-04-29 15:58:53 +02:00
parent 201ac47155
commit e3652d8901
13 changed files with 89 additions and 58 deletions

20
dwarf.c
View File

@ -467,7 +467,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 = as->task->is_64bit;
int is_64bit = task_is_64bit(as->task);
void *tmp_ptr;
int ret;
union {
@ -641,7 +641,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 (as->task->is_64bit)
if (task_is_64bit(as->task))
fde_encoding = DW_EH_PE_udata8;
else
fde_encoding = DW_EH_PE_udata4;
@ -958,8 +958,8 @@ 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 (!as->task->is_64bit)
dci->start_ip = (uint32_t)dci->start_ip;
if (!task_is_64bit(as->task))
dci->start_ip &= 0xffffffff;
if (ip < dci->start_ip || ip >= dci->start_ip + dci->ip_range) {
debug(DEBUG_DWARF, "IP %#lx out of range %#lx-%#lx", ip, dci->start_ip, dci->start_ip + dci->ip_range);
@ -991,11 +991,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 (!as->task->is_64bit)
if (!task_is_64bit(as->task))
val &= 0xffffffff;
if (DWARF_IS_MEM_LOC(loc))
return dwarf_readw(as, &val, valp, as->task->is_64bit);
return dwarf_readw(as, &val, valp, task_is_64bit(as->task));
*valp = val;
return 0;
@ -1331,7 +1331,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 (as->task->is_64bit)
if (task_is_64bit(as->task))
return (int64_t)val;
else
return (int32_t)val;
@ -1348,7 +1348,7 @@ static arch_addr_t read_operand(struct dwarf_addr_space *as, arch_addr_t *addr,
int ret;
if (operand_type == ADDR) {
if (as->task->is_64bit)
if (task_is_64bit(as->task))
operand_type = VAL64;
else
operand_type = VAL32;
@ -1509,7 +1509,7 @@ do { \
break;
case DW_OP_deref:
tmp1 = pop();
if ((ret = dwarf_readw(as, &tmp1, &tmp2, as->task->is_64bit)) < 0)
if ((ret = dwarf_readw(as, &tmp1, &tmp2, task_is_64bit(as->task))) < 0)
return ret;
push(tmp2);
break;
@ -1945,7 +1945,7 @@ fail:
unsigned int i;
for(i = 0; i < 16; ++i) {
if (dwarf_readw(as, &cfa, &ip, as->task->is_64bit))
if (dwarf_readw(as, &cfa, &ip, task_is_64bit(as->task)))
break;
if (!dwarf_locate_map(as, ip)) {

View File

@ -46,7 +46,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) ((as)->task->is_64bit ? 8 : 4)
#define DWARF_ADDR_SIZE(as) (task_is_64bit((as)->task) ? 8 : 4)
#define DWARF_ENOMEM 1 /* out of memory */
#define DWARF_EBADREG 2 /* bad register number */

View File

@ -265,7 +265,6 @@ static struct task *handle_breakpoint(struct task *task)
}
if (breakpoint_on_hit(task, bp)) {
set_instruction_pointer(task, bp->addr);
continue_task(task, 0);
return task;
}

View File

@ -98,7 +98,7 @@ static int report_alloc(struct task *task, enum mt_operation op, unsigned long p
debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size);
if (task->is_64bit)
if (task_is_64bit(task))
return report_alloc64(task, op, ptr, size, depth);
else
return report_alloc32(task, op, ptr, size, depth);
@ -202,7 +202,7 @@ static int _report_mmap64(struct task *task, struct library_symbol *libsym)
size.l = fetch_param(task, 1);
if (!task->is_64bit) {
if (!task_is_64bit(task)) {
size.v.v1 = fetch_param(task, 1);
size.v.v2 = fetch_param(task, 2);
}
@ -248,7 +248,7 @@ static int _report_posix_memalign(struct task *task, struct library_symbol *libs
unsigned long ptr = fetch_param(task, 0);
unsigned long new_ptr;
if (task->is_64bit)
if (task_is_64bit(task))
copy_from_proc(task, ARCH_ADDR_T(ptr), &new_ptr, sizeof(new_ptr));
else {
uint32_t tmp;
@ -421,7 +421,7 @@ int report_attach(struct task *task)
if (!server_connected())
return -1;
return server_send_msg(task->is_64bit ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, &state, sizeof(state));
return server_send_msg(task_is_64bit(task) ? MT_ATTACH64 : MT_ATTACH, task->pid, 0, &state, sizeof(state));
}
int report_fork(struct task *task, struct task *ptask)

View File

@ -56,8 +56,10 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
task->context.regs.ARM_pc = val;
if (ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct pt_regs, ARM_pc), val) == -1)
if (ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct pt_regs, ARM_pc), val) == -1) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno));
}
}
arch_addr_t get_return_addr(struct task *task)
@ -67,8 +69,13 @@ arch_addr_t get_return_addr(struct task *task)
int fetch_context(struct task *task)
{
if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1)
if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't fetch register context: %s\n", task->pid, strerror(errno));
memset(&task->context.regs, 0, sizeof(task->context.regs));
return -1;
}
return 0;
}

View File

@ -43,7 +43,7 @@
static inline unsigned long fix_machine(struct task *task, unsigned long val)
{
if (!task->is_64bit)
if (!task_is_64bit(task))
val &= 0xffffffff;
return val;
@ -70,8 +70,10 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
task->context.regs.nip = val;
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * PT_NIP), val) == -1)
if (ptrace(PTRACE_POKEUSER, task->pid, sizeof(unsigned long) * PT_NIP, val) == -1) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno));
}
}
arch_addr_t get_return_addr(struct task *task)
@ -84,9 +86,13 @@ arch_addr_t get_return_addr(struct task *task)
int fetch_context(struct task *task)
{
if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1)
if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.regs) == -1) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't fetch register context: %s\n", task->pid, strerror(errno));
memset(&task->context.regs, 0, sizeof(task->context.regs));
return -1;
}
return 0;
}
@ -146,7 +152,7 @@ unsigned long fetch_param(struct task *task, unsigned int param)
break;
default:
#ifdef __powerpc64__
if (task->is_64bit) {
if (task_is_64bit(task)) {
val = fetch_stack_64(task, param);
break;
}

View File

@ -191,7 +191,7 @@ int process_tasks(pid_t pid, pid_t ** ret_tasks, size_t *ret_n)
* branch. */
static void *select_32_64(struct task *task, void *p32, void *p64)
{
if (sizeof(long) == 4 || !task->is_64bit)
if (sizeof(long) == 4 || !task_is_64bit(task))
return p32;
else
return p64;

View File

@ -219,7 +219,6 @@ static void process_event(struct task *task, int status)
int stop_signal;
struct task *leader = task->leader;
struct breakpoint *bp = NULL;
unsigned int i;
arch_addr_t ip;
assert(leader != NULL);
@ -248,11 +247,11 @@ static void process_event(struct task *task, int status)
return;
}
if (!leader)
return;
ip = get_instruction_pointer(task);
#if HW_BREAKPOINTS > 0
unsigned int i;
for(i = 0; i < HW_BREAKPOINTS; ++i) {
if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) {
bp = task->hw_bp[i];
@ -261,13 +260,13 @@ static void process_event(struct task *task, int status)
}
if (bp) {
#if HW_BREAKPOINTS > 0
assert(bp->type != SW_BP);
assert(bp->hw_bp_slot == i);
#endif
}
else {
bp = breakpoint_find(leader, get_instruction_pointer(task) - DECR_PC_AFTER_BREAK);
else
#endif
{
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (!bp)
return;
assert(bp->type == SW_BP);
@ -373,6 +372,7 @@ int trace_attach(struct task *task)
assert(task->traced == 0);
if (ptrace(PTRACE_ATTACH, task->pid, 0, 0) == -1) {
if (errno != ESRCH)
fprintf(stderr, "PTRACE_ATTACH pid=%d %s\n", task->pid, strerror(errno));
trace_fail_warning();
return -1;
@ -393,6 +393,7 @@ int trace_set_options(struct task *task)
debug(DEBUG_PROCESS, "pid=%d", task->pid);
if (ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)options) == -1) {
if (errno != ESRCH)
fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno));
return -1;
}
@ -410,6 +411,7 @@ int continue_task(struct task *task, int signum)
task->stopped = 0;
if (ptrace(PTRACE_CONT, task->pid, 0, fix_signal(task, signum)) == -1) {
if (errno != ESRCH)
fprintf(stderr, "PTRACE_CONT pid=%d %s\n", task->pid, strerror(errno));
return -1;
}

View File

@ -64,7 +64,7 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, unsigned int
long ret;
#ifdef __x86_64__
if (!task->is_64bit)
if (!task_is_64bit(task))
addr &= 0xffffffff;
#endif

View File

@ -131,7 +131,7 @@ static int is_plt_entry(struct dwarf_addr_space *as)
int dwarf_arch_init(struct dwarf_addr_space *as)
{
#ifdef __x86_64__
if (as->task->is_64bit) {
if (task_is_64bit(as->task)) {
as->ip_reg = arch_reg64.ip;
as->ret_reg = arch_reg64.sp;
as->num_regs = ARRAY_SIZE(dwarf_to_regnum_map64);
@ -151,7 +151,7 @@ int dwarf_arch_init_unwind(struct dwarf_addr_space *as)
struct dwarf_cursor *c = &as->cursor;
#ifdef __x86_64__
if (as->task->is_64bit) {
if (task_is_64bit(as->task)) {
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);
@ -204,7 +204,7 @@ int dwarf_arch_step(struct dwarf_addr_space *as)
int ret;
#ifdef __x86_64__
arch_reg = as->task->is_64bit ? &arch_reg64 : &arch_reg32;
arch_reg = task_is_64bit(as->task) ? &arch_reg64 : &arch_reg32;
#else
arch_reg = &arch_reg32;
#endif
@ -268,7 +268,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 (as->task->is_64bit) {
if (task_is_64bit(as->task)) {
if (reg >= ARRAY_SIZE(dwarf_to_regnum_map64))
return -DWARF_EBADREG;

View File

@ -40,7 +40,7 @@
static inline unsigned long fix_machine(struct task *task, unsigned long val)
{
if (!task->is_64bit)
if (!task_is_64bit(task))
val &= 0xffffffff;
return val;
@ -75,16 +75,17 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr)
return;
task->context.iregs.rip = val;
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * RIP), val) != -1)
if (ptrace(PTRACE_POKEUSER, task->pid, sizeof(unsigned long) * RIP, val) != -1)
return;
#else
if (task->context.iregs.eip == (long)val)
return;
task->context.iregs.eip = val;
if (ptrace(PTRACE_POKEUSER, task->pid, (sizeof(unsigned long) * EIP), val) != -1)
if (ptrace(PTRACE_POKEUSER, task->pid, sizeof(unsigned long) * EIP, val) != -1)
return;
#endif
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno));
}
@ -96,7 +97,9 @@ arch_addr_t get_return_addr(struct task *task)
a = ptrace(PTRACE_PEEKTEXT, task->pid, get_stack_pointer(task), 0);
if (a == -1 && errno) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't read return value: %s\n", task->pid, strerror(errno));
return ARCH_ADDR_T(0);
}
@ -109,7 +112,10 @@ arch_addr_t get_return_addr(struct task *task)
int fetch_context(struct task *task)
{
if (ptrace(PTRACE_GETREGS, task->pid, 0, &task->context.iregs) == -1) {
if (errno != ESRCH)
fprintf(stderr, "pid=%d Couldn't fetch register context: %s\n", task->pid, strerror(errno));
memset(&task->context.iregs, 0, sizeof(task->context.iregs));
return -1;
}
@ -156,7 +162,7 @@ static unsigned long fetch_param_64(struct task *task, unsigned int param)
unsigned long fetch_param(struct task *task, unsigned int param)
{
#ifdef __x86_64__
if (task->is_64bit)
if (task_is_64bit(task))
return fetch_param_64(task, param);
unsigned long sp = fix_machine(task, task->saved_context.iregs.rsp);

21
task.c
View File

@ -403,6 +403,7 @@ static void show_attached(struct task *task, void *data)
void open_pid(pid_t pid)
{
struct task *leader;
struct list_head *it;
debug(DEBUG_PROCESS, "pid=%d", pid);
@ -441,14 +442,7 @@ void open_pid(pid_t pid)
have_all = 1;
for (i = 0; i < ntasks; ++i) {
if (!pid2task(tasks[i])) {
struct task *task = open_one_pid(tasks[i]);
if (task) {
if (backtrace_init(task) < 0) {
fprintf(stderr, "Cannot init backtrace for pid %d: %s\n", pid, strerror(errno));
goto fail1;
}
}
open_one_pid(tasks[i]);
have_all = 0;
}
@ -464,6 +458,17 @@ void open_pid(pid_t pid)
if (leader_setup(leader) < 0)
goto fail1;
list_for_each(it, &leader->task_list) {
struct task *task = container_of(it, struct task, task_list);
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)
each_task(leader, &show_attached, NULL);

6
task.h
View File

@ -138,5 +138,11 @@ void remove_proc(struct task *leader);
/* return true if no more task is traced */
int task_list_empty(void);
/* return true if task is 64 bit */
static inline int task_is_64bit(struct task *task)
{
return task->is_64bit;
}
#endif