Index: include/unwind.h =================================================================== --- include/unwind.h +++ include/unwind.h @@ -207,6 +207,7 @@ uint32_t discriminator, _Unwind_VRS_DataRepresentation representation); +extern uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*); extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context, uint32_t *data, size_t offset, size_t len); Index: src/Unwind/Unwind-EHABI.cpp =================================================================== --- src/Unwind/Unwind-EHABI.cpp +++ src/Unwind/Unwind-EHABI.cpp @@ -167,24 +167,13 @@ struct _Unwind_Context* context) { // Read the compact model EHT entry's header # 6.3 uint32_t* unwindingData = ucbp->pr_cache.ehtp; - uint32_t unwindInfo = *unwindingData; - assert((unwindInfo & 0xf0000000) == 0x80000000 && "Must be a compact entry"); Descriptor::Format format = - static_cast((unwindInfo & 0x0f000000) >> 24); + static_cast((*unwindingData & 0x0f000000) >> 24); size_t len = 0; - size_t startOffset = 0; - switch (format) { - case Descriptor::SU16: - len = 4; - startOffset = 1; - break; - case Descriptor::LU16: - case Descriptor::LU32: - len = 4 + 4 * ((unwindInfo & 0x00ff0000) >> 16); - startOffset = 2; - break; - default: - return _URC_FAILURE; + size_t off = 0; + unwindingData = decode_eht_entry(unwindingData, &off, &len); + if (unwindingData == nullptr) { + return _URC_FAILURE; } // Handle descriptors before unwinding so they are processed in the context @@ -198,7 +187,7 @@ if (result != _URC_CONTINUE_UNWIND) return result; - return _Unwind_VRS_Interpret(context, unwindingData, startOffset, len); + return _Unwind_VRS_Interpret(context, unwindingData, off, len); } // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE / @@ -215,6 +204,43 @@ } // end anonymous namespace +/** + * Decodes an EHT entry. + * + * @param data Pointer to EHT. + * @param[out] off Offset from return value (in bytes) to begin interpretation. + * @param[out] len Number of bytes in unwind code. + * @return Pointer to beginning of unwind code. + */ +extern "C" uint32_t* +decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) { + if ((*data & 0x80000000) == 0) { + // 6.2: Generic Model + *off = 1; // First byte is size data. + *len = (((data[1] >> 24) & 0xff) + 1) * 4; + data++; // Skip the first word, which is the prel31 offset. + } else { + // 6.3: ARM Compact Model + 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 const_cast(data); +} + _Unwind_Reason_Code _Unwind_VRS_Interpret( _Unwind_Context* context, uint32_t* data, Index: src/Unwind/UnwindLevel1-gcc-ext.c =================================================================== --- src/Unwind/UnwindLevel1-gcc-ext.c +++ src/Unwind/UnwindLevel1-gcc-ext.c @@ -141,6 +141,28 @@ result); return result; } + +#if LIBCXXABI_ARM_EHABI + // Get the information for this frame. + unw_proc_info_t frameInfo; + if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) { + return _URC_END_OF_STACK; + } + + struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor; + size_t off; + size_t len; + 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; + } +#endif // LIBCXXABI_ARM_EHABI } }