diff options
author | Greg Hackmann <ghackmann@google.com> | 2014-09-09 17:36:05 -0700 |
---|---|---|
committer | John Stultz <john.stultz@linaro.org> | 2016-02-16 13:54:04 -0800 |
commit | 565ae0937ee24576f480ffb755addf1be28aa980 (patch) | |
tree | eab26b6bab6a3c3ae3e018a6dbd80a2db0a63652 /arch/arm64 | |
parent | c6a9c8e51b188d049496643db2cfbb67df65190c (diff) |
arm64: process: dump memory around registers when displaying regs
A port of 8608d7c4418c75841c562a90cddd9beae5798a48 to ARM64. Both the
original code and this port are limited to dumping kernel addresses, so
don't bother if the registers are from a userspace process.
Change-Id: Idc76804c54efaaeb70311cbb500c54db6dac4525
Signed-off-by: Greg Hackmann <ghackmann@google.com>
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/kernel/process.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index f75b540bc3b4..62068ded1e90 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -164,6 +164,70 @@ void machine_restart(char *cmd) while (1); } +/* + * 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 > -256UL) + 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 + */ + printk("%04lx ", (unsigned long)p & 0xffff); + for (j = 0; j < 8; j++) { + u32 data; + if (probe_kernel_address(p, data)) { + printk(" ********"); + } else { + printk(" %08x", data); + } + ++p; + } + printk("\n"); + } +} + +static void show_extra_register_data(struct pt_regs *regs, int nbytes) +{ + mm_segment_t fs; + unsigned int i; + + fs = get_fs(); + set_fs(KERNEL_DS); + show_data(regs->pc - nbytes, nbytes * 2, "PC"); + show_data(regs->regs[30] - nbytes, nbytes * 2, "LR"); + show_data(regs->sp - nbytes, nbytes * 2, "SP"); + for (i = 0; i < 30; i++) { + char name[4]; + snprintf(name, sizeof(name), "X%u", i); + show_data(regs->regs[i] - nbytes, nbytes * 2, name); + } + set_fs(fs); +} + void __show_regs(struct pt_regs *regs) { int i, top_reg; @@ -190,6 +254,8 @@ void __show_regs(struct pt_regs *regs) if (i % 2 == 0) printk("\n"); } + if (!user_mode(regs)) + show_extra_register_data(regs, 128); printk("\n"); } |