forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
f9369910a6
commit
4945326499
|
@ -10,6 +10,8 @@ enum die_val {
|
|||
DIE_SSTEP,
|
||||
};
|
||||
|
||||
/* arch/sh/kernel/dumpstack.c */
|
||||
extern void printk_address(unsigned long address, int reliable);
|
||||
extern void dump_mem(const char *str, unsigned long bottom, unsigned long top);
|
||||
|
||||
#endif /* __ASM_SH_KDEBUG_H */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2,13 +2,48 @@
|
|||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
|
||||
* Copyright (C) 2009 Matt Fleming
|
||||
* Copyright (C) 2002 - 2012 Paul Mundt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unwinder.h>
|
||||
#include <asm/stacktrace.h>
|
||||
|
||||
void dump_mem(const char *str, unsigned long bottom, unsigned long top)
|
||||
{
|
||||
unsigned long p;
|
||||
int i;
|
||||
|
||||
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
|
||||
|
||||
for (p = bottom & ~31; p < top; ) {
|
||||
printk("%04lx: ", p & 0xffff);
|
||||
|
||||
for (i = 0; i < 8; i++, p += 4) {
|
||||
unsigned int val;
|
||||
|
||||
if (p < bottom || p >= top)
|
||||
printk(" ");
|
||||
else {
|
||||
if (__get_user(val, (unsigned int __user *)p)) {
|
||||
printk("\n");
|
||||
return;
|
||||
}
|
||||
printk("%08x ", val);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void printk_address(unsigned long address, int reliable)
|
||||
{
|
||||
printk(" [<%p>] %s%pS\n", (void *) address,
|
||||
|
@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,
|
|||
|
||||
debug_show_held_locks(tsk);
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *tsk, unsigned long *sp)
|
||||
{
|
||||
unsigned long stack;
|
||||
|
||||
if (!tsk)
|
||||
tsk = current;
|
||||
if (tsk == current)
|
||||
sp = (unsigned long *)current_stack_pointer;
|
||||
else
|
||||
sp = (unsigned long *)tsk->thread.sp;
|
||||
|
||||
stack = (unsigned long)sp;
|
||||
dump_mem("Stack: ", stack, THREAD_SIZE +
|
||||
(unsigned long)task_stack_page(tsk));
|
||||
show_trace(tsk, sp, NULL);
|
||||
}
|
||||
|
||||
void dump_stack(void)
|
||||
{
|
||||
show_stack(NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dump_stack);
|
||||
|
|
|
@ -48,33 +48,6 @@
|
|||
#define TRAP_ILLEGAL_SLOT_INST 13
|
||||
#endif
|
||||
|
||||
static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
|
||||
{
|
||||
unsigned long p;
|
||||
int i;
|
||||
|
||||
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
|
||||
|
||||
for (p = bottom & ~31; p < top; ) {
|
||||
printk("%04lx: ", p & 0xffff);
|
||||
|
||||
for (i = 0; i < 8; i++, p += 4) {
|
||||
unsigned int val;
|
||||
|
||||
if (p < bottom || p >= top)
|
||||
printk(" ");
|
||||
else {
|
||||
if (__get_user(val, (unsigned int __user *)p)) {
|
||||
printk("\n");
|
||||
return;
|
||||
}
|
||||
printk("%08x ", val);
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(die_lock);
|
||||
|
||||
void die(const char * str, struct pt_regs * regs, long err)
|
||||
|
@ -900,26 +873,3 @@ void __init trap_init(void)
|
|||
set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *tsk, unsigned long *sp)
|
||||
{
|
||||
unsigned long stack;
|
||||
|
||||
if (!tsk)
|
||||
tsk = current;
|
||||
if (tsk == current)
|
||||
sp = (unsigned long *)current_stack_pointer;
|
||||
else
|
||||
sp = (unsigned long *)tsk->thread.sp;
|
||||
|
||||
stack = (unsigned long)sp;
|
||||
dump_mem("Stack: ", stack, THREAD_SIZE +
|
||||
(unsigned long)task_stack_page(tsk));
|
||||
show_trace(tsk, sp, NULL);
|
||||
}
|
||||
|
||||
void dump_stack(void)
|
||||
{
|
||||
show_stack(NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(dump_stack);
|
||||
|
|
|
@ -253,32 +253,6 @@ int do_unknown_trapa(unsigned long scId, struct pt_regs *regs)
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void show_stack(struct task_struct *tsk, unsigned long *sp)
|
||||
{
|
||||
#ifdef CONFIG_KALLSYMS
|
||||
extern void sh64_unwind(struct pt_regs *regs);
|
||||
struct pt_regs *regs;
|
||||
|
||||
regs = tsk ? tsk->thread.kregs : NULL;
|
||||
|
||||
sh64_unwind(regs);
|
||||
#else
|
||||
printk(KERN_ERR "Can't backtrace on sh64 without CONFIG_KALLSYMS\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void show_task(unsigned long *sp)
|
||||
{
|
||||
show_stack(NULL, sp);
|
||||
}
|
||||
|
||||
void dump_stack(void)
|
||||
{
|
||||
show_task(NULL);
|
||||
}
|
||||
/* Needed by any user of WARN_ON in view of the defn in include/asm-sh/bug.h */
|
||||
EXPORT_SYMBOL(dump_stack);
|
||||
|
||||
static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_name,
|
||||
unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user