******************************************************************************/
#include <i2-icinga.h>
-#ifdef HAVE_BACKTRACE_SYMBOLS
-# include <execinfo.h>
-#endif /* HAVE_BACKTRACE_SYMBOLS */
+
#ifndef _WIN32
# include "icinga-version.h"
using namespace icinga;
-/**
- * Handler for unhandled exceptions.
- *
- */
-static void exception_handler(void)
-{
- static bool rethrow = true;
-
- try {
- rethrow = false;
- throw;
- } catch (const std::exception& ex) {
- std::cerr << std::endl;
- std::cerr << "Unhandled exception of type "
- << Utility::GetTypeName(typeid(ex))
- << std::endl;
- std::cerr << "Diagnostic Information: "
- << ex.what()
- << std::endl;
- }
-
-#ifdef HAVE_BACKTRACE_SYMBOLS
- void *frames[50];
- int framecount = backtrace(frames, sizeof(frames) / sizeof(frames[0]));
-
- char **messages = backtrace_symbols(frames, framecount);
-
- std::cerr << std::endl << "Stacktrace:" << std::endl;
-
- for (int i = 0; i < framecount && messages != NULL; ++i) {
- String message = messages[i];
-
- char *sym_begin = strchr(messages[i], '(');
-
- if (sym_begin != NULL) {
- char *sym_end = strchr(sym_begin, '+');
-
- if (sym_end != NULL) {
- String sym = String(sym_begin + 1, sym_end);
- String sym_demangled = Utility::DemangleSymbolName(sym);
-
- if (sym_demangled.IsEmpty())
- sym_demangled = "<unknown function>";
-
- message = String(messages[i], sym_begin) + ": " + sym_demangled + " (" + String(sym_end);
- }
- }
-
- std::cerr << "\t(" << i << ") " << message << std::endl;
- }
-
- free(messages);
-
- std::cerr << std::endl;
-#endif /* HAVE_BACKTRACE_SYMBOLS */
-
- abort();
-}
-
/**
* Entry point for the Icinga application.
*
*/
int main(int argc, char **argv)
{
- std::set_terminate(exception_handler);
-
#ifndef _WIN32
LTDL_SET_PRELOADED_SYMBOLS();
#endif /* _WIN32 */
* in the base library. */
Application::SetMainThread();
+ /* Install exception handlers to make debugging easier. */
+ Application::InstallExceptionHandlers();
+
#ifdef ICINGA_PREFIX
Application::SetPrefixDir(ICINGA_PREFIX);
#endif /* ICINGA_PREFIX */
sa.sa_handler = SIG_DFL;
sigaction(SIGINT, &sa, NULL);
}
+
+/**
+ * Signal handler for SIGABRT. Helps with debugging assert()s.
+ *
+ * @param signum The signal number.
+ */
+void Application::SigAbrtHandler(int signum)
+{
+ assert(signum == SIGABRT);
+
+ std::cerr << "Caught SIGABRT." << std::endl;
+
+ Utility::PrintStacktrace(std::cerr, 1);
+}
#else /* _WIN32 */
/**
* Console control handler. Prepares the application for cleanly
}
#endif /* _WIN32 */
+/**
+ * Handler for unhandled exceptions.
+ */
+void Application::ExceptionHandler(void)
+{
+ static bool rethrow = true;
+
+ try {
+ rethrow = false;
+ throw;
+ } catch (const std::exception& ex) {
+ std::cerr << std::endl;
+ std::cerr << "Unhandled exception of type "
+ << Utility::GetTypeName(typeid(ex))
+ << std::endl;
+ std::cerr << "Diagnostic Information: "
+ << ex.what()
+ << std::endl;
+ }
+
+ Utility::PrintStacktrace(std::cerr, 1);
+
+#ifndef _WIN32
+ struct sigaction sa;
+ memset(&sa, sizeof(sa), 0);
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGABRT, &sa, NULL);
+#endif /* _WIN32 */
+
+ abort();
+}
+
+
+/**
+ * Installs the exception handlers.
+ */
+void Application::InstallExceptionHandlers(void)
+{
+ std::set_terminate(&Application::ExceptionHandler);
+
+#ifndef _WIN32
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = &Application::SigAbrtHandler;
+ sigaction(SIGABRT, &sa, NULL);
+#endif /* _WIN32 */
+}
+
/**
* Runs the application.
*
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
-#else
+#else /* _WIN32 */
SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE);
#endif /* _WIN32 */
*/
virtual int Main(const vector<String>& args) = 0;
+ static void InstallExceptionHandlers(void);
+
static void RequestShutdown(void);
static void Terminate(int exitCode);
#ifndef _WIN32
static void SigIntHandler(int signum);
+ static void SigAbrtHandler(int signum);
#else /* _WIN32 */
static BOOL WINAPI CtrlHandler(DWORD type);
#endif /* _WIN32 */
+ static void ExceptionHandler(void);
+
static void TimeWatchThreadProc(void);
};
#include "i2-base.h"
#include <mmatch.h>
+#ifdef HAVE_BACKTRACE_SYMBOLS
+# include <execinfo.h>
+#endif /* HAVE_BACKTRACE_SYMBOLS */
using namespace icinga;
return DemangleSymbolName(ti.name());
}
+/**
+ * Prints a stacktrace to the specified stream.
+ *
+ * @param fp The stream.
+ * @param ignoreFrames The number of stackframes to ignore (in addition to
+ * the one this function is executing in).
+ * @returns true if the stacktrace was printed, false otherwise.
+ */
+bool Utility::PrintStacktrace(ostream& fp, int ignoreFrames)
+{
+#ifdef HAVE_BACKTRACE_SYMBOLS
+ void *frames[50];
+ int framecount = backtrace(frames, sizeof(frames) / sizeof(frames[0]));
+
+ char **messages = backtrace_symbols(frames, framecount);
+
+ fp << std::endl << "Stacktrace:" << std::endl;
+
+ for (int i = ignoreFrames + 1; i < framecount && messages != NULL; ++i) {
+ String message = messages[i];
+
+ char *sym_begin = strchr(messages[i], '(');
+
+ if (sym_begin != NULL) {
+ char *sym_end = strchr(sym_begin, '+');
+
+ if (sym_end != NULL) {
+ String sym = String(sym_begin + 1, sym_end);
+ String sym_demangled = Utility::DemangleSymbolName(sym);
+
+ if (sym_demangled.IsEmpty())
+ sym_demangled = "<unknown function>";
+
+ message = String(messages[i], sym_begin) + ": " + sym_demangled + " (" + String(sym_end);
+ }
+ }
+
+ fp << "\t(" << i - ignoreFrames - 1 << ") " << message << std::endl;
+ }
+
+ free(messages);
+
+ fp << std::endl;
+
+ return true;
+#else /* HAVE_BACKTRACE_SYMBOLS */
+ return false;
+#endif /* HAVE_BACKTRACE_SYMBOLS */
+}
+
/**
* Detaches from the controlling terminal.
*/
public:
static String DemangleSymbolName(const String& sym);
static String GetTypeName(const type_info& ti);
+ static bool PrintStacktrace(ostream& fp, int ignoreFrames = 0);
static void Daemonize(void);