static void print_backtrace(const intptr_t *bt, unsigned int depth) { const mapinfo *mi; unsigned int cnt; unsigned int rel_pc; intptr_t self_bt[MAX_BACKTRACE_DEPTH]; if (!bt) { depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH); bt = self_bt; } log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) { mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc); log_message("\t#%02d pc %08x %s\n", cnt, mi ? (intptr_t)rel_pc : bt[cnt], mi ? mi->name : "(unknown)"); } }
/* routine to determine if a word value represents a return address * This routine checks to see if the word value points to an address that * immediately follows a branch instruction. */ int is_ARM_return_address(int pid, mapinfo *milist, unsigned int value) { unsigned int addr; unsigned int data; unsigned int rel_addr; const mapinfo *mi; /* check 4 bytes before the address */ addr = value-4; /* FIXTHIS - check map to see if this is in text segment */ rel_addr = addr; mi = pc_to_mapinfo(milist, addr, &rel_addr); if (mi == NULL) { /* address is not in the executable memory map */ /* note that the [stack] map is not executable, * and has already been filtered from the map list */ return 0; } DLOG("checking addr=0x%08lx for instruction\n", addr); data = ptrace(PTRACE_PEEKTEXT, pid, (void*)addr, NULL); /* detect failure to read data from process memory */ if (data==0xffffffff) { return 0; } DLOG("instruction at %08lx is %08lx\n", addr, data); if (is_ARM_bl(data)) { DLOG("this instruction is a branch and link, with offset %d and target 0x%08x\n", branch_offset(data), branch_target(addr, data)); return 1; } else { return 0; } }
int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map, bool at_fault) { struct pt_regs_x86 r; unsigned int stack_level = 0; unsigned int stack_depth = 0; unsigned int rel_pc; unsigned int stack_ptr; unsigned int stack_content; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return 0; unsigned int eip = (unsigned int)r.eip; unsigned int ebp = (unsigned int)r.ebp; unsigned int cur_sp = (unsigned int)r.esp; const mapinfo *mi; const struct symbol* sym = 0; //ebp==0, it indicates that the stack is poped to the bottom or there is no stack at all. while (ebp) { mi = pc_to_mapinfo(map, eip, &rel_pc); /* See if we can determine what symbol this stack frame resides in */ if (mi != 0 && mi->symbols != 0) { sym = symbol_table_lookup(mi->symbols, rel_pc); } if (sym) { _LOG(tfd, !at_fault, " #%02d eip: %08x %s (%s)\n", stack_level, eip, mi ? mi->name : "", sym->name); } else { _LOG(tfd, !at_fault, " #%02d eip: %08x %s\n", stack_level, eip, mi ? mi->name : ""); } stack_level++; if (stack_level >= STACK_DEPTH || eip == 0) break; eip = ptrace(PTRACE_PEEKTEXT, pid, (void*)(ebp + 4), NULL); ebp = ptrace(PTRACE_PEEKTEXT, pid, (void*)ebp, NULL); } ebp = (unsigned int)r.ebp; stack_depth = stack_level; stack_level = 0; if (ebp) _LOG(tfd, !at_fault, "stack: \n"); while (ebp) { stack_ptr = cur_sp; while((int)(ebp - stack_ptr) >= 0) { stack_content = ptrace(PTRACE_PEEKTEXT, pid, (void*)stack_ptr, NULL); mi = pc_to_mapinfo(map, stack_content, &rel_pc); /* See if we can determine what symbol this stack frame resides in */ if (mi != 0 && mi->symbols != 0) { sym = symbol_table_lookup(mi->symbols, rel_pc); } if (sym) { _LOG(tfd, !at_fault, " #%02d %08x %08x %s (%s)\n", stack_level, stack_ptr, stack_content, mi ? mi->name : "", sym->name); } else { _LOG(tfd, !at_fault, " #%02d %08x %08x %s\n", stack_level, stack_ptr, stack_content, mi ? mi->name : ""); } stack_ptr = stack_ptr + 4; //the stack frame may be very deep. if((int)(stack_ptr - cur_sp) >= STACK_FRAME_DEPTH) { _LOG(tfd, !at_fault, " ...... ...... \n"); break; } } cur_sp = ebp + 4; stack_level++; if (stack_level >= STACK_DEPTH || stack_level >= stack_depth) break; ebp = ptrace(PTRACE_PEEKTEXT, pid, (void*)ebp, NULL); } return stack_depth; }