#ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE #include #include "symbols/symbols.hpp" #include "platform/program_name.hpp" #include "utils/error.hpp" #include "utils/common.hpp" #include #include #include #include #include #include #ifdef CPPTRACE_BACKTRACE_PATH #include CPPTRACE_BACKTRACE_PATH #else #include #endif namespace cpptrace { namespace detail { namespace libbacktrace { int full_callback(void* data, std::uintptr_t address, const char* file, int line, const char* symbol) { stacktrace_frame& frame = *static_cast(data); frame.raw_address = address; frame.line = line; frame.filename = file ? file : ""; frame.symbol = symbol ? symbol : ""; return 0; } void syminfo_callback(void* data, std::uintptr_t address, const char* symbol, std::uintptr_t, std::uintptr_t) { stacktrace_frame& frame = *static_cast(data); frame.raw_address = address; frame.line = 0; frame.filename = ""; frame.symbol = symbol ? symbol : ""; } void error_callback(void*, const char* msg, int errnum) { if(msg == std::string("no debug info in ELF executable")) { // https://github.com/jeremy-rifkin/cpptrace/issues/114 // https://github.com/ianlancetaylor/libbacktrace/blob/ae1e707dbacd4a5cc82fcf2d3816f410e9c5fec4/elf.c#L592 // not a critical error, just return return; } throw internal_error("Libbacktrace error: {}, code {}", msg, errnum); } backtrace_state* get_backtrace_state() { static std::mutex mutex; const std::lock_guard lock(mutex); // backtrace_create_state must be called only one time per program static backtrace_state* state = nullptr; static bool called = false; if(!called) { state = backtrace_create_state(program_name(), true, error_callback, nullptr); called = true; } return state; } // TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions stacktrace_frame resolve_frame(const frame_ptr addr) { try { stacktrace_frame frame = null_frame; frame.raw_address = addr; backtrace_pcinfo( get_backtrace_state(), addr, full_callback, error_callback, &frame ); if(frame.symbol.empty()) { // fallback, try to at least recover the symbol name with backtrace_syminfo backtrace_syminfo( get_backtrace_state(), addr, syminfo_callback, error_callback, &frame ); } return frame; } catch(...) { // NOSONAR if(!should_absorb_trace_exceptions()) { throw; } return null_frame; } } std::vector resolve_frames(const std::vector& frames) { std::vector trace; trace.reserve(frames.size()); for(const auto frame : frames) { trace.push_back(resolve_frame(frame)); } return trace; } } } } #endif