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