static void __TI_unwind_frame(_Unwind_Exception *uexcep, _Unwind_Context *context) { _Unwind_Reason_Code reason_code; /*-----------------------------------------------------------------------*/ /* Start Phase 2 unwinding, will unwind frames till we find a handler */ /* that needs to be run. */ /*-----------------------------------------------------------------------*/ while (1) { /*-------------------------------------------------------------------*/ /* Look up Unwind Table using PC to find the EHT, set up PR to call */ /*-------------------------------------------------------------------*/ _UINT32 v_pc = __TI_targ_regbuf_get_pc(context); if (find_et_setup_pr(uexcep, v_pc) != _URC_SUCCESS) abort(); /*-------------------------------------------------------------------*/ /* Save regbuf PC, it will be overwritten by PR */ /*-------------------------------------------------------------------*/ uexcep->unwinder_data.saved_callsite_addr = v_pc; #ifdef DEBUG_UNWINDER printf("UW: saved PC: %"PRIx32"\n", v_pc); #endif /*-------------------------------------------------------------------*/ /* Call PR with phase set to Phase2 Start */ /*-------------------------------------------------------------------*/ #pragma diag_suppress 1107 reason_code = ((_PR_TYPE)(uexcep->unwinder_data.pr_addr))(_UP_Phase2_Start, uexcep, context); #pragma diag_default 1107 #ifdef DEBUG_UNWINDER printf("UW: PR returned to __TI_unwind_frame\n"); #endif if (reason_code != _URC_CONTINUE_UNWIND) break; } if (reason_code != _URC_INSTALL_CONTEXT) abort(); /*-----------------------------------------------------------------------*/ /* Copy register buffer regs into machine regs, results in call to */ /* handler set up by the PR */ /*-----------------------------------------------------------------------*/ __TI_targ_regbuf_install(context); }
INLINE static bool process_cleanup(_Unwind_Exception *uexcep, _Unwind_Phase phase, _Unwind_Context *context, _UINT32 **descr_ptr, _UINT32 length, _UINT32 offset) { _UINT32 *p_lp = *descr_ptr; _UINT32 range_start = uexcep->pr_data.func_start + offset; _UINT32 curr_pc = __TI_targ_regbuf_get_pc(context); #ifdef DEBUG_PR printf("PR: (@ %p) Clean, Phase %d, " "Len %"PRId32", Off %"PRIx32", lp %"PRIx32"\n", *descr_ptr, phase, length, offset, **descr_ptr); #endif /* DEBUG_PR */ /*-----------------------------------------------------------------------*/ /* Increment desc ptr beyond landing pad */ /*-----------------------------------------------------------------------*/ (*descr_ptr)++; /*-----------------------------------------------------------------------*/ /* Phase 2, and PC is within the range, set up reg buff to call handler */ /*-----------------------------------------------------------------------*/ if (phase != _UP_Phase1 && curr_pc >= range_start && curr_pc < range_start+length) { /*-------------------------------------------------------------------*/ /* Save address of next EHT descriptor, to resume processing later */ /*-------------------------------------------------------------------*/ uexcep->cleanup_data.cleanup_ehtp = (_UINT32)(*descr_ptr); /*-------------------------------------------------------------------*/ /* __cxa_begin_cleanup must be called before starting any cleanups */ /*-------------------------------------------------------------------*/ __cxa_begin_cleanup(uexcep); /*-------------------------------------------------------------------*/ /* Set up registers to call cleanup landing pad */ /*-------------------------------------------------------------------*/ __TI_targ_regbuf_set_pc(context, __TI_prel2abs(p_lp)); return true; } return false; }
_Unwind_Reason_Code __TI_Unwind_RaiseException2(_Unwind_Exception *uexcep, _Unwind_Context *ph1_context, _Unwind_Context *ph2_context) { #ifdef DEBUG_UNWINDER printf("UW: In __TI_Unwind_RaiseException2, UE @ %p, ph1_context @ %p, ph2_context @ %p\n", uexcep, ph1_context, ph2_context); #endif /*-----------------------------------------------------------------------*/ /* Search for a handler */ /*-----------------------------------------------------------------------*/ _Unwind_Reason_Code reason_code; while (1) { /*-------------------------------------------------------------------*/ /* Look up Unwind Table using PC to find the EHT, set up PR to call */ /*-------------------------------------------------------------------*/ if (find_et_setup_pr(uexcep, __TI_targ_regbuf_get_pc(ph1_context)) != _URC_SUCCESS) { #ifdef DEBUG_UNWINDER printf("UW: find_et_setup_pr() != _URC_SUCCESS\n"); #endif return _URC_FATAL_PHASE1_ERROR; } /*-------------------------------------------------------------------*/ /* Call PR with phase set to Phase1 */ /*-------------------------------------------------------------------*/ #pragma diag_suppress 1107 reason_code = ((_PR_TYPE)(uexcep->unwinder_data.pr_addr))(_UP_Phase1, uexcep, ph1_context); #pragma diag_default 1107 #ifdef DEBUG_UNWINDER printf("UW: PR returned to __TI_Unwind_RaiseException\n"); #endif if (reason_code != _URC_CONTINUE_UNWIND) break; } #ifdef DEBUG_UNWINDER printf("UW: Unwind phase 1 finished\n"); #endif /*-----------------------------------------------------------------------*/ /* At this point, we should have found a handler for the exception */ /*-----------------------------------------------------------------------*/ if (reason_code != _URC_HANDLER_FOUND) return _URC_FATAL_PHASE1_ERROR; /*-----------------------------------------------------------------------*/ /* Start phase 2 unwinding */ /*-----------------------------------------------------------------------*/ __TI_unwind_frame(uexcep, ph2_context); /*-----------------------------------------------------------------------*/ /* Should not get here, if we do, indicate failure */ /*-----------------------------------------------------------------------*/ return _URC_FATAL_PHASE2_ERROR; }
_Unwind_Reason_Code __TI_Unwind_RaiseException(_Unwind_Exception *uexcep, _Unwind_Context *context) { #ifdef DEBUG_UNWINDER printf("UW: In __TI_Unwind_RaiseException, UE @ %p, context @ %p\n", uexcep, context); #endif /*-----------------------------------------------------------------------*/ /* Call target specific routine to make a copy of the register context */ /* for use by the Phase 1 unwinder. This needs to be a copy because */ /* we're going to simulate unwinding by writing to it, and we don't want */ /* to scribble on the original yet. Phase 2 will use the original, */ /* since at that time we are committed to unwinding the frame. */ /*-----------------------------------------------------------------------*/ _Unwind_Context *ph1_context = __TI_targ_unwind_regbuf_setup(uexcep, context); if (!ph1_context) { #ifdef DEBUG_UNWINDER printf("UW: __TI_targ_unwind_regbuf_setup() == NULL\n"); #endif return _URC_FAILURE; } /*-----------------------------------------------------------------------*/ /* Search for a handler */ /*-----------------------------------------------------------------------*/ _Unwind_Reason_Code reason_code; while (1) { /*-------------------------------------------------------------------*/ /* Look up Unwind Table using PC to find the EHT, set up PR to call */ /*-------------------------------------------------------------------*/ if (find_et_setup_pr(uexcep, __TI_targ_regbuf_get_pc(ph1_context)) != _URC_SUCCESS) { #ifdef DEBUG_UNWINDER printf("UW: find_et_setup_pr() != _URC_SUCCESS\n"); #endif return _URC_FATAL_PHASE1_ERROR; } /*-------------------------------------------------------------------*/ /* Call PR with phase set to Phase1 */ /*-------------------------------------------------------------------*/ #pragma diag_suppress 1107 reason_code = ((_PR_TYPE)(uexcep->unwinder_data.pr_addr))(_UP_Phase1, uexcep, ph1_context); #pragma diag_default 1107 #ifdef DEBUG_UNWINDER printf("UW: PR returned to __TI_Unwind_RaiseException\n"); #endif if (reason_code != _URC_CONTINUE_UNWIND) break; } #ifdef DEBUG_UNWINDER printf("UW: Unwind phase 1 finished\n"); #endif /*-----------------------------------------------------------------------*/ /* Phase 1 Register Context no longer required, free it */ /*-----------------------------------------------------------------------*/ free(ph1_context); /*-----------------------------------------------------------------------*/ /* At this point, we should have found a handler for the exception */ /*-----------------------------------------------------------------------*/ if (reason_code != _URC_HANDLER_FOUND) return _URC_FATAL_PHASE1_ERROR; /*-----------------------------------------------------------------------*/ /* Start phase 2 unwinding */ /*-----------------------------------------------------------------------*/ __TI_unwind_frame(uexcep, context); /*-----------------------------------------------------------------------*/ /* Should not get here, if we do, indicate failure */ /*-----------------------------------------------------------------------*/ return _URC_FATAL_PHASE2_ERROR; }
INLINE static bool process_fespec (_Unwind_Exception *uexcep, _Unwind_Phase phase, _Unwind_Context *context, _UINT32 **descr_ptr, _UINT32 length, _UINT32 offset, _Unwind_Reason_Code *reason, bool *ph2_call_unexpected) { bool reason_valid = false; _UINT32 rtti_count = **descr_ptr; _UINT32 range_start = uexcep->pr_data.func_start + offset; bool call_unexpected; _UINT32 curr_pc = __TI_targ_regbuf_get_pc(context); _UINT32 sp = __TI_targ_regbuf_get_sp(context); _UINT32 sb = __TI_targ_regbuf_get_sb(context); /*-----------------------------------------------------------------------*/ /* The MSB in rtti_count is used to indicate a call to call_unexpected */ /* MSB ==0, use call_unexpected, MSB ==1, use handler supplied in descr */ /*-----------------------------------------------------------------------*/ call_unexpected = (rtti_count & 0x80000000) ? false : true; rtti_count &= 0x7fffffff; #ifdef DEBUG_PR printf("PR: (@ %p) Fspec, Len %"PRId32", " "Off %"PRIx32", Count %"PRIx32"\n", *descr_ptr, length, offset, rtti_count); #endif /* DEBUG_PR */ /*-----------------------------------------------------------------------*/ /* Phase 1, check if fespec forms a propagation barrier */ /*-----------------------------------------------------------------------*/ if (phase == _UP_Phase1) { if (curr_pc >= range_start && curr_pc < range_start+length) { /*---------------------------------------------------------------*/ /* Check list of rtti types for match */ /*---------------------------------------------------------------*/ void *matched; _UINT32 idx; for (idx=0; idx < rtti_count; idx++) { _UINT32 rtti_offset = (_UINT32)*((*descr_ptr) + idx + 1); _UINT32 rtti_address = __TI_targ_rtti_address(rtti_offset, context); #pragma diag_suppress 1107 if (__cxa_type_match(uexcep, (std::type_info *)(uintptr_t)rtti_address, &matched)) break; #pragma diag_default 1107 } /*---------------------------------------------------------------*/ /* If no match, exception should not propagate beyond this func */ /* save propagation barrier */ /*---------------------------------------------------------------*/ if (idx == rtti_count) { #ifdef DEBUG_PR printf("PR: Found fespec propagation barrier\n"); #endif /* DEBUG_PR */ /*-----------------------------------------------------------*/ /* Save propagation barrier: SP and ptr to descr (Sec 7.3/5) */ /*-----------------------------------------------------------*/ uexcep->barrier_data.sp = sp; uexcep->barrier_data.data[1] = (_UINT32)*descr_ptr; /*-----------------------------------------------------------*/ /* cxa_begin_catch requires matched type in 0, Sec 8.2 - it */ /* is called from cxa_call_unexpected. */ /*-----------------------------------------------------------*/ uexcep->barrier_data.data[0] = (_UINT32)matched; *reason = _URC_HANDLER_FOUND; reason_valid = true; } } } /*-----------------------------------------------------------------------*/ /* Phase 2, check for a previously saved propagation barrier */ /*-----------------------------------------------------------------------*/ else { if (sp == uexcep->barrier_data.sp && (_UINT32)*descr_ptr == uexcep->barrier_data.data[1]) { /*---------------------------------------------------------------*/ /* Set up barrier cache with required data - Sec 8.2 */ /*---------------------------------------------------------------*/ uexcep->barrier_data.data[1] = rtti_count; uexcep->barrier_data.data[2] = sb; uexcep->barrier_data.data[3] = 4; uexcep->barrier_data.data[4] = (_UINT32)((*descr_ptr)+1); /*---------------------------------------------------------------*/ /* If descriptor specifies a landing pad, call landing pad else */ /* call cxa_call_unexpected _after_ unwinding */ /* Sec 8.5.3 - any permitted throw out of unexpected() must */ /* behave as if unwinding resumes at the call site to the func */ /* whose exception specification was violated. */ /*---------------------------------------------------------------*/ if (!call_unexpected) { _UINT32 *p_lp_offset = ((*descr_ptr) + 1 + rtti_count); __TI_targ_regbuf_set_pc(context, __TI_prel2abs(p_lp_offset)); __TI_targ_setup_call_parm0(context, (_UINT32)uexcep); *reason = _URC_INSTALL_CONTEXT; reason_valid = true; } else *ph2_call_unexpected = true; } } /*-----------------------------------------------------------------------*/ /* Skip over rtti count field, list of types & lp offset if any */ /*-----------------------------------------------------------------------*/ (*descr_ptr) += (rtti_count + 1 + (call_unexpected ? 0 : 1)); return reason_valid; }
INLINE static bool process_catch(_Unwind_Exception *uexcep, _Unwind_Phase phase, _Unwind_Context *context, _UINT32 **descr_ptr, _UINT32 length, _UINT32 offset, _Unwind_Reason_Code *reason) { bool reason_valid = false; _UINT32 *p_lp_offset = *descr_ptr; _UINT32 rtti_offset = *(*descr_ptr+1); _UINT32 range_start = uexcep->pr_data.func_start + offset; _UINT32 curr_pc = __TI_targ_regbuf_get_pc(context); _UINT32 sp = __TI_targ_regbuf_get_sp(context); _UINT32 rtti_address = __TI_targ_rtti_address(rtti_offset, context); #ifdef DEBUG_PR printf("PR: (@ %p) Catch, Phase %d, " "Len %"PRId32", Off %#"PRIx32", (%"PRIx32" - %"PRIx32") " "lp %"PRIx32", type %"PRIx32" (offset = %"PRIx32")\n", *descr_ptr, phase, length, offset, range_start, range_start+length, *p_lp_offset, rtti_address, rtti_offset); #endif /* DEBUG_PR */ /*-----------------------------------------------------------------------*/ /* Phase 1, Check if catch forms propagation barrier */ /*-----------------------------------------------------------------------*/ if (phase == _UP_Phase1) { /*-------------------------------------------------------------------*/ /* Check if PC is in range */ /*-------------------------------------------------------------------*/ if (curr_pc >= range_start && curr_pc < range_start+length) { /*---------------------------------------------------------------*/ /* Check for a type match, also check for catch all/terminate */ /*---------------------------------------------------------------*/ void *matched; if (rtti_offset == CATCH_ANY_TERMINATE) { *reason = _URC_FAILURE; reason_valid = true; } #pragma diag_suppress 1107 else if (rtti_offset == CATCH_ANY || __cxa_type_match(uexcep, (std::type_info *)(uintptr_t)rtti_address, &matched)) #pragma diag_default 1107 { #ifdef DEBUG_PR printf("PR: Found catch propagation barrier\n"); #endif /* DEBUG_PR */ /*-----------------------------------------------------------*/ /* Save propagation barrier: SP and ptr to descr (Sec 7.3/5) */ /*-----------------------------------------------------------*/ uexcep->barrier_data.sp = sp; uexcep->barrier_data.data[1] = (_UINT32)*descr_ptr; /*-----------------------------------------------------------*/ /* cxa_begin_catch requires matched type in 0, Sec 8.2 */ /*-----------------------------------------------------------*/ uexcep->barrier_data.data[0] = (_UINT32)matched; *reason = _URC_HANDLER_FOUND; reason_valid = true; } } } /*-----------------------------------------------------------------------*/ /* Phase 2 Start or Resume, check for barrier, set up catch handler */ /*-----------------------------------------------------------------------*/ else { /*-------------------------------------------------------------------*/ /* Check for a previously saved propagation barrier */ /*-------------------------------------------------------------------*/ if (sp == uexcep->barrier_data.sp && (_UINT32)*descr_ptr == uexcep->barrier_data.data[1]) { /*---------------------------------------------------------------*/ /* Set up PC to call catch handler, set up UE ptr in R0 */ /*---------------------------------------------------------------*/ __TI_targ_regbuf_set_pc(context, __TI_prel2abs(p_lp_offset)); __TI_targ_setup_call_parm0(context, (_UINT32)uexcep); *reason = _URC_INSTALL_CONTEXT; reason_valid = true; } } /*-----------------------------------------------------------------------*/ /* Increment desc ptr beyond landing pad & rtti offset */ /*-----------------------------------------------------------------------*/ (*descr_ptr) += 2; return reason_valid; }