diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 74b8500ec..616c9c6b0 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -18,9 +18,7 @@ ******************************************************************************/ #include -#ifdef HAVE_BACKTRACE_SYMBOLS -# include -#endif /* HAVE_BACKTRACE_SYMBOLS */ + #ifndef _WIN32 # include "icinga-version.h" @@ -31,65 +29,6 @@ using namespace icinga; -/** - * Handler for unhandled exceptions. - * - */ -static void exception_handler(void) -{ - static bool rethrow = true; - - try { - rethrow = false; - throw; - } catch (const std::exception& ex) { - std::cerr << std::endl; - std::cerr << "Unhandled exception of type " - << Utility::GetTypeName(typeid(ex)) - << std::endl; - std::cerr << "Diagnostic Information: " - << ex.what() - << std::endl; - } - -#ifdef HAVE_BACKTRACE_SYMBOLS - void *frames[50]; - int framecount = backtrace(frames, sizeof(frames) / sizeof(frames[0])); - - char **messages = backtrace_symbols(frames, framecount); - - std::cerr << std::endl << "Stacktrace:" << std::endl; - - for (int i = 0; i < framecount && messages != NULL; ++i) { - String message = messages[i]; - - char *sym_begin = strchr(messages[i], '('); - - if (sym_begin != NULL) { - char *sym_end = strchr(sym_begin, '+'); - - if (sym_end != NULL) { - String sym = String(sym_begin + 1, sym_end); - String sym_demangled = Utility::DemangleSymbolName(sym); - - if (sym_demangled.IsEmpty()) - sym_demangled = ""; - - message = String(messages[i], sym_begin) + ": " + sym_demangled + " (" + String(sym_end); - } - } - - std::cerr << "\t(" << i << ") " << message << std::endl; - } - - free(messages); - - std::cerr << std::endl; -#endif /* HAVE_BACKTRACE_SYMBOLS */ - - abort(); -} - /** * Entry point for the Icinga application. * @@ -99,8 +38,6 @@ static void exception_handler(void) */ int main(int argc, char **argv) { - std::set_terminate(exception_handler); - #ifndef _WIN32 LTDL_SET_PRELOADED_SYMBOLS(); #endif /* _WIN32 */ @@ -113,6 +50,9 @@ int main(int argc, char **argv) * in the base library. */ Application::SetMainThread(); + /* Install exception handlers to make debugging easier. */ + Application::InstallExceptionHandlers(); + #ifdef ICINGA_PREFIX Application::SetPrefixDir(ICINGA_PREFIX); #endif /* ICINGA_PREFIX */ diff --git a/lib/base/application.cpp b/lib/base/application.cpp index dcf4b2e2d..dcef64e5a 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -297,6 +297,20 @@ void Application::SigIntHandler(int signum) sa.sa_handler = SIG_DFL; sigaction(SIGINT, &sa, NULL); } + +/** + * Signal handler for SIGABRT. Helps with debugging assert()s. + * + * @param signum The signal number. + */ +void Application::SigAbrtHandler(int signum) +{ + assert(signum == SIGABRT); + + std::cerr << "Caught SIGABRT." << std::endl; + + Utility::PrintStacktrace(std::cerr, 1); +} #else /* _WIN32 */ /** * Console control handler. Prepares the application for cleanly @@ -316,6 +330,54 @@ BOOL WINAPI Application::CtrlHandler(DWORD type) } #endif /* _WIN32 */ +/** + * Handler for unhandled exceptions. + */ +void Application::ExceptionHandler(void) +{ + static bool rethrow = true; + + try { + rethrow = false; + throw; + } catch (const std::exception& ex) { + std::cerr << std::endl; + std::cerr << "Unhandled exception of type " + << Utility::GetTypeName(typeid(ex)) + << std::endl; + std::cerr << "Diagnostic Information: " + << ex.what() + << std::endl; + } + + Utility::PrintStacktrace(std::cerr, 1); + +#ifndef _WIN32 + struct sigaction sa; + memset(&sa, sizeof(sa), 0); + sa.sa_handler = SIG_DFL; + sigaction(SIGABRT, &sa, NULL); +#endif /* _WIN32 */ + + abort(); +} + + +/** + * Installs the exception handlers. + */ +void Application::InstallExceptionHandlers(void) +{ + std::set_terminate(&Application::ExceptionHandler); + +#ifndef _WIN32 + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &Application::SigAbrtHandler; + sigaction(SIGABRT, &sa, NULL); +#endif /* _WIN32 */ +} + /** * Runs the application. * @@ -335,7 +397,7 @@ int Application::Run(int argc, char **argv) sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); -#else +#else /* _WIN32 */ SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE); #endif /* _WIN32 */ diff --git a/lib/base/application.h b/lib/base/application.h index ca7aef88b..8d0615473 100644 --- a/lib/base/application.h +++ b/lib/base/application.h @@ -49,6 +49,8 @@ public: */ virtual int Main(const vector& args) = 0; + static void InstallExceptionHandlers(void); + static void RequestShutdown(void); static void Terminate(int exitCode); @@ -89,10 +91,13 @@ private: #ifndef _WIN32 static void SigIntHandler(int signum); + static void SigAbrtHandler(int signum); #else /* _WIN32 */ static BOOL WINAPI CtrlHandler(DWORD type); #endif /* _WIN32 */ + static void ExceptionHandler(void); + static void TimeWatchThreadProc(void); }; diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 66de8072d..ada3fbe89 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -19,6 +19,9 @@ #include "i2-base.h" #include +#ifdef HAVE_BACKTRACE_SYMBOLS +# include +#endif /* HAVE_BACKTRACE_SYMBOLS */ using namespace icinga; @@ -58,6 +61,56 @@ String Utility::GetTypeName(const type_info& ti) return DemangleSymbolName(ti.name()); } +/** + * Prints a stacktrace to the specified stream. + * + * @param fp The stream. + * @param ignoreFrames The number of stackframes to ignore (in addition to + * the one this function is executing in). + * @returns true if the stacktrace was printed, false otherwise. + */ +bool Utility::PrintStacktrace(ostream& fp, int ignoreFrames) +{ +#ifdef HAVE_BACKTRACE_SYMBOLS + void *frames[50]; + int framecount = backtrace(frames, sizeof(frames) / sizeof(frames[0])); + + char **messages = backtrace_symbols(frames, framecount); + + fp << std::endl << "Stacktrace:" << std::endl; + + for (int i = ignoreFrames + 1; i < framecount && messages != NULL; ++i) { + String message = messages[i]; + + char *sym_begin = strchr(messages[i], '('); + + if (sym_begin != NULL) { + char *sym_end = strchr(sym_begin, '+'); + + if (sym_end != NULL) { + String sym = String(sym_begin + 1, sym_end); + String sym_demangled = Utility::DemangleSymbolName(sym); + + if (sym_demangled.IsEmpty()) + sym_demangled = ""; + + message = String(messages[i], sym_begin) + ": " + sym_demangled + " (" + String(sym_end); + } + } + + fp << "\t(" << i - ignoreFrames - 1 << ") " << message << std::endl; + } + + free(messages); + + fp << std::endl; + + return true; +#else /* HAVE_BACKTRACE_SYMBOLS */ + return false; +#endif /* HAVE_BACKTRACE_SYMBOLS */ +} + /** * Detaches from the controlling terminal. */ diff --git a/lib/base/utility.h b/lib/base/utility.h index 0aa34f92c..9dc1d4d6c 100644 --- a/lib/base/utility.h +++ b/lib/base/utility.h @@ -33,6 +33,7 @@ class I2_BASE_API Utility public: static String DemangleSymbolName(const String& sym); static String GetTypeName(const type_info& ti); + static bool PrintStacktrace(ostream& fp, int ignoreFrames = 0); static void Daemonize(void);