From 734aea1ccebd70639af43c84d4f86f3d5456abe3 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 25 Aug 2009 16:52:22 -0700 Subject: [PATCH] ARM: process: Add display of memory around registers when displaying regs. This is extremely useful in diagnosing remote crashes, and is based heavily on original work by . Signed-off-by: San Mehat Cc: Michael Davidson [ARM] process: Use uber-safe probe_kernel_address() to read mem when dumping. This prevents the dump from taking pagefaults / external aborts. Signed-off-by: San Mehat Signed-off-by: Andy Yan Change-Id: I7586677c4ea0e064b5a38c7972102db3b5771500 --- arch/arm/kernel/process.c | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index ae60679939a4..cb49744c6d46 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -112,6 +112,88 @@ void __show_regs_alloc_free(struct pt_regs *regs) } } +static int arm_insn_read(void *addr, u32 *insnp) +{ + int ret; + __le32 val; + + ret = copy_from_kernel_nofault(&val, addr, 4); + if (!ret) + *insnp = le32_to_cpu(val); + + return ret; +} + +/* + * dump a block of kernel memory from around the given address + */ +static void show_data(unsigned long addr, int nbytes, const char *name) +{ + int i, j; + int nlines; + u32 *p; + + /* + * don't attempt to dump non-kernel addresses or + * values that are probably just small negative numbers + */ + if (addr < PAGE_OFFSET || addr > -4096UL) + return; + + printk("\n%s: %#lx:\n", name, addr); + + /* + * round address down to a 32 bit boundary + * and always dump a multiple of 32 bytes + */ + p = (u32 *)(addr & ~(sizeof(u32) - 1)); + nbytes += (addr & (sizeof(u32) - 1)); + nlines = (nbytes + 31) / 32; + + for (i = 0; i < nlines; i++) { + /* + * just display low 16 bits of address to keep + * each line of the dump < 80 characters + */ + if (i == (nlines / 2)) + printk("%04lx*", (unsigned long)p & 0xffff); + else + printk("%04lx ", (unsigned long)p & 0xffff); + + for (j = 0; j < 8; j++) { + u32 data; + + if (arm_insn_read(p, &data)) { + pr_cont(" ********"); + } else { + pr_cont(" %08x", data); + } + ++p; + } + pr_cont("\n"); + } +} + +static void show_extra_register_data(struct pt_regs *regs, int nbytes) +{ + show_data(regs->ARM_pc - nbytes, nbytes * 2, "PC"); + show_data(regs->ARM_lr - nbytes, nbytes * 2, "LR"); + show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); + show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); + show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); + show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); + show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); + show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); + show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); + show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); + show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); + show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); + show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); + show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); + show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); + show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); +} + void __show_regs(struct pt_regs *regs) { unsigned long flags; @@ -198,6 +280,8 @@ void __show_regs(struct pt_regs *regs) printk("Control: %08x%s\n", ctrl, buf); } #endif + if (!user_mode(regs)) + show_extra_register_data(regs, 512); } void show_regs(struct pt_regs * regs)