diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-21 14:49:58 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-21 14:49:58 -0400 |
commit | c153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (patch) | |
tree | 89639b00047f341f5ebf0b2029a861e3718f641f /arch/sh/kernel/unwinder.c | |
parent | 4ab8f241f6d510470c15b62ac10f6905ff5c97bd (diff) | |
parent | 5580e9044df9c0e87861739d8c527006ead92e52 (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.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 = { | |||
54 | 54 | ||
55 | static DEFINE_SPINLOCK(unwinder_lock); | 55 | static DEFINE_SPINLOCK(unwinder_lock); |
56 | 56 | ||
57 | static 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 | ||
124 | int 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 | */ | ||
169 | BUILD_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 | } |
164 | EXPORT_SYMBOL_GPL(unwind_stack); | 185 | EXPORT_SYMBOL_GPL(unwind_stack); |