forked from OSchip/llvm-project
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 llvm-svn: 216730
This commit is contained in:
parent
f28e7e7d34
commit
2c012d495d
|
@ -207,10 +207,6 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
|
|||
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;
|
||||
|
|
|
@ -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, uint8_t count_minus_one) {
|
|||
|
||||
} // 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;
|
||||
|
|
|
@ -109,6 +109,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
|
|||
|
||||
// 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 callback, void *ref) {
|
|||
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 callback, void *ref) {
|
|||
}
|
||||
|
||||
// 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",
|
||||
|
|
|
@ -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_cache(void (*func)(unw_word_t ip_start,
|
|||
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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(¬hrow_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;
|
||||
}
|
Loading…
Reference in New Issue