Skip to content

Commit

Permalink
Merge branch 'sh/multi-unwinders' into sh-latest
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Mundt committed Jun 13, 2012
2 parents 380622e + 3a898c0 commit f21efd4
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 98 deletions.
1 change: 1 addition & 0 deletions arch/sh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ config SUPERH32

config SUPERH64
def_bool ARCH = "sh64"
select KALLSYMS

config ARCH_DEFCONFIG
string
Expand Down
2 changes: 2 additions & 0 deletions arch/sh/include/asm/kdebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
63 changes: 41 additions & 22 deletions arch/sh/kernel/cpu/sh5/unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down Expand Up @@ -199,26 +201,31 @@ 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;
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;
Expand All @@ -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;
}

Expand All @@ -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
Expand All @@ -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) {
/*
Expand Down Expand Up @@ -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);
58 changes: 58 additions & 0 deletions arch/sh/kernel/dumpstack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
50 changes: 0 additions & 50 deletions arch/sh/kernel/traps_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
26 changes: 0 additions & 26 deletions arch/sh/kernel/traps_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit f21efd4

Please sign in to comment.