summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLogan Chien <tzuhsiang.chien@gmail.com>2015-01-22 13:38:11 +0000
committerLogan Chien <tzuhsiang.chien@gmail.com>2015-01-22 13:38:11 +0000
commit045a7c882bee744550c09c84109be93dc6142c11 (patch)
tree9465c07fcbd3474c7492901401c4b43eaee7fafd
parentf20383cada3162f3ea2437d62e8b9e47c632eaf3 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@226822 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--src/Unwind/Unwind-EHABI.cpp68
-rw-r--r--src/Unwind/Unwind-EHABI.h45
-rw-r--r--src/Unwind/UnwindCursor.hpp18
-rw-r--r--src/Unwind/UnwindLevel1-gcc-ext.c47
4 files changed, 109 insertions, 69 deletions
diff --git a/src/Unwind/Unwind-EHABI.cpp b/src/Unwind/Unwind-EHABI.cpp
index a719b16..deed6f0 100644
--- a/src/Unwind/Unwind-EHABI.cpp
+++ b/src/Unwind/Unwind-EHABI.cpp
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+#include "Unwind-EHABI.h"
+
#include <unwind.h>
#include <stdbool.h>
@@ -44,10 +46,6 @@ const char* getNextNibble(const char* data, uint32_t* out) {
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, uint8_t count_minus_one) {
*/
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;
}
diff --git a/src/Unwind/Unwind-EHABI.h b/src/Unwind/Unwind-EHABI.h
new file mode 100644
index 0000000..fdc0d27
--- /dev/null
+++ b/src/Unwind/Unwind-EHABI.h
@@ -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__
diff --git a/src/Unwind/UnwindCursor.hpp b/src/Unwind/UnwindCursor.hpp
index 0350dfd..ccacd6e 100644
--- a/src/Unwind/UnwindCursor.hpp
+++ b/src/Unwind/UnwindCursor.hpp
@@ -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;
diff --git a/src/Unwind/UnwindLevel1-gcc-ext.c b/src/Unwind/UnwindLevel1-gcc-ext.c
index c119d57..8e2fdd6 100644
--- a/src/Unwind/UnwindLevel1-gcc-ext.c
+++ b/src/Unwind/UnwindLevel1-gcc-ext.c
@@ -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_FindEnclosingFunction(void *pc) {
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 callback, void *ref) {
}
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