Skip to content

Commit 4c59e73

Browse files
committed
Split up cpptrace.hpp
1 parent c95ab97 commit 4c59e73

30 files changed

Lines changed: 915 additions & 792 deletions

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,10 @@ target_sources(
226226
src/binary/safe_dl.cpp
227227
src/cpptrace.cpp
228228
src/ctrace.cpp
229+
src/exceptions.cpp
229230
src/from_current.cpp
231+
src/options.cpp
232+
src/utils.cpp
230233
src/demangle/demangle_with_cxxabi.cpp
231234
src/demangle/demangle_with_nothing.cpp
232235
src/demangle/demangle_with_winapi.cpp

include/cpptrace/basic.hpp

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
#ifndef CPPTRACE_BASIC_HPP
2+
#define CPPTRACE_BASIC_HPP
3+
4+
#include <cpptrace/forward.hpp>
5+
6+
#include <limits>
7+
#include <string>
8+
#include <vector>
9+
#include <iosfwd>
10+
11+
#ifdef _WIN32
12+
#define CPPTRACE_EXPORT_ATTR __declspec(dllexport)
13+
#define CPPTRACE_IMPORT_ATTR __declspec(dllimport)
14+
#else
15+
#define CPPTRACE_EXPORT_ATTR __attribute__((visibility("default")))
16+
#define CPPTRACE_IMPORT_ATTR __attribute__((visibility("default")))
17+
#endif
18+
19+
#ifdef CPPTRACE_STATIC_DEFINE
20+
# define CPPTRACE_EXPORT
21+
# define CPPTRACE_NO_EXPORT
22+
#else
23+
# ifndef CPPTRACE_EXPORT
24+
# ifdef cpptrace_lib_EXPORTS
25+
/* We are building this library */
26+
# define CPPTRACE_EXPORT CPPTRACE_EXPORT_ATTR
27+
# else
28+
/* We are using this library */
29+
# define CPPTRACE_EXPORT CPPTRACE_IMPORT_ATTR
30+
# endif
31+
# endif
32+
#endif
33+
34+
#ifdef _MSC_VER
35+
#define CPPTRACE_FORCE_NO_INLINE __declspec(noinline)
36+
#else
37+
#define CPPTRACE_FORCE_NO_INLINE __attribute__((noinline))
38+
#endif
39+
40+
#ifdef _MSC_VER
41+
#pragma warning(push)
42+
// warning C4251: using non-dll-exported type in dll-exported type, firing on std::vector<frame_ptr> and others for some
43+
// reason
44+
// 4275 is the same thing but for base classes
45+
#pragma warning(disable: 4251; disable: 4275)
46+
#endif
47+
48+
namespace cpptrace {
49+
struct CPPTRACE_EXPORT raw_trace {
50+
std::vector<frame_ptr> frames;
51+
static raw_trace current(std::size_t skip = 0);
52+
static raw_trace current(std::size_t skip, std::size_t max_depth);
53+
object_trace resolve_object_trace() const;
54+
stacktrace resolve() const;
55+
void clear();
56+
bool empty() const noexcept;
57+
58+
using iterator = std::vector<frame_ptr>::iterator;
59+
using const_iterator = std::vector<frame_ptr>::const_iterator;
60+
inline iterator begin() noexcept { return frames.begin(); }
61+
inline iterator end() noexcept { return frames.end(); }
62+
inline const_iterator begin() const noexcept { return frames.begin(); }
63+
inline const_iterator end() const noexcept { return frames.end(); }
64+
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
65+
inline const_iterator cend() const noexcept { return frames.cend(); }
66+
};
67+
68+
struct CPPTRACE_EXPORT object_frame {
69+
frame_ptr raw_address;
70+
frame_ptr object_address;
71+
std::string object_path;
72+
};
73+
74+
struct CPPTRACE_EXPORT object_trace {
75+
std::vector<object_frame> frames;
76+
static object_trace current(std::size_t skip = 0);
77+
static object_trace current(std::size_t skip, std::size_t max_depth);
78+
stacktrace resolve() const;
79+
void clear();
80+
bool empty() const noexcept;
81+
82+
using iterator = std::vector<object_frame>::iterator;
83+
using const_iterator = std::vector<object_frame>::const_iterator;
84+
inline iterator begin() noexcept { return frames.begin(); }
85+
inline iterator end() noexcept { return frames.end(); }
86+
inline const_iterator begin() const noexcept { return frames.begin(); }
87+
inline const_iterator end() const noexcept { return frames.end(); }
88+
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
89+
inline const_iterator cend() const noexcept { return frames.cend(); }
90+
};
91+
92+
// This represents a nullable integer type
93+
// The max value of the type is used as a sentinel
94+
// This is used over std::optional because the library is C++11 and also std::optional is a bit heavy-duty for this
95+
// use.
96+
template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
97+
struct nullable {
98+
T raw_value;
99+
nullable& operator=(T value) {
100+
raw_value = value;
101+
return *this;
102+
}
103+
bool has_value() const noexcept {
104+
return raw_value != (std::numeric_limits<T>::max)();
105+
}
106+
T& value() noexcept {
107+
return raw_value;
108+
}
109+
const T& value() const noexcept {
110+
return raw_value;
111+
}
112+
T value_or(T alternative) const noexcept {
113+
return has_value() ? raw_value : alternative;
114+
}
115+
void swap(nullable& other) noexcept {
116+
std::swap(raw_value, other.raw_value);
117+
}
118+
void reset() noexcept {
119+
raw_value = (std::numeric_limits<T>::max)();
120+
}
121+
bool operator==(const nullable& other) const noexcept {
122+
return raw_value == other.raw_value;
123+
}
124+
bool operator!=(const nullable& other) const noexcept {
125+
return raw_value != other.raw_value;
126+
}
127+
constexpr static nullable null() noexcept {
128+
return { (std::numeric_limits<T>::max)() };
129+
}
130+
};
131+
132+
struct CPPTRACE_EXPORT stacktrace_frame {
133+
frame_ptr raw_address;
134+
frame_ptr object_address;
135+
nullable<std::uint32_t> line;
136+
nullable<std::uint32_t> column;
137+
std::string filename;
138+
std::string symbol;
139+
bool is_inline;
140+
141+
bool operator==(const stacktrace_frame& other) const {
142+
return raw_address == other.raw_address
143+
&& object_address == other.object_address
144+
&& line == other.line
145+
&& column == other.column
146+
&& filename == other.filename
147+
&& symbol == other.symbol;
148+
}
149+
150+
bool operator!=(const stacktrace_frame& other) const {
151+
return !operator==(other);
152+
}
153+
154+
object_frame get_object_info() const;
155+
156+
std::string to_string() const;
157+
friend std::ostream& operator<<(std::ostream& stream, const stacktrace_frame& frame);
158+
};
159+
160+
struct CPPTRACE_EXPORT stacktrace {
161+
std::vector<stacktrace_frame> frames;
162+
static stacktrace current(std::size_t skip = 0);
163+
static stacktrace current(std::size_t skip, std::size_t max_depth);
164+
void print() const;
165+
void print(std::ostream& stream) const;
166+
void print(std::ostream& stream, bool color) const;
167+
void print_with_snippets() const;
168+
void print_with_snippets(std::ostream& stream) const;
169+
void print_with_snippets(std::ostream& stream, bool color) const;
170+
void clear();
171+
bool empty() const noexcept;
172+
std::string to_string(bool color = false) const;
173+
friend std::ostream& operator<<(std::ostream& stream, const stacktrace& trace);
174+
175+
using iterator = std::vector<stacktrace_frame>::iterator;
176+
using const_iterator = std::vector<stacktrace_frame>::const_iterator;
177+
inline iterator begin() noexcept { return frames.begin(); }
178+
inline iterator end() noexcept { return frames.end(); }
179+
inline const_iterator begin() const noexcept { return frames.begin(); }
180+
inline const_iterator end() const noexcept { return frames.end(); }
181+
inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
182+
inline const_iterator cend() const noexcept { return frames.cend(); }
183+
private:
184+
void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
185+
void print_with_snippets(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
186+
friend void print_terminate_trace();
187+
};
188+
189+
CPPTRACE_EXPORT raw_trace generate_raw_trace(std::size_t skip = 0);
190+
CPPTRACE_EXPORT raw_trace generate_raw_trace(std::size_t skip, std::size_t max_depth);
191+
CPPTRACE_EXPORT object_trace generate_object_trace(std::size_t skip = 0);
192+
CPPTRACE_EXPORT object_trace generate_object_trace(std::size_t skip, std::size_t max_depth);
193+
CPPTRACE_EXPORT stacktrace generate_trace(std::size_t skip = 0);
194+
CPPTRACE_EXPORT stacktrace generate_trace(std::size_t skip, std::size_t max_depth);
195+
196+
// Path max isn't so simple, so I'm choosing 4096 which seems to encompass what all major OS's expect and should be
197+
// fine in all reasonable cases.
198+
// https://eklitzke.org/path-max-is-tricky
199+
// https://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
200+
#define CPPTRACE_PATH_MAX 4096
201+
202+
// safe tracing interface
203+
// signal-safe
204+
CPPTRACE_EXPORT std::size_t safe_generate_raw_trace(
205+
frame_ptr* buffer,
206+
std::size_t size,
207+
std::size_t skip = 0
208+
);
209+
// signal-safe
210+
CPPTRACE_EXPORT std::size_t safe_generate_raw_trace(
211+
frame_ptr* buffer,
212+
std::size_t size,
213+
std::size_t skip,
214+
std::size_t max_depth
215+
);
216+
struct CPPTRACE_EXPORT safe_object_frame {
217+
frame_ptr raw_address;
218+
// This ends up being the real object address. It was named at a time when I thought the object base address
219+
// still needed to be added in
220+
frame_ptr address_relative_to_object_start;
221+
char object_path[CPPTRACE_PATH_MAX + 1];
222+
// To be called outside a signal handler. Not signal safe.
223+
object_frame resolve() const;
224+
};
225+
// signal-safe
226+
CPPTRACE_EXPORT void get_safe_object_frame(frame_ptr address, safe_object_frame* out);
227+
CPPTRACE_EXPORT bool can_signal_safe_unwind();
228+
}
229+
230+
#ifdef _MSC_VER
231+
#pragma warning(pop)
232+
#endif
233+
234+
#endif

0 commit comments

Comments
 (0)