diff options
author | Paul Mundt <lethal@linux-sh.org> | 2012-06-12 23:12:14 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2012-06-12 23:12:14 -0400 |
commit | f21efd45362d555b3b93960a5736ad7c6fc1f367 (patch) | |
tree | e86510670b3543be81814d0099954b8a83cd8dfb /arch/sh/kernel/cpu/sh5 | |
parent | 380622e9ff56201f9c3c1f153d1ca0a24324a1d4 (diff) | |
parent | 3a898c0f36f9fe312cb6e98865a6833110e67cb2 (diff) |
Merge branch 'sh/multi-unwinders' into sh-latest
Diffstat (limited to 'arch/sh/kernel/cpu/sh5')
-rw-r--r-- | arch/sh/kernel/cpu/sh5/unwind.c | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/arch/sh/kernel/cpu/sh5/unwind.c b/arch/sh/kernel/cpu/sh5/unwind.c index b205b25eaf45..10aed41757fc 100644 --- a/arch/sh/kernel/cpu/sh5/unwind.c +++ b/arch/sh/kernel/cpu/sh5/unwind.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
17 | #include <asm/processor.h> | 17 | #include <asm/processor.h> |
18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
19 | #include <asm/unwinder.h> | ||
20 | #include <asm/stacktrace.h> | ||
19 | 21 | ||
20 | static u8 regcache[63]; | 22 | static u8 regcache[63]; |
21 | 23 | ||
@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc, | |||
199 | return 0; | 201 | return 0; |
200 | } | 202 | } |
201 | 203 | ||
202 | /* Don't put this on the stack since we'll want to call sh64_unwind | 204 | /* |
203 | * when we're close to underflowing the stack anyway. */ | 205 | * Don't put this on the stack since we'll want to call in to |
206 | * sh64_unwinder_dump() when we're close to underflowing the stack | ||
207 | * anyway. | ||
208 | */ | ||
204 | static struct pt_regs here_regs; | 209 | static struct pt_regs here_regs; |
205 | 210 | ||
206 | extern const char syscall_ret; | 211 | extern const char syscall_ret; |
@@ -208,17 +213,19 @@ extern const char ret_from_syscall; | |||
208 | extern const char ret_from_exception; | 213 | extern const char ret_from_exception; |
209 | extern const char ret_from_irq; | 214 | extern const char ret_from_irq; |
210 | 215 | ||
211 | static void sh64_unwind_inner(struct pt_regs *regs); | 216 | static void sh64_unwind_inner(const struct stacktrace_ops *ops, |
217 | void *data, struct pt_regs *regs); | ||
212 | 218 | ||
213 | static void unwind_nested (unsigned long pc, unsigned long fp) | 219 | static inline void unwind_nested(const struct stacktrace_ops *ops, void *data, |
220 | unsigned long pc, unsigned long fp) | ||
214 | { | 221 | { |
215 | if ((fp >= __MEMORY_START) && | 222 | if ((fp >= __MEMORY_START) && |
216 | ((fp & 7) == 0)) { | 223 | ((fp & 7) == 0)) |
217 | sh64_unwind_inner((struct pt_regs *) fp); | 224 | sh64_unwind_inner(ops, data, (struct pt_regs *)fp); |
218 | } | ||
219 | } | 225 | } |
220 | 226 | ||
221 | static void sh64_unwind_inner(struct pt_regs *regs) | 227 | static void sh64_unwind_inner(const struct stacktrace_ops *ops, |
228 | void *data, struct pt_regs *regs) | ||
222 | { | 229 | { |
223 | unsigned long pc, fp; | 230 | unsigned long pc, fp; |
224 | int ofs = 0; | 231 | int ofs = 0; |
@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs) | |||
232 | int cond; | 239 | int cond; |
233 | unsigned long next_fp, next_pc; | 240 | unsigned long next_fp, next_pc; |
234 | 241 | ||
235 | if (pc == ((unsigned long) &syscall_ret & ~1)) { | 242 | if (pc == ((unsigned long)&syscall_ret & ~1)) { |
236 | printk("SYSCALL\n"); | 243 | printk("SYSCALL\n"); |
237 | unwind_nested(pc,fp); | 244 | unwind_nested(ops, data, pc, fp); |
238 | return; | 245 | return; |
239 | } | 246 | } |
240 | 247 | ||
241 | if (pc == ((unsigned long) &ret_from_syscall & ~1)) { | 248 | if (pc == ((unsigned long)&ret_from_syscall & ~1)) { |
242 | printk("SYSCALL (PREEMPTED)\n"); | 249 | printk("SYSCALL (PREEMPTED)\n"); |
243 | unwind_nested(pc,fp); | 250 | unwind_nested(ops, data, pc, fp); |
244 | return; | 251 | return; |
245 | } | 252 | } |
246 | 253 | ||
247 | /* In this case, the PC is discovered by lookup_prev_stack_frame but | 254 | /* In this case, the PC is discovered by lookup_prev_stack_frame but |
248 | it has 4 taken off it to look like the 'caller' */ | 255 | it has 4 taken off it to look like the 'caller' */ |
249 | if (pc == ((unsigned long) &ret_from_exception & ~1)) { | 256 | if (pc == ((unsigned long)&ret_from_exception & ~1)) { |
250 | printk("EXCEPTION\n"); | 257 | printk("EXCEPTION\n"); |
251 | unwind_nested(pc,fp); | 258 | unwind_nested(ops, data, pc, fp); |
252 | return; | 259 | return; |
253 | } | 260 | } |
254 | 261 | ||
255 | if (pc == ((unsigned long) &ret_from_irq & ~1)) { | 262 | if (pc == ((unsigned long)&ret_from_irq & ~1)) { |
256 | printk("IRQ\n"); | 263 | printk("IRQ\n"); |
257 | unwind_nested(pc,fp); | 264 | unwind_nested(ops, data, pc, fp); |
258 | return; | 265 | return; |
259 | } | 266 | } |
260 | 267 | ||
@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs) | |||
263 | 270 | ||
264 | pc -= ofs; | 271 | pc -= ofs; |
265 | 272 | ||
266 | printk("[<%08lx>] ", pc); | 273 | ops->address(data, pc, 1); |
267 | print_symbol("%s\n", pc); | ||
268 | 274 | ||
269 | if (first_pass) { | 275 | if (first_pass) { |
270 | /* If the innermost frame is a leaf function, it's | 276 | /* If the innermost frame is a leaf function, it's |
@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs) | |||
287 | } | 293 | } |
288 | 294 | ||
289 | printk("\n"); | 295 | printk("\n"); |
290 | |||
291 | } | 296 | } |
292 | 297 | ||
293 | void sh64_unwind(struct pt_regs *regs) | 298 | static void sh64_unwinder_dump(struct task_struct *task, |
299 | struct pt_regs *regs, | ||
300 | unsigned long *sp, | ||
301 | const struct stacktrace_ops *ops, | ||
302 | void *data) | ||
294 | { | 303 | { |
295 | if (!regs) { | 304 | if (!regs) { |
296 | /* | 305 | /* |
@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs) | |||
320 | ); | 329 | ); |
321 | } | 330 | } |
322 | 331 | ||
323 | printk("\nCall Trace:\n"); | 332 | sh64_unwind_inner(ops, data, regs); |
324 | sh64_unwind_inner(regs); | ||
325 | } | 333 | } |
326 | 334 | ||
335 | static struct unwinder sh64_unwinder = { | ||
336 | .name = "sh64-unwinder", | ||
337 | .dump = sh64_unwinder_dump, | ||
338 | .rating = 150, | ||
339 | }; | ||
340 | |||
341 | static int __init sh64_unwinder_init(void) | ||
342 | { | ||
343 | return unwinder_register(&sh64_unwinder); | ||
344 | } | ||
345 | early_initcall(sh64_unwinder_init); | ||