|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
#if defined(PROJECT_ENABLE_BACKWARD_CPP)
|
|
|
|
|
/*
|
|
|
|
|
* backward.hpp
|
|
|
|
|
* Copyright 2013 Google Inc. All Rights Reserved.
|
|
|
|
@ -81,17 +82,17 @@
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
#include <exception>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <iomanip>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <new>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <streambuf>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <exception>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
|
|
|
|
|
#if defined(BACKWARD_SYSTEM_LINUX)
|
|
|
|
|
|
|
|
|
@ -507,11 +508,17 @@ typedef pdb_symbol current;
|
|
|
|
|
|
|
|
|
|
namespace details {
|
|
|
|
|
|
|
|
|
|
template <typename T> struct rm_ptr { typedef T type; };
|
|
|
|
|
template <typename T> struct rm_ptr {
|
|
|
|
|
typedef T type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T> struct rm_ptr<T *> { typedef T type; };
|
|
|
|
|
template <typename T> struct rm_ptr<T *> {
|
|
|
|
|
typedef T type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T> struct rm_ptr<const T *> { typedef const T type; };
|
|
|
|
|
template <typename T> struct rm_ptr<const T *> {
|
|
|
|
|
typedef const T type;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename R, typename T, R (*F)(T)> struct deleter {
|
|
|
|
|
template <typename U> void operator()(U &ptr) const { (*F)(ptr); }
|
|
|
|
@ -521,7 +528,7 @@ template <typename T> struct default_delete {
|
|
|
|
|
void operator()(T &ptr) const { delete ptr; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T, typename Deleter = deleter<void, void *, &::free> >
|
|
|
|
|
template <typename T, typename Deleter = deleter<void, void *, &::free>>
|
|
|
|
|
class handle {
|
|
|
|
|
struct dummy;
|
|
|
|
|
T _val;
|
|
|
|
@ -1134,7 +1141,7 @@ public:
|
|
|
|
|
NOINLINE
|
|
|
|
|
size_t load_here(size_t depth = 32, void *context = nullptr,
|
|
|
|
|
void *error_addr = nullptr) {
|
|
|
|
|
set_context(static_cast<CONTEXT*>(context));
|
|
|
|
|
set_context(static_cast<CONTEXT *>(context));
|
|
|
|
|
set_error_addr(error_addr);
|
|
|
|
|
CONTEXT localCtx; // used when no context is provided
|
|
|
|
|
|
|
|
|
@ -1228,7 +1235,7 @@ class TraceResolverImplBase {
|
|
|
|
|
public:
|
|
|
|
|
virtual ~TraceResolverImplBase() {}
|
|
|
|
|
|
|
|
|
|
virtual void load_addresses(void *const*addresses, int address_count) {
|
|
|
|
|
virtual void load_addresses(void *const *addresses, int address_count) {
|
|
|
|
|
(void)addresses;
|
|
|
|
|
(void)address_count;
|
|
|
|
|
}
|
|
|
|
@ -1252,7 +1259,8 @@ template <typename TAG> class TraceResolverImpl;
|
|
|
|
|
|
|
|
|
|
#ifdef BACKWARD_SYSTEM_UNKNOWN
|
|
|
|
|
|
|
|
|
|
template <> class TraceResolverImpl<system_tag::unknown_tag>
|
|
|
|
|
template <>
|
|
|
|
|
class TraceResolverImpl<system_tag::unknown_tag>
|
|
|
|
|
: public TraceResolverImplBase {};
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
@ -1327,7 +1335,7 @@ template <>
|
|
|
|
|
class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol>
|
|
|
|
|
: public TraceResolverLinuxBase {
|
|
|
|
|
public:
|
|
|
|
|
void load_addresses(void *const*addresses, int address_count) override {
|
|
|
|
|
void load_addresses(void *const *addresses, int address_count) override {
|
|
|
|
|
if (address_count == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -1428,7 +1436,7 @@ public:
|
|
|
|
|
// this is preferable. Libbfd will search for stripped debug
|
|
|
|
|
// symbols in the same directory.
|
|
|
|
|
fobj = load_object_with_bfd(trace.object_filename);
|
|
|
|
|
} else{
|
|
|
|
|
} 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
|
|
|
|
@ -1559,7 +1567,7 @@ private:
|
|
|
|
|
bool _bfd_loaded;
|
|
|
|
|
|
|
|
|
|
typedef details::handle<bfd *,
|
|
|
|
|
details::deleter<bfd_boolean, bfd *, &bfd_close> >
|
|
|
|
|
details::deleter<bfd_boolean, bfd *, &bfd_close>>
|
|
|
|
|
bfd_handle_t;
|
|
|
|
|
|
|
|
|
|
typedef details::handle<asymbol **> bfd_symtab_t;
|
|
|
|
@ -1867,7 +1875,7 @@ public:
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//#define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
|
|
|
|
|
// #define BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
|
|
|
|
|
#ifdef BACKWARD_I_DO_NOT_RECOMMEND_TO_ENABLE_THIS_HORRIBLE_PIECE_OF_CODE
|
|
|
|
|
if (!cudie) {
|
|
|
|
|
// If it's still not enough, lets dive deeper in the shit, and try
|
|
|
|
@ -1931,9 +1939,9 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
typedef details::handle<Dwfl *, details::deleter<void, Dwfl *, &dwfl_end> >
|
|
|
|
|
typedef details::handle<Dwfl *, details::deleter<void, Dwfl *, &dwfl_end>>
|
|
|
|
|
dwfl_handle_t;
|
|
|
|
|
details::handle<Dwfl_Callbacks *, details::default_delete<Dwfl_Callbacks *> >
|
|
|
|
|
details::handle<Dwfl_Callbacks *, details::default_delete<Dwfl_Callbacks *>>
|
|
|
|
|
_dwfl_cb;
|
|
|
|
|
dwfl_handle_t _dwfl_handle;
|
|
|
|
|
bool _dwfl_handle_initialized;
|
|
|
|
@ -2255,14 +2263,14 @@ public:
|
|
|
|
|
private:
|
|
|
|
|
bool _dwarf_loaded;
|
|
|
|
|
|
|
|
|
|
typedef details::handle<int, details::deleter<int, int, &::close> >
|
|
|
|
|
typedef details::handle<int, details::deleter<int, int, &::close>>
|
|
|
|
|
dwarf_file_t;
|
|
|
|
|
|
|
|
|
|
typedef details::handle<Elf *, details::deleter<int, Elf *, &elf_end> >
|
|
|
|
|
typedef details::handle<Elf *, details::deleter<int, Elf *, &elf_end>>
|
|
|
|
|
dwarf_elf_t;
|
|
|
|
|
|
|
|
|
|
typedef details::handle<Dwarf_Debug,
|
|
|
|
|
details::deleter<int, Dwarf_Debug, &close_dwarf> >
|
|
|
|
|
details::deleter<int, Dwarf_Debug, &close_dwarf>>
|
|
|
|
|
dwarf_handle_t;
|
|
|
|
|
|
|
|
|
|
typedef std::map<Dwarf_Addr, int> die_linemap_t;
|
|
|
|
@ -3349,7 +3357,8 @@ private:
|
|
|
|
|
char **srcfiles = 0;
|
|
|
|
|
Dwarf_Signed file_count = 0;
|
|
|
|
|
if (dwarf_srcfiles(cu_die, &srcfiles, &file_count, &error) == DW_DLV_OK) {
|
|
|
|
|
if (file_count > 0 && file_index <= static_cast<Dwarf_Unsigned>(file_count)) {
|
|
|
|
|
if (file_count > 0 &&
|
|
|
|
|
file_index <= static_cast<Dwarf_Unsigned>(file_count)) {
|
|
|
|
|
file = std::string(srcfiles[file_index - 1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3488,7 +3497,7 @@ template <>
|
|
|
|
|
class TraceResolverDarwinImpl<trace_resolver_tag::backtrace_symbol>
|
|
|
|
|
: public TraceResolverImplBase {
|
|
|
|
|
public:
|
|
|
|
|
void load_addresses(void *const*addresses, int address_count) override {
|
|
|
|
|
void load_addresses(void *const *addresses, int address_count) override {
|
|
|
|
|
if (address_count == 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -3605,7 +3614,8 @@ public:
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <> class TraceResolverImpl<system_tag::windows_tag>
|
|
|
|
|
template <>
|
|
|
|
|
class TraceResolverImpl<system_tag::windows_tag>
|
|
|
|
|
: public TraceResolverImplBase {
|
|
|
|
|
public:
|
|
|
|
|
TraceResolverImpl() {
|
|
|
|
@ -3619,13 +3629,13 @@ public:
|
|
|
|
|
DWORD symOptions = SymGetOptions();
|
|
|
|
|
symOptions |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME;
|
|
|
|
|
SymSetOptions(symOptions);
|
|
|
|
|
EnumProcessModules(process, &module_handles[0],
|
|
|
|
|
static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)),
|
|
|
|
|
&cbNeeded);
|
|
|
|
|
EnumProcessModules(
|
|
|
|
|
process, &module_handles[0],
|
|
|
|
|
static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)), &cbNeeded);
|
|
|
|
|
module_handles.resize(cbNeeded / sizeof(HMODULE));
|
|
|
|
|
EnumProcessModules(process, &module_handles[0],
|
|
|
|
|
static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)),
|
|
|
|
|
&cbNeeded);
|
|
|
|
|
EnumProcessModules(
|
|
|
|
|
process, &module_handles[0],
|
|
|
|
|
static_cast<DWORD>(module_handles.size() * sizeof(HMODULE)), &cbNeeded);
|
|
|
|
|
std::transform(module_handles.begin(), module_handles.end(),
|
|
|
|
|
std::back_inserter(modules), get_mod_info(process));
|
|
|
|
|
void *base = modules[0].base_address;
|
|
|
|
@ -3652,14 +3662,14 @@ public:
|
|
|
|
|
|
|
|
|
|
if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) {
|
|
|
|
|
// TODO: error handling everywhere
|
|
|
|
|
char* lpMsgBuf;
|
|
|
|
|
char *lpMsgBuf;
|
|
|
|
|
DWORD dw = GetLastError();
|
|
|
|
|
|
|
|
|
|
if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
|
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
|
(char*)&lpMsgBuf, 0, NULL)) {
|
|
|
|
|
(char *)&lpMsgBuf, 0, NULL)) {
|
|
|
|
|
std::fprintf(stderr, "%s\n", lpMsgBuf);
|
|
|
|
|
LocalFree(lpMsgBuf);
|
|
|
|
|
}
|
|
|
|
@ -3698,7 +3708,7 @@ class TraceResolver : public TraceResolverImpl<system_tag::current_tag> {};
|
|
|
|
|
|
|
|
|
|
class SourceFile {
|
|
|
|
|
public:
|
|
|
|
|
typedef std::vector<std::pair<unsigned, std::string> > lines_t;
|
|
|
|
|
typedef std::vector<std::pair<unsigned, std::string>> lines_t;
|
|
|
|
|
|
|
|
|
|
SourceFile() {}
|
|
|
|
|
SourceFile(const std::string &path) {
|
|
|
|
@ -3809,15 +3819,16 @@ public:
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Allow adding to paths gotten from BACKWARD_CXX_SOURCE_PREFIXES after loading the
|
|
|
|
|
// library; this can be useful when the library is loaded when the locations are unknown
|
|
|
|
|
// Warning: Because this edits the static paths variable, it is *not* intrinsiclly thread safe
|
|
|
|
|
static void add_paths_to_env_variable_impl(const std::string & to_add) {
|
|
|
|
|
// Allow adding to paths gotten from BACKWARD_CXX_SOURCE_PREFIXES after
|
|
|
|
|
// loading the library; this can be useful when the library is loaded when the
|
|
|
|
|
// locations are unknown Warning: Because this edits the static paths
|
|
|
|
|
// variable, it is *not* intrinsiclly thread safe
|
|
|
|
|
static void add_paths_to_env_variable_impl(const std::string &to_add) {
|
|
|
|
|
get_mutable_paths_from_env_variable().push_back(to_add);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
details::handle<std::ifstream *, details::default_delete<std::ifstream *> >
|
|
|
|
|
details::handle<std::ifstream *, details::default_delete<std::ifstream *>>
|
|
|
|
|
_file;
|
|
|
|
|
|
|
|
|
|
static std::vector<std::string> get_paths_from_env_variable_impl() {
|
|
|
|
@ -3830,8 +3841,9 @@ private:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::vector<std::string> &get_mutable_paths_from_env_variable() {
|
|
|
|
|
static volatile std::vector<std::string> paths = get_paths_from_env_variable_impl();
|
|
|
|
|
return const_cast<std::vector<std::string>&>(paths);
|
|
|
|
|
static volatile std::vector<std::string> paths =
|
|
|
|
|
get_paths_from_env_variable_impl();
|
|
|
|
|
return const_cast<std::vector<std::string> &>(paths);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const std::vector<std::string> &get_paths_from_env_variable() {
|
|
|
|
@ -4055,7 +4067,7 @@ private:
|
|
|
|
|
void print_stacktrace(ST &st, std::ostream &os, Colorize &colorize) {
|
|
|
|
|
print_header(os, st.thread_id());
|
|
|
|
|
_resolver.load_stacktrace(st);
|
|
|
|
|
if ( reverse ) {
|
|
|
|
|
if (reverse) {
|
|
|
|
|
for (size_t trace_idx = st.size(); trace_idx > 0; --trace_idx) {
|
|
|
|
|
print_trace(os, _resolver.resolve(st[trace_idx - 1]), colorize);
|
|
|
|
|
}
|
|
|
|
@ -4243,11 +4255,11 @@ public:
|
|
|
|
|
#elif defined(__arm__)
|
|
|
|
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.arm_pc);
|
|
|
|
|
#elif defined(__aarch64__)
|
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
|
#if defined(__APPLE__)
|
|
|
|
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext->__ss.__pc);
|
|
|
|
|
#else
|
|
|
|
|
#else
|
|
|
|
|
error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc);
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
#elif defined(__mips__)
|
|
|
|
|
error_addr = reinterpret_cast<void *>(
|
|
|
|
|
reinterpret_cast<struct sigcontext *>(&uctx->uc_mcontext)->sc_pc);
|
|
|
|
@ -4494,3 +4506,4 @@ public:
|
|
|
|
|
} // namespace backward
|
|
|
|
|
|
|
|
|
|
#endif /* H_GUARD */
|
|
|
|
|
#endif // defined(PROJECT_ENABLE_BACKWARD_CPP)
|