|
@@ -16,6 +16,8 @@
|
|
|
#include <asm/ptrace.h>
|
|
|
#include <asm/processor.h>
|
|
|
#include <asm/io.h>
|
|
|
+#include <asm/unwinder.h>
|
|
|
+#include <asm/stacktrace.h>
|
|
|
|
|
|
static u8 regcache[63];
|
|
|
|
|
@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* Don't put this on the stack since we'll want to call sh64_unwind
|
|
|
- * when we're close to underflowing the stack anyway. */
|
|
|
+/*
|
|
|
+ * Don't put this on the stack since we'll want to call in to
|
|
|
+ * sh64_unwinder_dump() when we're close to underflowing the stack
|
|
|
+ * anyway.
|
|
|
+ */
|
|
|
static struct pt_regs here_regs;
|
|
|
|
|
|
extern const char syscall_ret;
|
|
@@ -208,17 +213,19 @@ extern const char ret_from_syscall;
|
|
|
extern const char ret_from_exception;
|
|
|
extern const char ret_from_irq;
|
|
|
|
|
|
-static void sh64_unwind_inner(struct pt_regs *regs);
|
|
|
+static void sh64_unwind_inner(const struct stacktrace_ops *ops,
|
|
|
+ void *data, struct pt_regs *regs);
|
|
|
|
|
|
-static void unwind_nested (unsigned long pc, unsigned long fp)
|
|
|
+static inline void unwind_nested(const struct stacktrace_ops *ops, void *data,
|
|
|
+ unsigned long pc, unsigned long fp)
|
|
|
{
|
|
|
if ((fp >= __MEMORY_START) &&
|
|
|
- ((fp & 7) == 0)) {
|
|
|
- sh64_unwind_inner((struct pt_regs *) fp);
|
|
|
- }
|
|
|
+ ((fp & 7) == 0))
|
|
|
+ sh64_unwind_inner(ops, data, (struct pt_regs *)fp);
|
|
|
}
|
|
|
|
|
|
-static void sh64_unwind_inner(struct pt_regs *regs)
|
|
|
+static void sh64_unwind_inner(const struct stacktrace_ops *ops,
|
|
|
+ void *data, struct pt_regs *regs)
|
|
|
{
|
|
|
unsigned long pc, fp;
|
|
|
int ofs = 0;
|
|
@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs)
|
|
|
int cond;
|
|
|
unsigned long next_fp, next_pc;
|
|
|
|
|
|
- if (pc == ((unsigned long) &syscall_ret & ~1)) {
|
|
|
+ if (pc == ((unsigned long)&syscall_ret & ~1)) {
|
|
|
printk("SYSCALL\n");
|
|
|
- unwind_nested(pc,fp);
|
|
|
+ unwind_nested(ops, data, pc, fp);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (pc == ((unsigned long) &ret_from_syscall & ~1)) {
|
|
|
+ if (pc == ((unsigned long)&ret_from_syscall & ~1)) {
|
|
|
printk("SYSCALL (PREEMPTED)\n");
|
|
|
- unwind_nested(pc,fp);
|
|
|
+ unwind_nested(ops, data, pc, fp);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* In this case, the PC is discovered by lookup_prev_stack_frame but
|
|
|
it has 4 taken off it to look like the 'caller' */
|
|
|
- if (pc == ((unsigned long) &ret_from_exception & ~1)) {
|
|
|
+ if (pc == ((unsigned long)&ret_from_exception & ~1)) {
|
|
|
printk("EXCEPTION\n");
|
|
|
- unwind_nested(pc,fp);
|
|
|
+ unwind_nested(ops, data, pc, fp);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (pc == ((unsigned long) &ret_from_irq & ~1)) {
|
|
|
+ if (pc == ((unsigned long)&ret_from_irq & ~1)) {
|
|
|
printk("IRQ\n");
|
|
|
- unwind_nested(pc,fp);
|
|
|
+ unwind_nested(ops, data, pc, fp);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs)
|
|
|
|
|
|
pc -= ofs;
|
|
|
|
|
|
- printk("[<%08lx>] ", pc);
|
|
|
- print_symbol("%s\n", pc);
|
|
|
+ ops->address(data, pc, 1);
|
|
|
|
|
|
if (first_pass) {
|
|
|
/* If the innermost frame is a leaf function, it's
|
|
@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs)
|
|
|
}
|
|
|
|
|
|
printk("\n");
|
|
|
-
|
|
|
}
|
|
|
|
|
|
-void sh64_unwind(struct pt_regs *regs)
|
|
|
+static void sh64_unwinder_dump(struct task_struct *task,
|
|
|
+ struct pt_regs *regs,
|
|
|
+ unsigned long *sp,
|
|
|
+ const struct stacktrace_ops *ops,
|
|
|
+ void *data)
|
|
|
{
|
|
|
if (!regs) {
|
|
|
/*
|
|
@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs)
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- printk("\nCall Trace:\n");
|
|
|
- sh64_unwind_inner(regs);
|
|
|
+ sh64_unwind_inner(ops, data, regs);
|
|
|
}
|
|
|
|
|
|
+static struct unwinder sh64_unwinder = {
|
|
|
+ .name = "sh64-unwinder",
|
|
|
+ .dump = sh64_unwinder_dump,
|
|
|
+ .rating = 150,
|
|
|
+};
|
|
|
+
|
|
|
+static int __init sh64_unwinder_init(void)
|
|
|
+{
|
|
|
+ return unwinder_register(&sh64_unwinder);
|
|
|
+}
|
|
|
+early_initcall(sh64_unwinder_init);
|