From cada2abeb36d64e70ac00b447c2c20f781544075 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 7 Mar 2013 19:44:39 +0100 Subject: [PATCH] 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(-) delete mode 100644 m4/ax_c___attribute__.m4 diff --git a/components/compat/compatcomponent.cpp b/components/compat/compatcomponent.cpp index 139dbfae8..af6e6f05f 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 8bcaa7774..cf1ec7ea2 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 e5b2f19c7..326c7a2cb 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(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 04d64edf2..810c336b7 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(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 dbf574a91..8d7335796 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 StackTraceErrorInfo; + #define DEFINE_EXCEPTION_CLASS(klass) \ class klass : public Exception \ { \ diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp index 28c3ab147..4f0771166 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 a25994ac7..9728b47bc 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 de72451b2..c58da417e 100644 --- a/lib/base/unix.h +++ b/lib/base/unix.h @@ -37,6 +37,7 @@ #include #include #include +#include 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 cf3d62bbd..000000000 --- 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 -# Copyright (c) 2008 Christian Haggstrom -# Copyright (c) 2008 Ryan McCabe -# -# 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 . -# -# 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 - 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 -]) -- 2.40.0