[libcxxabi] r216730 - Make _Unwind_Backtrace() work on ARM.

Dan Albert danalbert at google.com
Fri Aug 29 08:26:06 PDT 2014


Author: danalbert
Date: Fri Aug 29 10:26:06 2014
New Revision: 216730

URL: http://llvm.org/viewvc/llvm-project?rev=216730&view=rev
Log:
Make _Unwind_Backtrace() work on ARM.

Summary: Since the personality functions do the actual unwinding on ARM,
and will also stop unwinding when they encounter a handler, we invoke
_Unwind_VRS_Interpret() directly form _Unwind_Backtrace().

To simplify, the logic for decoding an EHT is moved out of
unwindOneFrame() and into its own function, decode_eht_entry(). Unlike
unwindOneFrame(), which could only handle ARM's compact personality
function entries (section 6.3) decode_eht_entry() can handle the generic
entries (section 6.2).

Reviewers: jroelofs

Reviewed By: jroelofs

Subscribers: piman, aemerson, cfe-commits

Differential Revision: http://reviews.llvm.org/D5112

Added:
    libcxxabi/trunk/test/backtrace_test.cpp
Modified:
    libcxxabi/trunk/include/unwind.h
    libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp
    libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c
    libcxxabi/trunk/src/Unwind/libunwind_ext.h
    libcxxabi/trunk/src/cxa_personality.cpp

Modified: libcxxabi/trunk/include/unwind.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/include/unwind.h?rev=216730&r1=216729&r2=216730&view=diff
==============================================================================
--- libcxxabi/trunk/include/unwind.h (original)
+++ libcxxabi/trunk/include/unwind.h Fri Aug 29 10:26:06 2014
@@ -207,10 +207,6 @@ _Unwind_VRS_Pop(_Unwind_Context *context
                 uint32_t discriminator,
                 _Unwind_VRS_DataRepresentation representation);
 
-extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
-                                                 uint32_t *data, size_t offset,
-                                                 size_t len);
-
 static inline uintptr_t _Unwind_GetGR(struct _Unwind_Context* context,
                                       int index) {
   uintptr_t value = 0;

Modified: libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp?rev=216730&r1=216729&r2=216730&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp (original)
+++ libcxxabi/trunk/src/Unwind/Unwind-EHABI.cpp Fri Aug 29 10:26:06 2014
@@ -20,6 +20,7 @@
 
 #include "config.h"
 #include "libunwind.h"
+#include "libunwind_ext.h"
 #include "unwind.h"
 #include "../private_typeinfo.h"
 
@@ -28,8 +29,8 @@ namespace {
 
 // Strange order: take words in order, but inside word, take from most to least
 // signinficant byte.
-uint8_t getByte(uint32_t* data, size_t offset) {
-  uint8_t* byteData = reinterpret_cast<uint8_t*>(data);
+uint8_t getByte(const uint32_t* data, size_t offset) {
+  const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data);
   return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))];
 }
 
@@ -166,25 +167,15 @@ _Unwind_Reason_Code unwindOneFrame(
     _Unwind_Control_Block* ucbp,
     struct _Unwind_Context* context) {
   // Read the compact model EHT entry's header # 6.3
-  uint32_t* unwindingData = ucbp->pr_cache.ehtp;
-  uint32_t unwindInfo = *unwindingData;
-  assert((unwindInfo & 0xf0000000) == 0x80000000 && "Must be a compact entry");
+  const uint32_t* unwindingData = ucbp->pr_cache.ehtp;
+  assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");
   Descriptor::Format format =
-      static_cast<Descriptor::Format>((unwindInfo & 0x0f000000) >> 24);
+      static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24);
   size_t len = 0;
-  size_t startOffset = 0;
-  switch (format) {
-    case Descriptor::SU16:
-      len = 4;
-      startOffset = 1;
-      break;
-    case Descriptor::LU16:
-    case Descriptor::LU32:
-      len = 4 + 4 * ((unwindInfo & 0x00ff0000) >> 16);
-      startOffset = 2;
-      break;
-    default:
-      return _URC_FAILURE;
+  size_t off = 0;
+  unwindingData = decode_eht_entry(unwindingData, &off, &len);
+  if (unwindingData == nullptr) {
+    return _URC_FAILURE;
   }
 
   // Handle descriptors before unwinding so they are processed in the context
@@ -198,7 +189,7 @@ _Unwind_Reason_Code unwindOneFrame(
   if (result != _URC_CONTINUE_UNWIND)
     return result;
 
-  return _Unwind_VRS_Interpret(context, unwindingData, startOffset, len);
+  return _Unwind_VRS_Interpret(context, unwindingData, off, len);
 }
 
 // Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /
@@ -215,9 +206,46 @@ uint32_t RegisterRange(uint8_t start, ui
 
 } // end anonymous namespace
 
+/**
+ * Decodes an EHT entry.
+ *
+ * @param data Pointer to EHT.
+ * @param[out] off Offset from return value (in bytes) to begin interpretation.
+ * @param[out] len Number of bytes in unwind code.
+ * @return Pointer to beginning of unwind code.
+ */
+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
+    *off = 1; // First byte is size data.
+    *len = (((data[1] >> 24) & 0xff) + 1) * 4;
+    data++; // Skip the first word, which is the prel31 offset.
+  } else {
+    // 6.3: ARM Compact Model
+    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;
+}
+
 _Unwind_Reason_Code _Unwind_VRS_Interpret(
     _Unwind_Context* context,
-    uint32_t* data,
+    const uint32_t* data,
     size_t offset,
     size_t len) {
   bool wrotePC = false;

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=216730&r1=216729&r2=216730&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c (original)
+++ libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c Fri Aug 29 10:26:06 2014
@@ -109,6 +109,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callb
 
   // walk each frame
   while (true) {
+    _Unwind_Reason_Code result;
 
     // ask libuwind to get next frame (skip over first frame which is
     // _Unwind_Backtrace())
@@ -119,6 +120,28 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callb
       return _URC_END_OF_STACK;
     }
 
+#if LIBCXXABI_ARM_EHABI
+    // Get the information for this frame.
+    unw_proc_info_t frameInfo;
+    if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
+      return _URC_END_OF_STACK;
+    }
+
+    struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
+    size_t off;
+    size_t len;
+    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;
+    }
+#endif // LIBCXXABI_ARM_EHABI
+
     // debugging
     if (_LIBUNWIND_TRACING_UNWINDING) {
       char functionName[512];
@@ -133,8 +156,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callb
     }
 
     // call trace function with this frame
-    _Unwind_Reason_Code result =
-        (*callback)((struct _Unwind_Context *)(&cursor), ref);
+    result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
     if (result != _URC_NO_REASON) {
       _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because callback "
                                  "returned %d\n",

Modified: libcxxabi/trunk/src/Unwind/libunwind_ext.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/libunwind_ext.h?rev=216730&r1=216729&r2=216730&view=diff
==============================================================================
--- libcxxabi/trunk/src/Unwind/libunwind_ext.h (original)
+++ libcxxabi/trunk/src/Unwind/libunwind_ext.h Fri Aug 29 10:26:06 2014
@@ -13,7 +13,9 @@
 #ifndef __LIBUNWIND_EXT__
 #define __LIBUNWIND_EXT__
 
+#include "config.h"
 #include <libunwind.h>
+#include <unwind.h>
 
 #define UNW_STEP_SUCCESS 1
 #define UNW_STEP_END     0
@@ -31,6 +33,13 @@ extern void unw_iterate_dwarf_unwind_cac
 extern void _unw_add_dynamic_fde(unw_word_t fde);
 extern void _unw_remove_dynamic_fde(unw_word_t fde);
 
+#if LIBCXXABI_ARM_EHABI
+extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
+extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
+                                                 const uint32_t *data,
+                                                 size_t offset, size_t len);
+#endif
+
 #ifdef __cplusplus
 }
 #endif

Modified: libcxxabi/trunk/src/cxa_personality.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_personality.cpp?rev=216730&r1=216729&r2=216730&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_personality.cpp (original)
+++ libcxxabi/trunk/src/cxa_personality.cpp Fri Aug 29 10:26:06 2014
@@ -12,14 +12,19 @@
 //  
 //===----------------------------------------------------------------------===//
 
+#include <assert.h>
+#include <stdlib.h>
+#include <typeinfo>
+
 #include "config.h"
-#include "unwind.h"
 #include "cxa_exception.hpp"
 #include "cxa_handlers.hpp"
 #include "private_typeinfo.h"
-#include <typeinfo>
-#include <stdlib.h>
-#include <assert.h>
+#include "unwind.h"
+
+#if LIBCXXABI_ARM_EHABI
+#include "Unwind/libunwind_ext.h"
+#endif
 
 /*
     Exception Header Layout:

Added: libcxxabi/trunk/test/backtrace_test.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/backtrace_test.cpp?rev=216730&view=auto
==============================================================================
--- libcxxabi/trunk/test/backtrace_test.cpp (added)
+++ libcxxabi/trunk/test/backtrace_test.cpp Fri Aug 29 10:26:06 2014
@@ -0,0 +1,61 @@
+//===---------------------- backtrace_test.cpp ----------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+#include <assert.h>
+#include <unwind.h>
+
+extern "C" _Unwind_Reason_Code
+trace_function(struct _Unwind_Context* context, void* ntraced) {
+  (*reinterpret_cast<size_t*>(ntraced))++;
+  // We should never have a call stack this deep...
+  assert(*reinterpret_cast<size_t*>(ntraced) < 20);
+  return _URC_NO_REASON;
+}
+
+void call3_throw(size_t* ntraced) {
+  try {
+    _Unwind_Backtrace(trace_function, ntraced);
+  } catch (...) {
+    assert(false);
+  }
+}
+
+void call3_nothrow(size_t* ntraced) {
+  _Unwind_Backtrace(trace_function, ntraced);
+}
+
+void call2(size_t* ntraced, bool do_throw) {
+  if (do_throw) {
+    call3_throw(ntraced);
+  } else {
+    call3_nothrow(ntraced);
+  }
+}
+
+void call1(size_t* ntraced, bool do_throw) {
+  call2(ntraced, do_throw);
+}
+
+int main() {
+  size_t throw_ntraced = 0;
+  size_t nothrow_ntraced = 0;
+
+  call1(&nothrow_ntraced, false);
+
+  try {
+    call1(&throw_ntraced, true);
+  } catch (...) {
+    assert(false);
+  }
+
+  // Different platforms (and different runtimes) will unwind a different number
+  // of times, so we can't make any better assumptions than this.
+  assert(nothrow_ntraced > 1);
+  assert(throw_ntraced == nothrow_ntraced); // Make sure we unwind through catch
+  return 0;
+}





More information about the cfe-commits mailing list