[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