_Unwind_VRS_Result _Unwind_VRS_Get( _Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, void *valuep) { _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, regclass=%d reg=%d, rep=%d, " "value=0x%0llX)\n", context, regclass, regno, representation, *((uint32_t*)valuep)); unw_cursor_t *cursor = (unw_cursor_t *)context; switch (regclass) { case _UVRSC_CORE: { if (representation != _UVRSD_UINT32) _LIBUNWIND_ABORT("Core register representation must be _UVRSD_UINT32."); return unw_get_reg(cursor, regno, (unw_word_t*)valuep) == UNW_ESUCCESS ? _UVRSR_OK : _UVRSR_FAILED; } // FIXME: Are these right? See 4.7 on lazy-saving case _UVRSC_WMMXD: case _UVRSC_WMMXC: case _UVRSC_VFP: { unw_fpreg_t value; if (unw_get_fpreg(cursor, regno, &value) != UNW_ESUCCESS) return _UVRSR_FAILED; switch (representation) { case _UVRSD_VFPX: // TODO(ajwong): What does this mean? break; case _UVRSD_UINT64: { uint64_t tmp; memcpy(&tmp, &value, sizeof(tmp)); *(uint64_t*)valuep = tmp; break; } case _UVRSD_FLOAT: { float tmp; memcpy(&tmp, &value, sizeof(tmp)); *(float*)valuep = tmp; break; } case _UVRSD_DOUBLE: { double tmp; memcpy(&tmp, &value, sizeof(tmp)); *(double*)valuep = tmp; break; } case _UVRSD_UINT32: { uint32_t tmp; memcpy(&tmp, &value, sizeof(tmp)); *(uint32_t*)valuep = tmp; break; } default: _LIBUNWIND_ABORT("Invalid VFP data representation."); } return _UVRSR_OK; } } return _UVRSR_NOT_IMPLEMENTED; }
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( A &addressSpace, const R ®isters, pint_t cfa, const RegisterLocation &savedReg) { switch (savedReg.location) { case CFI_Parser<A>::kRegisterInCFA: return addressSpace.getP(cfa + (pint_t)savedReg.value); case CFI_Parser<A>::kRegisterAtExpression: return addressSpace.getP( evaluateExpression((pint_t)savedReg.value, addressSpace, registers, cfa)); case CFI_Parser<A>::kRegisterIsExpression: return evaluateExpression((pint_t)savedReg.value, addressSpace, registers, cfa); case CFI_Parser<A>::kRegisterInRegister: return registers.getRegister((int)savedReg.value); case CFI_Parser<A>::kRegisterUnused: case CFI_Parser<A>::kRegisterOffsetFromCFA: // FIX ME break; } _LIBUNWIND_ABORT("unsupported restore location for register"); }
/// Called by personality handler during phase 2 to get base address for text /// relative encodings. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { // Not supported or needed for sjlj based unwinding (void)context; _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context); _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); }
/// Called by __cxa_rethrow(). _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) { #if LIBCXXABI_ARM_EHABI _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), " "private_1=%ld\n", exception_object, (long)exception_object->unwinder_cache.reserved1); #else _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), " "private_1=%ld\n", exception_object, (long)exception_object->private_1); #endif #if LIBCXXABI_ARM_EHABI // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0, // which is in the same position as private_1 below. return _Unwind_RaiseException(exception_object); #else // If this is non-forced and a stopping place was found, then this is a // re-throw. // Call _Unwind_RaiseException() as if this was a new exception if (exception_object->private_1 == 0) { return _Unwind_RaiseException(exception_object); // Will return if there is no catch clause, so that __cxa_rethrow can call // std::terminate(). } // Call through to _Unwind_Resume() which distiguishes between forced and // regular exceptions. _Unwind_Resume(exception_object); _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" " which unexpectedly returned"); #endif }
size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) { switch (tableEnc & 0x0f) { case DW_EH_PE_sdata2: case DW_EH_PE_udata2: return 4; case DW_EH_PE_sdata4: case DW_EH_PE_udata4: return 8; case DW_EH_PE_sdata8: case DW_EH_PE_udata8: return 16; case DW_EH_PE_sleb128: case DW_EH_PE_uleb128: _LIBUNWIND_ABORT("Can't binary search on variable length encoded data."); case DW_EH_PE_omit: return 0; default: _LIBUNWIND_ABORT("Unknown DWARF encoding for search table."); } }
/// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler /// geneated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Re-throwing an exception is implemented by having the code call /// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() _LIBUNWIND_EXPORT void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object); if (exception_object->private_1 != 0) unwind_phase2_forced(exception_object, (_Unwind_Stop_Fn) exception_object->private_1, (void *)exception_object->private_2); else unwind_phase2(exception_object); // clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); }
/// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler /// geneated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Note: re-throwing an exception (as opposed to continuing the unwind) /// is implemented by having the code call __cxa_rethrow() which /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(_Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", (void *)exception_object); unw_context_t uc; unw_getcontext(&uc); if (exception_object->private_1 != 0) unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn) exception_object->private_1, (void *)exception_object->private_2); else unwind_phase2(&uc, exception_object); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); }
/// Called by __cxa_rethrow(). _LIBUNWIND_EXPORT _Unwind_Reason_Code _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " "private_1=%ld\n", exception_object, exception_object->private_1); // If this is non-forced and a stopping place was found, then this is a // re-throw. // Call _Unwind_RaiseException() as if this was a new exception. if (exception_object->private_1 == 0) { return _Unwind_SjLj_RaiseException(exception_object); // should return if there is no catch clause, so that __cxa_rethrow can call // std::terminate() } // Call through to _Unwind_Resume() which distiguishes between forced and // regular exceptions. _Unwind_SjLj_Resume(exception_object); _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " "_Unwind_SjLj_Resume() which unexpectedly returned"); }
/// When _Unwind_RaiseException() is in phase2, it hands control /// to the personality function at each frame. The personality /// may force a jump to a landing pad in that function, the landing /// pad code may then call _Unwind_Resume() to continue with the /// unwinding. Note: the call to _Unwind_Resume() is from compiler /// geneated user code. All other _Unwind_* routines are called /// by the C++ runtime __cxa_* routines. /// /// Note: re-throwing an exception (as opposed to continuing the unwind) /// is implemented by having the code call __cxa_rethrow() which /// in turn calls _Unwind_Resume_or_Rethrow(). _LIBUNWIND_EXPORT void _Unwind_Resume(struct _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", exception_object); unw_context_t uc; unw_getcontext(&uc); #ifdef __arm__ // TODO(piman): Do we need a "force unwind" mechanism? #else if (exception_object->private_1 != 0) unwind_phase2_forced(&uc, exception_object, (_Unwind_Stop_Fn) exception_object->private_1, (void *)exception_object->private_2); else #endif unwind_phase2(&uc, exception_object, true); // Clients assume _Unwind_Resume() does not return, so all we can do is abort. _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); }
_Unwind_VRS_Result _Unwind_VRS_Pop( _Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t discriminator, _Unwind_VRS_DataRepresentation representation) { if (regclass != _UVRSC_CORE || representation != _UVRSD_UINT32) { // TODO(piman): VFP, ... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now if phase2 it did not stop here"); return _UVRSR_NOT_IMPLEMENTED; } bool do13 = false; uint32_t reg13Value = 0; uint32_t* sp; if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp) != _UVRSR_OK) { return _UVRSR_FAILED; } for (int i = 0; i < 16; ++i) { if (!(discriminator & (1<<i))) continue; uint32_t value = *sp++; if (i == 13) { reg13Value = value; do13 = true; } else { if (_Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_R0 + i, _UVRSD_UINT32, &value) != _UVRSR_OK) { return _UVRSR_FAILED; } } } if (do13) { return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, ®13Value); } else { return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp); } }
typename A::pint_t DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace, const R ®isters, pint_t initialStackValue) { const bool log = false; pint_t p = expression; pint_t expressionEnd = expression + 20; // temp, until len read pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); expressionEnd = p + length; if (log) fprintf(stderr, "evaluateExpression(): length=%llu\n", (uint64_t)length); pint_t stack[100]; pint_t *sp = stack; *(++sp) = initialStackValue; while (p < expressionEnd) { if (log) { for (pint_t *t = sp; t > stack; --t) { fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t)); } } uint8_t opcode = addressSpace.get8(p++); sint_t svalue, svalue2; pint_t value; uint32_t reg; switch (opcode) { case DW_OP_addr: // push immediate address sized value value = addressSpace.getP(p); p += sizeof(pint_t); *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_deref: // pop stack, dereference, push result value = *sp--; *(++sp) = addressSpace.getP(value); if (log) fprintf(stderr, "dereference 0x%llX\n", (uint64_t) value); break; case DW_OP_const1u: // push immediate 1 byte value value = addressSpace.get8(p); p += 1; *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_const1s: // push immediate 1 byte signed value svalue = (int8_t) addressSpace.get8(p); p += 1; *(++sp) = (pint_t)svalue; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); break; case DW_OP_const2u: // push immediate 2 byte value value = addressSpace.get16(p); p += 2; *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_const2s: // push immediate 2 byte signed value svalue = (int16_t) addressSpace.get16(p); p += 2; *(++sp) = (pint_t)svalue; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); break; case DW_OP_const4u: // push immediate 4 byte value value = addressSpace.get32(p); p += 4; *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_const4s: // push immediate 4 byte signed value svalue = (int32_t)addressSpace.get32(p); p += 4; *(++sp) = (pint_t)svalue; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); break; case DW_OP_const8u: // push immediate 8 byte value value = (pint_t)addressSpace.get64(p); p += 8; *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_const8s: // push immediate 8 byte signed value value = (pint_t)addressSpace.get64(p); p += 8; *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_constu: // push immediate ULEB128 value value = (pint_t)addressSpace.getULEB128(p, expressionEnd); *(++sp) = value; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) value); break; case DW_OP_consts: // push immediate SLEB128 value svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); *(++sp) = (pint_t)svalue; if (log) fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); break; case DW_OP_dup: // push top of stack value = *sp; *(++sp) = value; if (log) fprintf(stderr, "duplicate top of stack\n"); break; case DW_OP_drop: // pop --sp; if (log) fprintf(stderr, "pop top of stack\n"); break; case DW_OP_over: // dup second value = sp[-1]; *(++sp) = value; if (log) fprintf(stderr, "duplicate second in stack\n"); break; case DW_OP_pick: // pick from reg = addressSpace.get8(p); p += 1; value = sp[-reg]; *(++sp) = value; if (log) fprintf(stderr, "duplicate %d in stack\n", reg); break; case DW_OP_swap: // swap top two value = sp[0]; sp[0] = sp[-1]; sp[-1] = value; if (log) fprintf(stderr, "swap top of stack\n"); break; case DW_OP_rot: // rotate top three value = sp[0]; sp[0] = sp[-1]; sp[-1] = sp[-2]; sp[-2] = value; if (log) fprintf(stderr, "rotate top three of stack\n"); break; case DW_OP_xderef: // pop stack, dereference, push result value = *sp--; *sp = *((pint_t*)value); if (log) fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t) value); break; case DW_OP_abs: svalue = (sint_t)*sp; if (svalue < 0) *sp = (pint_t)(-svalue); if (log) fprintf(stderr, "abs\n"); break; case DW_OP_and: value = *sp--; *sp &= value; if (log) fprintf(stderr, "and\n"); break; case DW_OP_div: svalue = (sint_t)(*sp--); svalue2 = (sint_t)*sp; *sp = (pint_t)(svalue2 / svalue); if (log) fprintf(stderr, "div\n"); break; case DW_OP_minus: value = *sp--; *sp = *sp - value; if (log) fprintf(stderr, "minus\n"); break; case DW_OP_mod: svalue = (sint_t)(*sp--); svalue2 = (sint_t)*sp; *sp = (pint_t)(svalue2 % svalue); if (log) fprintf(stderr, "module\n"); break; case DW_OP_mul: svalue = (sint_t)(*sp--); svalue2 = (sint_t)*sp; *sp = (pint_t)(svalue2 * svalue); if (log) fprintf(stderr, "mul\n"); break; case DW_OP_neg: *sp = 0 - *sp; if (log) fprintf(stderr, "neg\n"); break; case DW_OP_not: svalue = (sint_t)(*sp); *sp = (pint_t)(~svalue); if (log) fprintf(stderr, "not\n"); break; case DW_OP_or: value = *sp--; *sp |= value; if (log) fprintf(stderr, "or\n"); break; case DW_OP_plus: value = *sp--; *sp += value; if (log) fprintf(stderr, "plus\n"); break; case DW_OP_plus_uconst: // pop stack, add uelb128 constant, push result *sp += addressSpace.getULEB128(p, expressionEnd); if (log) fprintf(stderr, "add constant\n"); break; case DW_OP_shl: value = *sp--; *sp = *sp << value; if (log) fprintf(stderr, "shift left\n"); break; case DW_OP_shr: value = *sp--; *sp = *sp >> value; if (log) fprintf(stderr, "shift left\n"); break; case DW_OP_shra: value = *sp--; svalue = (sint_t)*sp; *sp = (pint_t)(svalue >> value); if (log) fprintf(stderr, "shift left arithmetric\n"); break; case DW_OP_xor: value = *sp--; *sp ^= value; if (log) fprintf(stderr, "xor\n"); break; case DW_OP_skip: svalue = (int16_t) addressSpace.get16(p); p += 2; p = (pint_t)((sint_t)p + svalue); if (log) fprintf(stderr, "skip %lld\n", (uint64_t) svalue); break; case DW_OP_bra: svalue = (int16_t) addressSpace.get16(p); p += 2; if (*sp--) p = (pint_t)((sint_t)p + svalue); if (log) fprintf(stderr, "bra %lld\n", (uint64_t) svalue); break; case DW_OP_eq: value = *sp--; *sp = (*sp == value); if (log) fprintf(stderr, "eq\n"); break; case DW_OP_ge: value = *sp--; *sp = (*sp >= value); if (log) fprintf(stderr, "ge\n"); break; case DW_OP_gt: value = *sp--; *sp = (*sp > value); if (log) fprintf(stderr, "gt\n"); break; case DW_OP_le: value = *sp--; *sp = (*sp <= value); if (log) fprintf(stderr, "le\n"); break; case DW_OP_lt: value = *sp--; *sp = (*sp < value); if (log) fprintf(stderr, "lt\n"); break; case DW_OP_ne: value = *sp--; *sp = (*sp != value); if (log) fprintf(stderr, "ne\n"); break; case DW_OP_lit0: case DW_OP_lit1: case DW_OP_lit2: case DW_OP_lit3: case DW_OP_lit4: case DW_OP_lit5: case DW_OP_lit6: case DW_OP_lit7: case DW_OP_lit8: case DW_OP_lit9: case DW_OP_lit10: case DW_OP_lit11: case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14: case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17: case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20: case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23: case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26: case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: value = opcode - DW_OP_lit0; *(++sp) = value; if (log) fprintf(stderr, "push literal 0x%llX\n", (uint64_t) value); break; case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3: case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7: case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11: case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23: case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: reg = opcode - DW_OP_reg0; *(++sp) = registers.getRegister((int)reg); if (log) fprintf(stderr, "push reg %d\n", reg); break; case DW_OP_regx: reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd); *(++sp) = registers.getRegister((int)reg); if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); break; case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3: case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7: case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11: case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23: case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31: reg = opcode - DW_OP_breg0; svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); svalue += registers.getRegister((int)reg); *(++sp) = (pint_t)(svalue); if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); break; case DW_OP_bregx: reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd); svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); svalue += registers.getRegister((int)reg); *(++sp) = (pint_t)(svalue); if (log) fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); break; case DW_OP_fbreg: _LIBUNWIND_ABORT("DW_OP_fbreg not implemented"); break; case DW_OP_piece: _LIBUNWIND_ABORT("DW_OP_piece not implemented"); break; case DW_OP_deref_size: // pop stack, dereference, push result value = *sp--; switch (addressSpace.get8(p++)) { case 1: value = addressSpace.get8(value); break; case 2: value = addressSpace.get16(value); break; case 4: value = addressSpace.get32(value); break; case 8: value = (pint_t)addressSpace.get64(value); break; default: _LIBUNWIND_ABORT("DW_OP_deref_size with bad size"); } *(++sp) = value; if (log) fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t) value); break; case DW_OP_xderef_size: case DW_OP_nop: case DW_OP_push_object_addres: case DW_OP_call2: case DW_OP_call4: case DW_OP_call_ref: default: _LIBUNWIND_ABORT("dwarf opcode not implemented"); } } if (log) fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t) * sp); return *sp; }
static _Unwind_Reason_Code unwind_phase2(struct _Unwind_Exception *exception_object) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); // walk each frame until we reach where search phase said to stop _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); while (true) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n", exception_object, c); // check for no more frames if (c == NULL) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", exception_object); return _URC_END_OF_STACK; } // if there is a personality routine, tell it we are unwinding if (c->personality != NULL) { _Unwind_Action action = _UA_CLEANUP_PHASE; if ((uintptr_t) c == exception_object->private_2) action = (_Unwind_Action)( _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); // tell personality this was the frame it marked // in phase 1 _Unwind_Reason_Code personalityResult = (*c->personality)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)c); switch (personalityResult) { case _URC_CONTINUE_UNWIND: // continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); if ((uintptr_t) c == exception_object->private_2) { // phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now if phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " "_URC_INSTALL_CONTEXT, will resume at " "landing pad %p\n", exception_object, c->jbuf[1]); // personality routine says to transfer control to landing pad // we may get control back if landing pad calls _Unwind_Resume() __Unwind_SjLj_SetTopOfFunctionStack(c); __builtin_longjmp(c->jbuf, 1); // unw_resume() only returns if there was an error return _URC_FATAL_PHASE2_ERROR; default: // something went wrong _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } c = c->prev; } // clean up phase did not resume at the frame that the search phase said it // would return _URC_FATAL_PHASE2_ERROR; }
static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, struct _Unwind_Exception *exception_object, bool resume) { // See comment at the start of unwind_phase1 regarding VRS integrity. unw_cursor_t cursor2; unw_init_local(&cursor2, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); int frame_count = 0; // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException or _Unwind_Resume). // // Resume only ever makes sense for 1 frame. _Unwind_State state = resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING; if (resume && frame_count == 1) { // On a resume, first unwind the _Unwind_Resume() frame. The next frame // is now the landing pad for the cleanup from a previous execution of // phase2. To continue unwindingly correctly, replace VRS[15] with the // IP of the frame that the previous run of phase2 installed the context // for. After this, continue unwinding as if normal. // // See #7.4.6 for details. unw_set_reg(&cursor2, UNW_REG_IP, exception_object->unwinder_cache.reserved2); resume = false; } int stepResult = unw_step(&cursor2); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " "_URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // Get info about this frame. unw_word_t sp; unw_proc_info_t frameInfo; unw_get_reg(&cursor2, UNW_REG_SP, &sp); if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionName[512]; unw_word_t offset; if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) strcpy(functionName, ".anonymous."); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " "lsda=0x%llX, personality=0x%llX\n", exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2); #ifdef __arm__ exception_object->pr_cache.fnstart = frameInfo.start_ip; exception_object->pr_cache.ehtp = (_Unwind_EHT_Header *)frameInfo.unwind_info; exception_object->pr_cache.additional = frameInfo.flags; _Unwind_Reason_Code personalityResult = (*p)(state, exception_object, context); #else _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); } _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, context); #endif switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); #ifdef __arm__ if (sp == exception_object->barrier_cache.sp) { #else if (sp == exception_object->private_2) { #endif // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). if (_LIBUNWIND_TRACING_UNWINDING) { unw_word_t pc; unw_get_reg(&cursor2, UNW_REG_IP, &pc); unw_get_reg(&cursor2, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " "user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp); } #ifdef __arm__ // #7.4.1 says we need to preserve pc for when _Unwind_Resume is called // back, to find this same frame. unw_word_t pc; unw_get_reg(&cursor2, UNW_REG_IP, &pc); exception_object->unwinder_cache.reserved2 = (uint32_t)pc; #endif unw_resume(&cursor2); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; #ifdef __arm__ // # 7.4.3 case _URC_FAILURE: abort(); #endif default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } frame_count++; } // Clean up phase did not resume at the frame that the search phase // said it would... return _URC_FATAL_PHASE2_ERROR; } #ifndef __arm__ static _Unwind_Reason_Code unwind_phase2_forced(unw_context_t *uc, struct _Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter) { unw_cursor_t cursor2; unw_init_local(&cursor2, uc); // Walk each frame until we reach where search phase said to stop while (unw_step(&cursor2) > 0) { // Update info about this frame. unw_proc_info_t frameInfo; if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " "failed => _URC_END_OF_STACK\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionName[512]; unw_word_t offset; if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) strcpy(functionName, ".anonymous."); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "start_ip=0x%llX, func=%s, lsda=0x%llX, " " personality=0x%llX\n", exception_object, frameInfo.start_ip, functionName, frameInfo.lsda, frameInfo.handler); } // Call stop function at each frame. _Unwind_Action action = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); _Unwind_Reason_Code stopResult = (*stop)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2), stop_parameter); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", exception_object, stopResult); if (stopResult != _URC_NO_REASON) { _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", exception_object, p); _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned _URC_CONTINUE_UNWIND\n", exception_object); // Destructors called, continue unwinding break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned _URC_INSTALL_CONTEXT\n", exception_object); // We may get control back if landing pad calls _Unwind_Resume(). unw_resume(&cursor2); break; default: // Personality routine returned an unknown result code. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " "personality returned %d, " "_URC_FATAL_PHASE2_ERROR\n", exception_object, personalityResult); return _URC_FATAL_PHASE2_ERROR; } } } // Call stop function one last time and tell it we've reached the end // of the stack. _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " "function with _UA_END_OF_STACK\n", exception_object); _Unwind_Action lastAction = (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); (*stop)(1, lastAction, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2), stop_parameter); // Clean up phase did not resume at the frame that the search phase said it // would. return _URC_FATAL_PHASE2_ERROR; }
static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object) { unw_cursor_t cursor2; unw_init_local(&cursor2, uc); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); // Walk each frame until we reach where search phase said to stop. while (true) { // Ask libuwind to get next frame (skip over first which is // _Unwind_RaiseException). int stepResult = unw_step(&cursor2); if (stepResult == 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " "bottom => _URC_END_OF_STACK\n", exception_object); return _URC_END_OF_STACK; } else if (stepResult < 0) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " "_URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // Get info about this frame. unw_word_t sp; unw_proc_info_t frameInfo; unw_get_reg(&cursor2, UNW_REG_SP, &sp); if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " "failed => _URC_FATAL_PHASE1_ERROR\n", exception_object); return _URC_FATAL_PHASE2_ERROR; } // When tracing, print state information. if (_LIBUNWIND_TRACING_UNWINDING) { char functionName[512]; unw_word_t offset; if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) strcpy(functionName, ".anonymous."); _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " "lsda=0x%llX, personality=0x%llX\n", exception_object, frameInfo.start_ip, functionName, sp, frameInfo.lsda, frameInfo.handler); } // If there is a personality routine, tell it we are unwinding. if (frameInfo.handler != 0) { __personality_routine p = (__personality_routine)(long)(frameInfo.handler); _Unwind_Action action = _UA_CLEANUP_PHASE; if (sp == exception_object->private_2) { // Tell personality this was the frame it marked in phase 1. action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); } _Unwind_Reason_Code personalityResult = (*p)(1, action, exception_object->exception_class, exception_object, (struct _Unwind_Context *)(&cursor2)); switch (personalityResult) { case _URC_CONTINUE_UNWIND: // Continue unwinding _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", exception_object); if (sp == exception_object->private_2) { // Phase 1 said we would stop at this frame, but we did not... _LIBUNWIND_ABORT("during phase1 personality function said it would " "stop here, but now in phase2 it did not stop here"); } break; case _URC_INSTALL_CONTEXT: _LIBUNWIND_TRACE_UNWINDING( "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", exception_object); // Personality routine says to transfer control to landing pad. // We may get control back if landing pad calls _Unwind_Resume(). if (_LIBUNWIND_TRACING_UNWINDING) { unw_word_t pc; unw_get_reg(&cursor2, UNW_REG_IP, &pc); unw_get_reg(&cursor2, UNW_REG_SP, &sp); _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " "user code with ip=0x%llX, sp=0x%llX\n", exception_object, pc, sp); } unw_resume(&cursor2); // unw_resume() only returns if there was an error. return _URC_FATAL_PHASE2_ERROR; default: // Personality routine returned an unknown result code. _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", personalityResult); return _URC_FATAL_PHASE2_ERROR; } } } // Clean up phase did not resume at the frame that the search phase // said it would... return _URC_FATAL_PHASE2_ERROR; }
/// Called by personality handler during phase 2 to get base address for text /// relative encodings. _LIBUNWIND_EXPORT uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) { (void)context; _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context); _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); }