aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/unwind.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/unwind.c')
-rw-r--r--kernel/unwind.c39
1 files changed, 31 insertions, 8 deletions
diff --git a/kernel/unwind.c b/kernel/unwind.c
index f69c804c8e62..2e2368607aab 100644
--- a/kernel/unwind.c
+++ b/kernel/unwind.c
@@ -102,7 +102,7 @@ static struct unwind_table {
102 unsigned long size; 102 unsigned long size;
103 struct unwind_table *link; 103 struct unwind_table *link;
104 const char *name; 104 const char *name;
105} root_table, *last_table; 105} root_table;
106 106
107struct unwind_item { 107struct unwind_item {
108 enum item_location { 108 enum item_location {
@@ -174,6 +174,8 @@ void __init unwind_init(void)
174 174
175#ifdef CONFIG_MODULES 175#ifdef CONFIG_MODULES
176 176
177static struct unwind_table *last_table;
178
177/* Must be called with module_mutex held. */ 179/* Must be called with module_mutex held. */
178void *unwind_add_table(struct module *module, 180void *unwind_add_table(struct module *module,
179 const void *table_start, 181 const void *table_start,
@@ -603,6 +605,7 @@ int unwind(struct unwind_frame_info *frame)
603#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) 605#define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
604 const u32 *fde = NULL, *cie = NULL; 606 const u32 *fde = NULL, *cie = NULL;
605 const u8 *ptr = NULL, *end = NULL; 607 const u8 *ptr = NULL, *end = NULL;
608 unsigned long pc = UNW_PC(frame) - frame->call_frame;
606 unsigned long startLoc = 0, endLoc = 0, cfa; 609 unsigned long startLoc = 0, endLoc = 0, cfa;
607 unsigned i; 610 unsigned i;
608 signed ptrType = -1; 611 signed ptrType = -1;
@@ -612,7 +615,7 @@ int unwind(struct unwind_frame_info *frame)
612 615
613 if (UNW_PC(frame) == 0) 616 if (UNW_PC(frame) == 0)
614 return -EINVAL; 617 return -EINVAL;
615 if ((table = find_table(UNW_PC(frame))) != NULL 618 if ((table = find_table(pc)) != NULL
616 && !(table->size & (sizeof(*fde) - 1))) { 619 && !(table->size & (sizeof(*fde) - 1))) {
617 unsigned long tableSize = table->size; 620 unsigned long tableSize = table->size;
618 621
@@ -647,7 +650,7 @@ int unwind(struct unwind_frame_info *frame)
647 ptrType & DW_EH_PE_indirect 650 ptrType & DW_EH_PE_indirect
648 ? ptrType 651 ? ptrType
649 : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); 652 : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
650 if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc) 653 if (pc >= startLoc && pc < endLoc)
651 break; 654 break;
652 cie = NULL; 655 cie = NULL;
653 } 656 }
@@ -657,16 +660,28 @@ int unwind(struct unwind_frame_info *frame)
657 state.cieEnd = ptr; /* keep here temporarily */ 660 state.cieEnd = ptr; /* keep here temporarily */
658 ptr = (const u8 *)(cie + 2); 661 ptr = (const u8 *)(cie + 2);
659 end = (const u8 *)(cie + 1) + *cie; 662 end = (const u8 *)(cie + 1) + *cie;
663 frame->call_frame = 1;
660 if ((state.version = *ptr) != 1) 664 if ((state.version = *ptr) != 1)
661 cie = NULL; /* unsupported version */ 665 cie = NULL; /* unsupported version */
662 else if (*++ptr) { 666 else if (*++ptr) {
663 /* check if augmentation size is first (and thus present) */ 667 /* check if augmentation size is first (and thus present) */
664 if (*ptr == 'z') { 668 if (*ptr == 'z') {
665 /* check for ignorable (or already handled) 669 while (++ptr < end && *ptr) {
666 * nul-terminated augmentation string */ 670 switch(*ptr) {
667 while (++ptr < end && *ptr) 671 /* check for ignorable (or already handled)
668 if (strchr("LPR", *ptr) == NULL) 672 * nul-terminated augmentation string */
673 case 'L':
674 case 'P':
675 case 'R':
676 continue;
677 case 'S':
678 frame->call_frame = 0;
679 continue;
680 default:
669 break; 681 break;
682 }
683 break;
684 }
670 } 685 }
671 if (ptr >= end || *ptr) 686 if (ptr >= end || *ptr)
672 cie = NULL; 687 cie = NULL;
@@ -755,7 +770,7 @@ int unwind(struct unwind_frame_info *frame)
755 state.org = startLoc; 770 state.org = startLoc;
756 memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); 771 memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
757 /* process instructions */ 772 /* process instructions */
758 if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state) 773 if (!processCFI(ptr, end, pc, ptrType, &state)
759 || state.loc > endLoc 774 || state.loc > endLoc
760 || state.regs[retAddrReg].where == Nowhere 775 || state.regs[retAddrReg].where == Nowhere
761 || state.cfa.reg >= ARRAY_SIZE(reg_info) 776 || state.cfa.reg >= ARRAY_SIZE(reg_info)
@@ -763,6 +778,11 @@ int unwind(struct unwind_frame_info *frame)
763 || state.cfa.offs % sizeof(unsigned long)) 778 || state.cfa.offs % sizeof(unsigned long))
764 return -EIO; 779 return -EIO;
765 /* update frame */ 780 /* update frame */
781#ifndef CONFIG_AS_CFI_SIGNAL_FRAME
782 if(frame->call_frame
783 && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign))
784 frame->call_frame = 0;
785#endif
766 cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; 786 cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
767 startLoc = min((unsigned long)UNW_SP(frame), cfa); 787 startLoc = min((unsigned long)UNW_SP(frame), cfa);
768 endLoc = max((unsigned long)UNW_SP(frame), cfa); 788 endLoc = max((unsigned long)UNW_SP(frame), cfa);
@@ -866,6 +886,7 @@ int unwind_init_frame_info(struct unwind_frame_info *info,
866 /*const*/ struct pt_regs *regs) 886 /*const*/ struct pt_regs *regs)
867{ 887{
868 info->task = tsk; 888 info->task = tsk;
889 info->call_frame = 0;
869 arch_unw_init_frame_info(info, regs); 890 arch_unw_init_frame_info(info, regs);
870 891
871 return 0; 892 return 0;
@@ -879,6 +900,7 @@ int unwind_init_blocked(struct unwind_frame_info *info,
879 struct task_struct *tsk) 900 struct task_struct *tsk)
880{ 901{
881 info->task = tsk; 902 info->task = tsk;
903 info->call_frame = 0;
882 arch_unw_init_blocked(info); 904 arch_unw_init_blocked(info);
883 905
884 return 0; 906 return 0;
@@ -894,6 +916,7 @@ int unwind_init_running(struct unwind_frame_info *info,
894 void *arg) 916 void *arg)
895{ 917{
896 info->task = current; 918 info->task = current;
919 info->call_frame = 0;
897 920
898 return arch_unwind_init_running(info, callback, arg); 921 return arch_unwind_init_running(info, callback, arg);
899} 922}