Commit 6b002230 authored by Paul Mundt's avatar Paul Mundt

sh: Proper show_stack/show_trace() implementation.

This splits out some of the previous show_stack() implementation which
was mostly doing the show_trace() work without actually dumping any of
the stack contents. This now gets split in to two sections, where we
do the fetching of the stack pointer and subsequent stack dumping in
show_stack(), while moving the call trace in to show_trace().
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent ce9e3d99
...@@ -105,7 +105,7 @@ void show_regs(struct pt_regs * regs) ...@@ -105,7 +105,7 @@ void show_regs(struct pt_regs * regs)
{ {
printk("\n"); printk("\n");
printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); printk("Pid : %d, Comm: %20s\n", current->pid, current->comm);
print_symbol("PC is at %s\n", regs->pc); print_symbol("PC is at %s\n", instruction_pointer(regs));
printk("PC : %08lx SP : %08lx SR : %08lx ", printk("PC : %08lx SP : %08lx SR : %08lx ",
regs->pc, regs->regs[15], regs->sr); regs->pc, regs->regs[15], regs->sr);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
...@@ -130,15 +130,7 @@ void show_regs(struct pt_regs * regs) ...@@ -130,15 +130,7 @@ void show_regs(struct pt_regs * regs)
printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
regs->mach, regs->macl, regs->gbr, regs->pr); regs->mach, regs->macl, regs->gbr, regs->pr);
/* show_trace(NULL, (unsigned long *)regs->regs[15], regs);
* If we're in kernel mode, dump the stack too..
*/
if (!user_mode(regs)) {
extern void show_task(unsigned long *sp);
unsigned long sp = regs->regs[15];
show_task((unsigned long *)sp);
}
} }
/* /*
......
/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $ /*
* * 'traps.c' handles hardware traps and faults after we have saved some
* linux/arch/sh/traps.c * state in 'entry.S'.
* *
* SuperH version: Copyright (C) 1999 Niibe Yutaka * SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf * Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells * Copyright (C) 2000 David Howells
* Copyright (C) 2002, 2003 Paul Mundt * Copyright (C) 2002 - 2006 Paul Mundt
*/ *
* This file is subject to the terms and conditions of the GNU General Public
/* * License. See the file "COPYING" in the main directory of this archive
* 'Traps.c' handles hardware traps and faults after we have saved some * for more details.
* state in 'entry.S'.
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -53,13 +52,32 @@ ...@@ -53,13 +52,32 @@
#define TRAP_ILLEGAL_SLOT_INST 13 #define TRAP_ILLEGAL_SLOT_INST 13
#endif #endif
/* static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
* These constants are for searching for possible module text {
* segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is unsigned long p;
* a guess of how much space is likely to be vmalloced. int i;
*/
#define VMALLOC_OFFSET (8*1024*1024) printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
#define MODULE_RANGE (8*1024*1024)
for (p = bottom & ~31; p < top; ) {
printk("%04lx: ", p & 0xffff);
for (i = 0; i < 8; i++, p += 4) {
unsigned int val;
if (p < bottom || p >= top)
printk(" ");
else {
if (__get_user(val, (unsigned int __user *)p)) {
printk("\n");
return;
}
printk("%08x ", val);
}
}
printk("\n");
}
}
DEFINE_SPINLOCK(die_lock); DEFINE_SPINLOCK(die_lock);
...@@ -69,14 +87,28 @@ void die(const char * str, struct pt_regs * regs, long err) ...@@ -69,14 +87,28 @@ void die(const char * str, struct pt_regs * regs, long err)
console_verbose(); console_verbose();
spin_lock_irq(&die_lock); spin_lock_irq(&die_lock);
bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
CHK_REMOTE_DEBUG(regs); CHK_REMOTE_DEBUG(regs);
print_modules();
show_regs(regs); show_regs(regs);
printk("Process: %s (pid: %d, stack limit = %p)\n",
current->comm, current->pid, task_stack_page(current) + 1);
if (!user_mode(regs) || in_interrupt())
dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
(unsigned long)task_stack_page(current));
bust_spinlocks(0);
spin_unlock_irq(&die_lock); spin_unlock_irq(&die_lock);
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) static inline void die_if_kernel(const char *str, struct pt_regs *regs,
long err)
{ {
if (!user_mode(regs)) if (!user_mode(regs))
die(str, regs, err); die(str, regs, err);
...@@ -93,8 +125,7 @@ static int handle_unaligned_notify_count = 10; ...@@ -93,8 +125,7 @@ static int handle_unaligned_notify_count = 10;
*/ */
static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
{ {
if (!user_mode(regs)) if (!user_mode(regs)) {
{
const struct exception_table_entry *fixup; const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->pc); fixup = search_exception_tables(regs->pc);
if (fixup) { if (fixup) {
...@@ -734,52 +765,43 @@ void __init trap_init(void) ...@@ -734,52 +765,43 @@ void __init trap_init(void)
per_cpu_trap_init(); per_cpu_trap_init();
} }
void show_stack(struct task_struct *tsk, unsigned long *sp) void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{ {
unsigned long *stack, addr; unsigned long addr;
unsigned long module_start = VMALLOC_START;
unsigned long module_end = VMALLOC_END;
int i = 1;
if (!tsk) if (regs && user_mode(regs))
tsk = current; return;
if (tsk == current)
sp = (unsigned long *)current_stack_pointer;
else
sp = (unsigned long *)tsk->thread.sp;
stack = sp;
printk("\nCall trace: "); printk("\nCall trace: ");
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
printk("\n"); printk("\n");
#endif #endif
while (!kstack_end(stack)) { while (!kstack_end(sp)) {
addr = *stack++; addr = *sp++;
if (((addr >= (unsigned long)_text) && if (kernel_text_address(addr))
(addr <= (unsigned long)_etext)) || print_ip_sym(addr);
((addr >= module_start) && (addr <= module_end))) {
/*
* For 80-columns display, 6 entry is maximum.
* NOTE: '[<8c00abcd>] ' consumes 13 columns .
*/
#ifndef CONFIG_KALLSYMS
if (i && ((i % 6) == 0))
printk("\n ");
#endif
printk("[<%08lx>] ", addr);
print_symbol("%s\n", addr);
i++;
}
} }
printk("\n"); printk("\n");
} }
void show_task(unsigned long *sp) void show_stack(struct task_struct *tsk, unsigned long *sp)
{ {
show_stack(NULL, sp); unsigned long stack;
if (!tsk)
tsk = current;
if (tsk == current)
sp = (unsigned long *)current_stack_pointer;
else
sp = (unsigned long *)tsk->thread.sp;
stack = (unsigned long)sp;
dump_mem("Stack: ", stack, THREAD_SIZE +
(unsigned long)task_stack_page(tsk));
show_trace(tsk, sp, NULL);
} }
void dump_stack(void) void dump_stack(void)
......
...@@ -255,6 +255,8 @@ extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs); ...@@ -255,6 +255,8 @@ extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
*/ */
#define thread_saved_pc(tsk) (tsk->thread.pc) #define thread_saved_pc(tsk) (tsk->thread.pc)
void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs);
extern unsigned long get_wchan(struct task_struct *p); extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.pc) #define KSTK_EIP(tsk) ((tsk)->thread.pc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment