diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarException_unix.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarException_unix.cpp')
-rw-r--r-- | source/core/StarException_unix.cpp | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/source/core/StarException_unix.cpp b/source/core/StarException_unix.cpp new file mode 100644 index 0000000..db23c7c --- /dev/null +++ b/source/core/StarException_unix.cpp @@ -0,0 +1,136 @@ +#include "StarException.hpp" +#include "StarCasting.hpp" +#include "StarLogging.hpp" + +#include <execinfo.h> +#include <cstdlib> + +namespace Star { + +static size_t const StackLimit = 256; + +typedef pair<Array<void*, StackLimit>, size_t> StackCapture; + +inline StackCapture captureStack() { + StackCapture stackCapture; + stackCapture.second = backtrace(stackCapture.first.ptr(), StackLimit); + return stackCapture; +} + +OutputProxy outputStack(StackCapture stack) { + return OutputProxy([stack = move(stack)](std::ostream & os) { + char** symbols = backtrace_symbols(stack.first.ptr(), stack.second); + for (size_t i = 0; i < stack.second; ++i) { + os << symbols[i]; + if (i + 1 < stack.second) + os << std::endl; + } + + if (stack.second == StackLimit) + os << std::endl << "[Stack Output Limit Reached]"; + + ::free(symbols); + }); +} + +StarException::StarException() noexcept + : StarException(std::string("StarException")) {} + +StarException::~StarException() noexcept {} + +StarException::StarException(std::string message) noexcept + : StarException("StarException", move(message)) {} + +StarException::StarException(std::exception const& cause) noexcept + : StarException("StarException", std::string(), cause) {} + +StarException::StarException(std::string message, std::exception const& cause) noexcept + : StarException("StarException", move(message), cause) {} + +const char* StarException::what() const throw() { + if (m_whatBuffer.empty()) { + std::ostringstream os; + m_printException(os, false); + m_whatBuffer = os.str(); + } + return m_whatBuffer.c_str(); +} + +StarException::StarException(char const* type, std::string message) noexcept { + auto printException = [](std::ostream& os, bool fullStacktrace, char const* type, std::string message, StackCapture stack) { + os << "(" << type << ")"; + if (!message.empty()) + os << " " << message; + + if (fullStacktrace) { + os << std::endl; + os << outputStack(stack); + } + }; + + m_printException = bind(printException, _1, _2, type, move(message), captureStack()); +} + +StarException::StarException(char const* type, std::string message, std::exception const& cause) noexcept + : StarException(type, move(message)) { + auto printException = [](std::ostream& os, bool fullStacktrace, function<void(std::ostream&, bool)> self, function<void(std::ostream&, bool)> cause) { + self(os, fullStacktrace); + os << std::endl << "Caused by: "; + cause(os, fullStacktrace); + }; + + std::function<void(std::ostream&, bool)> printCause; + if (auto starException = as<StarException>(&cause)) { + printCause = bind(starException->m_printException, _1, _2); + } else { + printCause = bind([](std::ostream& os, bool, std::string causeWhat) { + os << "std::exception: " << causeWhat; + }, _1, _2, std::string(cause.what())); + } + + m_printException = bind(printException, _1, _2, m_printException, move(printCause)); +} + +std::string printException(std::exception const& e, bool fullStacktrace) { + std::ostringstream os; + printException(os, e, fullStacktrace); + return os.str(); +} + +void printException(std::ostream& os, std::exception const& e, bool fullStacktrace) { + if (auto starException = as<StarException>(&e)) + starException->m_printException(os, fullStacktrace); + else + os << "std::exception: " << e.what(); +} + +OutputProxy outputException(std::exception const& e, bool fullStacktrace) { + if (auto starException = as<StarException>(&e)) + return OutputProxy(bind(starException->m_printException, _1, fullStacktrace)); + else + return OutputProxy(bind([](std::ostream& os, std::string what) { os << "std::exception: " << what; }, _1, std::string(e.what()))); +} + +void printStack(char const* message) { + Logger::info("Stack Trace (%s)...\n%s", message, outputStack(captureStack())); +} + +void fatalError(char const* message, bool showStackTrace) { + if (showStackTrace) + Logger::error("Fatal Error: %s\n%s", message, outputStack(captureStack())); + else + Logger::error("Fatal Error: %s", message); + + std::abort(); +} + +void fatalException(std::exception const& e, bool showStackTrace) { + if (showStackTrace) + Logger::error("Fatal Exception caught: %s\nCaught at:\n%s", outputException(e, true), outputStack(captureStack())); + else + Logger::error("Fatal Exception caught: %s", outputException(e, showStackTrace)); + + std::abort(); +} + +} |