aboutsummaryrefslogtreecommitdiffstats
path: root/debuggerd
diff options
context:
space:
mode:
Diffstat (limited to 'debuggerd')
-rw-r--r--debuggerd/arm/machine.c157
1 files changed, 103 insertions, 54 deletions
diff --git a/debuggerd/arm/machine.c b/debuggerd/arm/machine.c
index 58a7839b..fb0d6baa 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)
}
}
-
-void dump_stack_and_code(int tfd, int pid, mapinfo *map,
- int unwind_depth, unsigned int sp_list[],
- bool at_fault)
+/*
+ * 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)
{
- 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;
+ char code_buffer[64]; /* actual 8+1+((8+1)*4) + 1 == 45 */
+ char ascii_buffer[32]; /* actual 16 + 1 == 17 */
+ uintptr_t p, end;
- _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
-
- p = pc & ~3;
+ p = addr & ~3;
p -= 32;
- if (p > pc)
+ if (p > addr) {
+ /* catch underflow */
p = 0;
+ }
end = p + 80;
- /* 'end - p' has to be multiples of 16 */
+ /* catch overflow; '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
+ * addr contents ascii
+ * 00008d34 ef000000 e8bd0090 e1b00000 512fff1e ............../Q
+ * 00008d44 ea00b1f9 e92d0090 e3a070fc ef000000 ......-..p......
*/
- while (p < end) {
- int i;
+ while (p < end) {
+ char* asc_out = ascii_buffer;
sprintf(code_buffer, "%08x ", p);
+
+ int i;
for (i = 0; i < 4; i++) {
- data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
- sprintf(code_buffer + strlen(code_buffer), "%08x ", data);
+ /*
+ * 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;
}
- _LOG(tfd, only_in_tombstone, "%s\n", code_buffer);
+ *asc_out = '\0';
+ _LOG(tfd, only_in_tombstone, "%s %s\n", code_buffer, ascii_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
+}
+
+void dump_stack_and_code(int tfd, int pid, mapinfo *map,
+ int unwind_depth, unsigned int sp_list[],
+ bool at_fault)
+{
+ struct pt_regs r;
+ int sp_depth;
+ bool only_in_tombstone = !at_fault;
+
+ if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;
+
+ 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;
-
- 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;
+ static const char REG_NAMES[] = "R0R1R2R3R4R5R6R7R8R9SLFPIPSPLRPC";
+
+ 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",
+ &REG_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, ""));