diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-22 03:49:58 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-22 03:49:58 +0900 |
commit | c153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (patch) | |
tree | 89639b00047f341f5ebf0b2029a861e3718f641f /arch/sh/kernel/unwinder.c | |
parent | 4ab8f241f6d510470c15b62ac10f6905ff5c97bd (diff) | |
parent | 5580e9044df9c0e87861739d8c527006ead92e52 (diff) | |
download | blackbird-op-linux-c153a58e715e16ffcd6c4b3da7fc6b4a556bf917.tar.gz blackbird-op-linux-c153a58e715e16ffcd6c4b3da7fc6b4a556bf917.zip |
Merge branch 'sh/dwarf-unwinder' of git://github.com/mfleming/linux-2.6 into sh/dwarf-unwinder
Diffstat (limited to 'arch/sh/kernel/unwinder.c')
-rw-r--r-- | arch/sh/kernel/unwinder.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/arch/sh/kernel/unwinder.c b/arch/sh/kernel/unwinder.c index 5f56ff3f55e0..e83861d9739c 100644 --- a/arch/sh/kernel/unwinder.c +++ b/arch/sh/kernel/unwinder.c @@ -54,8 +54,6 @@ static struct list_head unwinder_list = { static DEFINE_SPINLOCK(unwinder_lock); -static atomic_t unwinder_running = ATOMIC_INIT(0); - /** * select_unwinder - Select the best registered stack unwinder. * @@ -123,6 +121,8 @@ int unwinder_register(struct unwinder *u) return ret; } +int unwinder_faulted = 0; + /* * Unwind the call stack and pass information to the stacktrace_ops * functions. Also handle the case where we need to switch to a new @@ -145,20 +145,41 @@ void unwind_stack(struct task_struct *task, struct pt_regs *regs, * Hopefully this will give us a semi-reliable stacktrace so we * can diagnose why curr_unwinder->dump() faulted. */ - if (atomic_inc_return(&unwinder_running) != 1) { + if (unwinder_faulted) { spin_lock_irqsave(&unwinder_lock, flags); - if (!list_is_singular(&unwinder_list)) { + /* Make sure no one beat us to changing the unwinder */ + if (unwinder_faulted && !list_is_singular(&unwinder_list)) { list_del(&curr_unwinder->list); curr_unwinder = select_unwinder(); + + unwinder_faulted = 0; } spin_unlock_irqrestore(&unwinder_lock, flags); - atomic_dec(&unwinder_running); } curr_unwinder->dump(task, regs, sp, ops, data); +} + +/* + * Trap handler for UWINDER_BUG() statements. We must switch to the + * unwinder with the next highest rating. + */ +BUILD_TRAP_HANDLER(unwinder) +{ + insn_size_t insn; + TRAP_HANDLER_DECL; + + /* Rewind */ + regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); + insn = *(insn_size_t *)instruction_pointer(regs); + + /* Switch unwinders when unwind_stack() is called */ + unwinder_faulted = 1; - atomic_dec(&unwinder_running); +#ifdef CONFIG_BUG + handle_BUG(regs); +#endif } EXPORT_SYMBOL_GPL(unwind_stack); |