[libcxxabi] r226822 - Force unwind frame with user-defined personality.

Logan Chien tzuhsiang.chien at gmail.com
Thu Jan 22 05:38:11 PST 2015


Author: logan
Date: Thu Jan 22 07:38:11 2015
New Revision: 226822

URL: http://llvm.org/viewvc/llvm-project?rev=226822&view=rev
Log:
Force unwind frame with user-defined personality.

If libcxxabi is compiled as a shared library, and the
executable references the user-defined personality routines
(e.g.  __gxx_personality_v0), then the pointer comparison in
Unwind-EHABI.cpp won't work.  This is due to the fact that
the PREL31 will point to the PLT stubs for the personality
routines (in the executable), while the __gxx_personality_v0
symbol reference is yet another (different) PLT stub (in the
libunwind.)

This will cause _Unwind_Backtrace() stops to unwind the frame
whenever it reaches __gxx_personality_v0().  This CL fix the
problem by calling the user-defined personality routines
with an undocumented API for force unwinding.

Added:
    libcxxabi/trunk/src/Unwind/Unwind-EHABI.h
Modified:
    libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp
    libcxxabi/trunk/src/Unwind/UnwindCursor.hpp
    libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c

Modified: libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp?rev=226822&r1=226821&r2=226822&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp (original)
+++ libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp Thu Jan 22 07:38:11 2015
@@ -10,6 +10,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Unwind-EHABI.h"
+
 #include <unwind.h>
 
 #include <stdbool.h>
@@ -44,10 +46,6 @@ const char* getNextNibble(const char* da
   return data + 2;
 }
 
-static inline uint32_t signExtendPrel31(uint32_t data) {
-  return data | ((data & 0x40000000u) << 1);
-}
-
 struct Descriptor {
    // See # 9.2
    typedef enum {
@@ -162,10 +160,9 @@ _Unwind_Reason_Code ProcessDescriptors(
   return _URC_CONTINUE_UNWIND;
 }
 
-_Unwind_Reason_Code unwindOneFrame(
-    _Unwind_State state,
-    _Unwind_Control_Block* ucbp,
-    struct _Unwind_Context* context) {
+static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state,
+                                          _Unwind_Control_Block* ucbp,
+                                          struct _Unwind_Context* context) {
   // Read the compact model EHT entry's header # 6.3
   const uint32_t* unwindingData = ucbp->pr_cache.ehtp;
   assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");
@@ -216,44 +213,27 @@ uint32_t RegisterRange(uint8_t start, ui
  */
 extern "C" const uint32_t*
 decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
-  if ((*data & 0x80000000) == 0) {
-    // 6.2: Generic Model
-    // EHT entry is a prel31 pointing to the PR, followed by data understood only
-    // by the personality routine. Since EHABI doesn't guarantee the location or
-    // availability of the unwind opcodes in the generic model, we have to check
-    // for them on a case-by-case basis:
-    _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions,
-                                             uint64_t exceptionClass,
-                                             _Unwind_Exception* unwind_exception,
-                                             _Unwind_Context* context);
-    void *PR = (void*)signExtendPrel31(*data);
-    if (PR == (void*)&__gxx_personality_v0) {
-      *off = 1; // First byte is size data.
-      *len = (((data[1] >> 24) & 0xff) + 1) * 4;
-    } else
+  assert((*data & 0x80000000) != 0 &&
+         "decode_eht_entry() does not support user-defined personality");
+
+  // 6.3: ARM Compact Model
+  // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
+  // by format:
+  Descriptor::Format format =
+      static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
+  switch (format) {
+    case Descriptor::SU16:
+      *len = 4;
+      *off = 1;
+      break;
+    case Descriptor::LU16:
+    case Descriptor::LU32:
+      *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
+      *off = 2;
+      break;
+    default:
       return nullptr;
-    data++; // Skip the first word, which is the prel31 offset.
-  } else {
-    // 6.3: ARM Compact Model
-    // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
-    // by format:
-    Descriptor::Format format =
-        static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
-    switch (format) {
-      case Descriptor::SU16:
-        *len = 4;
-        *off = 1;
-        break;
-      case Descriptor::LU16:
-      case Descriptor::LU32:
-        *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
-        *off = 2;
-        break;
-      default:
-        return nullptr;
-    }
   }
-
   return data;
 }
 

Added: libcxxabi/trunk/src/Unwind/Unwind-EHABI.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Unwind-EHABI.h?rev=226822&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/Unwind-EHABI.h (added)
+++ libcxxabi/trunk/src/Unwind/Unwind-EHABI.h Thu Jan 22 07:38:11 2015
@@ -0,0 +1,45 @@
+//===------------------------- Unwind-EHABI.hpp ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_EHABI_H__
+#define __UNWIND_EHABI_H__
+
+#include <stdint.h>
+#include <unwind.h>
+
+// Unable to unwind in the ARM index table (section 5 EHABI).
+#define UNW_EXIDX_CANTUNWIND 0x1
+
+static inline uint32_t signExtendPrel31(uint32_t data) {
+  return data | ((data & 0x40000000u) << 1);
+}
+
+static inline uint32_t readPrel31(const uint32_t *data) {
+  return (((uint32_t) data) + signExtendPrel31(*data));
+}
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
+    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif  // __UNWIND_EHABI_H__

Modified: libcxxabi/trunk/src/Unwind/UnwindCursor.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindCursor.hpp?rev=226822&r1=226821&r2=226822&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindCursor.hpp (original)
+++ libcxxabi/trunk/src/Unwind/UnwindCursor.hpp Thu Jan 22 07:38:11 2015
@@ -31,6 +31,10 @@
 #include "CompactUnwinder.hpp"
 #include "config.h"
 
+#if LIBCXXABI_ARM_EHABI
+#include "Unwind-EHABI.h"
+#endif
+
 namespace libunwind {
 
 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
@@ -605,20 +609,6 @@ struct EHABIIndexEntry {
   uint32_t data;
 };
 
-// Unable to unwind in the ARM index table (section 5 EHABI).
-#define UNW_EXIDX_CANTUNWIND 0x1
-
-static inline uint32_t signExtendPrel31(uint32_t data) {
-  return data | ((data & 0x40000000u) << 1);
-}
-
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
-    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
-    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
-    _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
-
 template<typename A>
 struct EHABISectionIterator {
   typedef EHABISectionIterator _Self;

Modified: libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c?rev=226822&r1=226821&r2=226822&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c (original)
+++ libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c Thu Jan 22 07:38:11 2015
@@ -21,6 +21,10 @@
 #include "libunwind_ext.h"
 #include "config.h"
 
+#if LIBCXXABI_ARM_EHABI
+#include "Unwind-EHABI.h"
+#endif
+
 #if _LIBUNWIND_BUILD_ZERO_COST_APIS
 
 ///  Called by __cxa_rethrow().
@@ -99,7 +103,6 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEncl
     return NULL;
 }
 
-
 /// Walk every frame and call trace function at each one.  If trace function
 /// returns anything other than _URC_NO_REASON, then walk is terminated.
 _LIBUNWIND_EXPORT _Unwind_Reason_Code
@@ -132,17 +135,39 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callb
     }
 
     struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
-    size_t off;
-    size_t len;
     const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
-    unwindInfo = decode_eht_entry(unwindInfo, &off, &len);
-    if (unwindInfo == NULL) {
-      return _URC_FAILURE;
-    }
-
-    result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
-    if (result != _URC_CONTINUE_UNWIND) {
-      return _URC_END_OF_STACK;
+    if ((*unwindInfo & 0x80000000) == 0) {
+      // 6.2: Generic Model
+      // EHT entry is a prel31 pointing to the PR, followed by data understood
+      // only by the personality routine. Since EHABI doesn't guarantee the
+      // location or availability of the unwind opcodes in the generic model,
+      // we have to call personality functions with (_US_VIRTUAL_UNWIND_FRAME |
+      // _US_FORCE_UNWIND) state.
+
+      // Create a mock exception object for force unwinding.
+      _Unwind_Exception ex;
+      ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
+      ex.pr_cache.fnstart = frameInfo.start_ip;
+      ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
+      ex.pr_cache.additional= frameInfo.flags;
+
+      // Get and call the personality function to unwind the frame.
+      __personality_routine pr = (__personality_routine) readPrel31(unwindInfo);
+      if (pr(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
+              _URC_CONTINUE_UNWIND) {
+        return _URC_END_OF_STACK;
+      }
+    } else {
+      size_t off, len;
+      unwindInfo = decode_eht_entry(unwindInfo, &off, &len);
+      if (unwindInfo == NULL) {
+        return _URC_FAILURE;
+      }
+
+      result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
+      if (result != _URC_CONTINUE_UNWIND) {
+        return _URC_END_OF_STACK;
+      }
     }
 #endif // LIBCXXABI_ARM_EHABI
 





More information about the cfe-commits mailing list