diff options
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) | |||
| 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: |
| @@ -892,18 +912,18 @@ static struct unwinder dwarf_unwinder = { | |||
| 892 | 912 | ||
| 893 | static void dwarf_unwinder_cleanup(void) | 913 | static void dwarf_unwinder_cleanup(void) |
| 894 | { | 914 | { |
| 895 | struct dwarf_cie *cie; | 915 | struct dwarf_cie *cie, *cie_tmp; |
| 896 | struct dwarf_fde *fde; | 916 | struct dwarf_fde *fde, *fde_tmp; |
| 897 | 917 | ||
| 898 | /* | 918 | /* |
| 899 | * Deallocate all the memory allocated for the DWARF unwinder. | 919 | * Deallocate all the memory allocated for the DWARF unwinder. |
| 900 | * Traverse all the FDE/CIE lists and remove and free all the | 920 | * Traverse all the FDE/CIE lists and remove and free all the |
| 901 | * memory associated with those data structures. | 921 | * memory associated with those data structures. |
| 902 | */ | 922 | */ |
| 903 | list_for_each_entry(cie, &dwarf_cie_list, link) | 923 | list_for_each_entry_safe(cie, cie_tmp, &dwarf_cie_list, link) |
| 904 | kfree(cie); | 924 | kfree(cie); |
| 905 | 925 | ||
| 906 | list_for_each_entry(fde, &dwarf_fde_list, link) | 926 | list_for_each_entry_safe(fde, fde_tmp, &dwarf_fde_list, link) |
| 907 | kfree(fde); | 927 | kfree(fde); |
| 908 | 928 | ||
| 909 | kmem_cache_destroy(dwarf_reg_cachep); | 929 | kmem_cache_destroy(dwarf_reg_cachep); |
