Add max_depth overloads

This commit is contained in:
Jeremy 2023-09-22 12:04:25 -04:00
parent 3e18bd3c10
commit dd928b249b
No known key found for this signature in database
GPG Key ID: 3E11861CB34E158C
8 changed files with 112 additions and 47 deletions

View File

@ -142,7 +142,8 @@ namespace cpptrace {
std::vector<stacktrace_frame> frames; std::vector<stacktrace_frame> frames;
explicit stacktrace(); explicit stacktrace();
explicit stacktrace(std::vector<stacktrace_frame>&& frames); explicit stacktrace(std::vector<stacktrace_frame>&& frames);
static stacktrace current(std::uint32_t skip = 0); // here as a drop-in for std::stacktrace static stacktrace current(std::uint_least32_t skip = 0); // here as a drop-in for std::stacktrace
static stacktrace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
void print() const; void print() const;
void print(std::ostream& stream) const; void print(std::ostream& stream) const;
void print(std::ostream& stream, bool color) const; void print(std::ostream& stream, bool color) const;
@ -152,7 +153,8 @@ namespace cpptrace {
/* operator<<(ostream, ..), std::format support, and iterators exist for this object */ /* operator<<(ostream, ..), std::format support, and iterators exist for this object */
}; };
stacktrace generate_trace(std::uint32_t skip = 0); stacktrace generate_trace(std::uint_least32_t skip = 0);
stacktrace generate_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
} }
``` ```
@ -174,14 +176,16 @@ namespace cpptrace {
struct object_trace { struct object_trace {
std::vector<object_frame> frames; std::vector<object_frame> frames;
explicit object_trace(std::vector<object_frame>&& frames); explicit object_trace(std::vector<object_frame>&& frames);
static object_trace current(std::uint32_t skip = 0); 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; stacktrace resolve() const;
void clear(); void clear();
bool empty() const noexcept; bool empty() const noexcept;
/* iterators exist for this object */ /* iterators exist for this object */
}; };
object_trace generate_object_trace(std::uint32_t skip = 0); object_trace generate_object_trace(std::uint_least32_t skip = 0);
object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
} }
``` ```
@ -197,7 +201,8 @@ namespace cpptrace {
struct raw_trace { struct raw_trace {
std::vector<uintptr_t> frames; std::vector<uintptr_t> frames;
explicit raw_trace(std::vector<uintptr_t>&& frames); explicit raw_trace(std::vector<uintptr_t>&& frames);
static raw_trace current(std::uint32_t skip = 0); 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; object_trace resolve_object_trace() const;
stacktrace resolve() const; stacktrace resolve() const;
void clear(); void clear();
@ -205,7 +210,8 @@ namespace cpptrace {
/* iterators exist for this object */ /* iterators exist for this object */
}; };
raw_trace generate_raw_trace(std::uint32_t skip = 0); raw_trace generate_raw_trace(std::uint_least32_t skip = 0);
raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
} }
``` ```
@ -236,7 +242,8 @@ namespace cpptrace {
mutable raw_trace trace; mutable raw_trace trace;
mutable stacktrace resolved_trace; mutable stacktrace resolved_trace;
mutable std::string resolved_what; mutable std::string resolved_what;
explicit exception(uint32_t skip) noexcept; explicit exception(std::uint_least32_t skip) noexcept;
explicit exception(std::uint_least32_t skip, std::uint_least32_t max_depth) noexcept;
const stacktrace& get_resolved_trace() const noexcept; const stacktrace& get_resolved_trace() const noexcept;
virtual const std::string& get_resolved_what() const noexcept; virtual const std::string& get_resolved_what() const noexcept;
public: public:
@ -249,7 +256,8 @@ namespace cpptrace {
class exception_with_message : public exception { class exception_with_message : public exception {
mutable std::string message; mutable std::string message;
explicit exception_with_message(std::string&& message_arg, uint32_t skip) noexcept; explicit exception_with_message(std::string&& message_arg, std::uint_least32_t skip) noexcept;
explicit exception_with_message(std::string&& message_arg, std::uint_least32_t skip, std::uint_least32_t max_depth) noexcept;
const std::string& get_resolved_what() const noexcept override; const std::string& get_resolved_what() const noexcept override;
public: public:
explicit exception_with_message(std::string&& message_arg); explicit exception_with_message(std::string&& message_arg);

View File

@ -30,7 +30,8 @@ namespace cpptrace {
struct raw_trace { struct raw_trace {
std::vector<uintptr_t> frames; std::vector<uintptr_t> frames;
explicit raw_trace(std::vector<uintptr_t>&& frames_) : frames(frames_) {} explicit raw_trace(std::vector<uintptr_t>&& frames_) : frames(frames_) {}
CPPTRACE_API static raw_trace current(std::uint32_t skip = 0); CPPTRACE_API static raw_trace current(std::uint_least32_t skip = 0);
CPPTRACE_API static raw_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_API object_trace resolve_object_trace() const; CPPTRACE_API object_trace resolve_object_trace() const;
CPPTRACE_API stacktrace resolve() const; CPPTRACE_API stacktrace resolve() const;
CPPTRACE_API void clear(); CPPTRACE_API void clear();
@ -54,7 +55,8 @@ namespace cpptrace {
struct object_trace { struct object_trace {
std::vector<object_frame> frames; std::vector<object_frame> frames;
explicit object_trace(std::vector<object_frame>&& frames_) : frames(frames_) {} explicit object_trace(std::vector<object_frame>&& frames_) : frames(frames_) {}
CPPTRACE_API static object_trace current(std::uint32_t skip = 0); CPPTRACE_API static object_trace current(std::uint_least32_t skip = 0);
CPPTRACE_API static object_trace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_API stacktrace resolve() const; CPPTRACE_API stacktrace resolve() const;
CPPTRACE_API void clear(); CPPTRACE_API void clear();
CPPTRACE_API bool empty() const noexcept; CPPTRACE_API bool empty() const noexcept;
@ -91,7 +93,8 @@ namespace cpptrace {
std::vector<stacktrace_frame> frames; std::vector<stacktrace_frame> frames;
explicit stacktrace() {} explicit stacktrace() {}
explicit stacktrace(std::vector<stacktrace_frame>&& frames_) : frames(frames_) {} explicit stacktrace(std::vector<stacktrace_frame>&& frames_) : frames(frames_) {}
CPPTRACE_API static stacktrace current(std::uint32_t skip = 0); CPPTRACE_API static stacktrace current(std::uint_least32_t skip = 0);
CPPTRACE_API static stacktrace current(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_API void print() const; CPPTRACE_API void print() const;
CPPTRACE_API void print(std::ostream& stream) const; CPPTRACE_API void print(std::ostream& stream) const;
CPPTRACE_API void print(std::ostream& stream, bool color) const; CPPTRACE_API void print(std::ostream& stream, bool color) const;
@ -110,9 +113,12 @@ namespace cpptrace {
CPPTRACE_API void print(std::ostream& stream, bool color, bool newline_at_end) const; CPPTRACE_API void print(std::ostream& stream, bool color, bool newline_at_end) const;
}; };
CPPTRACE_API raw_trace generate_raw_trace(std::uint32_t skip = 0); CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip = 0);
CPPTRACE_API object_trace generate_object_trace(std::uint32_t skip = 0); CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_API stacktrace generate_trace(std::uint32_t skip = 0); CPPTRACE_API object_trace generate_object_trace(std::uint_least32_t skip = 0);
CPPTRACE_API object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
CPPTRACE_API stacktrace generate_trace(std::uint_least32_t skip = 0);
CPPTRACE_API stacktrace generate_trace(std::uint_least32_t skip, std::uint_least32_t max_depth);
// utilities: // utilities:
CPPTRACE_API std::string demangle(const std::string& name); CPPTRACE_API std::string demangle(const std::string& name);
@ -127,9 +133,10 @@ namespace cpptrace {
mutable raw_trace trace; mutable raw_trace trace;
mutable stacktrace resolved_trace; mutable stacktrace resolved_trace;
mutable std::string resolved_what; mutable std::string resolved_what;
explicit exception(uint32_t skip) noexcept : trace([skip] () noexcept { explicit exception(std::uint_least32_t skip, std::uint_least32_t max_depth) noexcept
: trace([skip, max_depth] () noexcept {
try { try {
return generate_raw_trace(skip + 2); return generate_raw_trace(skip + 2, max_depth);
} catch(const std::exception& e) { } catch(const std::exception& e) {
if(!detail::should_absorb_trace_exceptions()) { if(!detail::should_absorb_trace_exceptions()) {
fprintf( fprintf(
@ -141,6 +148,7 @@ namespace cpptrace {
return raw_trace({}); return raw_trace({});
} }
} ()) {} } ()) {}
explicit exception(std::uint_least32_t skip) noexcept : exception(skip + 1, UINT_LEAST32_MAX) {}
const stacktrace& get_resolved_trace() const noexcept { const stacktrace& get_resolved_trace() const noexcept {
// I think a non-empty raw trace can never resolve as empty, so this will accurately prevent resolving more // I think a non-empty raw trace can never resolve as empty, so this will accurately prevent resolving more
// than once. Either way the raw trace is cleared. // than once. Either way the raw trace is cleared.
@ -186,8 +194,15 @@ namespace cpptrace {
class exception_with_message : public exception { class exception_with_message : public exception {
protected: protected:
mutable std::string message; mutable std::string message;
explicit exception_with_message(std::string&& message_arg, uint32_t skip) noexcept explicit exception_with_message(
: exception(skip + 1), message(std::move(message_arg)) {} std::string&& message_arg,
uint32_t skip
) noexcept : exception(skip + 1), message(std::move(message_arg)) {}
explicit exception_with_message(
std::string&& message_arg,
uint_least32_t skip,
uint_least32_t max_depth
) noexcept : exception(skip + 1, max_depth), message(std::move(message_arg)) {}
const std::string& get_resolved_what() const noexcept override { const std::string& get_resolved_what() const noexcept override {
if(resolved_what.empty()) { if(resolved_what.empty()) {
resolved_what = message + "\n" + get_resolved_trace().to_string(); resolved_what = message + "\n" + get_resolved_trace().to_string();

View File

@ -31,10 +31,15 @@ namespace cpptrace {
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
raw_trace raw_trace::current(std::uint32_t skip) { raw_trace raw_trace::current(std::uint_least32_t skip) {
return generate_raw_trace(skip + 1); return generate_raw_trace(skip + 1);
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
raw_trace raw_trace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_raw_trace(skip + 1, max_depth);
}
CPPTRACE_API CPPTRACE_API
object_trace raw_trace::resolve_object_trace() const { object_trace raw_trace::resolve_object_trace() const {
return object_trace(detail::get_frames_object_info(frames)); return object_trace(detail::get_frames_object_info(frames));
@ -60,10 +65,15 @@ namespace cpptrace {
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
object_trace object_trace::current(std::uint32_t skip) { object_trace object_trace::current(std::uint_least32_t skip) {
return generate_object_trace(skip + 1); return generate_object_trace(skip + 1);
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
object_trace object_trace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_object_trace(skip + 1, max_depth);
}
CPPTRACE_API CPPTRACE_API
stacktrace object_trace::resolve() const { stacktrace object_trace::resolve() const {
return stacktrace(detail::resolve_frames(frames)); return stacktrace(detail::resolve_frames(frames));
@ -114,6 +124,11 @@ namespace cpptrace {
return generate_trace(skip + 1); return generate_trace(skip + 1);
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
stacktrace stacktrace::current(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return generate_trace(skip + 1, max_depth);
}
CPPTRACE_API CPPTRACE_API
void stacktrace::print() const { void stacktrace::print() const {
print(std::cerr, true); print(std::cerr, true);
@ -206,18 +221,33 @@ namespace cpptrace {
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
raw_trace generate_raw_trace(std::uint32_t skip) { raw_trace generate_raw_trace(std::uint_least32_t skip) {
return raw_trace(detail::capture_frames(skip + 1)); return raw_trace(detail::capture_frames(skip + 1, UINT_LEAST32_MAX));
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
object_trace generate_object_trace(std::uint32_t skip) { raw_trace generate_raw_trace(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return object_trace(detail::get_frames_object_info(detail::capture_frames(skip + 1))); return raw_trace(detail::capture_frames(skip + 1, max_depth));
} }
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
stacktrace generate_trace(std::uint32_t skip) { object_trace generate_object_trace(std::uint_least32_t skip) {
std::vector<uintptr_t> frames = detail::capture_frames(skip + 1); return object_trace(detail::get_frames_object_info(detail::capture_frames(skip + 1, UINT_LEAST32_MAX)));
}
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
object_trace generate_object_trace(std::uint_least32_t skip, std::uint_least32_t max_depth) {
return object_trace(detail::get_frames_object_info(detail::capture_frames(skip + 1, max_depth)));
}
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
stacktrace generate_trace(std::uint_least32_t skip) {
return generate_trace(skip + 1, UINT_LEAST32_MAX);
}
CPPTRACE_FORCE_NO_INLINE CPPTRACE_API
stacktrace generate_trace(std::uint32_t skip, std::uint_least32_t max_depth) {
std::vector<uintptr_t> frames = detail::capture_frames(skip + 1, max_depth);
std::vector<stacktrace_frame> trace = detail::resolve_frames(frames); std::vector<stacktrace_frame> trace = detail::resolve_frames(frames);
for(auto& frame : trace) { for(auto& frame : trace) {
frame.symbol = detail::demangle(frame.symbol); frame.symbol = detail::demangle(frame.symbol);

View File

@ -15,7 +15,7 @@ namespace detail {
constexpr size_t hard_max_frames = 100; constexpr size_t hard_max_frames = 100;
#endif #endif
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
std::vector<uintptr_t> capture_frames(size_t skip); std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth);
} }
} }

View File

@ -13,15 +13,13 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
std::vector<uintptr_t> capture_frames(size_t skip) { std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
std::vector<void*> addrs(hard_max_frames + skip, nullptr); skip += 2; // TODO: Not sure where the other 1 comes from
const int n_frames = backtrace(addrs.data(), int(hard_max_frames + skip)); // thread safe std::vector<void*> addrs(std::min(hard_max_frames, skip + max_depth), nullptr);
addrs.resize(n_frames); const int n_frames = backtrace(addrs.data(), static_cast<int>(addrs.size())); // thread safe
addrs.erase(addrs.begin(), addrs.begin() + ptrdiff_t(std::min(skip + 1, addrs.size()))); std::vector<uintptr_t> frames(n_frames - skip, 0);
addrs.shrink_to_fit(); for(int i = skip; i < n_frames; i++) {
std::vector<uintptr_t> frames(addrs.size(), 0); frames[i - skip] = reinterpret_cast<uintptr_t>(addrs[i]);
for(std::size_t i = 0; i < addrs.size(); i++) {
frames[i] = reinterpret_cast<uintptr_t>(addrs[i]);
} }
return frames; return frames;
} }

View File

@ -7,7 +7,7 @@
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
std::vector<uintptr_t> capture_frames(size_t) { std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
return {}; return {};
} }
} }

View File

@ -40,18 +40,22 @@ namespace detail {
if(!is_before_instruction && ip != uintptr_t(0)) { if(!is_before_instruction && ip != uintptr_t(0)) {
ip--; ip--;
} }
if (ip == uintptr_t(0) || state.count == state.vec.size()) { if (ip == uintptr_t(0)) {
return _URC_END_OF_STACK; return _URC_END_OF_STACK;
} else { } else {
// TODO: push_back?... // TODO: push_back?...
state.vec[state.count++] = ip; state.vec[state.count++] = ip;
if(state.count == state.vec.size()) {
return _URC_END_OF_STACK;
} else {
return _URC_NO_REASON; return _URC_NO_REASON;
} }
} }
}
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
std::vector<uintptr_t> capture_frames(size_t skip) { std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
std::vector<uintptr_t> frames(hard_max_frames, 0); std::vector<uintptr_t> frames(std::min(hard_max_frames, max_depth), 0);
unwind_state state{skip + 1, 0, frames}; unwind_state state{skip + 1, 0, frames};
_Unwind_Backtrace(unwind_callback, &state); // presumably thread-safe _Unwind_Backtrace(unwind_callback, &state); // presumably thread-safe
frames.resize(state.count); frames.resize(state.count);

View File

@ -5,20 +5,30 @@
#include "../platform/common.hpp" #include "../platform/common.hpp"
#include "../platform/utils.hpp" #include "../platform/utils.hpp"
#include <algorithm>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <windows.h> #include <windows.h>
// Fucking windows headers
#ifdef min
#undef min
#endif
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
std::vector<uintptr_t> capture_frames(size_t skip) { std::vector<uintptr_t> capture_frames(size_t skip, size_t max_depth) {
std::vector<void*> addrs(hard_max_frames, nullptr); std::vector<void*> addrs(std::min(hard_max_frames, max_depth), nullptr);
int n_frames = CaptureStackBackTrace(static_cast<DWORD>(skip + 1), hard_max_frames, addrs.data(), NULL); int n_frames = CaptureStackBackTrace(
addrs.resize(n_frames); static_cast<ULONG>(skip + 1),
std::vector<uintptr_t> frames(addrs.size(), 0); static_cast<ULONG>(addrs.size()),
for(std::size_t i = 0; i < addrs.size(); i++) { addrs.data(),
NULL
);
std::vector<uintptr_t> frames(n_frames, 0);
for(std::size_t i = 0; i < n_frames; i++) {
frames[i] = reinterpret_cast<uintptr_t>(addrs[i]); frames[i] = reinterpret_cast<uintptr_t>(addrs[i]);
} }
return frames; return frames;