Update backward to 1.6
This commit is contained in:
parent
ec3c8e7701
commit
b58b8537b5
|
@ -35,6 +35,9 @@
|
||||||
#define BACKWARD_CXX11
|
#define BACKWARD_CXX11
|
||||||
#define BACKWARD_ATLEAST_CXX11
|
#define BACKWARD_ATLEAST_CXX11
|
||||||
#define BACKWARD_ATLEAST_CXX98
|
#define BACKWARD_ATLEAST_CXX98
|
||||||
|
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||||
|
#define BACKWARD_ATLEAST_CXX17
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define BACKWARD_CXX98
|
#define BACKWARD_CXX98
|
||||||
#define BACKWARD_ATLEAST_CXX98
|
#define BACKWARD_ATLEAST_CXX98
|
||||||
|
@ -49,6 +52,9 @@
|
||||||
// #define BACKWARD_SYSTEM_DARWIN
|
// #define BACKWARD_SYSTEM_DARWIN
|
||||||
// - specialization for Mac OS X 10.5 and later.
|
// - specialization for Mac OS X 10.5 and later.
|
||||||
//
|
//
|
||||||
|
// #define BACKWARD_SYSTEM_WINDOWS
|
||||||
|
// - specialization for Windows (Clang 9 and MSVC2017)
|
||||||
|
//
|
||||||
// #define BACKWARD_SYSTEM_UNKNOWN
|
// #define BACKWARD_SYSTEM_UNKNOWN
|
||||||
// - placebo implementation, does nothing.
|
// - placebo implementation, does nothing.
|
||||||
//
|
//
|
||||||
|
@ -84,6 +90,8 @@
|
||||||
#include <streambuf>
|
#include <streambuf>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <exception>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#if defined(BACKWARD_SYSTEM_LINUX)
|
#if defined(BACKWARD_SYSTEM_LINUX)
|
||||||
|
|
||||||
|
@ -97,6 +105,11 @@
|
||||||
// exception.
|
// exception.
|
||||||
// - normally libgcc is already linked to your program by default.
|
// - normally libgcc is already linked to your program by default.
|
||||||
//
|
//
|
||||||
|
// #define BACKWARD_HAS_LIBUNWIND 1
|
||||||
|
// - libunwind provides, in some cases, a more accurate stacktrace as it knows
|
||||||
|
// to decode signal handler frames and lets us edit the context registers when
|
||||||
|
// unwinding, allowing stack traces over bad function references.
|
||||||
|
//
|
||||||
// #define BACKWARD_HAS_BACKTRACE == 1
|
// #define BACKWARD_HAS_BACKTRACE == 1
|
||||||
// - backtrace seems to be a little bit more portable than libunwind, but on
|
// - backtrace seems to be a little bit more portable than libunwind, but on
|
||||||
// linux, it uses unwind anyway, but abstract away a tiny information that is
|
// linux, it uses unwind anyway, but abstract away a tiny information that is
|
||||||
|
@ -109,10 +122,13 @@
|
||||||
// Note that only one of the define should be set to 1 at a time.
|
// Note that only one of the define should be set to 1 at a time.
|
||||||
//
|
//
|
||||||
#if BACKWARD_HAS_UNWIND == 1
|
#if BACKWARD_HAS_UNWIND == 1
|
||||||
|
#elif BACKWARD_HAS_LIBUNWIND == 1
|
||||||
#elif BACKWARD_HAS_BACKTRACE == 1
|
#elif BACKWARD_HAS_BACKTRACE == 1
|
||||||
#else
|
#else
|
||||||
#undef BACKWARD_HAS_UNWIND
|
#undef BACKWARD_HAS_UNWIND
|
||||||
#define BACKWARD_HAS_UNWIND 1
|
#define BACKWARD_HAS_UNWIND 1
|
||||||
|
#undef BACKWARD_HAS_LIBUNWIND
|
||||||
|
#define BACKWARD_HAS_LIBUNWIND 0
|
||||||
#undef BACKWARD_HAS_BACKTRACE
|
#undef BACKWARD_HAS_BACKTRACE
|
||||||
#define BACKWARD_HAS_BACKTRACE 0
|
#define BACKWARD_HAS_BACKTRACE 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,7 +143,8 @@
|
||||||
// - source filename
|
// - source filename
|
||||||
// - line and column numbers
|
// - line and column numbers
|
||||||
// - source code snippet (assuming the file is accessible)
|
// - source code snippet (assuming the file is accessible)
|
||||||
// - variables name and values (if not optimized out)
|
// - variable names (if not optimized out)
|
||||||
|
// - variable values (not supported by backward-cpp)
|
||||||
// - You need to link with the lib "dw":
|
// - You need to link with the lib "dw":
|
||||||
// - apt-get install libdw-dev
|
// - apt-get install libdw-dev
|
||||||
// - g++/clang++ -ldw ...
|
// - g++/clang++ -ldw ...
|
||||||
|
@ -150,7 +167,8 @@
|
||||||
// - source filename
|
// - source filename
|
||||||
// - line and column numbers
|
// - line and column numbers
|
||||||
// - source code snippet (assuming the file is accessible)
|
// - source code snippet (assuming the file is accessible)
|
||||||
// - variables name and values (if not optimized out)
|
// - variable names (if not optimized out)
|
||||||
|
// - variable values (not supported by backward-cpp)
|
||||||
// - You need to link with the lib "dwarf":
|
// - You need to link with the lib "dwarf":
|
||||||
// - apt-get install libdwarf-dev
|
// - apt-get install libdwarf-dev
|
||||||
// - g++/clang++ -ldwarf ...
|
// - g++/clang++ -ldwarf ...
|
||||||
|
@ -257,6 +275,12 @@
|
||||||
// exception.
|
// exception.
|
||||||
// - normally libgcc is already linked to your program by default.
|
// - normally libgcc is already linked to your program by default.
|
||||||
//
|
//
|
||||||
|
// #define BACKWARD_HAS_LIBUNWIND 1
|
||||||
|
// - libunwind comes from clang, which implements an API compatible version.
|
||||||
|
// - libunwind provides, in some cases, a more accurate stacktrace as it knows
|
||||||
|
// to decode signal handler frames and lets us edit the context registers when
|
||||||
|
// unwinding, allowing stack traces over bad function references.
|
||||||
|
//
|
||||||
// #define BACKWARD_HAS_BACKTRACE == 1
|
// #define BACKWARD_HAS_BACKTRACE == 1
|
||||||
// - backtrace is available by default, though it does not produce as much
|
// - backtrace is available by default, though it does not produce as much
|
||||||
// information as another library might.
|
// information as another library might.
|
||||||
|
@ -268,11 +292,14 @@
|
||||||
//
|
//
|
||||||
#if BACKWARD_HAS_UNWIND == 1
|
#if BACKWARD_HAS_UNWIND == 1
|
||||||
#elif BACKWARD_HAS_BACKTRACE == 1
|
#elif BACKWARD_HAS_BACKTRACE == 1
|
||||||
|
#elif BACKWARD_HAS_LIBUNWIND == 1
|
||||||
#else
|
#else
|
||||||
#undef BACKWARD_HAS_UNWIND
|
#undef BACKWARD_HAS_UNWIND
|
||||||
#define BACKWARD_HAS_UNWIND 1
|
#define BACKWARD_HAS_UNWIND 1
|
||||||
#undef BACKWARD_HAS_BACKTRACE
|
#undef BACKWARD_HAS_BACKTRACE
|
||||||
#define BACKWARD_HAS_BACKTRACE 0
|
#define BACKWARD_HAS_BACKTRACE 0
|
||||||
|
#undef BACKWARD_HAS_LIBUNWIND
|
||||||
|
#define BACKWARD_HAS_LIBUNWIND 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On Darwin, backward can extract detailed information about a stack trace
|
// On Darwin, backward can extract detailed information about a stack trace
|
||||||
|
@ -327,6 +354,11 @@ typedef SSIZE_T ssize_t;
|
||||||
#define NOINLINE __declspec(noinline)
|
#define NOINLINE __declspec(noinline)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma comment(lib, "psapi.lib")
|
||||||
|
#pragma comment(lib, "dbghelp.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
// Comment / packing is from stackoverflow:
|
// Comment / packing is from stackoverflow:
|
||||||
// https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227
|
// https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227
|
||||||
// Some versions of imagehlp.dll lack the proper packing directives themselves
|
// Some versions of imagehlp.dll lack the proper packing directives themselves
|
||||||
|
@ -370,6 +402,11 @@ extern "C" uintptr_t _Unwind_GetIPInfo(_Unwind_Context *, int *);
|
||||||
|
|
||||||
#endif // BACKWARD_HAS_UNWIND == 1
|
#endif // BACKWARD_HAS_UNWIND == 1
|
||||||
|
|
||||||
|
#if BACKWARD_HAS_LIBUNWIND == 1
|
||||||
|
#define UNW_LOCAL_ONLY
|
||||||
|
#include <libunwind.h>
|
||||||
|
#endif // BACKWARD_HAS_LIBUNWIND == 1
|
||||||
|
|
||||||
#ifdef BACKWARD_ATLEAST_CXX11
|
#ifdef BACKWARD_ATLEAST_CXX11
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility> // for std::swap
|
#include <utility> // for std::swap
|
||||||
|
@ -529,7 +566,7 @@ typedef pdb_symbol current;
|
||||||
|
|
||||||
void update(T new_val) {
|
void update(T new_val) {
|
||||||
_val = new_val;
|
_val = new_val;
|
||||||
_empty = static_cast<bool>(new_val);
|
_empty = !static_cast<bool>(new_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
operator const dummy *() const {
|
operator const dummy *() const {
|
||||||
|
@ -681,14 +718,17 @@ typedef pdb_symbol current;
|
||||||
size_t size() const { return 0; }
|
size_t size() const { return 0; }
|
||||||
Trace operator[](size_t) const { return Trace(); }
|
Trace operator[](size_t) const { return Trace(); }
|
||||||
size_t load_here(size_t = 0) { return 0; }
|
size_t load_here(size_t = 0) { return 0; }
|
||||||
size_t load_from(void *, size_t = 0) { return 0; }
|
size_t load_from(void *, size_t = 0, void * = nullptr, void * = nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
size_t thread_id() const { return 0; }
|
size_t thread_id() const { return 0; }
|
||||||
void skip_n_firsts(size_t) {}
|
void skip_n_firsts(size_t) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class StackTraceImplBase {
|
class StackTraceImplBase {
|
||||||
public:
|
public:
|
||||||
StackTraceImplBase() : _thread_id(0), _skip(0) {}
|
StackTraceImplBase()
|
||||||
|
: _thread_id(0), _skip(0), _context(nullptr), _error_addr(nullptr) {}
|
||||||
|
|
||||||
size_t thread_id() const { return _thread_id; }
|
size_t thread_id() const { return _thread_id; }
|
||||||
|
|
||||||
|
@ -716,17 +756,27 @@ typedef pdb_symbol current;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_context(void *context) { _context = context; }
|
||||||
|
void *context() const { return _context; }
|
||||||
|
|
||||||
|
void set_error_addr(void *error_addr) { _error_addr = error_addr; }
|
||||||
|
void *error_addr() const { return _error_addr; }
|
||||||
|
|
||||||
size_t skip_n_firsts() const { return _skip; }
|
size_t skip_n_firsts() const { return _skip; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t _thread_id;
|
size_t _thread_id;
|
||||||
size_t _skip;
|
size_t _skip;
|
||||||
|
void *_context;
|
||||||
|
void *_error_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StackTraceImplHolder : public StackTraceImplBase {
|
class StackTraceImplHolder : public StackTraceImplBase {
|
||||||
public:
|
public:
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return (_stacktrace.size() >= skip_n_firsts()) ? _stacktrace.size() - skip_n_firsts() : 0;
|
return (_stacktrace.size() >= skip_n_firsts())
|
||||||
|
? _stacktrace.size() - skip_n_firsts()
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
Trace operator[](size_t idx) const {
|
Trace operator[](size_t idx) const {
|
||||||
if (idx >= size()) {
|
if (idx >= size()) {
|
||||||
|
@ -807,8 +857,11 @@ typedef pdb_symbol current;
|
||||||
class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder {
|
class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder {
|
||||||
public:
|
public:
|
||||||
NOINLINE
|
NOINLINE
|
||||||
size_t load_here(size_t depth = 32) {
|
size_t load_here(size_t depth = 32, void *context = nullptr,
|
||||||
|
void *error_addr = nullptr) {
|
||||||
load_thread_info();
|
load_thread_info();
|
||||||
|
set_context(context);
|
||||||
|
set_error_addr(error_addr);
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -818,8 +871,9 @@ typedef pdb_symbol current;
|
||||||
skip_n_firsts(0);
|
skip_n_firsts(0);
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
size_t load_from(void *addr, size_t depth = 32) {
|
size_t load_from(void *addr, size_t depth = 32, void *context = nullptr,
|
||||||
load_here(depth + 8);
|
void *error_addr = nullptr) {
|
||||||
|
load_here(depth + 8, context, error_addr);
|
||||||
|
|
||||||
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
||||||
if (_stacktrace[i] == addr) {
|
if (_stacktrace[i] == addr) {
|
||||||
|
@ -841,13 +895,193 @@ typedef pdb_symbol current;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#elif BACKWARD_HAS_LIBUNWIND == 1
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder {
|
||||||
|
public:
|
||||||
|
__attribute__((noinline)) size_t load_here(size_t depth = 32,
|
||||||
|
void *_context = nullptr,
|
||||||
|
void *_error_addr = nullptr) {
|
||||||
|
set_context(_context);
|
||||||
|
set_error_addr(_error_addr);
|
||||||
|
load_thread_info();
|
||||||
|
if (depth == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_stacktrace.resize(depth + 1);
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
unw_context_t ctx;
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
// Add the tail call. If the Instruction Pointer is the crash address it
|
||||||
|
// means we got a bad function pointer dereference, so we "unwind" the
|
||||||
|
// bad pointer manually by using the return address pointed to by the
|
||||||
|
// Stack Pointer as the Instruction Pointer and letting libunwind do
|
||||||
|
// the rest
|
||||||
|
|
||||||
|
if (context()) {
|
||||||
|
ucontext_t *uctx = reinterpret_cast<ucontext_t *>(context());
|
||||||
|
#ifdef REG_RIP // x86_64
|
||||||
|
if (uctx->uc_mcontext.gregs[REG_RIP] ==
|
||||||
|
reinterpret_cast<greg_t>(error_addr())) {
|
||||||
|
uctx->uc_mcontext.gregs[REG_RIP] =
|
||||||
|
*reinterpret_cast<size_t *>(uctx->uc_mcontext.gregs[REG_RSP]);
|
||||||
|
}
|
||||||
|
_stacktrace[index] =
|
||||||
|
reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_RIP]);
|
||||||
|
++index;
|
||||||
|
ctx = *reinterpret_cast<unw_context_t *>(uctx);
|
||||||
|
#elif defined(REG_EIP) // x86_32
|
||||||
|
if (uctx->uc_mcontext.gregs[REG_EIP] ==
|
||||||
|
reinterpret_cast<greg_t>(error_addr())) {
|
||||||
|
uctx->uc_mcontext.gregs[REG_EIP] =
|
||||||
|
*reinterpret_cast<size_t *>(uctx->uc_mcontext.gregs[REG_ESP]);
|
||||||
|
}
|
||||||
|
_stacktrace[index] =
|
||||||
|
reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_EIP]);
|
||||||
|
++index;
|
||||||
|
ctx = *reinterpret_cast<unw_context_t *>(uctx);
|
||||||
|
#elif defined(__arm__)
|
||||||
|
// libunwind uses its own context type for ARM unwinding.
|
||||||
|
// Copy the registers from the signal handler's context so we can
|
||||||
|
// unwind
|
||||||
|
unw_getcontext(&ctx);
|
||||||
|
ctx.regs[UNW_ARM_R0] = uctx->uc_mcontext.arm_r0;
|
||||||
|
ctx.regs[UNW_ARM_R1] = uctx->uc_mcontext.arm_r1;
|
||||||
|
ctx.regs[UNW_ARM_R2] = uctx->uc_mcontext.arm_r2;
|
||||||
|
ctx.regs[UNW_ARM_R3] = uctx->uc_mcontext.arm_r3;
|
||||||
|
ctx.regs[UNW_ARM_R4] = uctx->uc_mcontext.arm_r4;
|
||||||
|
ctx.regs[UNW_ARM_R5] = uctx->uc_mcontext.arm_r5;
|
||||||
|
ctx.regs[UNW_ARM_R6] = uctx->uc_mcontext.arm_r6;
|
||||||
|
ctx.regs[UNW_ARM_R7] = uctx->uc_mcontext.arm_r7;
|
||||||
|
ctx.regs[UNW_ARM_R8] = uctx->uc_mcontext.arm_r8;
|
||||||
|
ctx.regs[UNW_ARM_R9] = uctx->uc_mcontext.arm_r9;
|
||||||
|
ctx.regs[UNW_ARM_R10] = uctx->uc_mcontext.arm_r10;
|
||||||
|
ctx.regs[UNW_ARM_R11] = uctx->uc_mcontext.arm_fp;
|
||||||
|
ctx.regs[UNW_ARM_R12] = uctx->uc_mcontext.arm_ip;
|
||||||
|
ctx.regs[UNW_ARM_R13] = uctx->uc_mcontext.arm_sp;
|
||||||
|
ctx.regs[UNW_ARM_R14] = uctx->uc_mcontext.arm_lr;
|
||||||
|
ctx.regs[UNW_ARM_R15] = uctx->uc_mcontext.arm_pc;
|
||||||
|
|
||||||
|
// If we have crashed in the PC use the LR instead, as this was
|
||||||
|
// a bad function dereference
|
||||||
|
if (reinterpret_cast<unsigned long>(error_addr()) ==
|
||||||
|
uctx->uc_mcontext.arm_pc) {
|
||||||
|
ctx.regs[UNW_ARM_R15] =
|
||||||
|
uctx->uc_mcontext.arm_lr - sizeof(unsigned long);
|
||||||
|
}
|
||||||
|
_stacktrace[index] = reinterpret_cast<void *>(ctx.regs[UNW_ARM_R15]);
|
||||||
|
++index;
|
||||||
|
#elif defined(__APPLE__) && defined(__x86_64__)
|
||||||
|
unw_getcontext(&ctx);
|
||||||
|
// OS X's implementation of libunwind uses its own context object
|
||||||
|
// so we need to convert the passed context to libunwind's format
|
||||||
|
// (information about the data layout taken from unw_getcontext.s
|
||||||
|
// in Apple's libunwind source
|
||||||
|
ctx.data[0] = uctx->uc_mcontext->__ss.__rax;
|
||||||
|
ctx.data[1] = uctx->uc_mcontext->__ss.__rbx;
|
||||||
|
ctx.data[2] = uctx->uc_mcontext->__ss.__rcx;
|
||||||
|
ctx.data[3] = uctx->uc_mcontext->__ss.__rdx;
|
||||||
|
ctx.data[4] = uctx->uc_mcontext->__ss.__rdi;
|
||||||
|
ctx.data[5] = uctx->uc_mcontext->__ss.__rsi;
|
||||||
|
ctx.data[6] = uctx->uc_mcontext->__ss.__rbp;
|
||||||
|
ctx.data[7] = uctx->uc_mcontext->__ss.__rsp;
|
||||||
|
ctx.data[8] = uctx->uc_mcontext->__ss.__r8;
|
||||||
|
ctx.data[9] = uctx->uc_mcontext->__ss.__r9;
|
||||||
|
ctx.data[10] = uctx->uc_mcontext->__ss.__r10;
|
||||||
|
ctx.data[11] = uctx->uc_mcontext->__ss.__r11;
|
||||||
|
ctx.data[12] = uctx->uc_mcontext->__ss.__r12;
|
||||||
|
ctx.data[13] = uctx->uc_mcontext->__ss.__r13;
|
||||||
|
ctx.data[14] = uctx->uc_mcontext->__ss.__r14;
|
||||||
|
ctx.data[15] = uctx->uc_mcontext->__ss.__r15;
|
||||||
|
ctx.data[16] = uctx->uc_mcontext->__ss.__rip;
|
||||||
|
|
||||||
|
// If the IP is the same as the crash address we have a bad function
|
||||||
|
// dereference The caller's address is pointed to by %rsp, so we
|
||||||
|
// dereference that value and set it to be the next frame's IP.
|
||||||
|
if (uctx->uc_mcontext->__ss.__rip ==
|
||||||
|
reinterpret_cast<__uint64_t>(error_addr())) {
|
||||||
|
ctx.data[16] =
|
||||||
|
*reinterpret_cast<__uint64_t *>(uctx->uc_mcontext->__ss.__rsp);
|
||||||
|
}
|
||||||
|
_stacktrace[index] = reinterpret_cast<void *>(ctx.data[16]);
|
||||||
|
++index;
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
unw_getcontext(&ctx)
|
||||||
|
// TODO: Convert the ucontext_t to libunwind's unw_context_t like
|
||||||
|
// we do in 64 bits
|
||||||
|
if (ctx.uc_mcontext->__ss.__eip ==
|
||||||
|
reinterpret_cast<greg_t>(error_addr())) {
|
||||||
|
ctx.uc_mcontext->__ss.__eip = ctx.uc_mcontext->__ss.__esp;
|
||||||
|
}
|
||||||
|
_stacktrace[index] =
|
||||||
|
reinterpret_cast<void *>(ctx.uc_mcontext->__ss.__eip);
|
||||||
|
++index;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
unw_cursor_t cursor;
|
||||||
|
if (context()) {
|
||||||
|
#if defined(UNW_INIT_SIGNAL_FRAME)
|
||||||
|
result = unw_init_local2(&cursor, &ctx, UNW_INIT_SIGNAL_FRAME);
|
||||||
|
#else
|
||||||
|
result = unw_init_local(&cursor, &ctx);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
unw_getcontext(&ctx);
|
||||||
|
;
|
||||||
|
result = unw_init_local(&cursor, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
unw_word_t ip = 0;
|
||||||
|
|
||||||
|
while (index <= depth && unw_step(&cursor) > 0) {
|
||||||
|
result = unw_get_reg(&cursor, UNW_REG_IP, &ip);
|
||||||
|
if (result == 0) {
|
||||||
|
_stacktrace[index] = reinterpret_cast<void *>(--ip);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--index;
|
||||||
|
|
||||||
|
_stacktrace.resize(index + 1);
|
||||||
|
skip_n_firsts(0);
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t load_from(void *addr, size_t depth = 32, void *context = nullptr,
|
||||||
|
void *error_addr = nullptr) {
|
||||||
|
load_here(depth + 8, context, error_addr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
||||||
|
if (_stacktrace[i] == addr) {
|
||||||
|
skip_n_firsts(i);
|
||||||
|
_stacktrace[i] = (void *)((uintptr_t)_stacktrace[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_stacktrace.resize(std::min(_stacktrace.size(), skip_n_firsts() + depth));
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#elif defined(BACKWARD_HAS_BACKTRACE)
|
#elif defined(BACKWARD_HAS_BACKTRACE)
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder {
|
class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder {
|
||||||
public:
|
public:
|
||||||
NOINLINE
|
NOINLINE
|
||||||
size_t load_here(size_t depth = 32) {
|
size_t load_here(size_t depth = 32, void *context = nullptr,
|
||||||
|
void *error_addr = nullptr) {
|
||||||
|
set_context(context);
|
||||||
|
set_error_addr(error_addr);
|
||||||
load_thread_info();
|
load_thread_info();
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -859,8 +1093,9 @@ public:
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t load_from(void *addr, size_t depth = 32) {
|
size_t load_from(void *addr, size_t depth = 32, void *context = nullptr,
|
||||||
load_here(depth + 8);
|
void *error_addr = nullptr) {
|
||||||
|
load_here(depth + 8, context, error_addr);
|
||||||
|
|
||||||
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
||||||
if (_stacktrace[i] == addr) {
|
if (_stacktrace[i] == addr) {
|
||||||
|
@ -887,8 +1122,10 @@ public:
|
||||||
void set_thread_handle(HANDLE handle) { thd_ = handle; }
|
void set_thread_handle(HANDLE handle) { thd_ = handle; }
|
||||||
|
|
||||||
NOINLINE
|
NOINLINE
|
||||||
size_t load_here(size_t depth = 32) {
|
size_t load_here(size_t depth = 32, void *context = nullptr,
|
||||||
|
void *error_addr = nullptr) {
|
||||||
|
set_context(static_cast<CONTEXT*>(context));
|
||||||
|
set_error_addr(error_addr);
|
||||||
CONTEXT localCtx; // used when no context is provided
|
CONTEXT localCtx; // used when no context is provided
|
||||||
|
|
||||||
if (depth == 0) {
|
if (depth == 0) {
|
||||||
|
@ -950,8 +1187,9 @@ public:
|
||||||
return size();
|
return size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t load_from(void *addr, size_t depth = 32) {
|
size_t load_from(void *addr, size_t depth = 32, void *context = nullptr,
|
||||||
load_here(depth + 8);
|
void *error_addr = nullptr) {
|
||||||
|
load_here(depth + 8, context, error_addr);
|
||||||
|
|
||||||
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
for (size_t i = 0; i < _stacktrace.size(); ++i) {
|
||||||
if (_stacktrace[i] == addr) {
|
if (_stacktrace[i] == addr) {
|
||||||
|
@ -976,19 +1214,21 @@ private:
|
||||||
|
|
||||||
/*************** TRACE RESOLVER ***************/
|
/*************** TRACE RESOLVER ***************/
|
||||||
|
|
||||||
template <typename TAG> class TraceResolverImpl;
|
|
||||||
|
|
||||||
#ifdef BACKWARD_SYSTEM_UNKNOWN
|
|
||||||
|
|
||||||
template <> class TraceResolverImpl<system_tag::unknown_tag> {
|
|
||||||
public:
|
|
||||||
template <class ST> void load_stacktrace(ST &) {}
|
|
||||||
ResolvedTrace resolve(ResolvedTrace t) { return t; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class TraceResolverImplBase {
|
class TraceResolverImplBase {
|
||||||
|
public:
|
||||||
|
virtual ~TraceResolverImplBase() {}
|
||||||
|
|
||||||
|
virtual void load_addresses(void *const*addresses, int address_count) {
|
||||||
|
(void)addresses;
|
||||||
|
(void)address_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ST> void load_stacktrace(ST &st) {
|
||||||
|
load_addresses(st.begin(), (int)st.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ResolvedTrace resolve(ResolvedTrace t) { return t; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string demangle(const char *funcname) {
|
std::string demangle(const char *funcname) {
|
||||||
return _demangler.demangle(funcname);
|
return _demangler.demangle(funcname);
|
||||||
|
@ -998,6 +1238,15 @@ public:
|
||||||
details::demangler _demangler;
|
details::demangler _demangler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename TAG> class TraceResolverImpl;
|
||||||
|
|
||||||
|
#ifdef BACKWARD_SYSTEM_UNKNOWN
|
||||||
|
|
||||||
|
template <> class TraceResolverImpl<system_tag::unknown_tag>
|
||||||
|
: public TraceResolverImplBase {};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BACKWARD_SYSTEM_LINUX
|
#ifdef BACKWARD_SYSTEM_LINUX
|
||||||
|
|
||||||
class TraceResolverLinuxBase : public TraceResolverImplBase {
|
class TraceResolverLinuxBase : public TraceResolverImplBase {
|
||||||
|
@ -1014,6 +1263,12 @@ public:
|
||||||
// variable; In that case, we actually open /proc/self/exe, which
|
// variable; In that case, we actually open /proc/self/exe, which
|
||||||
// is always the actual executable (even if it was deleted/replaced!)
|
// is always the actual executable (even if it was deleted/replaced!)
|
||||||
// but display the path that /proc/self/exe links to.
|
// but display the path that /proc/self/exe links to.
|
||||||
|
// However, this right away reduces probability of successful symbol
|
||||||
|
// resolution, because libbfd may try to find *.debug files in the
|
||||||
|
// same dir, in case symbols are stripped. As a result, it may try
|
||||||
|
// to find a file /proc/self/<exe_name>.debug, which obviously does
|
||||||
|
// not exist. /proc/self/exe is a last resort. First load attempt
|
||||||
|
// should go for the original executable file path.
|
||||||
symbol_info.dli_fname = "/proc/self/exe";
|
symbol_info.dli_fname = "/proc/self/exe";
|
||||||
return exec_path_;
|
return exec_path_;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1062,15 +1317,14 @@ public:
|
||||||
class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>
|
class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>
|
||||||
: public TraceResolverLinuxBase {
|
: public TraceResolverLinuxBase {
|
||||||
public:
|
public:
|
||||||
template <class ST> void load_stacktrace(ST &st) {
|
void load_addresses(void *const*addresses, int address_count) override {
|
||||||
using namespace details;
|
if (address_count == 0) {
|
||||||
if (st.size() == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_symbols.reset(backtrace_symbols(st.begin(), (int)st.size()));
|
_symbols.reset(backtrace_symbols(addresses, address_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace trace) {
|
ResolvedTrace resolve(ResolvedTrace trace) override {
|
||||||
char *filename = _symbols[trace.idx];
|
char *filename = _symbols[trace.idx];
|
||||||
char *funcname = filename;
|
char *funcname = filename;
|
||||||
while (*funcname && *funcname != '(') {
|
while (*funcname && *funcname != '(') {
|
||||||
|
@ -1107,9 +1361,7 @@ class TraceResolverLinuxImpl<trace_resolver_tag::libbfd>
|
||||||
public:
|
public:
|
||||||
TraceResolverLinuxImpl() : _bfd_loaded(false) {}
|
TraceResolverLinuxImpl() : _bfd_loaded(false) {}
|
||||||
|
|
||||||
template <class ST> void load_stacktrace(ST &) {}
|
ResolvedTrace resolve(ResolvedTrace trace) override {
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace trace) {
|
|
||||||
Dl_info symbol_info;
|
Dl_info symbol_info;
|
||||||
|
|
||||||
// trace.addr is a virtual address in memory pointing to some code.
|
// trace.addr is a virtual address in memory pointing to some code.
|
||||||
|
@ -1139,9 +1391,45 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
trace.object_filename = resolve_exec_path(symbol_info);
|
trace.object_filename = resolve_exec_path(symbol_info);
|
||||||
bfd_fileobject &fobj = load_object_with_bfd(symbol_info.dli_fname);
|
bfd_fileobject *fobj;
|
||||||
if (!fobj.handle) {
|
// Before rushing to resolution need to ensure the executable
|
||||||
return trace; // sad, we couldn't load the object :(
|
// file still can be used. For that compare inode numbers of
|
||||||
|
// what is stored by the executable's file path, and in the
|
||||||
|
// dli_fname, which not necessarily equals to the executable.
|
||||||
|
// It can be a shared library, or /proc/self/exe, and in the
|
||||||
|
// latter case has drawbacks. See the exec path resolution for
|
||||||
|
// details. In short - the dli object should be used only as
|
||||||
|
// the last resort.
|
||||||
|
// If inode numbers are equal, it is known dli_fname and the
|
||||||
|
// executable file are the same. This is guaranteed by Linux,
|
||||||
|
// because if the executable file is changed/deleted, it will
|
||||||
|
// be done in a new inode. The old file will be preserved in
|
||||||
|
// /proc/self/exe, and may even have inode 0. The latter can
|
||||||
|
// happen if the inode was actually reused, and the file was
|
||||||
|
// kept only in the main memory.
|
||||||
|
//
|
||||||
|
struct stat obj_stat;
|
||||||
|
struct stat dli_stat;
|
||||||
|
if (stat(trace.object_filename.c_str(), &obj_stat) == 0 &&
|
||||||
|
stat(symbol_info.dli_fname, &dli_stat) == 0 &&
|
||||||
|
obj_stat.st_ino == dli_stat.st_ino) {
|
||||||
|
// The executable file, and the shared object containing the
|
||||||
|
// address are the same file. Safe to use the original path.
|
||||||
|
// this is preferable. Libbfd will search for stripped debug
|
||||||
|
// symbols in the same directory.
|
||||||
|
fobj = load_object_with_bfd(trace.object_filename);
|
||||||
|
} else{
|
||||||
|
// The original object file was *deleted*! The only hope is
|
||||||
|
// that the debug symbols are either inside the shared
|
||||||
|
// object file, or are in the same directory, and this is
|
||||||
|
// not /proc/self/exe.
|
||||||
|
fobj = nullptr;
|
||||||
|
}
|
||||||
|
if (fobj == nullptr || !fobj->handle) {
|
||||||
|
fobj = load_object_with_bfd(symbol_info.dli_fname);
|
||||||
|
if (!fobj->handle) {
|
||||||
|
return trace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
find_sym_result *details_selected; // to be filled.
|
find_sym_result *details_selected; // to be filled.
|
||||||
|
@ -1276,7 +1564,7 @@ private:
|
||||||
typedef details::hashtable<std::string, bfd_fileobject>::type fobj_bfd_map_t;
|
typedef details::hashtable<std::string, bfd_fileobject>::type fobj_bfd_map_t;
|
||||||
fobj_bfd_map_t _fobj_bfd_map;
|
fobj_bfd_map_t _fobj_bfd_map;
|
||||||
|
|
||||||
bfd_fileobject &load_object_with_bfd(const std::string &filename_object) {
|
bfd_fileobject *load_object_with_bfd(const std::string &filename_object) {
|
||||||
using namespace details;
|
using namespace details;
|
||||||
|
|
||||||
if (!_bfd_loaded) {
|
if (!_bfd_loaded) {
|
||||||
|
@ -1287,11 +1575,11 @@ private:
|
||||||
|
|
||||||
fobj_bfd_map_t::iterator it = _fobj_bfd_map.find(filename_object);
|
fobj_bfd_map_t::iterator it = _fobj_bfd_map.find(filename_object);
|
||||||
if (it != _fobj_bfd_map.end()) {
|
if (it != _fobj_bfd_map.end()) {
|
||||||
return it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this new object is empty for now.
|
// this new object is empty for now.
|
||||||
bfd_fileobject &r = _fobj_bfd_map[filename_object];
|
bfd_fileobject *r = &_fobj_bfd_map[filename_object];
|
||||||
|
|
||||||
// we do the work temporary in this one;
|
// we do the work temporary in this one;
|
||||||
bfd_handle_t bfd_handle;
|
bfd_handle_t bfd_handle;
|
||||||
|
@ -1340,9 +1628,9 @@ private:
|
||||||
return r; // damned, that's a stripped file that you got there!
|
return r; // damned, that's a stripped file that you got there!
|
||||||
}
|
}
|
||||||
|
|
||||||
r.handle = move(bfd_handle);
|
r->handle = move(bfd_handle);
|
||||||
r.symtab = move(symtab);
|
r->symtab = move(symtab);
|
||||||
r.dynamic_symtab = move(dynamic_symtab);
|
r->dynamic_symtab = move(dynamic_symtab);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1361,15 +1649,15 @@ private:
|
||||||
find_sym_result result;
|
find_sym_result result;
|
||||||
};
|
};
|
||||||
|
|
||||||
find_sym_result find_symbol_details(bfd_fileobject &fobj, void *addr,
|
find_sym_result find_symbol_details(bfd_fileobject *fobj, void *addr,
|
||||||
void *base_addr) {
|
void *base_addr) {
|
||||||
find_sym_context context;
|
find_sym_context context;
|
||||||
context.self = this;
|
context.self = this;
|
||||||
context.fobj = &fobj;
|
context.fobj = fobj;
|
||||||
context.addr = addr;
|
context.addr = addr;
|
||||||
context.base_addr = base_addr;
|
context.base_addr = base_addr;
|
||||||
context.result.found = false;
|
context.result.found = false;
|
||||||
bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline,
|
bfd_map_over_sections(fobj->handle.get(), &find_in_section_trampoline,
|
||||||
static_cast<void *>(&context));
|
static_cast<void *>(&context));
|
||||||
return context.result;
|
return context.result;
|
||||||
}
|
}
|
||||||
|
@ -1378,24 +1666,24 @@ private:
|
||||||
find_sym_context *context = static_cast<find_sym_context *>(data);
|
find_sym_context *context = static_cast<find_sym_context *>(data);
|
||||||
context->self->find_in_section(
|
context->self->find_in_section(
|
||||||
reinterpret_cast<bfd_vma>(context->addr),
|
reinterpret_cast<bfd_vma>(context->addr),
|
||||||
reinterpret_cast<bfd_vma>(context->base_addr), *context->fobj, section,
|
reinterpret_cast<bfd_vma>(context->base_addr), context->fobj, section,
|
||||||
context->result);
|
context->result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void find_in_section(bfd_vma addr, bfd_vma base_addr, bfd_fileobject &fobj,
|
void find_in_section(bfd_vma addr, bfd_vma base_addr, bfd_fileobject *fobj,
|
||||||
asection *section, find_sym_result &result) {
|
asection *section, find_sym_result &result) {
|
||||||
if (result.found)
|
if (result.found)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#ifdef bfd_get_section_flags
|
#ifdef bfd_get_section_flags
|
||||||
if ((bfd_get_section_flags(fobj.handle.get(), section) & SEC_ALLOC) == 0)
|
if ((bfd_get_section_flags(fobj->handle.get(), section) & SEC_ALLOC) == 0)
|
||||||
#else
|
#else
|
||||||
if ((bfd_section_flags(section) & SEC_ALLOC) == 0)
|
if ((bfd_section_flags(section) & SEC_ALLOC) == 0)
|
||||||
#endif
|
#endif
|
||||||
return; // a debug section is never loaded automatically.
|
return; // a debug section is never loaded automatically.
|
||||||
|
|
||||||
#ifdef bfd_get_section_vma
|
#ifdef bfd_get_section_vma
|
||||||
bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section);
|
bfd_vma sec_addr = bfd_get_section_vma(fobj->handle.get(), section);
|
||||||
#else
|
#else
|
||||||
bfd_vma sec_addr = bfd_section_vma(section);
|
bfd_vma sec_addr = bfd_section_vma(section);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1417,15 +1705,15 @@ private:
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
|
||||||
#endif
|
#endif
|
||||||
if (!result.found && fobj.symtab) {
|
if (!result.found && fobj->symtab) {
|
||||||
result.found = bfd_find_nearest_line(
|
result.found = bfd_find_nearest_line(
|
||||||
fobj.handle.get(), section, fobj.symtab.get(), addr - sec_addr,
|
fobj->handle.get(), section, fobj->symtab.get(), addr - sec_addr,
|
||||||
&result.filename, &result.funcname, &result.line);
|
&result.filename, &result.funcname, &result.line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.found && fobj.dynamic_symtab) {
|
if (!result.found && fobj->dynamic_symtab) {
|
||||||
result.found = bfd_find_nearest_line(
|
result.found = bfd_find_nearest_line(
|
||||||
fobj.handle.get(), section, fobj.dynamic_symtab.get(),
|
fobj->handle.get(), section, fobj->dynamic_symtab.get(),
|
||||||
addr - sec_addr, &result.filename, &result.funcname, &result.line);
|
addr - sec_addr, &result.filename, &result.funcname, &result.line);
|
||||||
}
|
}
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
|
@ -1434,13 +1722,13 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedTrace::source_locs_t
|
ResolvedTrace::source_locs_t
|
||||||
backtrace_inliners(bfd_fileobject &fobj, find_sym_result previous_result) {
|
backtrace_inliners(bfd_fileobject *fobj, find_sym_result previous_result) {
|
||||||
// This function can be called ONLY after a SUCCESSFUL call to
|
// This function can be called ONLY after a SUCCESSFUL call to
|
||||||
// find_symbol_details. The state is global to the bfd_handle.
|
// find_symbol_details. The state is global to the bfd_handle.
|
||||||
ResolvedTrace::source_locs_t results;
|
ResolvedTrace::source_locs_t results;
|
||||||
while (previous_result.found) {
|
while (previous_result.found) {
|
||||||
find_sym_result result;
|
find_sym_result result;
|
||||||
result.found = bfd_find_inliner_info(fobj.handle.get(), &result.filename,
|
result.found = bfd_find_inliner_info(fobj->handle.get(), &result.filename,
|
||||||
&result.funcname, &result.line);
|
&result.funcname, &result.line);
|
||||||
|
|
||||||
if (result
|
if (result
|
||||||
|
@ -1483,9 +1771,7 @@ class TraceResolverLinuxImpl<trace_resolver_tag::libdw>
|
||||||
public:
|
public:
|
||||||
TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {}
|
TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {}
|
||||||
|
|
||||||
template <class ST> void load_stacktrace(ST &) {}
|
ResolvedTrace resolve(ResolvedTrace trace) override {
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace trace) {
|
|
||||||
using namespace details;
|
using namespace details;
|
||||||
|
|
||||||
Dwarf_Addr trace_addr = (Dwarf_Addr)trace.addr;
|
Dwarf_Addr trace_addr = (Dwarf_Addr)trace.addr;
|
||||||
|
@ -1778,9 +2064,9 @@ private:
|
||||||
|
|
||||||
static const char *die_call_file(Dwarf_Die *die) {
|
static const char *die_call_file(Dwarf_Die *die) {
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Sword file_idx = 0;
|
Dwarf_Word file_idx = 0;
|
||||||
|
|
||||||
dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx);
|
dwarf_formudata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx);
|
||||||
|
|
||||||
if (file_idx == 0) {
|
if (file_idx == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1812,9 +2098,7 @@ class TraceResolverLinuxImpl<trace_resolver_tag::libdwarf>
|
||||||
public:
|
public:
|
||||||
TraceResolverLinuxImpl() : _dwarf_loaded(false) {}
|
TraceResolverLinuxImpl() : _dwarf_loaded(false) {}
|
||||||
|
|
||||||
template <class ST> void load_stacktrace(ST &) {}
|
ResolvedTrace resolve(ResolvedTrace trace) override {
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace trace) {
|
|
||||||
// trace.addr is a virtual address in memory pointing to some code.
|
// trace.addr is a virtual address in memory pointing to some code.
|
||||||
// Let's try to find from which loaded object it comes from.
|
// Let's try to find from which loaded object it comes from.
|
||||||
// The loaded object can be yourself btw.
|
// The loaded object can be yourself btw.
|
||||||
|
@ -3038,12 +3322,12 @@ private:
|
||||||
Dwarf_Die cu_die) {
|
Dwarf_Die cu_die) {
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Error error = DW_DLE_NE;
|
Dwarf_Error error = DW_DLE_NE;
|
||||||
Dwarf_Signed file_index;
|
Dwarf_Unsigned file_index;
|
||||||
|
|
||||||
std::string file;
|
std::string file;
|
||||||
|
|
||||||
if (dwarf_attr(die, DW_AT_call_file, &attr_mem, &error) == DW_DLV_OK) {
|
if (dwarf_attr(die, DW_AT_call_file, &attr_mem, &error) == DW_DLV_OK) {
|
||||||
if (dwarf_formsdata(attr_mem, &file_index, &error) != DW_DLV_OK) {
|
if (dwarf_formudata(attr_mem, &file_index, &error) != DW_DLV_OK) {
|
||||||
file_index = 0;
|
file_index = 0;
|
||||||
}
|
}
|
||||||
dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR);
|
dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR);
|
||||||
|
@ -3055,8 +3339,9 @@ private:
|
||||||
char **srcfiles = 0;
|
char **srcfiles = 0;
|
||||||
Dwarf_Signed file_count = 0;
|
Dwarf_Signed file_count = 0;
|
||||||
if (dwarf_srcfiles(cu_die, &srcfiles, &file_count, &error) == DW_DLV_OK) {
|
if (dwarf_srcfiles(cu_die, &srcfiles, &file_count, &error) == DW_DLV_OK) {
|
||||||
if (file_index <= file_count)
|
if (file_count > 0 && file_index <= static_cast<Dwarf_Unsigned>(file_count)) {
|
||||||
file = std::string(srcfiles[file_index - 1]);
|
file = std::string(srcfiles[file_index - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
// Deallocate all strings!
|
// Deallocate all strings!
|
||||||
for (int i = 0; i < file_count; ++i) {
|
for (int i = 0; i < file_count; ++i) {
|
||||||
|
@ -3193,15 +3478,14 @@ template <>
|
||||||
class TraceResolverDarwinImpl<trace_resolver_tag::backtrace_symbol>
|
class TraceResolverDarwinImpl<trace_resolver_tag::backtrace_symbol>
|
||||||
: public TraceResolverImplBase {
|
: public TraceResolverImplBase {
|
||||||
public:
|
public:
|
||||||
template <class ST> void load_stacktrace(ST &st) {
|
void load_addresses(void *const*addresses, int address_count) override {
|
||||||
using namespace details;
|
if (address_count == 0) {
|
||||||
if (st.size() == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_symbols.reset(backtrace_symbols(st.begin(), st.size()));
|
_symbols.reset(backtrace_symbols(addresses, address_count));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace trace) {
|
ResolvedTrace resolve(ResolvedTrace trace) override {
|
||||||
// parse:
|
// parse:
|
||||||
// <n> <file> <addr> <mangled-name> + <offset>
|
// <n> <file> <addr> <mangled-name> + <offset>
|
||||||
char *filename = _symbols[trace.idx];
|
char *filename = _symbols[trace.idx];
|
||||||
|
@ -3299,9 +3583,9 @@ public:
|
||||||
ret.base_address = mi.lpBaseOfDll;
|
ret.base_address = mi.lpBaseOfDll;
|
||||||
ret.load_size = mi.SizeOfImage;
|
ret.load_size = mi.SizeOfImage;
|
||||||
|
|
||||||
GetModuleFileNameEx(process, module, temp, sizeof(temp));
|
GetModuleFileNameExA(process, module, temp, sizeof(temp));
|
||||||
ret.image_name = temp;
|
ret.image_name = temp;
|
||||||
GetModuleBaseName(process, module, temp, sizeof(temp));
|
GetModuleBaseNameA(process, module, temp, sizeof(temp));
|
||||||
ret.module_name = temp;
|
ret.module_name = temp;
|
||||||
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
|
std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
|
||||||
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
|
std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
|
||||||
|
@ -3311,7 +3595,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> class TraceResolverImpl<system_tag::windows_tag> {
|
template <> class TraceResolverImpl<system_tag::windows_tag>
|
||||||
|
: public TraceResolverImplBase {
|
||||||
public:
|
public:
|
||||||
TraceResolverImpl() {
|
TraceResolverImpl() {
|
||||||
|
|
||||||
|
@ -3336,8 +3621,6 @@ public:
|
||||||
image_type = h->FileHeader.Machine;
|
image_type = h->FileHeader.Machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ST> void load_stacktrace(ST &) {}
|
|
||||||
|
|
||||||
static const int max_sym_len = 255;
|
static const int max_sym_len = 255;
|
||||||
struct symbol_t {
|
struct symbol_t {
|
||||||
SYMBOL_INFO sym;
|
SYMBOL_INFO sym;
|
||||||
|
@ -3346,27 +3629,28 @@ public:
|
||||||
|
|
||||||
DWORD64 displacement;
|
DWORD64 displacement;
|
||||||
|
|
||||||
ResolvedTrace resolve(ResolvedTrace t) {
|
ResolvedTrace resolve(ResolvedTrace t) override {
|
||||||
HANDLE process = GetCurrentProcess();
|
HANDLE process = GetCurrentProcess();
|
||||||
|
|
||||||
char name[256];
|
char name[256];
|
||||||
|
|
||||||
memset(&sym, 0, sizeof sym);
|
memset(&sym, 0, sizeof(sym));
|
||||||
sym.sym.SizeOfStruct = sizeof(SYMBOL_INFO);
|
sym.sym.SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
sym.sym.MaxNameLen = max_sym_len;
|
sym.sym.MaxNameLen = max_sym_len;
|
||||||
|
|
||||||
if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) {
|
if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) {
|
||||||
// TODO: error handling everywhere
|
// TODO: error handling everywhere
|
||||||
LPTSTR lpMsgBuf;
|
char* lpMsgBuf;
|
||||||
DWORD dw = GetLastError();
|
DWORD dw = GetLastError();
|
||||||
|
|
||||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
(char*)&lpMsgBuf, 0, NULL)) {
|
||||||
|
std::fprintf(stderr, "%s\n", lpMsgBuf);
|
||||||
printf(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
|
}
|
||||||
|
|
||||||
// abort();
|
// abort();
|
||||||
}
|
}
|
||||||
|
@ -3605,7 +3889,7 @@ private:
|
||||||
cfile_streambuf(FILE *_sink) : sink(_sink) {}
|
cfile_streambuf(FILE *_sink) : sink(_sink) {}
|
||||||
int_type underflow() override { return traits_type::eof(); }
|
int_type underflow() override { return traits_type::eof(); }
|
||||||
int_type overflow(int_type ch) override {
|
int_type overflow(int_type ch) override {
|
||||||
if (traits_type::not_eof(ch) && fwrite(&ch, sizeof ch, 1, sink) == 1) {
|
if (traits_type::not_eof(ch) && fputc(ch, sink) != EOF) {
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
return traits_type::eof();
|
return traits_type::eof();
|
||||||
|
@ -3928,13 +4212,19 @@ public:
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.arm_pc);
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.arm_pc);
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext->__ss.__pc);
|
||||||
|
#else
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc);
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc);
|
||||||
|
#endif
|
||||||
#elif defined(__mips__)
|
#elif defined(__mips__)
|
||||||
error_addr = reinterpret_cast<void *>(
|
error_addr = reinterpret_cast<void *>(
|
||||||
reinterpret_cast<struct sigcontext *>(&uctx->uc_mcontext)->sc_pc);
|
reinterpret_cast<struct sigcontext *>(&uctx->uc_mcontext)->sc_pc);
|
||||||
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \
|
#elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \
|
||||||
defined(__POWERPC__)
|
defined(__POWERPC__)
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.regs->nip);
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.regs->nip);
|
||||||
|
#elif defined(__riscv)
|
||||||
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.__gregs[REG_PC]);
|
||||||
#elif defined(__s390x__)
|
#elif defined(__s390x__)
|
||||||
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.psw.addr);
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.psw.addr);
|
||||||
#elif defined(__APPLE__) && defined(__x86_64__)
|
#elif defined(__APPLE__) && defined(__x86_64__)
|
||||||
|
@ -3945,9 +4235,10 @@ public:
|
||||||
#warning ":/ sorry, ain't know no nothing none not of your architecture!"
|
#warning ":/ sorry, ain't know no nothing none not of your architecture!"
|
||||||
#endif
|
#endif
|
||||||
if (error_addr) {
|
if (error_addr) {
|
||||||
st.load_from(error_addr, 32);
|
st.load_from(error_addr, 32, reinterpret_cast<void *>(uctx),
|
||||||
|
info->si_addr);
|
||||||
} else {
|
} else {
|
||||||
st.load_here(32);
|
st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Printer printer;
|
Printer printer;
|
||||||
|
@ -4016,7 +4307,9 @@ public:
|
||||||
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
||||||
|
|
||||||
std::set_terminate(&terminator);
|
std::set_terminate(&terminator);
|
||||||
|
#ifndef BACKWARD_ATLEAST_CXX17
|
||||||
std::set_unexpected(&terminator);
|
std::set_unexpected(&terminator);
|
||||||
|
#endif
|
||||||
_set_purecall_handler(&terminator);
|
_set_purecall_handler(&terminator);
|
||||||
_set_invalid_parameter_handler(&invalid_parameter_handler);
|
_set_invalid_parameter_handler(&invalid_parameter_handler);
|
||||||
}
|
}
|
||||||
|
@ -4144,9 +4437,8 @@ private:
|
||||||
|
|
||||||
StackTrace st;
|
StackTrace st;
|
||||||
st.set_machine_type(printer.resolver().machine_type());
|
st.set_machine_type(printer.resolver().machine_type());
|
||||||
st.set_context(ctx());
|
|
||||||
st.set_thread_handle(thread_handle());
|
st.set_thread_handle(thread_handle());
|
||||||
st.load_here(32 + skip_frames);
|
st.load_here(32 + skip_frames, ctx());
|
||||||
st.skip_n_firsts(skip_frames);
|
st.skip_n_firsts(skip_frames);
|
||||||
|
|
||||||
printer.address = true;
|
printer.address = true;
|
||||||
|
|
Loading…
Reference in New Issue