mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-05 12:51:16 +00:00
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. llvm-svn: 226822
This commit is contained in:
parent
d38af30b74
commit
6b2c971524
@ -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
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
45
libcxxabi/src/Unwind/Unwind-EHABI.h
Normal file
45
libcxxabi/src/Unwind/Unwind-EHABI.h
Normal file
@ -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__
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
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.
|
||||
|
||||
result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
|
||||
if (result != _URC_CONTINUE_UNWIND) {
|
||||
return _URC_END_OF_STACK;
|
||||
// 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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user