Implement automated stacktraces for exceptions.

This commit is contained in:
Gunnar Beutner 2013-03-07 19:44:39 +01:00
parent e2416b5b54
commit cada2abeb3
9 changed files with 75 additions and 77 deletions

View 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;
}

View 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])

View 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();

View 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);
}

View 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 \
{ \

View 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);
}

View 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 */

View File

@ -37,6 +37,7 @@
#include <poll.h>
#include <glob.h>
#include <ltdl.h>
#include <dlfcn.h>
typedef int SOCKET;
#define INVALID_SOCKET (-1)

View File

@ -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
])