aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/unwinder.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-08-21 14:49:58 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-08-21 14:49:58 -0400
commitc153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (patch)
tree89639b00047f341f5ebf0b2029a861e3718f641f /arch/sh/kernel/unwinder.c
parent4ab8f241f6d510470c15b62ac10f6905ff5c97bd (diff)
parent5580e9044df9c0e87861739d8c527006ead92e52 (diff)
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.c33
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 = {
54 54
55static DEFINE_SPINLOCK(unwinder_lock); 55static DEFINE_SPINLOCK(unwinder_lock);
56 56
57static atomic_t unwinder_running = ATOMIC_INIT(0);
58
59/** 57/**
60 * select_unwinder - Select the best registered stack unwinder. 58 * select_unwinder - Select the best registered stack unwinder.
61 * 59 *
@@ -123,6 +121,8 @@ int unwinder_register(struct unwinder *u)
123 return ret; 121 return ret;
124} 122}
125 123
124int unwinder_faulted = 0;
125
126/* 126/*
127 * Unwind the call stack and pass information to the stacktrace_ops 127 * Unwind the call stack and pass information to the stacktrace_ops
128 * functions. Also handle the case where we need to switch to a new 128 * 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,
145 * Hopefully this will give us a semi-reliable stacktrace so we 145 * Hopefully this will give us a semi-reliable stacktrace so we
146 * can diagnose why curr_unwinder->dump() faulted. 146 * can diagnose why curr_unwinder->dump() faulted.
147 */ 147 */
148 if (atomic_inc_return(&unwinder_running) != 1) { 148 if (unwinder_faulted) {
149 spin_lock_irqsave(&unwinder_lock, flags); 149 spin_lock_irqsave(&unwinder_lock, flags);
150 150
151 if (!list_is_singular(&unwinder_list)) { 151 /* Make sure no one beat us to changing the unwinder */
152 if (unwinder_faulted && !list_is_singular(&unwinder_list)) {
152 list_del(&curr_unwinder->list); 153 list_del(&curr_unwinder->list);
153 curr_unwinder = select_unwinder(); 154 curr_unwinder = select_unwinder();
155
156 unwinder_faulted = 0;
154 } 157 }
155 158
156 spin_unlock_irqrestore(&unwinder_lock, flags); 159 spin_unlock_irqrestore(&unwinder_lock, flags);
157 atomic_dec(&unwinder_running);
158 } 160 }
159 161
160 curr_unwinder->dump(task, regs, sp, ops, data); 162 curr_unwinder->dump(task, regs, sp, ops, data);
163}
164
165/*
166 * Trap handler for UWINDER_BUG() statements. We must switch to the
167 * unwinder with the next highest rating.
168 */
169BUILD_TRAP_HANDLER(unwinder)
170{
171 insn_size_t insn;
172 TRAP_HANDLER_DECL;
173
174 /* Rewind */
175 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
176 insn = *(insn_size_t *)instruction_pointer(regs);
177
178 /* Switch unwinders when unwind_stack() is called */
179 unwinder_faulted = 1;
161 180
162 atomic_dec(&unwinder_running); 181#ifdef CONFIG_BUG
182 handle_BUG(regs);
183#endif
163} 184}
164EXPORT_SYMBOL_GPL(unwind_stack); 185EXPORT_SYMBOL_GPL(unwind_stack);