Merge branch 'sh/multi-unwinders' into sh-latest
This commit is contained in:
Коммит
f21efd4536
|
@ -60,6 +60,7 @@ config SUPERH32
|
|||
|
||||
config SUPERH64
|
||||
def_bool ARCH = "sh64"
|
||||
select KALLSYMS
|
||||
|
||||
config ARCH_DEFCONFIG
|
||||
string
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче