[PATCH][cxxabi] ARM EHABI zero-cost exception handling for libc++abi
Logan Chien
tzuhsiang.chien at gmail.com
Sat May 3 09:29:04 PDT 2014
Hi Jonathan,
After some try-and-error, now I can compile the libcxxabi from [1]. I need
some patch [2] to build it properly, and here's [3] my build script.
However, I feel that there are still several works to be done if we wish to
use [1]. From my test result, it seems that 24 tests (out of 32 tests) are
failing, and it seems that some changes cause some regression on x86_64.
IMO, maybe we can focus on my patch first? Although, it still relies on
the unwinding facilities from libgcc, I feel that we can replace them
step-by-step. And fortunately, it seems that most of your work are
focusing on the language-independent unwinding library which is orthogonal
to my changes. Once the language-independent unwinding library is
complete, we can ifdef (or remove) the function call to libgcc. Does this
plan sound reasonable? Thanks.
Sincerely,
Logan
[1]
https://github.com/awong-dev/ndk/tree/use-libc++abi/sources/cxx-stl/llvm-libc++abi/libcxxabi
[2] https://github.com/loganchien/libcxxabi/commits/awong-dev-ndk
[3] https://github.com/loganchien/libcxx-scripts/commits/awong-dev-ndk
On Thu, Apr 17, 2014 at 1:05 AM, Jonathan Roelofs <jonathan at codesourcery.com
> wrote:
> Logan,
>
> I've been building it for bare-metal ARM using clang (with patches that
> haven't been upstreamed yet), but the process should be similar for an
> arm-linux-gnu target, assuming you want to make a static library out of it:
>
> Compile all the *.cpp files with:
> clang++ -target $TRIPLE --sysroot=/path/to/your/targets/sysroot
> -funwind-tables -std=c++11 -stdlib=libc++ -fstrict-aliasing
> -Wstrict-aliasing=2 -Wsign-conversion -Wshadow -Wconversion
> -Wunused-variable -Wmissing-field-initializers -Wchar-subscripts
> -Wmismatched-tags -Wmissing-braces -Wshorten-64-to-32 -Wsign-compare
> -Wstrict-aliasing=2 -Wstrict-overflow=4 -Wunused-parameter -Wnewline-eof
>
> And similarly, all the *.c files with:
> clang -target $TRIPLE --sysroot=/path/to/your/targets/sysroot
> -funwind-tables -std=c11 -fstrict-aliasing -Wstrict-aliasing=2
> -Wsign-conversion -Wshadow -Wconversion -Wunused-variable
> -Wmissing-field-initializers -Wchar-subscripts -Wmismatched-tags
> -Wmissing-braces -Wshorten-64-to-32 -Wsign-compare -Wstrict-aliasing=2
> -Wstrict-overflow=4 -Wunused-parameter -Wnewline-eof
>
> On bare-metal, I also build the unwinder's *.c,*.cpp, and *.S files, but
> on linux you'll want to skip that step.
>
> Finally, archive all the *.o files into a static libarary with ar, and
> ranlib. At link time, you'll need to pull in -lgcc_s (which is for the
> unwinder).
>
> I can share my modifications to the buildit & testit scripts if you think
> they would be useful to you.
>
>
> As for __USING_SJLJ_EXCEPTIONS__, I checked and it is indeed a compiler
> builtin for both clang and gcc. __ARM_EABI_UNWINDER__ does not seem to be,
> and I don't see anything nearby to where I found the SJLJ one that would
> indicate what we want. I think the right thing to check for here is:
> #if __arm__ && !defined(__USING_SJLJ_EXCEPTIONS__)
>
>
> Cheers,
> Jon
>
>
> On 4/16/14, 5:11 AM, Logan Chien wrote:
>
>> Hi all,
>>
>> Sorry for the typo.
>>
>> I was trying to build and test libc++abi from [1] but failed. I have
>> tried to
>> build the library by compiling all the *.cpp and *.c, but it seems not
>> working.
>> May you provide some instructions to build it?
>>
>> BTW, I agree with Jonathan. It seems that __ARM_EABI_UNWINDER__ is not
>> pre-defined.
>> I am not sure for __USING_SJLJ_EXCEPTIONS__ at the moment. I will check
>> out ASAP.
>>
>> Logan
>>
>> [1]:
>> https://github.com/awong-dev/ndk/tree/use-libc%2B%2Babi/
>> sources/cxx-stl/llvm-libc%2B%2Babi/libcxxabi
>> [2] http://www.sourceware.org/ml/libc-alpha/2004-02/msg00138.html
>>
>>
>> On Wed, Apr 16, 2014 at 7:58 PM, Logan Chien <tzuhsiang.chien at gmail.com
>> <mailto:tzuhsiang.chien at gmail.com>> wrote:
>>
>> Hi Jonathan and Nick,
>>
>> I was trying to build libc++abi from repository but failed. May you
>> provide
>> some instruction to cross compile libc++abi for ARM Linux? Thanks.
>>
>> Logan
>>
>>
>> On Tue, Apr 15, 2014 at 5:23 AM, Jonathan Roelofs <
>> jonathan at codesourcery.com
>> <mailto:jonathan at codesourcery.com>> wrote:
>>
>>
> --
> Jon Roelofs
> jonathan at codesourcery.com
> CodeSourcery / Mentor Embedded
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140504/85b8eb26/attachment.html>
-------------- next part --------------
From 0a1a0a896cf26cb5a97b38a470bfc0d7f0b57fcc Mon Sep 17 00:00:00 2001
From: Logan Chien <tzuhsiang.chien at gmail.com>
Date: Tue, 29 Apr 2014 23:49:46 +0800
Subject: [PATCH] Implement ARM EHABI exception handling
This commit implements the zero-cost exception handling support
for libc++abi.
---
include/unwind.h | 156 ++++++++++++++++++++++++++++++++++----
src/cxa_demangle.cpp | 4 +
src/cxa_exception.cpp | 9 +++
src/cxa_exception.hpp | 10 +--
src/cxa_personality.cpp | 197 ++++++++++++++++++++++++++++++++++++++++++++----
test/test_demangle.cpp | 7 ++
6 files changed, 347 insertions(+), 36 deletions(-)
diff --git a/include/unwind.h b/include/unwind.h
index 20634ae..a8ff894 100644
--- a/include/unwind.h
+++ b/include/unwind.h
@@ -23,8 +23,15 @@
#define LIBUNWIND_UNAVAIL
#endif
+#if !__USING_SJLJ_EXCEPTIONS__
+# if defined(__arm__) && !defined(__APPLE__)
+# define LIBCXXABI_ARM_EHABI 1
+# endif
+#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 +39,8 @@ typedef enum {
_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 +51,69 @@ typedef enum {
_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 +129,7 @@ typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(int version,
_Unwind_Action actions,
uint64_t exceptionClass,
- struct _Unwind_Exception* exceptionObject,
+ _Unwind_Exception* exceptionObject,
struct _Unwind_Context* context,
void* stop_parameter );
@@ -73,8 +137,9 @@ typedef _Unwind_Reason_Code (*__personality_routine)
(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 +150,94 @@ extern "C" {
//
#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);
@@ -126,10 +252,10 @@ extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
//
#if __arm__
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
diff --git a/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index d1661e8..2ad832a 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -155,7 +155,11 @@ constexpr const char* float_data<double>::spec;
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";
};
diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp
index 64040fd..5a40682 100644
--- a/src/cxa_exception.cpp
+++ b/src/cxa_exception.cpp
@@ -254,10 +254,15 @@ The adjusted pointer is computed by the personality routine during phase 1
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[4]);
+#else
return cxa_exception_from_exception_unwind_exception
(
static_cast<_Unwind_Exception*>(unwind_exception)
)->adjustedPtr;
+#endif
}
/*
@@ -318,7 +323,11 @@ __cxa_begin_catch(void* unwind_arg) throw()
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[4]);
+#else
return exception_header->adjustedPtr;
+#endif
}
// Else this is a foreign exception
// If the caughtExceptions stack is not empty, terminate
diff --git a/src/cxa_exception.hpp b/src/cxa_exception.hpp
index 03b7a84..592dd50 100644
--- a/src/cxa_exception.hpp
+++ b/src/cxa_exception.hpp
@@ -27,7 +27,7 @@ static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC
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 @@ struct __cxa_exception {
int handlerCount;
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
@@ -56,7 +56,7 @@ struct __cxa_exception {
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 @@ struct __cxa_dependent_exception {
int handlerCount;
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
__cxa_exception* nextPropagatingException;
int propagationCount;
#else
@@ -103,7 +103,7 @@ struct __cxa_dependent_exception {
struct __cxa_eh_globals {
__cxa_exception * caughtExceptions;
unsigned int uncaughtExceptions;
-#ifdef __ARM_EABI_UNWINDER__
+#if LIBCXXABI_ARM_EHABI
__cxa_exception* propagatingExceptions;
#endif
};
diff --git a/src/cxa_personality.cpp b/src/cxa_personality.cpp
index 60b7db5..6856966 100644
--- a/src/cxa_personality.cpp
+++ b/src/cxa_personality.cpp
@@ -307,6 +307,29 @@ call_terminate(bool native_exception, _Unwind_Exception* unwind_exception)
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 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
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 @@ get_shim_type_info(uint64_t ttypeIndex, const uint8_t* classInfo,
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 @@ exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
}
return true;
}
+#endif
static
void*
@@ -511,7 +564,7 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
// 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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
// 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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
// 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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
// 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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
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 @@ scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception
// 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,17 +890,19 @@ _UA_CLEANUP_PHASE
Else a cleanup is not found: return _URC_CONTINUE_UNWIND
*/
+#if !LIBCXXABI_ARM_EHABI
_Unwind_Reason_Code
#if __USING_SJLJ_EXCEPTIONS__
-__gxx_personality_sj0
+__gxx_personality_sj0(int version, _Unwind_Action actions, uint64_t exceptionClass,
+ _Unwind_Exception* unwind_exception, _Unwind_Context* context)
#else
-__gxx_personality_v0
-#endif
- (int version, _Unwind_Action actions, uint64_t exceptionClass,
+__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
_Unwind_Exception* unwind_exception, _Unwind_Context* context)
+#endif
{
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,111 @@ __gxx_personality_v0
// 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*);
+
+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.ttypeIndex;
+ 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.adjustedPtr;
+}
+
+#if 0
+static void load_results_from_barrier_cache(scan_results& results,
+ const _Unwind_Exception* unwind_exception) {
+ results.ttypeIndex = (int64_t)(int32_t)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.adjustedPtr = (void*)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))
+ {
+ // TODO: Load the result from barrier_cache.
+ // load_results_from_barrier_cache(results, unwind_exception);
+ // results.reason = _URC_HANDLER_FOUND;
+ scan_eh_tab(results, static_cast<_Unwind_Action>(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME),
+ native_exception, unwind_exception, context);
+ if (native_exception)
+ save_results_to_barrier_cache(unwind_exception, results);
+ if (results.reason != _URC_HANDLER_FOUND) // phase1 search should guarantee to find one
+ call_terminate(native_exception, unwind_exception);
+ set_registers(unwind_exception, context, results);
+ return _URC_INSTALL_CONTEXT;
+ }
+
+ // Force unwinding
+ scan_eh_tab(results, _UA_CLEANUP_PHASE, native_exception, unwind_exception, context);
+ if (results.reason == _URC_HANDLER_FOUND)
+ {
+ // Found a non-catching handler. Jump to it:
+ set_registers(unwind_exception, context, results);
+ return _URC_INSTALL_CONTEXT;
+ }
+ // 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_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 +1108,13 @@ __cxa_call_unexpected(void* arg)
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[0];
+ lsda = (const uint8_t*)unwind_exception->barrier_cache.bitpattern[2];
+#else
ttypeIndex = old_exception_header->handlerSwitchValue;
lsda = old_exception_header->languageSpecificData;
+#endif
}
else
{
diff --git a/test/test_demangle.cpp b/test/test_demangle.cpp
index bb5b66d..7347236 100644
--- a/test/test_demangle.cpp
+++ b/test/test_demangle.cpp
@@ -29513,7 +29513,10 @@ const char* cases[][2] =
{"_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 @@ const char* invalid_cases[] =
"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]);
--
1.9.1
More information about the cfe-commits
mailing list