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