]> granicus.if.org Git - icinga2/commitdiff
Move exception_handler into libbase. Add handler for SIGABRT.
authorGunnar Beutner <gunnar.beutner@netways.de>
Wed, 30 Jan 2013 10:51:15 +0000 (11:51 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Wed, 30 Jan 2013 10:51:15 +0000 (11:51 +0100)
Fixes #3590

icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.h
lib/base/utility.cpp
lib/base/utility.h

index 74b8500ec01ea45470df3ff4b2c7bd84918bc24b..616c9c6b07a6bb89f9ee88a8e89a0a966980c8e4 100644 (file)
@@ -18,9 +18,7 @@
  ******************************************************************************/
 
 #include <i2-icinga.h>
-#ifdef HAVE_BACKTRACE_SYMBOLS
-#      include <execinfo.h>
-#endif /* HAVE_BACKTRACE_SYMBOLS */
+
 
 #ifndef _WIN32
 #      include "icinga-version.h"
 
 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 = "<unknown function>";
-
-                               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 */
index dcf4b2e2d8cfd2795e6c45721c91448affa3a9b0..dcef64e5a163b8958ac72756475fabbfd99e1b23 100644 (file)
@@ -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 */
 
index ca7aef88b5377043bea1ec5382bb1dcb3a511747..8d061547373798eb7d4704db58f67d8638d2fb20 100644 (file)
@@ -49,6 +49,8 @@ public:
         */
        virtual int Main(const vector<String>& 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);
 };
 
index 66de8072d7929771ccc3c81449638b04377b8e87..ada3fbe89d6ff9abf8fe14569b91d6720d9201dd 100644 (file)
@@ -19,6 +19,9 @@
 
 #include "i2-base.h"
 #include <mmatch.h>
+#ifdef HAVE_BACKTRACE_SYMBOLS
+#      include <execinfo.h>
+#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 = "<unknown function>";
+
+                               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.
  */
index 0aa34f92cbc695d58625e2e045ab636428202ad3..9dc1d4d6c5a3dd65477060cb275bbfb1bae2231b 100644 (file)
@@ -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);