Line data Source code
1 : #include "Error.h" 2 : 3 : #include <sstream> 4 : 5 : #include "Backtrace.h" 6 : 7 : namespace elsa 8 : { 9 : constexpr const char* runtime_error_message = "polymorphic elsa error, catch by reference!"; 10 : 11 : Error::Error(std::string msg, bool generate_backtrace, bool store_cause) 12 : : std::runtime_error{runtime_error_message}, backtrace{nullptr}, msg{std::move(msg)} 13 536 : { 14 : 15 536 : if (generate_backtrace) { 16 536 : this->backtrace = std::make_shared<Backtrace>(); 17 536 : this->backtrace->analyze(); 18 536 : } 19 : 20 536 : if (store_cause) { 21 536 : this->storeCause(); 22 536 : } 23 536 : } 24 : 25 534 : std::string Error::str() const { return this->msg; } 26 : 27 : const char* Error::what() const noexcept 28 534 : { 29 534 : this->what_cache = this->str(); 30 534 : return this->what_cache.c_str(); 31 534 : } 32 : 33 : void Error::storeCause() 34 536 : { 35 536 : if (not std::current_exception()) { 36 534 : return; 37 534 : } 38 : 39 2 : try { 40 2 : throw; 41 2 : } catch (Error& cause) { 42 2 : cause.trimBacktrace(); 43 2 : this->cause = std::current_exception(); 44 2 : } catch (...) { 45 0 : this->cause = std::current_exception(); 46 0 : } 47 2 : } 48 : 49 : void Error::trimBacktrace() 50 2 : { 51 2 : if (this->backtrace) { 52 2 : this->backtrace->trimToCurrentStackFrame(); 53 2 : } 54 2 : } 55 : 56 : void Error::rethrowCause() const 57 0 : { 58 0 : if (this->cause) { 59 0 : std::rethrow_exception(this->cause); 60 0 : } 61 0 : } 62 : 63 0 : std::string Error::typeName() const { return detail::symbolDemangle(typeid(*this).name()); } 64 : 65 0 : Backtrace* Error::getBacktrace() const { return this->backtrace.get(); } 66 : 67 0 : const std::string& Error::getMsg() const { return this->msg; } 68 : 69 : std::ostream& operator<<(std::ostream& os, const Error& e) 70 0 : { 71 : // output the exception cause 72 0 : bool had_a_cause = true; 73 0 : try { 74 0 : e.rethrowCause(); 75 0 : had_a_cause = false; 76 0 : } catch (Error& cause) { 77 0 : os << cause << std::endl; 78 0 : } catch (std::exception& cause) { 79 0 : os << detail::symbolDemangle(typeid(cause).name()) << ": " << cause.what() << std::endl; 80 0 : } 81 : 82 0 : if (had_a_cause) { 83 0 : os << std::endl 84 0 : << "The above exception was the direct cause " 85 0 : "of the following exception:" 86 0 : << std::endl 87 0 : << std::endl; 88 0 : } 89 : 90 : // output the exception backtrace 91 0 : auto* bt = e.getBacktrace(); 92 0 : if (bt != nullptr) { 93 0 : os << *bt; 94 0 : } else { 95 0 : os << "origin:" << std::endl; 96 0 : } 97 : 98 0 : os << e.typeName() << ":" << std::endl; 99 0 : os << e.str(); 100 : 101 0 : return os; 102 0 : } 103 : 104 : /** 105 : * Prints a backtrace_symbol object. 106 : */ 107 : std::ostream& operator<<(std::ostream& os, const backtrace_symbol& bt_sym) 108 0 : { 109 : // imitate the looks of a Python traceback. 110 0 : os << " -> "; 111 : 112 0 : if (bt_sym.functionname.empty()) { 113 0 : os << '?'; 114 0 : } else { 115 0 : os << bt_sym.functionname; 116 0 : } 117 : 118 0 : if (bt_sym.pc != nullptr) { 119 0 : os << " " << detail::addrToString(bt_sym.pc); 120 0 : } 121 : 122 0 : return os; 123 0 : } 124 : 125 : /** 126 : * Prints an entire Backtrace object. 127 : */ 128 : std::ostream& operator<<(std::ostream& os, const Backtrace& bt) 129 0 : { 130 : // imitate the looks of a Python traceback. 131 0 : os << "Traceback (most recent call last):" << std::endl; 132 : 133 0 : bt.getSymbols([&os](const backtrace_symbol* symbol) { os << *symbol << std::endl; }, true); 134 : 135 0 : return os; 136 0 : } 137 : 138 0 : InternalError::InternalError(const std::string& msg) : Error{msg} {} 139 : 140 104 : LogicError::LogicError(const std::string& msg) : Error{msg} {} 141 : 142 399 : InvalidArgumentError::InvalidArgumentError(const std::string& msg) : Error{msg} {} 143 : 144 3 : BadCastError::BadCastError(const std::string& msg) : Error{msg} {} 145 : 146 : } // namespace elsa