Index: src/Unwind/Unwind-EHABI.cpp =================================================================== --- src/Unwind/Unwind-EHABI.cpp +++ src/Unwind/Unwind-EHABI.cpp @@ -162,10 +162,9 @@ return _URC_CONTINUE_UNWIND; } -_Unwind_Reason_Code unwindOneFrame( - _Unwind_State state, - _Unwind_Control_Block* ucbp, - struct _Unwind_Context* context) { +static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state, + _Unwind_Control_Block* ucbp, + struct _Unwind_Context* context) { // Read the compact model EHT entry's header # 6.3 const uint32_t* unwindingData = ucbp->pr_cache.ehtp; assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry"); @@ -216,44 +215,27 @@ */ extern "C" const uint32_t* decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { - if ((*data & 0x80000000) == 0) { - // 6.2: Generic Model - // EHT entry is a prel31 pointing to the PR, followed by data understood only - // by the personality routine. Since EHABI doesn't guarantee the location or - // availability of the unwind opcodes in the generic model, we have to check - // for them on a case-by-case basis: - _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, - uint64_t exceptionClass, - _Unwind_Exception* unwind_exception, - _Unwind_Context* context); - void *PR = (void*)signExtendPrel31(*data); - if (PR == (void*)&__gxx_personality_v0) { - *off = 1; // First byte is size data. - *len = (((data[1] >> 24) & 0xff) + 1) * 4; - } else + assert((*data & 0x80000000) != 0 && + "decode_eht_entry() does not support user-defined personality"); + + // 6.3: ARM Compact Model + // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded + // by format: + Descriptor::Format format = + static_cast((*data & 0x0f000000) >> 24); + switch (format) { + case Descriptor::SU16: + *len = 4; + *off = 1; + break; + case Descriptor::LU16: + case Descriptor::LU32: + *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); + *off = 2; + break; + default: return nullptr; - data++; // Skip the first word, which is the prel31 offset. - } else { - // 6.3: ARM Compact Model - // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded - // by format: - Descriptor::Format format = - static_cast((*data & 0x0f000000) >> 24); - switch (format) { - case Descriptor::SU16: - *len = 4; - *off = 1; - break; - case Descriptor::LU16: - case Descriptor::LU32: - *len = 4 + 4 * ((*data & 0x00ff0000) >> 16); - *off = 2; - break; - default: - return nullptr; - } } - return data; } Index: src/Unwind/UnwindLevel1-gcc-ext.c =================================================================== --- src/Unwind/UnwindLevel1-gcc-ext.c +++ src/Unwind/UnwindLevel1-gcc-ext.c @@ -99,6 +99,13 @@ return NULL; } +#if LIBCXXABI_ARM_EHABI +static inline uint32_t readPREL31(const uint32_t *data) { + uint32_t base = (uintptr_t) data; + uint32_t off = *data | ((0x40000000 & *data) << 1); + return (base + off); +} +#endif // LIBCXXABI_ARM_EHABI /// Walk every frame and call trace function at each one. If trace function /// returns anything other than _URC_NO_REASON, then walk is terminated. @@ -132,17 +139,43 @@ } struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor; - size_t off; - size_t len; const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info; - unwindInfo = decode_eht_entry(unwindInfo, &off, &len); - if (unwindInfo == NULL) { - return _URC_FAILURE; - } - - result = _Unwind_VRS_Interpret(context, unwindInfo, off, len); - if (result != _URC_CONTINUE_UNWIND) { - return _URC_END_OF_STACK; + if ((*unwindInfo & 0x80000000) == 0) { + // 6.2: Generic Model + // EHT entry is a prel31 pointing to the PR, followed by data understood + // only by the personality routine. Since EHABI doesn't guarantee the + // location or availability of the unwind opcodes in the generic model, + // we have to use an undocumented API of personality functions. + + // Create a mock exception object for force unwinding. + _Unwind_Exception ex; + ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0 + ex.pr_cache.fnstart = frameInfo.start_ip; + ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo; + ex.pr_cache.additional= frameInfo.flags; + + // Get and call the personality function to unwind the frame. + typedef _Unwind_Reason_Code __personality_routine(_Unwind_State, + _Unwind_Exception*, + _Unwind_Context*); + __personality_routine *pr = + (__personality_routine *) readPREL31(unwindInfo); + + const _Unwind_State _US_FORCE_UNWIND = 8u; + if (pr(_US_FORCE_UNWIND, &ex, context) != _URC_CONTINUE_UNWIND) { + return _URC_END_OF_STACK; + } + } else { + size_t off, len; + unwindInfo = decode_eht_entry(unwindInfo, &off, &len); + if (unwindInfo == NULL) { + return _URC_FAILURE; + } + + result = _Unwind_VRS_Interpret(context, unwindInfo, off, len); + if (result != _URC_CONTINUE_UNWIND) { + return _URC_END_OF_STACK; + } } #endif // LIBCXXABI_ARM_EHABI