diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c index 58a7839bc..fb0d6baa5 100644 --- a/debuggerd/arm/machine.c +++ b/debuggerd/arm/machine.c @@ -36,6 +36,9 @@ #include "utility.h" +/* enable to dump memory pointed to by every register */ +#define DUMP_MEM_FOR_ALL_REGS 0 + #ifdef WITH_VFP #ifdef WITH_VFP_D32 #define NUM_VFP_REGS 32 @@ -117,82 +120,128 @@ static void show_nearby_maps(int tfd, int pid, mapinfo *map) } } +/* + * Dumps a few bytes of memory, starting a bit before and ending a bit + * after the specified address. + */ +static void dump_memory(int tfd, int pid, uintptr_t addr, + bool only_in_tombstone) +{ + char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */ + char ascii_buffer[32]; /* actual 16 + 1 == 17 */ + uintptr_t p, end; + + p = addr & ~3; + p -= 32; + if (p > addr) { + /* catch underflow */ + p = 0; + } + end = p + 80; + /* catch overflow; 'end - p' has to be multiples of 16 */ + while (end < p) + end -= 16; + + /* Dump the code around PC as: + * addr contents ascii + * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q + * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p...... + */ + while (p < end) { + char* asc_out = ascii_buffer; + + sprintf(code_buffer, "%08x ", p); + + int i; + for (i = 0; i < 4; i++) { + /* + * If we see (data == -1 && errno != 0), we know that the ptrace + * call failed, probably because we're dumping memory in an + * unmapped or inaccessible page. I don't know if there's + * value in making that explicit in the output -- it likely + * just complicates parsing and clarifies nothing for the + * enlightened reader. + */ + long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); + sprintf(code_buffer + strlen(code_buffer), "%08lx ", data); + + int j; + for (j = 0; j < 4; j++) { + /* + * Our isprint() allows high-ASCII characters that display + * differently (often badly) in different viewers, so we + * just use a simpler test. + */ + char val = (data >> (j*8)) & 0xff; + if (val >= 0x20 && val < 0x7f) { + *asc_out++ = val; + } else { + *asc_out++ = '.'; + } + } + p += 4; + } + *asc_out = '\0'; + _LOG(tfd, only_in_tombstone, "%s %s\n", code_buffer, ascii_buffer); + } + +} void dump_stack_and_code(int tfd, int pid, mapinfo *map, int unwind_depth, unsigned int sp_list[], bool at_fault) { - unsigned int sp, pc, lr, p, end, data; struct pt_regs r; int sp_depth; bool only_in_tombstone = !at_fault; - char code_buffer[80]; if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return; - sp = r.ARM_sp; - pc = r.ARM_pc; - lr = r.ARM_lr; - _LOG(tfd, only_in_tombstone, "\ncode around pc:\n"); - - p = pc & ~3; - p -= 32; - if (p > pc) - p = 0; - end = p + 80; - /* 'end - p' has to be multiples of 16 */ - while (end < p) - end -= 16; - - /* Dump the code around PC as: - * addr contents - * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c - * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 - */ - while (p < end) { - int i; - - sprintf(code_buffer, "%08x ", p); - for (i = 0; i < 4; i++) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - sprintf(code_buffer + strlen(code_buffer), "%08x ", data); - p += 4; - } - _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); - } - - if (lr != pc) { - _LOG(tfd, only_in_tombstone, "\ncode around lr:\n"); - - p = lr & ~3; - p -= 32; - if (p > lr) - p = 0; - end = p + 80; - /* 'end - p' has to be multiples of 16 */ - while (end < p) - end -= 16; - - /* Dump the code around LR as: - * addr contents - * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c - * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 + if (DUMP_MEM_FOR_ALL_REGS && at_fault) { + /* + * If configured to do so, dump memory around *all* registers + * for the crashing thread. + * + * TODO: remove duplicates. */ - while (p < end) { - int i; + static const char REG_NAMES[] = "R0R1R2R3R4R5R6R7R8R9SLFPIPSPLRPC"; - sprintf(code_buffer, "%08x ", p); - for (i = 0; i < 4; i++) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - sprintf(code_buffer + strlen(code_buffer), "%08x ", data); - p += 4; + int reg; + for (reg = 0; reg < 16; reg++) { + /* this may not be a valid way to access, but it'll do for now */ + uintptr_t addr = r.uregs[reg]; + + /* + * Don't bother if it looks like a small int or ~= null, or if + * it's in the kernel area. + */ + if (addr < 4096 || addr >= 0xc0000000) { + continue; } - _LOG(tfd, only_in_tombstone, "%s\n", code_buffer); + + _LOG(tfd, only_in_tombstone, "\nmem near %.2s:\n", + ®_NAMES[reg*2]); + dump_memory(tfd, pid, addr, false); + } + } else { + unsigned int pc, lr; + pc = r.ARM_pc; + lr = r.ARM_lr; + + _LOG(tfd, only_in_tombstone, "\ncode around pc:\n"); + dump_memory(tfd, pid, (uintptr_t) pc, only_in_tombstone); + + if (lr != pc) { + _LOG(tfd, only_in_tombstone, "\ncode around lr:\n"); + dump_memory(tfd, pid, (uintptr_t) lr, only_in_tombstone); } } show_nearby_maps(tfd, pid, map); + unsigned int p, end; + unsigned int sp = r.ARM_sp; + p = sp - 64; if (p > sp) p = 0; @@ -227,7 +276,7 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, while (p <= end) { char *prompt; char level[16]; - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); + long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); if (p == sp_list[sp_depth]) { sprintf(level, "#%02d", sp_depth++); prompt = level; @@ -252,7 +301,7 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map, end = ~7; while (p <= end) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); + long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); _LOG(tfd, (sp_depth > 2) || only_in_tombstone, " %08x %08x %s\n", p, data, map_to_name(map, data, ""));