1 /* 2 fuzzylite (R), a fuzzy logic control library in C++. 3 Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved. 4 Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com> 5 6 This file is part of fuzzylite. 7 8 fuzzylite is free software: you can redistribute it and/or modify it under 9 the terms of the FuzzyLite License included with the software. 10 11 You should have received a copy of the FuzzyLite License along with 12 fuzzylite. If not, see <http://www.fuzzylite.com/license/>. 13 14 fuzzylite is a registered trademark of FuzzyLite Limited. 15 */ 16 17 #include "fl/Exception.h" 18 19 20 #ifdef FL_BACKTRACE 21 22 #ifdef FL_UNIX 23 #include <execinfo.h> 24 25 #elif defined FL_WINDOWS 26 #include <windows.h> 27 #include <winbase.h> 28 29 #ifndef __MINGW32__ 30 /*Disable warning 8.1\Include\um\dbghelp.h(1544): 31 warning C4091: 'typedef ': ignored on left of '' when no variable is declared*/ 32 #pragma warning (push) 33 #pragma warning (disable:4091) 34 #include <dbghelp.h> 35 #pragma warning (pop) 36 #endif 37 38 #endif 39 40 #endif 41 42 43 #include <csignal> 44 #include <cstring> 45 46 namespace fl { 47 Exception(const std::string & what)48 Exception::Exception(const std::string& what) 49 : std::exception(), _what(what) { 50 FL_DBG(this->what()); 51 } 52 Exception(const std::string & what,const std::string & file,int line,const std::string & function)53 Exception::Exception(const std::string& what, const std::string& file, int line, 54 const std::string& function) 55 : std::exception(), _what(what) { 56 append(file, line, function); 57 FL_DBG(this->what()); 58 } 59 ~Exception()60 Exception::~Exception() FL_INOEXCEPT { } 61 setWhat(const std::string & what)62 void Exception::setWhat(const std::string& what) { 63 this->_what = what; 64 } 65 getWhat() const66 std::string Exception::getWhat() const { 67 return this->_what; 68 } 69 what() const70 const char* Exception::what() const FL_INOEXCEPT { 71 return this->_what.c_str(); 72 } 73 append(const std::string & whatElse)74 void Exception::append(const std::string& whatElse) { 75 this->_what += whatElse + "\n"; 76 } 77 append(const std::string & file,int line,const std::string & function)78 void Exception::append(const std::string& file, int line, const std::string& function) { 79 std::ostringstream ss; 80 ss << "\n{at " << file << "::" << function << "() [line:" << line << "]}"; 81 _what += ss.str(); 82 } 83 append(const std::string & whatElse,const std::string & file,int line,const std::string & function)84 void Exception::append(const std::string& whatElse, 85 const std::string& file, int line, const std::string& function) { 86 append(whatElse); 87 append(file, line, function); 88 } 89 btCallStack()90 std::string Exception::btCallStack() { 91 #ifndef FL_BACKTRACE 92 return "[backtrace disabled] fuzzylite was built without -DFL_BACKTRACE"; 93 #elif defined FL_UNIX 94 std::ostringstream btStream; 95 const int bufferSize = 30; 96 void* buffer[bufferSize]; 97 int backtraceSize = ::backtrace(buffer, bufferSize); 98 char **btSymbols = ::backtrace_symbols(buffer, backtraceSize); 99 if (btSymbols == fl::null) { 100 btStream << "[backtrace error] no symbols could be retrieved"; 101 } else { 102 if (backtraceSize == 0) { 103 btStream << "[backtrace is empty]"; 104 } 105 for (int i = 0; i < backtraceSize; ++i) { 106 btStream << btSymbols[i] << "\n"; 107 } 108 } 109 ::free(btSymbols); 110 return btStream.str(); 111 112 113 #elif defined FL_WINDOWS && ! defined __MINGW32__ 114 std::ostringstream btStream; 115 const int bufferSize = 30; 116 void* buffer[bufferSize]; 117 SymInitialize(GetCurrentProcess(), fl::null, TRUE); 118 119 int backtraceSize = CaptureStackBackTrace(0, bufferSize, buffer, fl::null); 120 SYMBOL_INFO* btSymbol = (SYMBOL_INFO *) calloc(sizeof ( SYMBOL_INFO) + 256 * sizeof ( char), 1); 121 if (not btSymbol) { 122 btStream << "[backtrace error] no symbols could be retrieved"; 123 } else { 124 btSymbol->MaxNameLen = 255; 125 btSymbol->SizeOfStruct = sizeof ( SYMBOL_INFO); 126 if (backtraceSize == 0) { 127 btStream << "[backtrace is empty]"; 128 } 129 for (int i = 0; i < backtraceSize; ++i) { 130 SymFromAddr(GetCurrentProcess(), (DWORD64) (buffer[ i ]), 0, btSymbol); 131 btStream << (backtraceSize - i - 1) << ": " << 132 btSymbol->Name << " at 0x" << btSymbol->Address << "\n"; 133 } 134 } 135 ::free(btSymbol); 136 return btStream.str(); 137 #else 138 return "[backtrace missing] supported only in Unix and Windows platforms"; 139 #endif 140 } 141 signalHandler(int unixSignal)142 void Exception::signalHandler(int unixSignal) { 143 std::ostringstream ex; 144 ex << "[unexpected signal " << unixSignal << "] "; 145 #ifdef FL_UNIX 146 ex << ::strsignal(unixSignal); 147 #endif 148 ex << "\nBACKTRACE:\n" << btCallStack(); 149 Exception::catchException(Exception(ex.str(), FL_AT)); 150 ::exit(EXIT_FAILURE); 151 } 152 convertToException(int unixSignal)153 void Exception::convertToException(int unixSignal) { 154 std::string signalDescription; 155 #ifdef FL_UNIX 156 //Unblock the signal 157 sigset_t empty; 158 sigemptyset(&empty); 159 sigaddset(&empty, unixSignal); 160 sigprocmask(SIG_UNBLOCK, &empty, fl::null); 161 signalDescription = ::strsignal(unixSignal); 162 #endif 163 std::ostringstream ex; 164 ex << "[signal " << unixSignal << "] " << signalDescription << "\n"; 165 ex << "BACKTRACE:\n" << btCallStack(); 166 throw Exception(ex.str(), FL_AT); 167 } 168 terminate()169 void Exception::terminate() { 170 Exception::catchException(Exception("[unexpected exception] BACKTRACE:\n" + btCallStack(), FL_AT)); 171 ::exit(EXIT_FAILURE); 172 } 173 catchException(const std::exception & exception)174 void Exception::catchException(const std::exception& exception) { 175 std::ostringstream ss; 176 ss << exception.what(); 177 std::string backtrace = btCallStack(); 178 if (not backtrace.empty()) { 179 ss << "\n\nBACKTRACE:\n" << backtrace; 180 } 181 FL_LOG(ss.str()); 182 } 183 184 } 185