]> granicus.if.org Git - icinga2/commitdiff
Implement automated stacktraces for exceptions.
authorGunnar Beutner <gunnar.beutner@netways.de>
Thu, 7 Mar 2013 18:44:39 +0000 (19:44 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Thu, 7 Mar 2013 18:44:39 +0000 (19:44 +0100)
components/compat/compatcomponent.cpp
configure.ac
lib/base/application.cpp
lib/base/exception.cpp
lib/base/exception.h
lib/base/stacktrace.cpp
lib/base/stacktrace.h
lib/base/unix.h
m4/ax_c___attribute__.m4 [deleted file]

index 139dbfae8ec437fa2015670ace1ee1587aa502ac..af6e6f05f66dd978ad45e47eb5777e6f29693abd 100644 (file)
@@ -88,7 +88,7 @@ String CompatComponent::GetCommandPath(void) const
 
        Value commandPath = config->Get("command_path");
        if (commandPath.IsEmpty())
-               return Application::GetLocalStateDir() + "/run/icinga/icinga2.cmd";
+               return Application::GetLocalStateDir() + "/run/icinga2/icinga2.cmd";
        else
                return commandPath;
 }
index 8bcaa77743942c5d3b304decd26f7632132f1ece..cf1ec7ea2e588d743d0bca1ef7900ad620c6b36a 100644 (file)
@@ -83,12 +83,6 @@ else
 fi
 AC_MSG_RESULT($enable_debug)
 
-AX_C___ATTRIBUTE__
-if test "$ax_cv___attribute__" = "yes" && test "x$enable_debug" = "xno"; then
-       CFLAGS="$CFLAGS -fvisibility=hidden"
-       CXXFLAGS="$CXXFLAGS -fvisibility=hidden"
-fi
-
 AX_PYTHON_DEFAULT
 AX_PYTHON_ENABLE
 AX_PYTHON_VERSION_ENSURE([2.5])
index e5b2f19c75b7f91b963e0e1b2b81a9a455b51441..326c7a2cbe773905c2a22efc820bd69048108425 100644 (file)
@@ -353,16 +353,24 @@ void Application::ExceptionHandler(void)
        sigaction(SIGABRT, &sa, NULL);
 #endif /* _WIN32 */
 
+       bool has_trace = false;
+
        try {
                throw;
        } catch (const std::exception& ex) {
                std::cerr << std::endl
                          << diagnostic_information(ex)
                          << std::endl;
+
+               has_trace = (boost::get_error_info<StackTraceErrorInfo>(ex) != NULL);
+       } catch (...) {
+               std::cerr << "Exception of unknown type." << std::endl;
        }
 
-       StackTrace trace;
-       trace.Print(std::cerr, 1);
+       if (!has_trace) {
+               StackTrace trace;
+               trace.Print(std::cerr, 1);
+       }
 
        DisplayBugMessage();
 
index 04d64edf2adaef082c7249304c8e6a7767f5cf70..810c336b75486f5ca45b3c6abf40a528fb9e211e 100644 (file)
@@ -21,6 +21,8 @@
 
 using namespace icinga;
 
+StackTrace *Exception::m_StackTrace = NULL;
+
 /**
  * Retrieves the error code for the exception.
  *
@@ -125,3 +127,47 @@ String OpenSSLException::FormatErrorCode(int code)
 
        return message;
 }
+
+#ifndef _WIN32
+extern "C"
+void __cxa_throw(void *obj, void *pvtinfo, void (*dest)(void *))
+{
+       typedef void (*cxa_throw_fn)(void *, void *, void (*) (void *)) __attribute__((noreturn));
+       static cxa_throw_fn real_cxa_throw;
+
+       if (real_cxa_throw == 0)
+               real_cxa_throw = (cxa_throw_fn)dlsym(RTLD_NEXT, "__cxa_throw");
+
+       void *thrown_ptr = obj;
+       const type_info *tinfo = static_cast<type_info *>(pvtinfo);
+       const type_info *boost_exc = &typeid(boost::exception);
+
+       /* Check if the exception is a pointer type. */
+       if (tinfo->__is_pointer_p())
+               thrown_ptr = *(void **)thrown_ptr;
+
+       /* Check if thrown_ptr inherits from boost::exception. */
+       if (boost_exc->__do_catch(tinfo, &thrown_ptr, 1)) {
+               boost::exception *ex = (boost::exception *)thrown_ptr;
+
+               StackTrace trace;
+               *ex << StackTraceErrorInfo(trace);
+       }
+
+       real_cxa_throw(obj, pvtinfo, dest);
+}
+#endif /* _WIN32 */
+
+StackTrace *Exception::GetLastStackTrace(void)
+{
+       return m_StackTrace;
+}
+
+void Exception::SetLastStackTrace(const StackTrace& trace)
+{
+       if (m_StackTrace)
+               delete m_StackTrace;
+
+       m_StackTrace = new StackTrace(trace);
+}
+
index dbf574a91c0ab8754e70e8e9617450fb98f4d140..8d7335796f587d81f0f3347ffbc0ed74eb631979 100644 (file)
@@ -54,6 +54,9 @@ public:
 
        virtual const char *what(void) const throw();
 
+       static StackTrace *GetLastStackTrace(void);
+       static void SetLastStackTrace(const StackTrace& trace);
+
 protected:
        void SetCode(int code);
        void SetMessage(String message);
@@ -61,8 +64,12 @@ protected:
 private:
        String m_Message;
        int m_Code;
+
+       static StackTrace *m_StackTrace;
 };
 
+typedef boost::error_info<StackTrace, StackTrace> StackTraceErrorInfo;
+
 #define DEFINE_EXCEPTION_CLASS(klass)                                  \
        class klass : public Exception                                  \
        {                                                               \
index 28c3ab14753b07d989d8d007453db3af524057b8..4f0771166794ea723990f7732ee8ebcb560710fa 100644 (file)
@@ -102,7 +102,7 @@ void StackTrace::Initialize(void)
  *                    the one this function is executing in).
  * @returns true if the stacktrace was printed, false otherwise.
  */
-void StackTrace::Print(ostream& fp, int ignoreFrames)
+void StackTrace::Print(ostream& fp, int ignoreFrames) const
 {
        fp << std::endl << "Stacktrace:" << std::endl;
 
@@ -170,3 +170,9 @@ void StackTrace::Print(ostream& fp, int ignoreFrames)
        }
 #endif /* _WIN32 */
 }
+
+ostream& icinga::operator<<(ostream& stream, const StackTrace& trace)
+{
+       trace.Print(stream, 1);
+}
+
index a25994ac76d720b478644eb2f335357d33dc51bd..9728b47bcc7dcc2404293adb34cc945f4114c7d4 100644 (file)
@@ -36,7 +36,7 @@ public:
        StackTrace(PEXCEPTION_POINTERS exi);
 #endif /* _WIN32 */
 
-       void Print(ostream& fp, int ignoreFrames = 0);
+       void Print(ostream& fp, int ignoreFrames = 0) const;
 
 private:
        void *m_Frames[64];
@@ -47,6 +47,8 @@ private:
        static void Initialize(void);
 };
 
+I2_BASE_API ostream& operator<<(ostream& stream, const StackTrace& trace);
+
 }
 
 #endif /* UTILITY_H */
index de72451b2c02693b15d4fed4ca7efd8ef0a0c504..c58da417e78dd2bb42a8aa8d19974c3efc18cae2 100644 (file)
@@ -37,6 +37,7 @@
 #include <poll.h>
 #include <glob.h>
 #include <ltdl.h>
+#include <dlfcn.h>
 
 typedef int SOCKET;
 #define INVALID_SOCKET (-1)
diff --git a/m4/ax_c___attribute__.m4 b/m4/ax_c___attribute__.m4
deleted file mode 100644 (file)
index cf3d62b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-# ===========================================================================
-#    http://www.gnu.org/software/autoconf-archive/ax_c___attribute__.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-#   AX_C___ATTRIBUTE__
-#
-# DESCRIPTION
-#
-#   Provides a test for the compiler support of __attribute__ extensions.
-#   Defines HAVE___ATTRIBUTE__ if it is found.
-#
-# LICENSE
-#
-#   Copyright (c) 2008 Stepan Kasal <skasal@redhat.com>
-#   Copyright (c) 2008 Christian Haggstrom
-#   Copyright (c) 2008 Ryan McCabe <ryan@numb.org>
-#
-#   This program is free software; you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by the
-#   Free Software Foundation; either version 2 of the License, or (at your
-#   option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-#   Public License for more details.
-#
-#   You should have received a copy of the GNU General Public License along
-#   with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-#   As a special exception, the respective Autoconf Macro's copyright owner
-#   gives unlimited permission to copy, distribute and modify the configure
-#   scripts that are the output of Autoconf when processing the Macro. You
-#   need not follow the terms of the GNU General Public License when using
-#   or distributing such scripts, even though portions of the text of the
-#   Macro appear in them. The GNU General Public License (GPL) does govern
-#   all other use of the material that constitutes the Autoconf Macro.
-#
-#   This special exception to the GPL applies to versions of the Autoconf
-#   Macro released by the Autoconf Archive. When you make and distribute a
-#   modified version of the Autoconf Macro, you may extend this special
-#   exception to the GPL to apply to your modified version as well.
-
-#serial 8
-
-AC_DEFUN([AX_C___ATTRIBUTE__], [
-  AC_CACHE_CHECK([for __attribute__], [ax_cv___attribute__],
-    [AC_COMPILE_IFELSE(
-      [AC_LANG_PROGRAM(
-       [[#include <stdlib.h>
-         static void foo(void) __attribute__ ((unused));
-         static void
-         foo(void) {
-             exit(1);
-         }
-        ]], [])],
-      [ax_cv___attribute__=yes],
-      [ax_cv___attribute__=no]
-    )
-  ])
-  if test "$ax_cv___attribute__" = "yes"; then
-    AC_DEFINE([HAVE___ATTRIBUTE__], 1, [define if your compiler has __attribute__])
-  fi
-])