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); | ||
