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 <md@google.com>.

Signed-off-by: San Mehat <san@google.com>
Cc: Michael Davidson <md@google.com>

[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 <san@google.com>
Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Change-Id: I7586677c4ea0e064b5a38c7972102db3b5771500
This commit is contained in:
San Mehat
2009-08-25 16:52:22 -07:00
committed by Tao Huang
parent a8677e8afa
commit 734aea1cce

View File

@@ -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)