aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-06-12 23:12:14 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-06-12 23:12:14 -0400
commitf21efd45362d555b3b93960a5736ad7c6fc1f367 (patch)
treee86510670b3543be81814d0099954b8a83cd8dfb /arch/sh
parent380622e9ff56201f9c3c1f153d1ca0a24324a1d4 (diff)
parent3a898c0f36f9fe312cb6e98865a6833110e67cb2 (diff)
Merge branch 'sh/multi-unwinders' into sh-latest
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/Kconfig1
-rw-r--r--arch/sh/include/asm/kdebug.h2
-rw-r--r--arch/sh/kernel/cpu/sh5/unwind.c63
-rw-r--r--arch/sh/kernel/dumpstack.c58
-rw-r--r--arch/sh/kernel/traps_32.c50
-rw-r--r--arch/sh/kernel/traps_64.c26
6 files changed, 102 insertions, 98 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 31d9db7913e4..a24595d83ad6 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -60,6 +60,7 @@ config SUPERH32
60 60
61config SUPERH64 61config SUPERH64
62 def_bool ARCH = "sh64" 62 def_bool ARCH = "sh64"
63 select KALLSYMS
63 64
64config ARCH_DEFCONFIG 65config ARCH_DEFCONFIG
65 string 66 string
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index a6201f10c273..8d6a831e7ba1 100644
--- a/arch/sh/include/asm/kdebug.h
+++ b/arch/sh/include/asm/kdebug.h
@@ -10,6 +10,8 @@ enum die_val {
10 DIE_SSTEP, 10 DIE_SSTEP,
11}; 11};
12 12
13/* arch/sh/kernel/dumpstack.c */
13extern void printk_address(unsigned long address, int reliable); 14extern void printk_address(unsigned long address, int reliable);
15extern void dump_mem(const char *str, unsigned long bottom, unsigned long top);
14 16
15#endif /* __ASM_SH_KDEBUG_H */ 17#endif /* __ASM_SH_KDEBUG_H */
diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c
index b205b25eaf45..10aed41757fc 100644
--- a/arch/sh/kernel/cpu/sh5/unwind.c
+++ b/arch/sh/kernel/cpu/sh5/unwind.c
@@ -16,6 +16,8 @@
16#include <asm/ptrace.h> 16#include <asm/ptrace.h>
17#include <asm/processor.h> 17#include <asm/processor.h>
18#include <asm/io.h> 18#include <asm/io.h>
19#include <asm/unwinder.h>
20#include <asm/stacktrace.h>
19 21
20static u8 regcache[63]; 22static u8 regcache[63];
21 23
@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
199 return 0; 201 return 0;
200} 202}
201 203
202/* Don't put this on the stack since we'll want to call sh64_unwind 204/*
203 * when we're close to underflowing the stack anyway. */ 205 * Don't put this on the stack since we'll want to call in to
206 * sh64_unwinder_dump() when we're close to underflowing the stack
207 * anyway.
208 */
204static struct pt_regs here_regs; 209static struct pt_regs here_regs;
205 210
206extern const char syscall_ret; 211extern const char syscall_ret;
@@ -208,17 +213,19 @@ extern const char ret_from_syscall;
208extern const char ret_from_exception; 213extern const char ret_from_exception;
209extern const char ret_from_irq; 214extern const char ret_from_irq;
210 215
211static void sh64_unwind_inner(struct pt_regs *regs); 216static void sh64_unwind_inner(const struct stacktrace_ops *ops,
217 void *data, struct pt_regs *regs);
212 218
213static void unwind_nested (unsigned long pc, unsigned long fp) 219static inline void unwind_nested(const struct stacktrace_ops *ops, void *data,
220 unsigned long pc, unsigned long fp)
214{ 221{
215 if ((fp >= __MEMORY_START) && 222 if ((fp >= __MEMORY_START) &&
216 ((fp & 7) == 0)) { 223 ((fp & 7) == 0))
217 sh64_unwind_inner((struct pt_regs *) fp); 224 sh64_unwind_inner(ops, data, (struct pt_regs *)fp);
218 }
219} 225}
220 226
221static void sh64_unwind_inner(struct pt_regs *regs) 227static void sh64_unwind_inner(const struct stacktrace_ops *ops,
228 void *data, struct pt_regs *regs)
222{ 229{
223 unsigned long pc, fp; 230 unsigned long pc, fp;
224 int ofs = 0; 231 int ofs = 0;
@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs)
232 int cond; 239 int cond;
233 unsigned long next_fp, next_pc; 240 unsigned long next_fp, next_pc;
234 241
235 if (pc == ((unsigned long) &syscall_ret & ~1)) { 242 if (pc == ((unsigned long)&syscall_ret & ~1)) {
236 printk("SYSCALL\n"); 243 printk("SYSCALL\n");
237 unwind_nested(pc,fp); 244 unwind_nested(ops, data, pc, fp);
238 return; 245 return;
239 } 246 }
240 247
241 if (pc == ((unsigned long) &ret_from_syscall & ~1)) { 248 if (pc == ((unsigned long)&ret_from_syscall & ~1)) {
242 printk("SYSCALL (PREEMPTED)\n"); 249 printk("SYSCALL (PREEMPTED)\n");
243 unwind_nested(pc,fp); 250 unwind_nested(ops, data, pc, fp);
244 return; 251 return;
245 } 252 }
246 253
247 /* In this case, the PC is discovered by lookup_prev_stack_frame but 254 /* In this case, the PC is discovered by lookup_prev_stack_frame but
248 it has 4 taken off it to look like the 'caller' */ 255 it has 4 taken off it to look like the 'caller' */
249 if (pc == ((unsigned long) &ret_from_exception & ~1)) { 256 if (pc == ((unsigned long)&ret_from_exception & ~1)) {
250 printk("EXCEPTION\n"); 257 printk("EXCEPTION\n");
251 unwind_nested(pc,fp); 258 unwind_nested(ops, data, pc, fp);
252 return; 259 return;
253 } 260 }
254 261
255 if (pc == ((unsigned long) &ret_from_irq & ~1)) { 262 if (pc == ((unsigned long)&ret_from_irq & ~1)) {
256 printk("IRQ\n"); 263 printk("IRQ\n");
257 unwind_nested(pc,fp); 264 unwind_nested(ops, data, pc, fp);
258 return; 265 return;
259 } 266 }
260 267
@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs)
263 270
264 pc -= ofs; 271 pc -= ofs;
265 272
266 printk("[<%08lx>] ", pc); 273 ops->address(data, pc, 1);
267 print_symbol("%s\n", pc);
268 274
269 if (first_pass) { 275 if (first_pass) {
270 /* If the innermost frame is a leaf function, it's 276 /* If the innermost frame is a leaf function, it's
@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs)
287 } 293 }
288 294
289 printk("\n"); 295 printk("\n");
290
291} 296}
292 297
293void sh64_unwind(struct pt_regs *regs) 298static void sh64_unwinder_dump(struct task_struct *task,
299 struct pt_regs *regs,
300 unsigned long *sp,
301 const struct stacktrace_ops *ops,
302 void *data)
294{ 303{
295 if (!regs) { 304 if (!regs) {
296 /* 305 /*
@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs)
320 ); 329 );
321 } 330 }
322 331
323 printk("\nCall Trace:\n"); 332 sh64_unwind_inner(ops, data, regs);
324 sh64_unwind_inner(regs);
325} 333}
326 334
335static struct unwinder sh64_unwinder = {
336 .name = "sh64-unwinder",
337 .dump = sh64_unwinder_dump,
338 .rating = 150,
339};
340
341static int __init sh64_unwinder_init(void)
342{
343 return unwinder_register(&sh64_unwinder);
344}
345early_initcall(sh64_unwinder_init);
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
index 694158b9a50f..7617dc4129ac 100644
--- a/arch/sh/kernel/dumpstack.c
+++ b/arch/sh/kernel/dumpstack.c
@@ -2,13 +2,48 @@
2 * Copyright (C) 1991, 1992 Linus Torvalds 2 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs 3 * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4 * Copyright (C) 2009 Matt Fleming 4 * Copyright (C) 2009 Matt Fleming
5 * Copyright (C) 2002 - 2012 Paul Mundt
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
5 */ 10 */
6#include <linux/kallsyms.h> 11#include <linux/kallsyms.h>
7#include <linux/ftrace.h> 12#include <linux/ftrace.h>
8#include <linux/debug_locks.h> 13#include <linux/debug_locks.h>
14#include <linux/kdebug.h>
15#include <linux/export.h>
16#include <linux/uaccess.h>
9#include <asm/unwinder.h> 17#include <asm/unwinder.h>
10#include <asm/stacktrace.h> 18#include <asm/stacktrace.h>
11 19
20void dump_mem(const char *str, unsigned long bottom, unsigned long top)
21{
22 unsigned long p;
23 int i;
24
25 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
26
27 for (p = bottom & ~31; p < top; ) {
28 printk("%04lx: ", p & 0xffff);
29
30 for (i = 0; i < 8; i++, p += 4) {
31 unsigned int val;
32
33 if (p < bottom || p >= top)
34 printk(" ");
35 else {
36 if (__get_user(val, (unsigned int __user *)p)) {
37 printk("\n");
38 return;
39 }
40 printk("%08x ", val);
41 }
42 }
43 printk("\n");
44 }
45}
46
12void printk_address(unsigned long address, int reliable) 47void printk_address(unsigned long address, int reliable)
13{ 48{
14 printk(" [<%p>] %s%pS\n", (void *) address, 49 printk(" [<%p>] %s%pS\n", (void *) address,
@@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,
106 141
107 debug_show_held_locks(tsk); 142 debug_show_held_locks(tsk);
108} 143}
144
145void show_stack(struct task_struct *tsk, unsigned long *sp)
146{
147 unsigned long stack;
148
149 if (!tsk)
150 tsk = current;
151 if (tsk == current)
152 sp = (unsigned long *)current_stack_pointer;
153 else
154 sp = (unsigned long *)tsk->thread.sp;
155
156 stack = (unsigned long)sp;
157 dump_mem("Stack: ", stack, THREAD_SIZE +
158 (unsigned long)task_stack_page(tsk));
159 show_trace(tsk, sp, NULL);
160}
161
162void dump_stack(void)
163{
164 show_stack(NULL, NULL);
165}
166EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index a37175deb73f..b8f5a51841ec 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -48,33 +48,6 @@
48#define TRAP_ILLEGAL_SLOT_INST 13 48#define TRAP_ILLEGAL_SLOT_INST 13
49#endif 49#endif
50 50
51static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
52{
53 unsigned long p;
54 int i;
55
56 printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
57
58 for (p = bottom & ~31; p < top; ) {
59 printk("%04lx: ", p & 0xffff);
60
61 for (i = 0; i < 8; i++, p += 4) {
62 unsigned int val;
63
64 if (p < bottom || p >= top)
65 printk(" ");
66 else {
67 if (__get_user(val, (unsigned int __user *)p)) {
68 printk("\n");
69 return;
70 }
71 printk("%08x ", val);
72 }
73 }
74 printk("\n");
75 }
76}
77
78static DEFINE_SPINLOCK(die_lock); 51static DEFINE_SPINLOCK(die_lock);
79 52
80void die(const char * str, struct pt_regs * regs, long err) 53void die(const char * str, struct pt_regs * regs, long err)
@@ -900,26 +873,3 @@ void __init trap_init(void)
900 set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler); 873 set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
901#endif 874#endif
902} 875}
903
904void show_stack(struct task_struct *tsk, unsigned long *sp)
905{
906 unsigned long stack;
907
908 if (!tsk)
909 tsk = current;
910 if (tsk == current)
911 sp = (unsigned long *)current_stack_pointer;
912 else
913 sp = (unsigned long *)tsk->thread.sp;
914
915 stack = (unsigned long)sp;
916 dump_mem("Stack: ", stack, THREAD_SIZE +
917 (unsigned long)task_stack_page(tsk));
918 show_trace(tsk, sp, NULL);
919}
920
921void dump_stack(void)
922{
923 show_stack(NULL, NULL);
924}
925EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index 8dae93ed8aff..ba95d63e623d 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -253,32 +253,6 @@ int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
253 return -ENOSYS; 253 return -ENOSYS;
254} 254}
255 255
256void show_stack(struct task_struct *tsk, unsigned long *sp)
257{
258#ifdef CONFIG_KALLSYMS
259 extern void sh64_unwind(struct pt_regs *regs);
260 struct pt_regs *regs;
261
262 regs = tsk ? tsk->thread.kregs : NULL;
263
264 sh64_unwind(regs);
265#else
266 printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
267#endif
268}
269
270void show_task(unsigned long *sp)
271{
272 show_stack(NULL, sp);
273}
274
275void dump_stack(void)
276{
277 show_task(NULL);
278}
279/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
280EXPORT_SYMBOL(dump_stack);
281
282static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name, 256static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
283 unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk) 257 unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
284{ 258{