source: XIOS3/trunk/extern/cpptrace/src/full_trace_with_libbacktrace.cpp

Last change on this file was 2573, checked in by ymipsl, 9 months ago

create new external source lib : cpptrace, for statck trace output
YM

File size: 3.1 KB
Line 
1#ifdef CPPTRACE_FULL_TRACE_WITH_LIBBACKTRACE
2
3#include "cpptrace.hpp"
4#include "program_name.hpp"
5#include "common.hpp"
6
7#include <cstddef>
8#include <cstdint>
9#include <cstdio>
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
19namespace cpptrace {
20    namespace detail {
21        struct trace_data {
22            // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
23            std::vector<stacktrace_frame>& frames;
24            // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
25            size_t& skip;
26        };
27
28        int full_callback(void* data_pointer, uintptr_t address, const char* file, int line, const char* symbol) {
29            trace_data& data = *reinterpret_cast<trace_data*>(data_pointer);
30            if(data.skip > 0) {
31                data.skip--;
32            } else if(address == uintptr_t(-1)) {
33                // sentinel for libbacktrace, stop tracing
34                return 1;
35            } else {
36                data.frames.push_back({
37                    address,
38                    static_cast<std::uint_least32_t>(line),
39                    0,
40                    file ? file : "",
41                    symbol ? symbol : ""
42                });
43            }
44            return 0;
45        }
46
47        void syminfo_callback(void* data, uintptr_t, const char* symbol, uintptr_t, uintptr_t) {
48            stacktrace_frame& frame = *static_cast<stacktrace_frame*>(data);
49            frame.symbol = symbol ? symbol : "";
50        }
51
52        void error_callback(void*, const char* msg, int errnum) {
53            fprintf(stderr, "Libbacktrace error: %s, code %d\n", msg, errnum);
54        }
55
56        backtrace_state* get_backtrace_state() {
57            static std::mutex mutex;
58            const std::lock_guard<std::mutex> lock(mutex);
59            // backtrace_create_state must be called only one time per program
60            // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
61            static backtrace_state* state = nullptr;
62            static bool called = false;
63            if(!called) {
64                state = backtrace_create_state(nullptr, true, error_callback, nullptr);
65                called = true;
66            }
67            return state;
68        }
69
70        CPPTRACE_FORCE_NO_INLINE
71        std::vector<stacktrace_frame> generate_trace(size_t skip) {
72            std::vector<stacktrace_frame> frames;
73            skip++; // add one for this call
74            trace_data data { frames, skip };
75            backtrace_full(get_backtrace_state(), 0, full_callback, error_callback, &data);
76            for(auto& frame : frames) {
77                if(frame.symbol.empty()) {
78                    // fallback, try to at least recover the symbol name with backtrace_syminfo
79                    backtrace_syminfo(
80                        get_backtrace_state(),
81                        frame.address,
82                        syminfo_callback,
83                        error_callback,
84                        &frame
85                    );
86                }
87            }
88            return frames;
89        }
90    }
91}
92
93#endif
Note: See TracBrowser for help on using the repository browser.