#ifndef ARBUTILS_EXCEPTION_HPP #define ARBUTILS_EXCEPTION_HPP #include #include #include #include #if !WINDOWS #define BACKWARD_HAS_BFD 1 #include "../extern/backward.hpp" #endif namespace ArbUt { class Exception : std::exception { std::string _msg; #if !WINDOWS backward::StackTrace _stack; #endif public: explicit Exception(std::string msg) : _msg(std::move(msg)) { _stack.load_here(9); } [[nodiscard]] const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { return _msg.c_str(); } [[nodiscard]] std::string GetStacktrace(size_t depth = 6, bool include_addr = true) const { #if !WINDOWS backward::TraceResolver tr; tr.load_stacktrace(_stack); std::stringstream ss; for (size_t i = 3; i < _stack.size() && i < depth + 3; ++i) { backward::ResolvedTrace trace = tr.resolve(_stack[i]); if (trace.source.filename.empty()) { auto objectName = (strrchr(trace.object_filename.c_str(), '/') ? strrchr(trace.object_filename.c_str(), '/') + 1 : trace.object_filename.c_str()); auto function = trace.object_function; if (function.length() > 70) { function = function.substr(0, 67); function += "..."; } ss << objectName; if (include_addr) { ss << "[" << trace.addr << "]"; } ss << " " << function << std::endl; } else { auto fileName = (strrchr(trace.source.filename.c_str(), '/') ? strrchr(trace.source.filename.c_str(), '/') + 1 : trace.source.filename.c_str()); auto function = trace.object_function; if (function.length() > 70) { function = function.substr(0, 67); function += "..."; } ss << fileName << "[" << trace.source.line << "] " << function << std::endl; } } return ss.str(); #else return "Stack trace not available on Windows."; #endif } }; } #endif // ARBUTILS_EXCEPTION_HPP