diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 11:18:43 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 11:18:43 -0400 |
commit | 12dce6263d43daeb4e16fa4eb964c1c99fa4fa2e (patch) | |
tree | e70a514e5fec67be191e12eba508db8ced967a4b /arch/mips/kernel/process.c | |
parent | 3f2e05e90e0846c42626e3d272454f26be34a1bc (diff) | |
parent | 04b314b2c3732bb5aa752fdbb3076de16decdab6 (diff) |
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
[MIPS] Remove unused galileo-boars header files
[MIPS] Rename SERIAL_PORT_DEFNS for EV64120
[MIPS] Add UART IRQ number for EV64120
[MIPS] Remove excite_flash.c
[MIPS] Update i8259 resources.
[MIPS] Make unwind_stack() can dig into interrupted context
[MIPS] Stacktrace build-fix and improvement
[MIPS] QEMU: Add support for little endian mips
[MIPS] Remove __flush_icache_page
[MIPS] lockdep: update defconfigs
[MIPS] lockdep: Add STACKTRACE_SUPPORT and enable LOCKDEP_SUPPORT
[MIPS] lockdep: fix TRACE_IRQFLAGS_SUPPORT
Diffstat (limited to 'arch/mips/kernel/process.c')
-rw-r--r-- | arch/mips/kernel/process.c | 37 |
1 files changed, 32 insertions, 5 deletions
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 2613a0dd4b82..045d987bc683 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/elf.h> | 40 | #include <asm/elf.h> |
41 | #include <asm/isadep.h> | 41 | #include <asm/isadep.h> |
42 | #include <asm/inst.h> | 42 | #include <asm/inst.h> |
43 | #include <asm/stacktrace.h> | ||
43 | #ifdef CONFIG_MIPS_MT_SMTC | 44 | #ifdef CONFIG_MIPS_MT_SMTC |
44 | #include <asm/mipsmtregs.h> | 45 | #include <asm/mipsmtregs.h> |
45 | extern void smtc_idle_loop_hook(void); | 46 | extern void smtc_idle_loop_hook(void); |
@@ -398,7 +399,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
398 | #ifdef CONFIG_KALLSYMS | 399 | #ifdef CONFIG_KALLSYMS |
399 | /* used by show_backtrace() */ | 400 | /* used by show_backtrace() */ |
400 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | 401 | unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, |
401 | unsigned long pc, unsigned long ra) | 402 | unsigned long pc, unsigned long *ra) |
402 | { | 403 | { |
403 | unsigned long stack_page; | 404 | unsigned long stack_page; |
404 | struct mips_frame_info info; | 405 | struct mips_frame_info info; |
@@ -406,18 +407,42 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | |||
406 | char namebuf[KSYM_NAME_LEN + 1]; | 407 | char namebuf[KSYM_NAME_LEN + 1]; |
407 | unsigned long size, ofs; | 408 | unsigned long size, ofs; |
408 | int leaf; | 409 | int leaf; |
410 | extern void ret_from_irq(void); | ||
411 | extern void ret_from_exception(void); | ||
409 | 412 | ||
410 | stack_page = (unsigned long)task_stack_page(task); | 413 | stack_page = (unsigned long)task_stack_page(task); |
411 | if (!stack_page) | 414 | if (!stack_page) |
412 | return 0; | 415 | return 0; |
413 | 416 | ||
417 | /* | ||
418 | * If we reached the bottom of interrupt context, | ||
419 | * return saved pc in pt_regs. | ||
420 | */ | ||
421 | if (pc == (unsigned long)ret_from_irq || | ||
422 | pc == (unsigned long)ret_from_exception) { | ||
423 | struct pt_regs *regs; | ||
424 | if (*sp >= stack_page && | ||
425 | *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) { | ||
426 | regs = (struct pt_regs *)*sp; | ||
427 | pc = regs->cp0_epc; | ||
428 | if (__kernel_text_address(pc)) { | ||
429 | *sp = regs->regs[29]; | ||
430 | *ra = regs->regs[31]; | ||
431 | return pc; | ||
432 | } | ||
433 | } | ||
434 | return 0; | ||
435 | } | ||
414 | if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) | 436 | if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) |
415 | return 0; | 437 | return 0; |
416 | /* | 438 | /* |
417 | * Return ra if an exception occured at the first instruction | 439 | * Return ra if an exception occured at the first instruction |
418 | */ | 440 | */ |
419 | if (unlikely(ofs == 0)) | 441 | if (unlikely(ofs == 0)) { |
420 | return ra; | 442 | pc = *ra; |
443 | *ra = 0; | ||
444 | return pc; | ||
445 | } | ||
421 | 446 | ||
422 | info.func = (void *)(pc - ofs); | 447 | info.func = (void *)(pc - ofs); |
423 | info.func_size = ofs; /* analyze from start to ofs */ | 448 | info.func_size = ofs; /* analyze from start to ofs */ |
@@ -436,11 +461,12 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | |||
436 | * one. In that cases avoid to return always the | 461 | * one. In that cases avoid to return always the |
437 | * same value. | 462 | * same value. |
438 | */ | 463 | */ |
439 | pc = pc != ra ? ra : 0; | 464 | pc = pc != *ra ? *ra : 0; |
440 | else | 465 | else |
441 | pc = ((unsigned long *)(*sp))[info.pc_offset]; | 466 | pc = ((unsigned long *)(*sp))[info.pc_offset]; |
442 | 467 | ||
443 | *sp += info.frame_size; | 468 | *sp += info.frame_size; |
469 | *ra = 0; | ||
444 | return __kernel_text_address(pc) ? pc : 0; | 470 | return __kernel_text_address(pc) ? pc : 0; |
445 | } | 471 | } |
446 | #endif | 472 | #endif |
@@ -453,6 +479,7 @@ unsigned long get_wchan(struct task_struct *task) | |||
453 | unsigned long pc = 0; | 479 | unsigned long pc = 0; |
454 | #ifdef CONFIG_KALLSYMS | 480 | #ifdef CONFIG_KALLSYMS |
455 | unsigned long sp; | 481 | unsigned long sp; |
482 | unsigned long ra = 0; | ||
456 | #endif | 483 | #endif |
457 | 484 | ||
458 | if (!task || task == current || task->state == TASK_RUNNING) | 485 | if (!task || task == current || task->state == TASK_RUNNING) |
@@ -466,7 +493,7 @@ unsigned long get_wchan(struct task_struct *task) | |||
466 | sp = task->thread.reg29 + schedule_mfi.frame_size; | 493 | sp = task->thread.reg29 + schedule_mfi.frame_size; |
467 | 494 | ||
468 | while (in_sched_functions(pc)) | 495 | while (in_sched_functions(pc)) |
469 | pc = unwind_stack(task, &sp, pc, 0); | 496 | pc = unwind_stack(task, &sp, pc, &ra); |
470 | #endif | 497 | #endif |
471 | 498 | ||
472 | out: | 499 | out: |