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 |
---|