aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-05-24 02:03:46 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-05-24 02:03:46 -0400
commit49453264997f232008efae457553d82381f9614f (patch)
treeab5e697e26453774c5aece0936aaf4c59173ec1b
parentf9369910a6225b8d4892c3f20ae740a711cd5ace (diff)
sh64: Convert to unwinder API.
This switches over to use the sh unwinder API which brings it all in line with the general sh routines (which we shuffle around at the same time), and lets us kill off more sh64-specific cruft. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-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
5 files changed, 101 insertions, 98 deletions
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index a6201f10c27..8d6a831e7ba 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 b205b25eaf4..10aed41757f 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 694158b9a50..7617dc4129a 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 a37175deb73..b8f5a51841e 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 8dae93ed8af..ba95d63e623 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{