-
Notifications
You must be signed in to change notification settings - Fork 5
/
Backtrace.hpp
113 lines (93 loc) · 3.36 KB
/
Backtrace.hpp
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#ifndef CHEAP_BACKTRACE_HPP
#define CHEAP_BACKTRACE_HPP
#include <backtrace.h>
#include <cxxabi.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <iostream>
#include <string>
#include <vector>
namespace Backtrace {
namespace {
static backtrace_state* state = nullptr;
}
struct StackFrame {
std::string function;
std::string filename;
int lineno;
};
}
extern "C"
int onStackFrame(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
auto* backtrace = static_cast<std::vector<Backtrace::StackFrame>*>(data);
Backtrace::StackFrame frame;
// If we have no information, look up info using the pc.
if (!function && !filename) {
Dl_info info;
dladdr((void *) pc, &info);
int status;
if (info.dli_sname) {
char* demangled_function = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (demangled_function) {
frame.function = std::string(demangled_function);
} else {
frame.function = std::string(info.dli_sname);
}
}
frame.filename = std::string(info.dli_fname);
backtrace->insert(backtrace->begin(), frame);
return 0;
}
// std::cerr << "in " << filename << " at line " << lineno << std::endl;
if (!function) {
frame.function = "[UNKNOWN]";
} else {
int status;
char* demangled_function = abi::__cxa_demangle(function, nullptr, nullptr, &status);
if (!demangled_function) {
Dl_info info;
int status = dladdr((void *) pc, &info);
if (status) {
filename = info.dli_sname;
}
}
if (status == 0) {
frame.function = std::string(demangled_function);
static decltype(::free)* free = (decltype(::free)*) dlsym(RTLD_DEFAULT, "free");
(*free)(demangled_function);
} else {
frame.function = std::string(function);
}
}
frame.filename = (!filename) ? "[UNKNOWN]" : std::string(filename);
frame.lineno = lineno;
backtrace->insert(backtrace->begin(), frame);
return 0;
};
// Small utility file I wrote while testing libbacktrace with Intel Pin.
namespace Backtrace {
void initialize(char* filename) {
if (state == nullptr) {
const auto onError = [](void*, const char* msg, int errnum) {
std::cerr << "Error #" << errnum << " while setting up backtrace. Message: " << msg << std::endl;
};
state = backtrace_create_state(filename, true, onError, nullptr);
}
}
std::vector<StackFrame> getBacktrace(int skip) {
// If we have not initialized the utility yet, we return an empty stack trace.
if (state == nullptr) {
return std::vector<StackFrame>();
}
const auto onError = [](void*, const char* msg, int errnum) {
std::cerr << "Error #" << errnum << " while getting backtrace. Message: " << msg << std::endl;
};
std::vector<StackFrame> backtrace;
backtrace_full(state, skip, onStackFrame, onError, &backtrace);
return backtrace;
}
std::vector<StackFrame> getBacktrace() {
return getBacktrace(0);
}
} // namespace Backtrace
#endif // CHEAP_BACKTRACE_HPP