diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-02-17 14:24:46 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-02-17 14:24:46 +0100 |
commit | 7fb3a069bc5d3577409c2ae89f89cd264ff85816 (patch) | |
tree | 7fe3ba3b95faeecb01e4feafb9288ef4b523c6b3 /arch/sh/kernel/dwarf.c | |
parent | 291186e049d7f8178ad31d43c38a53889f25d79e (diff) | |
parent | 9d3415a8cc76ff65c6602a121ac318432c5cd7ba (diff) | |
download | linux-7fb3a069bc5d3577409c2ae89f89cd264ff85816.tar.bz2 |
Merge branch 'fix/misc' into topic/misc
Conflicts:
sound/pci/hda/patch_realtek.c
Diffstat (limited to 'arch/sh/kernel/dwarf.c')
-rw-r--r-- | arch/sh/kernel/dwarf.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 3576b709f052..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) 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: @@ -892,18 +912,18 @@ static struct unwinder dwarf_unwinder = { static void dwarf_unwinder_cleanup(void) { - struct dwarf_cie *cie; - struct dwarf_fde *fde; + struct dwarf_cie *cie, *cie_tmp; + struct dwarf_fde *fde, *fde_tmp; /* * Deallocate all the memory allocated for the DWARF unwinder. * Traverse all the FDE/CIE lists and remove and free all the * memory associated with those data structures. */ - list_for_each_entry(cie, &dwarf_cie_list, link) + list_for_each_entry_safe(cie, cie_tmp, &dwarf_cie_list, link) kfree(cie); - list_for_each_entry(fde, &dwarf_fde_list, link) + list_for_each_entry_safe(fde, fde_tmp, &dwarf_fde_list, link) kfree(fde); kmem_cache_destroy(dwarf_reg_cachep); |