Merge branch 'sh/multi-unwinders' into sh-latest

This commit is contained in:
Paul Mundt 2012-06-13 12:12:14 +09:00
commit f21efd4536
6 changed files with 102 additions and 98 deletions

View file

@ -60,6 +60,7 @@ config SUPERH32
config SUPERH64
def_bool ARCH = "sh64"
select KALLSYMS
config ARCH_DEFCONFIG
string

View file

@ -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 */

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)
{