diff options
author | Logan Chien <tzuhsiang.chien@gmail.com> | 2015-01-22 13:38:11 +0000 |
---|---|---|
committer | Logan Chien <tzuhsiang.chien@gmail.com> | 2015-01-22 13:38:11 +0000 |
commit | 045a7c882bee744550c09c84109be93dc6142c11 (patch) | |
tree | 9465c07fcbd3474c7492901401c4b43eaee7fafd | |
parent | f20383cada3162f3ea2437d62e8b9e47c632eaf3 (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.cpp | 68 | ||||
-rw-r--r-- | src/Unwind/Unwind-EHABI.h | 45 | ||||
-rw-r--r-- | src/Unwind/UnwindCursor.hpp | 18 | ||||
-rw-r--r-- | src/Unwind/UnwindLevel1-gcc-ext.c | 47 |
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 |