diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sh/kernel/dwarf.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 88d28ec3780a..e51168064e56 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c | |||
@@ -540,6 +540,8 @@ void dwarf_free_frame(struct dwarf_frame *frame) | |||
540 | mempool_free(frame, dwarf_frame_pool); | 540 | mempool_free(frame, dwarf_frame_pool); |
541 | } | 541 | } |
542 | 542 | ||
543 | extern void ret_from_irq(void); | ||
544 | |||
543 | /** | 545 | /** |
544 | * dwarf_unwind_stack - unwind the stack | 546 | * dwarf_unwind_stack - unwind the stack |
545 | * | 547 | * |
@@ -678,6 +680,24 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
678 | addr = frame->cfa + reg->addr; | 680 | addr = frame->cfa + reg->addr; |
679 | frame->return_addr = __raw_readl(addr); | 681 | frame->return_addr = __raw_readl(addr); |
680 | 682 | ||
683 | /* | ||
684 | * Ah, the joys of unwinding through interrupts. | ||
685 | * | ||
686 | * Interrupts are tricky - the DWARF info needs to be _really_ | ||
687 | * accurate and unfortunately I'm seeing a lot of bogus DWARF | ||
688 | * info. For example, I've seen interrupts occur in epilogues | ||
689 | * just after the frame pointer (r14) had been restored. The | ||
690 | * problem was that the DWARF info claimed that the CFA could be | ||
691 | * reached by using the value of the frame pointer before it was | ||
692 | * restored. | ||
693 | * | ||
694 | * So until the compiler can be trusted to produce reliable | ||
695 | * DWARF info when it really matters, let's stop unwinding once | ||
696 | * we've calculated the function that was interrupted. | ||
697 | */ | ||
698 | if (prev && prev->pc == (unsigned long)ret_from_irq) | ||
699 | frame->return_addr = 0; | ||
700 | |||
681 | return frame; | 701 | return frame; |
682 | 702 | ||
683 | bail: | 703 | bail: |