summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/dwarf.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-02-08 10:09:55 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2010-02-08 10:09:55 -0800
commit8bd73803e18354add19b050d05770b646ecbffd0 (patch)
treec2aa0467418491890b972177dfc64f7fe8e47d9b /arch/sh/kernel/dwarf.c
parent6339204ecc2aa2067a99595522de0403f0854bb8 (diff)
parent1af0b2fc676009d9b5b71a82ea6a3c2b20b7ea56 (diff)
downloadop-kernel-dev-8bd73803e18354add19b050d05770b646ecbffd0.zip
op-kernel-dev-8bd73803e18354add19b050d05770b646ecbffd0.tar.gz
Merge branch 'sh/for-2.6.33' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
* 'sh/for-2.6.33' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6: sh: Remove superfluous setup_frame_reg call sh: Don't continue unwinding across interrupts sh: Setup frame pointer in handle_exception path sh: Correct the offset of the return address in ret_from_exception usb: r8a66597-hcd: Fix up spinlock recursion in root hub polling. usb: r8a66597-hcd: Flush the D-cache for the pipe-in transfer buffers.
Diffstat (limited to 'arch/sh/kernel/dwarf.c')
-rw-r--r--arch/sh/kernel/dwarf.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 88d28ec..e511680 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)
mempool_free(frame, dwarf_frame_pool);
}
+extern void ret_from_irq(void);
+
/**
* dwarf_unwind_stack - unwind the stack
*
@@ -678,6 +680,24 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc,
addr = frame->cfa + reg->addr;
frame->return_addr = __raw_readl(addr);
+ /*
+ * Ah, the joys of unwinding through interrupts.
+ *
+ * Interrupts are tricky - the DWARF info needs to be _really_
+ * accurate and unfortunately I'm seeing a lot of bogus DWARF
+ * info. For example, I've seen interrupts occur in epilogues
+ * just after the frame pointer (r14) had been restored. The
+ * problem was that the DWARF info claimed that the CFA could be
+ * reached by using the value of the frame pointer before it was
+ * restored.
+ *
+ * So until the compiler can be trusted to produce reliable
+ * DWARF info when it really matters, let's stop unwinding once
+ * we've calculated the function that was interrupted.
+ */
+ if (prev && prev->pc == (unsigned long)ret_from_irq)
+ frame->return_addr = 0;
+
return frame;
bail:
OpenPOWER on IntegriCloud