This commit implements the zero-cost exception handling support
for libc++abi.
http://reviews.llvm.org/D3613
Files:
include/cxxabi.h
include/unwind.h
src/cxa_demangle.cpp
src/cxa_exception.cpp
src/cxa_exception.hpp
src/cxa_personality.cpp
test/test_demangle.cpp
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,13 @@
#define LIBUNWIND_UNAVAIL
#endif
+#if !__USING_SJLJ_EXCEPTIONS__ && defined(__arm__) && !defined(__APPLE__)
+#define LIBCXXABI_ARM_EHABI 1
+#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 +37,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 +49,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 +127,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 +135,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 +148,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 +248,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<long double>
{
+#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.cpp
===================================================================
--- src/cxa_exception.cpp
+++ src/cxa_exception.cpp
@@ -254,11 +254,101 @@
void*
__cxa_get_exception_ptr(void* unwind_exception) throw()
{
+#if LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(
+ 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
+registers, thus we have to write this function in assembly so that we can
+save {r1-r3}. Besides, in order to make sure that the stack is aligned to
+16 bytes, we are saving r4 as well, even though it is callee-save register.
+*/
+__attribute__((visibility("hidden"))) _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 +408,11 @@
globals->caughtExceptions = exception_header;
}
globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
+#if LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(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_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_personality.cpp
===================================================================
--- src/cxa_personality.cpp
+++ src/cxa_personality.cpp
@@ -307,6 +307,29 @@
std::terminate();
}
+#if LIBCXXABI_ARM_EHABI
+static const void* read_target2_value(const void* ptr)
+{
+ uintptr_t offset = *reinterpret_cast<const uintptr_t*>(ptr);
+ if (!offset)
+ return 0;
+ return *reinterpret_cast<const void**>(reinterpret_cast<uintptr_t>(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);
+ }
+ const uint8_t* ttypePtr = classInfo - ttypeIndex * sizeof(uintptr_t);
+ return reinterpret_cast<const __shim_type_info*>(read_target2_value(ttypePtr));
+}
+#else
static
const __shim_type_info*
get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
@@ -342,6 +365,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 +376,34 @@
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);
+ }
+ // specIndex is negative of 1-based byte offset into classInfo;
+ uintptr_t table = reinterpret_cast<uintptr_t>(classInfo) +
+ static_cast<uintptr_t>(-specIndex - 1) * sizeof(uintptr_t);
+ // If any type in the spec list can catch excpType, return false, else return true
+ // adjustments to adjustedPtr are ignored.
+ for (const void** ttypePtr = reinterpret_cast<const void**>(table); *ttypePtr; ++ttypePtr)
+ {
+ const __shim_type_info* catchType =
+ static_cast<const __shim_type_info*>(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 +437,7 @@
}
return true;
}
+#endif
static
void*
@@ -511,7 +564,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 +597,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<uint32_t>(readULEB128(&lsda));
@@ -555,7 +608,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 +616,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 +632,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
@@ -656,7 +709,7 @@
// If this is a type 1 search save state and return _URC_HANDLER_FOUND
// If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
// If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
- if (actions & _UA_SEARCH_PHASE)
+ if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
{
// Save state and return _URC_HANDLER_FOUND
results.ttypeIndex = ttypeIndex;
@@ -700,7 +753,7 @@
// If this is a type 1 search, save state and return _URC_HANDLER_FOUND
// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
- if (actions & _UA_SEARCH_PHASE)
+ if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
{
// Save state and return _URC_HANDLER_FOUND
results.ttypeIndex = ttypeIndex;
@@ -773,7 +826,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 +834,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 +890,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 +902,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 +979,131 @@
// 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;
+}
+
+#if 0
+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];
+}
+#endif
+
+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<uint32_t>(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
+
+ // TODO: Load the phase 1 result from unwind_exception if this is a native exception.
+ // load_results_from_barrier_cache(results, unwind_exception);
+ // results.reason = _URC_HANDLER_FOUND;
+
+ // Search for the catching handler again
+ 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 +1128,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
@@ -29513,7 +29513,10 @@
{"_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c", "void test0::f<int>(int, char (&) [sizeof (ovl((int)()))])"},
{"_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c", "void test0::g<float>(char (&) [sizeof (((float)()) + (0x1.4p+2f))])"},
{"_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c", "void test0::h<float>(char (&) [sizeof (((float)()) + (0x1.4p+2))])"},
+#if !defined(__arm__)
+ // This case assumes 80-bit long double.
{"_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c", "void test0::h<float>(char (&) [(unsigned int)((sizeof (float)) + (0xap-1L))])"},
+#endif
{"_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c", "void test0::j<test0::A>(char (&) [sizeof ((test0::A)().buffer)])"},
{"_ZN5test11fINS_1XEiEEvT_IT0_E", "void test1::f<test1::X, int>(test1::X<int>)"},
{"_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_", "decltype((test2::A*)(0)->member) test2::read_member<test2::A>(test2::A&)"},
@@ -29597,6 +29600,10 @@
"NSoERj5E=Y1[uM:ga",
"Aon_PmKVPDk7?fg4XP5smMUL6;<WsI_mgbf23cCgsHbT<l8EE\0uVRkNOoXDrgdA4[8IU>Vl<>IL8ayHpiVDDDXTY;^o9;i",
"_ZNSt16allocator_traitsISaIN4llvm3sys2fs18directory_iteratorEEE9constructIS3_IS3_EEEDTcl12_S_constructfp_fp0_spcl7forwardIT0_Efp1_EEERS4_PT_DpOS7_",
+#if defined(__arm__)
+ // Since ARM does not have 80-bit long double, this should fail.
+ "_ZN5test01hIfEEvRAcvjplstT_Le4001a000000000000000E_c",
+#endif
};
const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits