#ifndef ARBUTILS_EXCEPTION_HPP #define ARBUTILS_EXCEPTION_HPP #include #include #include #include #if !WINDOWS #define BACKWARD_HAS_DW 1 #include "../extern/backward.hpp" #endif namespace ArbUt { class Exception : std::logic_error { #if !WINDOWS backward::StackTrace _stack; #endif public: explicit Exception(const std::string& msg) : std::logic_error(msg) { #if !WINDOWS _stack.load_here(32); #endif } Exception(const Exception& e) noexcept : std::logic_error(e.what()) #if !WINDOWS , _stack(e._stack) #endif { } [[nodiscard]] const char* what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_NOTHROW override { return logic_error::what(); } [[nodiscard]] std::string GetStacktrace([[maybe_unused]] size_t depth = 6, [[maybe_unused]] bool include_addr = true) const { #if !WINDOWS if (_stack.size() == 0) { return "No stack trace could be retrieved."; } backward::TraceResolver tr; backward::SnippetFactory snippetFactory; tr.load_stacktrace(_stack); std::stringstream ss; ss << "Stacktrace with depth " << depth << ": " << std::endl; bool foundExceptionClass = false; size_t framesAppended = 0; for (size_t i = 0; i < _stack.size() && framesAppended <= depth; ++i) { backward::ResolvedTrace trace = tr.resolve(_stack[i]); if (trace.source.filename.empty()) { AppendNoSourceStack(ss, trace, include_addr); } else { AppendSourceStack(ss, trace.source, foundExceptionClass, snippetFactory); if (foundExceptionClass) { framesAppended++; } } for (auto& t : trace.inliners) { AppendSourceStack(ss, t, foundExceptionClass, snippetFactory); if (foundExceptionClass) { framesAppended++; if (framesAppended >= depth) break; } } } return ss.str(); #else return "Stack trace not available on Windows."; #endif } #if !WINDOWS private: static void AppendNoSourceStack(std::stringstream& ss, const backward::ResolvedTrace& trace, bool include_addr) { 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; } static void AppendSourceStack(std::stringstream& ss, const backward::ResolvedTrace::SourceLoc& source, bool& foundExceptionClass, backward::SnippetFactory& snippetFactory) { auto fileName = (strrchr(source.filename.c_str(), '/') ? strrchr(source.filename.c_str(), '/') + 1 : source.filename.c_str()); if (strcmp(fileName, "Exception.hpp") == 0) { foundExceptionClass = true; return; } else if (!foundExceptionClass) { return; } auto snippet = snippetFactory.get_snippet(source.filename, source.line, 1)[0].second; size_t p = snippet.find_first_not_of(" \t"); snippet.erase(0, p); p = snippet.find_last_not_of(" \t"); if (std::string::npos != p) snippet.erase(p + 1); if (snippet.length() > 70) { snippet = snippet.substr(0, 67); snippet += "..."; } ss << fileName << "[" << source.line << "] " << snippet << std::endl; } #endif }; } #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define THROW(message) \ std::stringstream ___ss; \ ___ss << "[" << __FILENAME__ << ":" << __LINE__ << "] " << message; \ throw ArbUt::Exception(___ss.str()); #define NOT_REACHABLE THROW("Not reachable"); #define NOT_IMPLEMENTED THROW("Not implemented"); #endif // ARBUTILS_EXCEPTION_HPP