📄 unwind-arm.c
字号:
void *stop_arg = (void *)UCB_FORCED_STOP_ARG (ucbp); _Unwind_Reason_Code pr_result = 0; /* We use phase1_vrs here even though we do not demand save, for the prev_sp field. */ phase1_vrs saved_vrs, next_vrs; /* Save the core registers. */ saved_vrs.core = entry_vrs->core; /* We don't need to demand-save the non-core registers, because we unwind in a single pass. */ saved_vrs.demand_save_flags = 0; /* Unwind until we reach a propagation barrier. */ do { _Unwind_State action; _Unwind_Reason_Code entry_code; _Unwind_Reason_Code stop_code; /* Find the entry for this routine. */ entry_code = get_eit_entry (ucbp, saved_vrs.core.r[R_PC]); if (resuming) { action = _US_UNWIND_FRAME_RESUME | _US_FORCE_UNWIND; resuming = 0; } else action = _US_UNWIND_FRAME_STARTING | _US_FORCE_UNWIND; if (entry_code == _URC_OK) { UCB_SAVED_CALLSITE_ADDR (ucbp) = saved_vrs.core.r[R_PC]; next_vrs = saved_vrs; /* Call the pr to decide what to do. */ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (action, ucbp, (void *) &next_vrs); saved_vrs.prev_sp = next_vrs.core.r[R_SP]; } else { /* Treat any failure as the end of unwinding, to cope more gracefully with missing EH information. Mixed EH and non-EH within one object will usually result in failure, because the .ARM.exidx tables do not indicate the end of the code to which they apply; but mixed EH and non-EH shared objects should return an unwind failure at the entry of a non-EH shared object. */ action |= _US_END_OF_STACK; saved_vrs.prev_sp = saved_vrs.core.r[R_SP]; } stop_code = stop_fn (1, action, ucbp->exception_class, ucbp, (void *)&saved_vrs, stop_arg); if (stop_code != _URC_NO_REASON) return _URC_FAILURE; if (entry_code != _URC_OK) return entry_code; saved_vrs = next_vrs; } while (pr_result == _URC_CONTINUE_UNWIND); if (pr_result != _URC_INSTALL_CONTEXT) { /* Some sort of failure has occurred in the pr and probably the pr returned _URC_FAILURE. */ return _URC_FAILURE; } restore_core_regs (&saved_vrs.core);}/* This is a very limited implementation of _Unwind_GetCFA. It returns the stack pointer as it is about to be unwound, and is only valid while calling the stop function during forced unwinding. If the current personality routine result is going to run a cleanup, this will not be the CFA; but when the frame is really unwound, it will be. */_Unwind_Word_Unwind_GetCFA (_Unwind_Context *context){ return ((phase1_vrs *) context)->prev_sp;}/* Perform phase1 unwinding. UCBP is the exception being thrown, and entry_VRS is the register state on entry to _Unwind_RaiseException. */_Unwind_Reason_Code__gnu_Unwind_RaiseException (_Unwind_Control_Block *, phase2_vrs *);_Unwind_Reason_Code__gnu_Unwind_RaiseException (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs){ phase1_vrs saved_vrs; _Unwind_Reason_Code pr_result; /* Set the pc to the call site. */ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; /* Save the core registers. */ saved_vrs.core = entry_vrs->core; /* Set demand-save flags. */ saved_vrs.demand_save_flags = ~(_uw) 0; /* Unwind until we reach a propagation barrier. */ do { /* Find the entry for this routine. */ if (get_eit_entry (ucbp, saved_vrs.core.r[R_PC]) != _URC_OK) return _URC_FAILURE; /* Call the pr to decide what to do. */ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_VIRTUAL_UNWIND_FRAME, ucbp, (void *) &saved_vrs); } while (pr_result == _URC_CONTINUE_UNWIND); /* We've unwound as far as we want to go, so restore the original register state. */ restore_non_core_regs (&saved_vrs); if (pr_result != _URC_HANDLER_FOUND) { /* Some sort of failure has occurred in the pr and probably the pr returned _URC_FAILURE. */ return _URC_FAILURE; } unwind_phase2 (ucbp, entry_vrs);}/* Resume unwinding after a cleanup has been run. UCBP is the exception being thrown and ENTRY_VRS is the register state on entry to _Unwind_Resume. */_Unwind_Reason_Code__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *, _Unwind_Stop_Fn, void *, phase2_vrs *);_Unwind_Reason_Code__gnu_Unwind_ForcedUnwind (_Unwind_Control_Block *ucbp, _Unwind_Stop_Fn stop_fn, void *stop_arg, phase2_vrs *entry_vrs){ UCB_FORCED_STOP_FN (ucbp) = (_uw) stop_fn; UCB_FORCED_STOP_ARG (ucbp) = (_uw) stop_arg; /* Set the pc to the call site. */ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; return unwind_phase2_forced (ucbp, entry_vrs, 0);}_Unwind_Reason_Code__gnu_Unwind_Resume (_Unwind_Control_Block *, phase2_vrs *);_Unwind_Reason_Code__gnu_Unwind_Resume (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs){ _Unwind_Reason_Code pr_result; /* Recover the saved address. */ entry_vrs->core.r[R_PC] = UCB_SAVED_CALLSITE_ADDR (ucbp); if (UCB_FORCED_STOP_FN (ucbp)) { unwind_phase2_forced (ucbp, entry_vrs, 1); /* We can't return failure at this point. */ abort (); } /* Call the cached PR. */ pr_result = ((personality_routine) UCB_PR_ADDR (ucbp)) (_US_UNWIND_FRAME_RESUME, ucbp, (_Unwind_Context *) entry_vrs); switch (pr_result) { case _URC_INSTALL_CONTEXT: /* Upload the registers to enter the landing pad. */ restore_core_regs (&entry_vrs->core); case _URC_CONTINUE_UNWIND: /* Continue unwinding the next frame. */ unwind_phase2 (ucbp, entry_vrs); default: abort (); }}_Unwind_Reason_Code__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block *, phase2_vrs *);_Unwind_Reason_Code__gnu_Unwind_Resume_or_Rethrow (_Unwind_Control_Block * ucbp, phase2_vrs * entry_vrs){ if (!UCB_FORCED_STOP_FN (ucbp)) return __gnu_Unwind_RaiseException (ucbp, entry_vrs); /* Set the pc to the call site. */ entry_vrs->core.r[R_PC] = entry_vrs->core.r[R_LR]; /* Continue unwinding the next frame. */ return unwind_phase2_forced (ucbp, entry_vrs, 0);}/* Clean up an exception object when unwinding is complete. */void_Unwind_Complete (_Unwind_Control_Block * ucbp __attribute__((unused))){}/* Get the _Unwind_Control_Block from an _Unwind_Context. */static inline _Unwind_Control_Block *unwind_UCB_from_context (_Unwind_Context * context){ return (_Unwind_Control_Block *) _Unwind_GetGR (context, R_IP);}/* Free an exception. */void_Unwind_DeleteException (_Unwind_Exception * exc){ if (exc->exception_cleanup) (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);}/* Common implementation for ARM ABI defined personality routines. ID is the index of the personality routine, other arguments are as defined by __aeabi_unwind_cpp_pr{0,1,2}. */static _Unwind_Reason_Code__gnu_unwind_pr_common (_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context, int id){ __gnu_unwind_state uws; _uw *data; _uw offset; _uw len; _uw rtti_count; int phase2_call_unexpected_after_unwind = 0; int in_range = 0; int forced_unwind = state & _US_FORCE_UNWIND; state &= _US_ACTION_MASK; data = (_uw *) ucbp->pr_cache.ehtp; uws.data = *(data++); uws.next = data; if (id == 0) { uws.data <<= 8; uws.words_left = 0; uws.bytes_left = 3; } else { uws.words_left = (uws.data >> 16) & 0xff; uws.data <<= 16; uws.bytes_left = 2; data += uws.words_left; } /* Restore the saved pointer. */ if (state == _US_UNWIND_FRAME_RESUME) data = (_uw *) ucbp->cleanup_cache.bitpattern[0]; if ((ucbp->pr_cache.additional & 1) == 0) { /* Process descriptors. */ while (*data) { _uw addr; _uw fnstart; if (id == 2) { len = ((EHT32 *) data)->length; offset = ((EHT32 *) data)->offset; data += 2; } else { len = ((EHT16 *) data)->length; offset = ((EHT16 *) data)->offset; data++; } fnstart = ucbp->pr_cache.fnstart + (offset & ~1); addr = _Unwind_GetGR (context, R_PC); in_range = (fnstart <= addr && addr < fnstart + (len & ~1)); switch (((offset & 1) << 1) | (len & 1)) { case 0: /* Cleanup. */ if (state != _US_VIRTUAL_UNWIND_FRAME && in_range) { /* Cleanup in range, and we are running cleanups. */ _uw lp; /* Landing pad address is 31-bit pc-relative offset. */ lp = selfrel_offset31 (data); data++; /* Save the exception data pointer. */ ucbp->cleanup_cache.bitpattern[0] = (_uw) data; if (!__cxa_begin_cleanup (ucbp)) return _URC_FAILURE; /* Setup the VRS to enter the landing pad. */ _Unwind_SetGR (context, R_PC, lp); return _URC_INSTALL_CONTEXT; } /* Cleanup not in range, or we are in stage 1. */ data++; break; case 1: /* Catch handler. */ if (state == _US_VIRTUAL_UNWIND_FRAME) { if (in_range) { /* Check for a barrier. */ _uw rtti; void *matched; /* Check for no-throw areas. */ if (data[1] == (_uw) -2) return _URC_FAILURE; /* The thrown object immediately follows the ECB. */ matched = (void *)(ucbp + 1); if (data[1] != (_uw) -1) { /* Match a catch specification. */ rtti = _Unwind_decode_target2 ((_uw) &data[1]); if (!__cxa_type_match (ucbp, (type_info *) rtti, &matched)) matched = (void *)0; } if (matched) { ucbp->barrier_cache.sp = _Unwind_GetGR (context, R_SP); ucbp->barrier_cache.bitpattern[0] = (_uw) matched; ucbp->barrier_cache.bitpattern[1] = (_uw) data; return _URC_HANDLER_FOUND; } } /* Handler out of range, or not matched. */ } else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) && ucbp->barrier_cache.bitpattern[1] == (_uw) data) { /* Matched a previous propagation barrier. */ _uw lp; /* Setup for entry to the handler. */ lp = selfrel_offset31 (data); _Unwind_SetGR (context, R_PC, lp); _Unwind_SetGR (context, 0, (_uw) ucbp); return _URC_INSTALL_CONTEXT; } /* Catch handler not matched. Advance to the next descriptor. */ data += 2; break; case 2: rtti_count = data[0] & 0x7fffffff; /* Exception specification. */ if (state == _US_VIRTUAL_UNWIND_FRAME) { if (in_range && (!forced_unwind || !rtti_count)) { /* Match against the exception specification. */ _uw i; _uw rtti; void *matched; for (i = 0; i < rtti_count; i++) { matched = (void *)(ucbp + 1); rtti = _Unwind_decode_target2 ((_uw) &data[i + 1]); if (__cxa_type_match (ucbp, (type_info *) rtti, &matched)) break; } if (i == rtti_count) { /* Exception does not match the spec. */ ucbp->barrier_cache.sp = _Unwind_GetGR (context, R_SP); ucbp->barrier_cache.bitpattern[0] = (_uw) matched; ucbp->barrier_cache.bitpattern[1] = (_uw) data; return _URC_HANDLER_FOUND; } } /* Handler out of range, or exception is permitted. */ } else if (ucbp->barrier_cache.sp == _Unwind_GetGR (context, R_SP) && ucbp->barrier_cache.bitpattern[1] == (_uw) data) { /* Matched a previous propagation barrier. */ _uw lp; /* Record the RTTI list for __cxa_call_unexpected. */ ucbp->barrier_cache.bitpattern[1] = rtti_count; ucbp->barrier_cache.bitpattern[2] = 0; ucbp->barrier_cache.bitpattern[3] = 4; ucbp->barrier_cache.bitpattern[4] = (_uw) &data[1]; if (data[0] & uint32_highbit) phase2_call_unexpected_after_unwind = 1; else { data += rtti_count + 1; /* Setup for entry to the handler. */ lp = selfrel_offset31 (data); data++; _Unwind_SetGR (context, R_PC, lp); _Unwind_SetGR (context, 0, (_uw) ucbp); return _URC_INSTALL_CONTEXT; } } if (data[0] & uint32_highbit) data++; data += rtti_count + 1; break; default: /* Should never happen. */ return _URC_FAILURE; } /* Finished processing this descriptor. */ } } if (__gnu_unwind_execute (context, &uws) != _URC_OK) return _URC_FAILURE; if (phase2_call_unexpected_after_unwind) { /* Enter __cxa_unexpected as if called from the call site. */ _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC)); _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected); return _URC_INSTALL_CONTEXT; } return _URC_CONTINUE_UNWIND;}/* ABI defined personality routine entry points. */_Unwind_Reason_Code__aeabi_unwind_cpp_pr0 (_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context){ return __gnu_unwind_pr_common (state, ucbp, context, 0);}_Unwind_Reason_Code__aeabi_unwind_cpp_pr1 (_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context){ return __gnu_unwind_pr_common (state, ucbp, context, 1);}_Unwind_Reason_Code__aeabi_unwind_cpp_pr2 (_Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context){ return __gnu_unwind_pr_common (state, ucbp, context, 2);}/* These two should never be used. */_Unwind_Ptr_Unwind_GetDataRelBase (_Unwind_Context *context __attribute__ ((unused))){ abort ();}_Unwind_Ptr_Unwind_GetTextRelBase (_Unwind_Context *context __attribute__ ((unused))){ abort ();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -