diff --git a/CMakeLists.txt b/CMakeLists.txt index bebda7145..9717f16a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,11 @@ check_function_exists(backtrace_symbols HAVE_BACKTRACE_SYMBOLS) check_function_exists(pipe2 HAVE_PIPE2) check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR) check_library_exists(crypto BIO_f_zlib "" HAVE_BIOZLIB) +check_library_exists(execinfo backtrace_symbols "" HAVE_LIBEXECINFO) + +if(HAVE_LIBEXECINFO) + set(HAVE_BACKTRACE_SYMBOLS TRUE) +endif() include(GNUInstallDirs) configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ESCAPE_QUOTES) diff --git a/INSTALL b/INSTALL index d1c53258c..a991ce12b 100644 --- a/INSTALL +++ b/INSTALL @@ -27,6 +27,7 @@ parentheses): on Debian) * GNU bison (bison) * GNU flex (flex) >= 2.5.35 +* recommended: libexecinfo on FreeBSD * optional: Doxygen (doxygen) * optional: MySQL (mysql-devel on RHEL, libmysqlclient-dev on Debian) * optional: Python (python-devel on RHEL, python-dev on Debian) diff --git a/config.h.cmake b/config.h.cmake index 68dec8472..6ecb997e2 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -6,6 +6,7 @@ #cmakedefine HAVE_PIPE2 #cmakedefine HAVE_VFORK #cmakedefine HAVE_DLADDR +#cmakedefine HAVE_LIBEXECINFO #define ICINGA_PREFIX "${CMAKE_INSTALL_PREFIX}" #define ICINGA_SYSCONFDIR "${CMAKE_INSTALL_FULL_SYSCONFDIR}" diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 9c0ec21b9..7709d2a0a 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -38,6 +38,10 @@ add_library(base SHARED target_link_libraries(base ${CMAKE_DL_LIBS} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} cJSON mmatch) +if(HAVE_LIBEXECINFO) + target_link_libraries(base execinfo) +endif() + include_directories(${icinga2_SOURCE_DIR}/third-party/cJSON) link_directories(${icinga2_BINARY_DIR}/third-party/cJSON) diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 06accac69..3845e0733 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -452,7 +452,7 @@ void Application::ExceptionHandler(void) DisplayVersionMessage(); try { - throw; + RethrowUncaughtException(); } catch (const std::exception& ex) { std::cerr << std::endl << DiagnosticInformation(ex) diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index 2e785371f..7f0f60ba6 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -25,12 +25,38 @@ static boost::thread_specific_ptr l_LastExceptionStack; static boost::thread_specific_ptr l_LastExceptionContext; #ifndef _WIN32 +#ifndef __GLIBCXX__ +static boost::thread_specific_ptr l_LastExceptionObj; +static boost::thread_specific_ptr l_LastExceptionPvtInfo; + +typedef void (*DestCallback)(void *); +static boost::thread_specific_ptr l_LastExceptionDest; + +extern "C" void __cxa_throw(void *obj, void *pvtinfo, void (*dest)(void *)); +extern "C" void __cxa_rethrow_primary_exception(void* thrown_object); +#endif /* __GLIBCXX__ */ + +void icinga::RethrowUncaughtException(void) +{ +#ifdef __GLIBCXX__ + throw; +#else /* __GLIBCXX__ */ + __cxa_throw(*l_LastExceptionObj.get(), *l_LastExceptionPvtInfo.get(), *l_LastExceptionDest.get()); +#endif /* __GLIBCXX__ */ +} + 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; +#ifndef __GLIBCXX__ + l_LastExceptionObj.reset(new void *(obj)); + l_LastExceptionPvtInfo.reset(new void *(pvtinfo)); + l_LastExceptionDest.reset(new DestCallback(dest)); +#endif /* __GLIBCXX__ */ + if (real_cxa_throw == 0) real_cxa_throw = (cxa_throw_fn)dlsym(RTLD_NEXT, "__cxa_throw"); diff --git a/lib/base/exception.h b/lib/base/exception.h index 79783c5e7..0cb79634f 100644 --- a/lib/base/exception.h +++ b/lib/base/exception.h @@ -47,6 +47,8 @@ I2_BASE_API void SetLastExceptionStack(const StackTrace& trace); I2_BASE_API ContextTrace *GetLastExceptionContext(void); I2_BASE_API void SetLastExceptionContext(const ContextTrace& context); +I2_BASE_API void RethrowUncaughtException(void); + typedef boost::error_info StackTraceErrorInfo; typedef boost::error_info ContextTraceErrorInfo;