[2573] | 1 | #ifdef CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE |
---|
| 2 | |
---|
| 3 | #include "cpptrace.hpp" |
---|
| 4 | #include "symbols.hpp" |
---|
| 5 | #include "program_name.hpp" |
---|
| 6 | |
---|
| 7 | #include <cstdint> |
---|
| 8 | #include <cstdio> |
---|
| 9 | #include <memory> |
---|
| 10 | #include <mutex> |
---|
| 11 | #include <vector> |
---|
| 12 | |
---|
| 13 | #ifdef CPPTRACE_BACKTRACE_PATH |
---|
| 14 | #include CPPTRACE_BACKTRACE_PATH |
---|
| 15 | #else |
---|
| 16 | #include <backtrace.h> |
---|
| 17 | #endif |
---|
| 18 | |
---|
| 19 | namespace cpptrace { |
---|
| 20 | namespace detail { |
---|
| 21 | namespace libbacktrace { |
---|
| 22 | int full_callback(void* data, uintptr_t address, const char* file, int line, const char* symbol) { |
---|
| 23 | stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data); |
---|
| 24 | if(line == 0) { |
---|
| 25 | ///fprintf(stderr, "Getting bad data for some reason\n"); // TODO: Eliminate |
---|
| 26 | } |
---|
| 27 | frame.address = address; |
---|
| 28 | frame.line = line; |
---|
| 29 | frame.filename = file ? file : ""; |
---|
| 30 | frame.symbol = symbol ? symbol : ""; |
---|
| 31 | return 0; |
---|
| 32 | } |
---|
| 33 | |
---|
| 34 | void syminfo_callback(void* data, uintptr_t address, const char* symbol, uintptr_t, uintptr_t) { |
---|
| 35 | stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data); |
---|
| 36 | frame.address = address; |
---|
| 37 | frame.line = 0; |
---|
| 38 | frame.filename = ""; |
---|
| 39 | frame.symbol = symbol ? symbol : ""; |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | void error_callback(void*, const char* msg, int errnum) { |
---|
| 43 | fprintf(stderr, "Libbacktrace error: %s, code %d\n", msg, errnum); |
---|
| 44 | } |
---|
| 45 | |
---|
| 46 | backtrace_state* get_backtrace_state() { |
---|
| 47 | static std::mutex mutex; |
---|
| 48 | const std::lock_guard<std::mutex> lock(mutex); |
---|
| 49 | // backtrace_create_state must be called only one time per program |
---|
| 50 | // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) |
---|
| 51 | static backtrace_state* state = nullptr; |
---|
| 52 | static bool called = false; |
---|
| 53 | if(!called) { |
---|
| 54 | state = backtrace_create_state(program_name(), true, error_callback, nullptr); |
---|
| 55 | called = true; |
---|
| 56 | } |
---|
| 57 | return state; |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | // TODO: Handle backtrace_pcinfo calling the callback multiple times on inlined functions |
---|
| 61 | stacktrace_frame resolve_frame(const void* addr) { |
---|
| 62 | stacktrace_frame frame; |
---|
| 63 | frame.col = 0; |
---|
| 64 | backtrace_pcinfo( |
---|
| 65 | get_backtrace_state(), |
---|
| 66 | reinterpret_cast<uintptr_t>(addr), |
---|
| 67 | full_callback, |
---|
| 68 | error_callback, |
---|
| 69 | &frame |
---|
| 70 | ); |
---|
| 71 | if(frame.symbol.empty()) { |
---|
| 72 | // fallback, try to at least recover the symbol name with backtrace_syminfo |
---|
| 73 | backtrace_syminfo( |
---|
| 74 | get_backtrace_state(), |
---|
| 75 | reinterpret_cast<uintptr_t>(addr), |
---|
| 76 | syminfo_callback, |
---|
| 77 | error_callback, |
---|
| 78 | &frame |
---|
| 79 | ); |
---|
| 80 | } |
---|
| 81 | return frame; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | std::vector<stacktrace_frame> resolve_frames(const std::vector<void*>& frames) { |
---|
| 85 | std::vector<stacktrace_frame> trace; |
---|
| 86 | trace.reserve(frames.size()); |
---|
| 87 | for(const void* frame : frames) { |
---|
| 88 | trace.push_back(resolve_frame(frame)); |
---|
| 89 | } |
---|
| 90 | return trace; |
---|
| 91 | } |
---|
| 92 | } |
---|
| 93 | } |
---|
| 94 | } |
---|
| 95 | |
---|
| 96 | #endif |
---|