posix_backtrace.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "crucible/core/backtrace.hpp" #include "crucible/core/demangle.hpp" #include "crucible/core/format.hpp" #include <dlfcn.h> #include <execinfo.h> #include <cstddef> #include <cstring> #include <mutex> #include <utility> namespace crucible::core { namespace { constexpr std::size_t MAXIMUM_STACK_FRAMES { 1024 }; std::mutex backtrace_mutex; } auto backtrace() -> Backtrace_Result<Heap_Buffer<Stack_Frame>> { std::unique_lock<std::mutex> const backtrace_lock { backtrace_mutex }; Heap_Buffer<Stack_Frame> result {}; void *stack_data[MAXIMUM_STACK_FRAMES]; int const stack_size { ::backtrace(stack_data, MAXIMUM_STACK_FRAMES) }; if (stack_size <= 0) { return make_failure<Backtrace_Error>(Backtrace_Unavailable {}); } // We can't use `iterate()` here because it would inject a lamda into the call stack, so we have // to use a normal loop for (int i { 0 }; i < stack_size; ++i) { ::Dl_info symbol_table_entry {}; // Try to read out the symbol name from the dynamic symbol table if (::dladdr(stack_data[i], &symbol_table_entry) == 0) { Stack_Frame frame; frame.function = "<unknown>"; frame.details = "Failed to read symbol"; result.push(frame); continue; } // Even if ::dladdr() succeeds, we can still end up with `dli_sname == nullptr` if (symbol_table_entry.dli_sname == nullptr) { Stack_Frame frame; frame.function = "<unknown>"; frame.details = "No associated symbol"; result.push(frame); continue; } FFI_String<char> const mangled_symbol { symbol_table_entry.dli_sname, std::strlen(symbol_table_entry.dli_sname) }; auto const handle_failure { [&mangled_symbol](Demangle_Error const &/* error */) { Stack_Frame frame; frame.function = String { mangled_symbol.data(), mangled_symbol.size() }; frame.details = "Symbol demangling failed"; return frame; } }; auto const handle_success { [](FFI_String<char> const &demangled_symbol) { Stack_Frame frame; frame.function = String { demangled_symbol.data(), demangled_symbol.size() }; return frame; } }; auto const frame = demangle(mangled_symbol) .resolve(handle_failure, handle_success); result.push(frame); } return make_success(std::move(result)); } }