aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-10-12 04:07:45 -0400
committerPaul Mundt <lethal@linux-sh.org>2006-10-19 03:30:31 -0400
commit6b0022305f80cf249de69e746f6f5ccf7ffc5b7c (patch)
tree6434c1856bd3f38e03df04d6337b35e26760cf12 /arch/sh
parentce9e3d9953c8cb67001719b5516da2928e956be4 (diff)
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: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/kernel/process.c12
-rw-r--r--arch/sh/kernel/traps.c124
2 files changed, 75 insertions, 61 deletions
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index 91516dca4a85..a52b13ac6b7f 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -105,7 +105,7 @@ void show_regs(struct pt_regs * regs)
105{ 105{
106 printk("\n"); 106 printk("\n");
107 printk("Pid : %d, Comm: %20s\n", current->pid, current->comm); 107 printk("Pid : %d, Comm: %20s\n", current->pid, current->comm);
108 print_symbol("PC is at %s\n", regs->pc); 108 print_symbol("PC is at %s\n", instruction_pointer(regs));
109 printk("PC : %08lx SP : %08lx SR : %08lx ", 109 printk("PC : %08lx SP : %08lx SR : %08lx ",
110 regs->pc, regs->regs[15], regs->sr); 110 regs->pc, regs->regs[15], regs->sr);
111#ifdef CONFIG_MMU 111#ifdef CONFIG_MMU
@@ -130,15 +130,7 @@ void show_regs(struct pt_regs * regs)
130 printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n", 130 printk("MACH: %08lx MACL: %08lx GBR : %08lx PR : %08lx\n",
131 regs->mach, regs->macl, regs->gbr, regs->pr); 131 regs->mach, regs->macl, regs->gbr, regs->pr);
132 132
133 /* 133 show_trace(NULL, (unsigned long *)regs->regs[15], regs);
134 * If we're in kernel mode, dump the stack too..
135 */
136 if (!user_mode(regs)) {
137 extern void show_task(unsigned long *sp);
138 unsigned long sp = regs->regs[15];
139
140 show_task((unsigned long *)sp);
141 }
142} 134}
143 135
144/* 136/*
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index c2c597e09482..ffe127f09f3e 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -1,16 +1,15 @@
1/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $ 1/*
2 * 2 * 'traps.c' handles hardware traps and faults after we have saved some
3 * linux/arch/sh/traps.c 3 * state in 'entry.S'.
4 * 4 *
5 * SuperH version: Copyright (C) 1999 Niibe Yutaka 5 * SuperH version: Copyright (C) 1999 Niibe Yutaka
6 * Copyright (C) 2000 Philipp Rumpf 6 * Copyright (C) 2000 Philipp Rumpf
7 * Copyright (C) 2000 David Howells 7 * Copyright (C) 2000 David Howells
8 * Copyright (C) 2002, 2003 Paul Mundt 8 * Copyright (C) 2002 - 2006 Paul Mundt
9 */ 9 *
10 10 * This file is subject to the terms and conditions of the GNU General Public
11/* 11 * License. See the file "COPYING" in the main directory of this archive
12 * 'Traps.c' handles hardware traps and faults after we have saved some 12 * for more details.
13 * state in 'entry.S'.
14 */ 13 */
15#include <linux/sched.h> 14#include <linux/sched.h>
16#include <linux/kernel.h> 15#include <linux/kernel.h>
@@ -53,13 +52,32 @@
53#define TRAP_ILLEGAL_SLOT_INST 13 52#define TRAP_ILLEGAL_SLOT_INST 13
54#endif 53#endif
55 54
56/* 55static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
57 * These constants are for searching for possible module text 56{
58 * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is 57 unsigned long p;
59 * a guess of how much space is likely to be vmalloced. 58 int i;
60 */ 59
61#define VMALLOC_OFFSET (8*1024*1024) 60 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
62#define MODULE_RANGE (8*1024*1024) 61
62 for (p = bottom & ~31; p < top; ) {
63 printk("%04lx: ", p & 0xffff);
64
65 for (i = 0; i < 8; i++, p += 4) {
66 unsigned int val;
67
68 if (p < bottom || p >= top)
69 printk(" ");
70 else {
71 if (__get_user(val, (unsigned int __user *)p)) {
72 printk("\n");
73 return;
74 }
75 printk("%08x ", val);
76 }
77 }
78 printk("\n");
79 }
80}
63 81
64DEFINE_SPINLOCK(die_lock); 82DEFINE_SPINLOCK(die_lock);
65 83
@@ -69,14 +87,28 @@ void die(const char * str, struct pt_regs * regs, long err)
69 87
70 console_verbose(); 88 console_verbose();
71 spin_lock_irq(&die_lock); 89 spin_lock_irq(&die_lock);
90 bust_spinlocks(1);
91
72 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); 92 printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
93
73 CHK_REMOTE_DEBUG(regs); 94 CHK_REMOTE_DEBUG(regs);
95 print_modules();
74 show_regs(regs); 96 show_regs(regs);
97
98 printk("Process: %s (pid: %d, stack limit = %p)\n",
99 current->comm, current->pid, task_stack_page(current) + 1);
100
101 if (!user_mode(regs) || in_interrupt())
102 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
103 (unsigned long)task_stack_page(current));
104
105 bust_spinlocks(0);
75 spin_unlock_irq(&die_lock); 106 spin_unlock_irq(&die_lock);
76 do_exit(SIGSEGV); 107 do_exit(SIGSEGV);
77} 108}
78 109
79static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) 110static inline void die_if_kernel(const char *str, struct pt_regs *regs,
111 long err)
80{ 112{
81 if (!user_mode(regs)) 113 if (!user_mode(regs))
82 die(str, regs, err); 114 die(str, regs, err);
@@ -93,8 +125,7 @@ static int handle_unaligned_notify_count = 10;
93 */ 125 */
94static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) 126static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
95{ 127{
96 if (!user_mode(regs)) 128 if (!user_mode(regs)) {
97 {
98 const struct exception_table_entry *fixup; 129 const struct exception_table_entry *fixup;
99 fixup = search_exception_tables(regs->pc); 130 fixup = search_exception_tables(regs->pc);
100 if (fixup) { 131 if (fixup) {
@@ -734,52 +765,43 @@ void __init trap_init(void)
734 per_cpu_trap_init(); 765 per_cpu_trap_init();
735} 766}
736 767
737void show_stack(struct task_struct *tsk, unsigned long *sp) 768void show_trace(struct task_struct *tsk, unsigned long *sp,
769 struct pt_regs *regs)
738{ 770{
739 unsigned long *stack, addr; 771 unsigned long addr;
740 unsigned long module_start = VMALLOC_START;
741 unsigned long module_end = VMALLOC_END;
742 int i = 1;
743 772
744 if (!tsk) 773 if (regs && user_mode(regs))
745 tsk = current; 774 return;
746 if (tsk == current)
747 sp = (unsigned long *)current_stack_pointer;
748 else
749 sp = (unsigned long *)tsk->thread.sp;
750
751 stack = sp;
752 775
753 printk("\nCall trace: "); 776 printk("\nCall trace: ");
754#ifdef CONFIG_KALLSYMS 777#ifdef CONFIG_KALLSYMS
755 printk("\n"); 778 printk("\n");
756#endif 779#endif
757 780
758 while (!kstack_end(stack)) { 781 while (!kstack_end(sp)) {
759 addr = *stack++; 782 addr = *sp++;
760 if (((addr >= (unsigned long)_text) && 783 if (kernel_text_address(addr))
761 (addr <= (unsigned long)_etext)) || 784 print_ip_sym(addr);
762 ((addr >= module_start) && (addr <= module_end))) {
763 /*
764 * For 80-columns display, 6 entry is maximum.
765 * NOTE: '[<8c00abcd>] ' consumes 13 columns .
766 */
767#ifndef CONFIG_KALLSYMS
768 if (i && ((i % 6) == 0))
769 printk("\n ");
770#endif
771 printk("[<%08lx>] ", addr);
772 print_symbol("%s\n", addr);
773 i++;
774 }
775 } 785 }
776 786
777 printk("\n"); 787 printk("\n");
778} 788}
779 789
780void show_task(unsigned long *sp) 790void show_stack(struct task_struct *tsk, unsigned long *sp)
781{ 791{
782 show_stack(NULL, sp); 792 unsigned long stack;
793
794 if (!tsk)
795 tsk = current;
796 if (tsk == current)
797 sp = (unsigned long *)current_stack_pointer;
798 else
799 sp = (unsigned long *)tsk->thread.sp;
800
801 stack = (unsigned long)sp;
802 dump_mem("Stack: ", stack, THREAD_SIZE +
803 (unsigned long)task_stack_page(tsk));
804 show_trace(tsk, sp, NULL);
783} 805}
784 806
785void dump_stack(void) 807void dump_stack(void)