sh: Proper show_stack/show_trace() implementation.
authorPaul Mundt <lethal@linux-sh.org>
Thu, 12 Oct 2006 08:07:45 +0000 (17:07 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Thu, 19 Oct 2006 07:30:31 +0000 (16:30 +0900)
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: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/process.c
arch/sh/kernel/traps.c
include/asm-sh/processor.h

index 91516dca4a857180dacb51bd37b68c72ab3630e4..a52b13ac6b7f80a32e81a5daeef04a115de406da 100644 (file)
@@ -105,7 +105,7 @@ void show_regs(struct pt_regs * regs)
 {
        printk("\n");
        printk("Pid : %d, Comm: %20s\n", current->pid, current->comm);
 {
        printk("\n");
        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 ",
               regs->pc, regs->regs[15], regs->sr);
 #ifdef CONFIG_MMU
        printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
               regs->pc, regs->regs[15], regs->sr);
 #ifdef CONFIG_MMU
@@ -130,15 +130,7 @@ void show_regs(struct pt_regs * regs)
        printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
               regs->mach, regs->macl, regs->gbr, regs->pr);
 
        printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
               regs->mach, regs->macl, regs->gbr, regs->pr);
 
-       /*
-        * 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);
-       }
+       show_trace(NULL, (unsigned long *)regs->regs[15], regs);
 }
 
 /*
 }
 
 /*
index c2c597e0948242c780d4d369dff64c69dee14c59..ffe127f09f3e7d7d758284446e0d066cf674688c 100644 (file)
@@ -1,16 +1,15 @@
-/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $
- *
- *  linux/arch/sh/traps.c
+/*
+ * 'traps.c' handles hardware traps and faults after we have saved some
+ * state in 'entry.S'.
  *
  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  *                  Copyright (C) 2000 Philipp Rumpf
  *                  Copyright (C) 2000 David Howells
  *
  *  SuperH version: Copyright (C) 1999 Niibe Yutaka
  *                  Copyright (C) 2000 Philipp Rumpf
  *                  Copyright (C) 2000 David Howells
- *                  Copyright (C) 2002, 2003 Paul Mundt
- */
-
-/*
- * 'Traps.c' handles hardware traps and faults after we have saved some
- * state in 'entry.S'.
+ *                  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
+ * for more details.
  */
 #include <linux/sched.h>
 #include <linux/kernel.h>
  */
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #define TRAP_ILLEGAL_SLOT_INST 13
 #endif
 
 #define TRAP_ILLEGAL_SLOT_INST 13
 #endif
 
-/*
- * These constants are for searching for possible module text
- * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+{
+       unsigned long p;
+       int i;
+
+       printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+
+       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)
 
        console_verbose();
        spin_lock_irq(&die_lock);
 
        console_verbose();
        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);
        do_exit(SIGSEGV);
 }
 
        spin_unlock_irq(&die_lock);
        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))
                die(str, regs, err);
 {
        if (!user_mode(regs))
                die(str, regs, err);
@@ -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;
                fixup = search_exception_tables(regs->pc);
                if (fixup) {
                const struct exception_table_entry *fixup;
                fixup = search_exception_tables(regs->pc);
                if (fixup) {
@@ -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 module_start = VMALLOC_START;
-       unsigned long module_end = VMALLOC_END;
-       int i = 1;
+       unsigned long addr;
 
 
-       if (!tsk)
-               tsk = current;
-       if (tsk == current)
-               sp = (unsigned long *)current_stack_pointer;
-       else
-               sp = (unsigned long *)tsk->thread.sp;
-
-       stack = sp;
+       if (regs && user_mode(regs))
+               return;
 
        printk("\nCall trace: ");
 #ifdef CONFIG_KALLSYMS
        printk("\n");
 #endif
 
 
        printk("\nCall trace: ");
 #ifdef CONFIG_KALLSYMS
        printk("\n");
 #endif
 
-       while (!kstack_end(stack)) {
-               addr = *stack++;
-               if (((addr >= (unsigned long)_text) &&
-                    (addr <= (unsigned long)_etext)) ||
-                   ((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++;
-               }
+       while (!kstack_end(sp)) {
+               addr = *sp++;
+               if (kernel_text_address(addr))
+                       print_ip_sym(addr);
        }
 
        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)
index 474773853cd1a71f3184d85daf62468f3cfc2de0..45bb74e35d325acbbccc4607528ea2c4e07d0a59 100644 (file)
@@ -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);
 
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)
 extern unsigned long get_wchan(struct task_struct *p);
 
 #define KSTK_EIP(tsk)  ((tsk)->thread.pc)