forked from jeremy-rifkin/cpptrace
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpptrace.hpp
More file actions
269 lines (227 loc) · 10.3 KB
/
Copy pathcpptrace.hpp
File metadata and controls
269 lines (227 loc) · 10.3 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#ifndef CPPTRACE_HPP
#define CPPTRACE_HPP
#include <cstdint>
#include <exception>
#include <ostream>
#include <string>
#include <vector>
#include "cpptrace/cpptrace_export.hpp"
#if __cplusplus >= 202002L
#ifdef __has_include
#if __has_include(<format>)
#define CPPTRACE_STD_FORMAT
#include <format>
#endif
#endif
#endif
namespace cpptrace {
struct object_trace;
struct stacktrace;
struct CPPTRACE_EXPORT raw_trace {
std::vector<std::uintptr_t> frames;
static raw_trace current(std::uint_least32_t skip = 0);
static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
object_trace resolve_object_trace() const;
stacktrace resolve() const;
void clear();
bool empty() const noexcept;
using iterator = std::vector<std::uintptr_t>::iterator;
using const_iterator = std::vector<std::uintptr_t>::const_iterator;
inline iterator begin() noexcept { return frames.begin(); }
inline iterator end() noexcept { return frames.end(); }
inline const_iterator begin() const noexcept { return frames.begin(); }
inline const_iterator end() const noexcept { return frames.end(); }
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
inline const_iterator cend() const noexcept { return frames.cend(); }
};
struct CPPTRACE_EXPORT object_frame {
std::string obj_path;
std::string symbol;
std::uintptr_t raw_address = 0;
std::uintptr_t obj_address = 0;
};
struct CPPTRACE_EXPORT object_trace {
std::vector<object_frame> frames;
static object_trace current(std::uint_least32_t skip = 0);
static object_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
stacktrace resolve() const;
void clear();
bool empty() const noexcept;
using iterator = std::vector<object_frame>::iterator;
using const_iterator = std::vector<object_frame>::const_iterator;
inline iterator begin() noexcept { return frames.begin(); }
inline iterator end() noexcept { return frames.end(); }
inline const_iterator begin() const noexcept { return frames.begin(); }
inline const_iterator end() const noexcept { return frames.end(); }
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
inline const_iterator cend() const noexcept { return frames.cend(); }
};
struct CPPTRACE_EXPORT stacktrace_frame {
std::uintptr_t address;
std::uint_least32_t line; // TODO: This should use UINT_LEAST32_MAX as a sentinel
std::uint_least32_t column; // UINT_LEAST32_MAX if not present
std::string filename;
std::string symbol;
bool operator==(const stacktrace_frame& other) const {
return address == other.address
&& line == other.line
&& column == other.column
&& filename == other.filename
&& symbol == other.symbol;
}
bool operator!=(const stacktrace_frame& other) const {
return !operator==(other);
}
std::string to_string() const;
friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
};
struct CPPTRACE_EXPORT stacktrace {
std::vector<stacktrace_frame> frames;
static stacktrace current(std::uint_least32_t skip = 0);
static stacktrace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
void print() const;
void print(std::ostream& stream) const;
void print(std::ostream& stream, bool color) const;
void clear();
bool empty() const noexcept;
std::string to_string(bool color = false) const;
friend std::ostream& operator<<(std::ostream& stream, const stacktrace& trace);
using iterator = std::vector<stacktrace_frame>::iterator;
using const_iterator = std::vector<stacktrace_frame>::const_iterator;
inline iterator begin() noexcept { return frames.begin(); }
inline iterator end() noexcept { return frames.end(); }
inline const_iterator begin() const noexcept { return frames.begin(); }
inline const_iterator end() const noexcept { return frames.end(); }
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
inline const_iterator cend() const noexcept { return frames.cend(); }
private:
void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
friend void print_terminate_trace();
};
CPPTRACE_EXPORT raw_trace generate_raw_trace(std::uint_least32_t skip = 0);
CPPTRACE_EXPORT raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_EXPORT object_trace generate_object_trace(std::uint_least32_t skip = 0);
CPPTRACE_EXPORT object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_EXPORT stacktrace generate_trace(std::uint_least32_t skip = 0);
CPPTRACE_EXPORT stacktrace generate_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
// utilities:
CPPTRACE_EXPORT std::string demangle(const std::string& name);
CPPTRACE_EXPORT void absorb_trace_exceptions(bool absorb);
CPPTRACE_EXPORT bool isatty(int fd);
CPPTRACE_EXPORT extern const int stdin_fileno;
CPPTRACE_EXPORT extern const int stderr_fileno;
CPPTRACE_EXPORT extern const int stdout_fileno;
CPPTRACE_EXPORT void register_terminate_handler();
enum class cache_mode {
// Only minimal lookup tables
prioritize_memory,
// Build lookup tables but don't keep them around between trace calls
hybrid,
// Build lookup tables as needed
prioritize_speed
};
namespace experimental {
CPPTRACE_EXPORT void set_cache_mode(cache_mode mode);
}
namespace detail {
CPPTRACE_EXPORT bool should_absorb_trace_exceptions();
CPPTRACE_EXPORT enum cache_mode get_cache_mode();
}
class CPPTRACE_EXPORT exception : public std::exception {
mutable raw_trace trace;
mutable stacktrace resolved_trace;
mutable std::string what_string;
protected:
explicit exception(std::uint_least32_t skip, std::uint_least32_t max_depth) noexcept;
explicit exception(std::uint_least32_t skip) noexcept : exception(skip + 1, UINT_LEAST32_MAX) {}
public:
explicit exception() noexcept : exception(1) {}
const char* what() const noexcept override;
// what(), but not a C-string. Performs lazy evaluation of the full what string.
virtual const std::string& get_what() const noexcept;
// Just the plain what() value without the stacktrace. This value is called by get_what() during lazy
// evaluation.
virtual const char* get_raw_what() const noexcept;
// Returns internal raw_trace
const raw_trace& get_raw_trace() const noexcept;
// Returns a resolved trace from the raw_trace. Handles lazy evaluation of the resolved trace.
const stacktrace& get_trace() const noexcept;
};
class CPPTRACE_EXPORT exception_with_message : public exception {
mutable std::string message;
protected:
explicit exception_with_message(
std::string&& message_arg,
std::uint32_t skip
) noexcept : exception(skip + 1), message(std::move(message_arg)) {}
explicit exception_with_message(
std::string&& message_arg,
std::uint_least32_t skip,
std::uint_least32_t max_depth
) noexcept : exception(skip + 1, max_depth), message(std::move(message_arg)) {}
public:
explicit exception_with_message(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
const char* get_raw_what() const noexcept override;
};
class logic_error : public exception_with_message {
public:
explicit logic_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class domain_error : public exception_with_message {
public:
explicit domain_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class invalid_argument : public exception_with_message {
public:
explicit invalid_argument(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class length_error : public exception_with_message {
public:
explicit length_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class out_of_range : public exception_with_message {
public:
explicit out_of_range(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class runtime_error : public exception_with_message {
public:
explicit runtime_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class range_error : public exception_with_message {
public:
explicit range_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class overflow_error : public exception_with_message {
public:
explicit overflow_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
class underflow_error : public exception_with_message {
public:
explicit underflow_error(std::string&& message_arg) noexcept
: exception_with_message(std::move(message_arg), 1) {}
};
}
#if defined(CPPTRACE_STD_FORMAT) && defined(__cpp_lib_format)
template <>
struct std::formatter<cpptrace::stacktrace_frame> : std::formatter<std::string> {
auto format(cpptrace::stacktrace_frame frame, format_context& ctx) const {
return formatter<string>::format(frame.to_string(), ctx);
}
};
template <>
struct std::formatter<cpptrace::stacktrace> : std::formatter<std::string> {
auto format(cpptrace::stacktrace trace, format_context& ctx) const {
return formatter<string>::format(trace.to_string(), ctx);
}
};
#endif
#endif