[icinga-checkins] icinga.org: icinga2/master: Implement automated stacktraces for exceptions.

git at icinga.org git at icinga.org
Thu Mar 7 19:44:54 CET 2013


Module: icinga2
Branch: master
Commit: cada2abeb36d64e70ac00b447c2c20f781544075
URL:    https://git.icinga.org/?p=icinga2.git;a=commit;h=cada2abeb36d64e70ac00b447c2c20f781544075

Author: Gunnar Beutner <gunnar.beutner at netways.de>
Date:   Thu Mar  7 19:44:39 2013 +0100

Implement automated stacktraces for exceptions.

---

 components/compat/compatcomponent.cpp |    2 +-
 configure.ac                          |    6 ---
 lib/base/application.cpp              |   12 +++++-
 lib/base/exception.cpp                |   46 +++++++++++++++++++++++
 lib/base/exception.h                  |    7 +++
 lib/base/stacktrace.cpp               |    8 +++-
 lib/base/stacktrace.h                 |    4 +-
 lib/base/unix.h                       |    1 +
 m4/ax_c___attribute__.m4              |   66 ---------------------------------
 9 files changed, 75 insertions(+), 77 deletions(-)

diff --git a/components/compat/compatcomponent.cpp b/components/compat/compatcomponent.cpp
index 139dbfa..af6e6f0 100644
--- a/components/compat/compatcomponent.cpp
+++ b/components/compat/compatcomponent.cpp
@@ -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;
 }
diff --git a/configure.ac b/configure.ac
index 8bcaa77..cf1ec7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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])
diff --git a/lib/base/application.cpp b/lib/base/application.cpp
index e5b2f19..326c7a2 100644
--- a/lib/base/application.cpp
+++ b/lib/base/application.cpp
@@ -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();
 
diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp
index 04d64ed..810c336 100644
--- a/lib/base/exception.cpp
+++ b/lib/base/exception.cpp
@@ -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);
+}
+
diff --git a/lib/base/exception.h b/lib/base/exception.h
index dbf574a..8d73357 100644
--- a/lib/base/exception.h
+++ b/lib/base/exception.h
@@ -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					\
 	{								\
diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp
index 28c3ab1..4f07711 100644
--- a/lib/base/stacktrace.cpp
+++ b/lib/base/stacktrace.cpp
@@ -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);
+}
+
diff --git a/lib/base/stacktrace.h b/lib/base/stacktrace.h
index a25994a..9728b47 100644
--- a/lib/base/stacktrace.h
+++ b/lib/base/stacktrace.h
@@ -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 */
diff --git a/lib/base/unix.h b/lib/base/unix.h
index de72451..c58da41 100644
--- a/lib/base/unix.h
+++ b/lib/base/unix.h
@@ -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
index cf3d62b..0000000
--- a/m4/ax_c___attribute__.m4
+++ /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 at redhat.com>
-#   Copyright (c) 2008 Christian Haggstrom
-#   Copyright (c) 2008 Ryan McCabe <ryan at 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
-])





More information about the icinga-checkins mailing list