diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-10-12 04:07:45 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-10-19 03:30:31 -0400 |
commit | 6b0022305f80cf249de69e746f6f5ccf7ffc5b7c (patch) | |
tree | 6434c1856bd3f38e03df04d6337b35e26760cf12 /arch/sh | |
parent | ce9e3d9953c8cb67001719b5516da2928e956be4 (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.c | 12 | ||||
-rw-r--r-- | arch/sh/kernel/traps.c | 124 |
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 | /* | 55 | static 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 | ||
64 | DEFINE_SPINLOCK(die_lock); | 82 | DEFINE_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 | ||
79 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | 110 | static 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 | */ |
94 | static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) | 126 | static 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 | ||
737 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 768 | void 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 | ||
780 | void show_task(unsigned long *sp) | 790 | void 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 | ||
785 | void dump_stack(void) | 807 | void dump_stack(void) |