Index: include/cxxabi.h =================================================================== --- include/cxxabi.h +++ include/cxxabi.h @@ -44,6 +44,10 @@ extern void * __cxa_get_exception_ptr(void * exceptionObject) throw(); extern void * __cxa_begin_catch(void * exceptionObject) throw(); extern void __cxa_end_catch(); +#if __arm__ +extern bool __cxa_begin_cleanup(void * exceptionObject) throw(); +extern void __cxa_end_cleanup(); +#endif extern std::type_info * __cxa_current_exception_type(); // 2.5.4 Rethrowing Exceptions Index: include/unwind.h =================================================================== --- include/unwind.h +++ include/unwind.h @@ -23,8 +23,16 @@ #define LIBUNWIND_UNAVAIL #endif +#if !defined(__USING_SJLJ_EXCEPTIONS__) && defined(__arm__) && \ + !defined(__ARM_DWARF_EH__) && !defined(__APPLE__) +#define LIBCXXABI_ARM_EHABI 1 +#else +#define LIBCXXABI_ARM_EHABI 0 +#endif + typedef enum { _URC_NO_REASON = 0, + _URC_OK = 0, _URC_FOREIGN_EXCEPTION_CAUGHT = 1, _URC_FATAL_PHASE2_ERROR = 2, _URC_FATAL_PHASE1_ERROR = 3, @@ -32,7 +40,8 @@ _URC_END_OF_STACK = 5, _URC_HANDLER_FOUND = 6, _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8 + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9 } _Unwind_Reason_Code; typedef enum { @@ -43,13 +52,69 @@ _UA_END_OF_STACK = 16 // gcc extension to C++ ABI } _Unwind_Action; + +#if LIBCXXABI_ARM_EHABI +typedef uint32_t _Unwind_State; + +static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0; +static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1; +static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2; + +typedef uint32_t _Unwind_EHT_Header; + +struct _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Control_Block; +typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */ + +struct _Unwind_Control_Block { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*); + + struct { + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + uint32_t reserved5; + } unwinder_cache; + + struct { + uint32_t sp; + uint32_t bitpattern[5]; + } barrier_cache; + + struct { + uint32_t bitpattern[4]; + } cleanup_cache; + + struct { + uint32_t fnstart; + _Unwind_EHT_Header* ehtp; + uint32_t additional; + uint32_t reserved1; + } pr_cache; + + long long int :0; /* Enforce the 8-byte alignment */ +}; + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (_Unwind_State state, + _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context); + +typedef _Unwind_Reason_Code (*__personality_routine) + (_Unwind_State state, + _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context); +#else struct _Unwind_Context; // opaque struct _Unwind_Exception; // forward declaration +typedef struct _Unwind_Exception _Unwind_Exception; struct _Unwind_Exception { uint64_t exception_class; void (*exception_cleanup)(_Unwind_Reason_Code reason, - struct _Unwind_Exception *exc); + _Unwind_Exception *exc); uintptr_t private_1; // non-zero means forced unwind uintptr_t private_2; // holds sp that phase1 found for phase2 to use #if !__LP64__ @@ -65,7 +130,7 @@ (int version, _Unwind_Action actions, uint64_t exceptionClass, - struct _Unwind_Exception* exceptionObject, + _Unwind_Exception* exceptionObject, struct _Unwind_Context* context, void* stop_parameter ); @@ -73,8 +138,9 @@ (int version, _Unwind_Action actions, uint64_t exceptionClass, - struct _Unwind_Exception* exceptionObject, + _Unwind_Exception* exceptionObject, struct _Unwind_Context* context); +#endif #ifdef __cplusplus extern "C" { @@ -85,33 +151,94 @@ // #if __USING_SJLJ_EXCEPTIONS__ extern _Unwind_Reason_Code - _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object); -extern void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object); + _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object); #else extern _Unwind_Reason_Code - _Unwind_RaiseException(struct _Unwind_Exception *exception_object); -extern void _Unwind_Resume(struct _Unwind_Exception *exception_object); + _Unwind_RaiseException(_Unwind_Exception *exception_object); +extern void _Unwind_Resume(_Unwind_Exception *exception_object); #endif -extern void _Unwind_DeleteException(struct _Unwind_Exception *exception_object); +extern void _Unwind_DeleteException(_Unwind_Exception *exception_object); + +#if LIBCXXABI_ARM_EHABI +typedef enum { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4 +} _Unwind_VRS_RegClass; + +typedef enum { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5 +} _Unwind_VRS_DataRepresentation; + +typedef enum { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2 +} _Unwind_VRS_Result; + +extern _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context* context, + _Unwind_VRS_RegClass regclass, + uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep); + +extern _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context* context, + _Unwind_VRS_RegClass regclass, + uint32_t regno, + _Unwind_VRS_DataRepresentation representation, + void *valuep); + +static inline uintptr_t _Unwind_GetGR(struct _Unwind_Context* context, + int index) { + uintptr_t value = 0; + _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value); + return value; +} + +static inline void _Unwind_SetGR(struct _Unwind_Context* context, int index, + uintptr_t new_value) { + _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, + _UVRSD_UINT32, &new_value); +} + +static inline uintptr_t _Unwind_GetIP(struct _Unwind_Context* context) { + // remove the thumb-bit before returning + return (_Unwind_GetGR(context, 15) & (~(uintptr_t)0x1)); +} + +static inline void _Unwind_SetIP(struct _Unwind_Context* context, + uintptr_t new_value) { + uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1); + _Unwind_SetGR(context, 15, new_value | thumb_bit); +} +#else extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, uintptr_t new_value); extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); +#endif + extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); extern uintptr_t _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); -#if __arm__ +#if __USING_SJLJ_EXCEPTIONS__ extern _Unwind_Reason_Code - _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *exception_object, + _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter); #else extern _Unwind_Reason_Code - _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, + _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, _Unwind_Stop_Fn stop, void *stop_parameter); #endif -#if __arm__ +#if __USING_SJLJ_EXCEPTIONS__ typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); @@ -124,12 +251,12 @@ // // called by __cxa_rethrow(). // -#if __arm__ +#if __USING_SJLJ_EXCEPTIONS__ extern _Unwind_Reason_Code - _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object); + _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object); #else extern _Unwind_Reason_Code - _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object); + _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object); #endif // _Unwind_Backtrace() is a gcc extension that walks the stack and calls the Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -155,7 +155,11 @@ template <> struct float_data { +#if defined(__arm__) + static const size_t mangled_size = 16; +#else static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms +#endif static const size_t max_demangled_size = 40; static constexpr const char* spec = "%LaL"; }; Index: src/cxa_exception.hpp =================================================================== --- src/cxa_exception.hpp +++ src/cxa_exception.hpp @@ -27,7 +27,7 @@ static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ struct __cxa_exception { -#if __LP64__ +#if __LP64__ || LIBCXXABI_ARM_EHABI // This is a new field to support C++ 0x exception_ptr. // For binary compatibility it is at the start of this // struct which is prepended to the object thrown in @@ -45,7 +45,7 @@ int handlerCount; -#ifdef __ARM_EABI_UNWINDER__ +#if LIBCXXABI_ARM_EHABI __cxa_exception* nextPropagatingException; int propagationCount; #else @@ -56,7 +56,7 @@ void *adjustedPtr; #endif -#if !__LP64__ +#if !__LP64__ && !LIBCXXABI_ARM_EHABI // This is a new field to support C++ 0x exception_ptr. // For binary compatibility it is placed where the compiler // previously adding padded to 64-bit align unwindHeader. @@ -82,7 +82,7 @@ int handlerCount; -#ifdef __ARM_EABI_UNWINDER__ +#if LIBCXXABI_ARM_EHABI __cxa_exception* nextPropagatingException; int propagationCount; #else @@ -103,7 +103,7 @@ struct __cxa_eh_globals { __cxa_exception * caughtExceptions; unsigned int uncaughtExceptions; -#ifdef __ARM_EABI_UNWINDER__ +#if LIBCXXABI_ARM_EHABI __cxa_exception* propagatingExceptions; #endif }; Index: src/cxa_exception.cpp =================================================================== --- src/cxa_exception.cpp +++ src/cxa_exception.cpp @@ -254,11 +254,102 @@ void* __cxa_get_exception_ptr(void* unwind_exception) throw() { +#if LIBCXXABI_ARM_EHABI + return reinterpret_cast( + static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); +#else return cxa_exception_from_exception_unwind_exception ( static_cast<_Unwind_Exception*>(unwind_exception) )->adjustedPtr; +#endif +} + +#if LIBCXXABI_ARM_EHABI +/* +The routine to be called before the cleanup. This will save __cxa_exception in +__cxa_eh_globals, so that __cxa_end_cleanup() can recover later. +*/ +bool +__cxa_begin_cleanup(void* unwind_arg) throw () +{ + _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = + cxa_exception_from_exception_unwind_exception(unwind_exception); + + if (isOurExceptionClass(unwind_exception)) + { + if (0 == exception_header->propagationCount) + { + exception_header->nextPropagatingException = globals->propagatingExceptions; + globals->propagatingExceptions = exception_header; + } + ++exception_header->propagationCount; + } + else + { + // If the propagatingExceptions stack is not empty, since we can't + // chain the foreign exception, terminate it. + if (NULL != globals->propagatingExceptions) + std::terminate(); + globals->propagatingExceptions = exception_header; + } + return true; +} + +/* +The routine to be called after the cleanup has been performed. It will get the +propagating __cxa_exception from __cxa_eh_globals, and continue the stack +unwinding with _Unwind_Resume. + +According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any +register, thus we have to write this function in assembly so that we can save +{r1, r2, r3}. We don't have to save r0 because it is the return value and the +first argument to _Unwind_Resume(). In addition, we are saving r4 in order to +align the stack to 16 bytes, even though it is a callee-save register. +*/ +__attribute__((used)) static _Unwind_Exception * +__cxa_end_cleanup_impl() +{ + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = globals->propagatingExceptions; + if (NULL == exception_header) + { + // It seems that __cxa_begin_cleanup() is not called properly. + // We have no choice but terminate the program now. + std::terminate(); + } + + if (isOurExceptionClass(&exception_header->unwindHeader)) + { + --exception_header->propagationCount; + if (0 == exception_header->propagationCount) + { + globals->propagatingExceptions = exception_header->nextPropagatingException; + exception_header->nextPropagatingException = NULL; + } + } + else + { + globals->propagatingExceptions = NULL; + } + return &exception_header->unwindHeader; } + +asm ( + " .pushsection .text.__cxa_end_cleanup\n" + " .globl __cxa_end_cleanup\n" + " .type __cxa_end_cleanup,%function\n" + "__cxa_end_cleanup:\n" + " push {r1, r2, r3, r4}\n" + " bl __cxa_end_cleanup_impl\n" + " pop {r1, r2, r3, r4}\n" + " bl _Unwind_Resume\n" + " bl abort\n" + " .popsection" +); +#endif // LIBCXXABI_ARM_EHABI /* This routine can catch foreign or native exceptions. If native, the exception @@ -318,7 +409,11 @@ globals->caughtExceptions = exception_header; } globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local +#if LIBCXXABI_ARM_EHABI + return reinterpret_cast(exception_header->unwindHeader.barrier_cache.bitpattern[0]); +#else return exception_header->adjustedPtr; +#endif } // Else this is a foreign exception // If the caughtExceptions stack is not empty, terminate Index: src/cxa_personality.cpp =================================================================== --- src/cxa_personality.cpp +++ src/cxa_personality.cpp @@ -307,6 +307,33 @@ std::terminate(); } +#if LIBCXXABI_ARM_EHABI +static const void* read_target2_value(const void* ptr) +{ + uintptr_t offset = *reinterpret_cast(ptr); + if (!offset) + return 0; + return *reinterpret_cast(reinterpret_cast(ptr) + offset); +} + +static const __shim_type_info* +get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, + uint8_t ttypeEncoding, bool native_exception, + _Unwind_Exception* unwind_exception) +{ + if (classInfo == 0) + { + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + + assert(ttypeEncoding == DW_EH_PE_absptr && "Unexpected TTypeEncoding"); + (void)ttypeEncoding; + + const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t); + return reinterpret_cast(read_target2_value(ttypePtr)); +} +#else static const __shim_type_info* get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo, @@ -342,6 +369,7 @@ classInfo -= ttypeIndex; return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); } +#endif /* This is checking a thrown exception type, excpType, against a possibly empty @@ -352,6 +380,49 @@ the list will catch a excpType. If any catchType in the list can catch an excpType, then this exception spec does not catch the excpType. */ +#if LIBCXXABI_ARM_EHABI +static +bool +exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, + uint8_t ttypeEncoding, const __shim_type_info* excpType, + void* adjustedPtr, _Unwind_Exception* unwind_exception) +{ + if (classInfo == 0) + { + // this should not happen. Indicates corrupted eh_table. + call_terminate(false, unwind_exception); + } + + assert(ttypeEncoding == DW_EH_PE_absptr && "Unexpected TTypeEncoding"); + (void)ttypeEncoding; + + // specIndex is negative of 1-based byte offset into classInfo; + specIndex = -specIndex; + --specIndex; + const void** temp = reinterpret_cast( + reinterpret_cast(classInfo) + + static_cast(specIndex) * sizeof(uintptr_t)); + // If any type in the spec list can catch excpType, return false, else return true + // adjustments to adjustedPtr are ignored. + while (true) + { + // ARM EHABI exception specification table (filter table) consists of + // several pointers which will directly point to the type info object + // (instead of ttypeIndex). The table will be terminated with 0. + const void** ttypePtr = temp++; + if (*ttypePtr == 0) + break; + // We can get the __shim_type_info simply by performing a + // R_ARM_TARGET2 relocation, and cast the result to __shim_type_info. + const __shim_type_info* catchType = + static_cast(read_target2_value(ttypePtr)); + void* tempPtr = adjustedPtr; + if (catchType->can_catch(excpType, tempPtr)) + return false; + } + return true; +} +#else static bool exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, @@ -385,6 +456,7 @@ } return true; } +#endif static void* @@ -511,7 +583,7 @@ // Get beginning current frame's code (as defined by the // emitted dwarf code) uintptr_t funcStart = _Unwind_GetRegionStart(context); -#if __arm__ +#if __USING_SJLJ_EXCEPTIONS__ if (ip == uintptr_t(-1)) { // no action @@ -544,7 +616,7 @@ // Walk call-site table looking for range that // includes current PC. uint8_t callSiteEncoding = *lsda++; -#if __arm__ +#if __USING_SJLJ_EXCEPTIONS__ (void)callSiteEncoding; // On arm callSiteEncoding is never used #endif uint32_t callSiteTableLength = static_cast(readULEB128(&lsda)); @@ -555,7 +627,7 @@ while (callSitePtr < callSiteTableEnd) { // There is one entry per call site. -#if !__arm__ +#if !__USING_SJLJ_EXCEPTIONS__ // The call sites are non-overlapping in [start, start+length) // The call sites are ordered in increasing value of start uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); @@ -563,15 +635,15 @@ uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); uintptr_t actionEntry = readULEB128(&callSitePtr); if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __arm__ +#else // __USING_SJLJ_EXCEPTIONS__ // ip is 1-based index into this table uintptr_t landingPad = readULEB128(&callSitePtr); uintptr_t actionEntry = readULEB128(&callSitePtr); if (--ip == 0) -#endif // __arm__ +#endif // __USING_SJLJ_EXCEPTIONS__ { // Found the call site containing ip. -#if !__arm__ +#if !__USING_SJLJ_EXCEPTIONS__ if (landingPad == 0) { // No handler here @@ -579,9 +651,9 @@ return; } landingPad = (uintptr_t)lpStart + landingPad; -#else // __arm__ +#else // __USING_SJLJ_EXCEPTIONS__ ++landingPad; -#endif // __arm__ +#endif // __USING_SJLJ_EXCEPTIONS__ if (actionEntry == 0) { // Found a cleanup @@ -773,7 +845,7 @@ action += actionOffset; } // there is no break out of this loop, only return } -#if !__arm__ +#if !__USING_SJLJ_EXCEPTIONS__ else if (ipOffset < start) { // There is no call site for this ip @@ -781,7 +853,7 @@ // Possible stack corruption. call_terminate(native_exception, unwind_exception); } -#endif // !__arm__ +#endif // !__USING_SJLJ_EXCEPTIONS__ } // there might be some tricky cases which break out of this loop // It is possible that no eh table entry specify how to handle @@ -837,6 +909,7 @@ Else a cleanup is not found: return _URC_CONTINUE_UNWIND */ +#if !LIBCXXABI_ARM_EHABI _Unwind_Reason_Code #if __USING_SJLJ_EXCEPTIONS__ __gxx_personality_sj0 @@ -848,6 +921,7 @@ { if (version != 1 || unwind_exception == 0 || context == 0) return _URC_FATAL_PHASE1_ERROR; + bool native_exception = (exceptionClass & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); scan_results results; @@ -924,6 +998,133 @@ // We were called improperly: neither a phase 1 or phase 2 search return _URC_FATAL_PHASE1_ERROR; } +#else + +extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*, _Unwind_Context*); + +// Helper function to unwind one frame. +// ARM EHABI 7.3 and 7.4: If the personality function returns _URC_CONTINUE_UNWIND, the +// personality routine should update the virtual register set (VRS) according to the +// corresponding frame unwinding instructions (ARM EHABI 9.3.) +static _Unwind_Reason_Code continue_unwind(_Unwind_Exception* unwind_exception, + _Unwind_Context* context) +{ + if (__gnu_unwind_frame(unwind_exception, context) != _URC_OK) + return _URC_FAILURE; + return _URC_CONTINUE_UNWIND; +} + +// ARM register names +static const uint32_t REG_UCB = 12; // Register to save _Unwind_Control_Block +static const uint32_t REG_SP = 13; + +static void save_results_to_barrier_cache(_Unwind_Exception* unwind_exception, + const scan_results& results) +{ + unwind_exception->barrier_cache.bitpattern[0] = (uint32_t)results.adjustedPtr; + unwind_exception->barrier_cache.bitpattern[1] = (uint32_t)results.actionRecord; + unwind_exception->barrier_cache.bitpattern[2] = (uint32_t)results.languageSpecificData; + unwind_exception->barrier_cache.bitpattern[3] = (uint32_t)results.landingPad; + unwind_exception->barrier_cache.bitpattern[4] = (uint32_t)results.ttypeIndex; +} + +static void load_results_from_barrier_cache(scan_results& results, + const _Unwind_Exception* unwind_exception) +{ + results.adjustedPtr = (void*)unwind_exception->barrier_cache.bitpattern[0]; + results.actionRecord = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[1]; + results.languageSpecificData = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; + results.landingPad = (uintptr_t)unwind_exception->barrier_cache.bitpattern[3]; + results.ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; +} + +extern "C" _Unwind_Reason_Code +__gxx_personality_v0(_Unwind_State state, + _Unwind_Exception* unwind_exception, + _Unwind_Context* context) +{ + if (unwind_exception == 0 || context == 0) + return _URC_FATAL_PHASE1_ERROR; + + bool native_exception = (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + + // Copy the address of _Unwind_Control_Block to r12 so that _Unwind_GetLangauageSpecificData() + // and _Unwind_GetRegionStart() can return correct address. + _Unwind_SetGR(context, REG_UCB, reinterpret_cast(unwind_exception)); + + scan_results results; + switch (state) { + case _US_VIRTUAL_UNWIND_FRAME: + // Phase 1 search: All we're looking for in phase 1 is a handler that halts unwinding + scan_eh_tab(results, _UA_SEARCH_PHASE, native_exception, unwind_exception, context); + if (results.reason == _URC_HANDLER_FOUND) + { + unwind_exception->barrier_cache.sp = _Unwind_GetGR(context, REG_SP); + if (native_exception) + save_results_to_barrier_cache(unwind_exception, results); + return _URC_HANDLER_FOUND; + } + // Did not find the catch handler + if (results.reason == _URC_CONTINUE_UNWIND) + return continue_unwind(unwind_exception, context); + return results.reason; + + case _US_UNWIND_FRAME_STARTING: + // Phase 2 search + if (unwind_exception->barrier_cache.sp == _Unwind_GetGR(context, REG_SP)) + { + // Found a catching handler in phase 1 + if (native_exception) + { + // Load the result from the native exception barrier cache. + load_results_from_barrier_cache(results, unwind_exception); + results.reason = _URC_HANDLER_FOUND; + } + else + { + // Search for the catching handler again for the foreign exception. + scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME), + native_exception, unwind_exception, context); + if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one + call_terminate(native_exception, unwind_exception); + } + + // Install the context for the catching handler + set_registers(unwind_exception, context, results); + return _URC_INSTALL_CONTEXT; + } + + // Search for a (non-catching) cleanup + scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context); + if (results.reason == _URC_HANDLER_FOUND) + { + // Found a non-catching handler + + // ARM EHABI 8.4.2: Before we can jump to the cleanup handler, we have to setup some + // internal data structures, so that __cxa_end_cleanup() can get unwind_exception from + // __cxa_get_globals(). + __cxa_begin_cleanup(unwind_exception); + + // Install the context for the cleanup handler + set_registers(unwind_exception, context, results); + return _URC_INSTALL_CONTEXT; + } + + // Did not find any handler + if (results.reason == _URC_CONTINUE_UNWIND) + return continue_unwind(unwind_exception, context); + return results.reason; + + case _US_UNWIND_FRAME_RESUME: + return continue_unwind(unwind_exception, context); + } + + // We were called improperly: neither a phase 1 or phase 2 search + return _URC_FATAL_PHASE1_ERROR; +} +#endif + __attribute__((noreturn)) void @@ -948,8 +1149,13 @@ u_handler = old_exception_header->unexpectedHandler; // If std::__unexpected(u_handler) rethrows the same exception, // these values get overwritten by the rethrow. So save them now: +#if LIBCXXABI_ARM_EHABI + ttypeIndex = (int64_t)(int32_t)unwind_exception->barrier_cache.bitpattern[4]; + lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2]; +#else ttypeIndex = old_exception_header->handlerSwitchValue; lsda = old_exception_header->languageSpecificData; +#endif } else { Index: test/test_demangle.cpp =================================================================== --- test/test_demangle.cpp +++ test/test_demangle.cpp @@ -14,6 +14,9 @@ #include #include +// Is long double fp80? (Only x87 extended double has 64-bit mantissa) +#define LDBL_FP80 (__LDBL_MANT_DIG__ == 64) + const char* cases[][2] = { {"_Z1A", "A"}, @@ -29513,7 +29516,9 @@ {"_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c", "void test0::f(int, char (&) [sizeof (ovl((int)()))])"}, {"_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c", "void test0::g(char (&) [sizeof (((float)()) + (0x1.4p+2f))])"}, {"_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c", "void test0::h(char (&) [sizeof (((float)()) + (0x1.4p+2))])"}, +#if LDBL_FP80 {"_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c", "void test0::h(char (&) [(unsigned int)((sizeof (float)) + (0xap-1L))])"}, +#endif {"_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c", "void test0::j(char (&) [sizeof ((test0::A)().buffer)])"}, {"_ZN5test11fINS_1XEiEEvT_IT0_E", "void test1::f(test1::X)"}, {"_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_", "decltype((test2::A*)(0)->member) test2::read_member(test2::A&)"}, @@ -29597,6 +29602,9 @@ "NSoERj5E=Y1[uM:ga", "Aon_PmKVPDk7?fg4XP5smMUL6;Vl<>IL8ayHpiVDDDXTY;^o9;i", "_ZNSt16allocator_traitsISaIN4llvm3sys2fs18directory_iteratorEEE9constructIS3_IS3_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS4_PT_DpOS7_", +#if !LDBL_FP80 + "_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c", +#endif }; const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]);