]> granicus.if.org Git - icinga2/commitdiff
Include GDB backtrace in crash reports
authorGunnar Beutner <gunnar@beutner.name>
Tue, 3 Mar 2015 12:53:11 +0000 (13:53 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Tue, 3 Mar 2015 12:53:11 +0000 (13:53 +0100)
fixes #8575

lib/base/application.cpp
lib/base/application.hpp

index 0bef83db3cb186752b810174b9c83e95207aacd0..b0a0ad4b2f174782fd0ae3ce2b0b4888c5cea5f4 100644 (file)
@@ -38,6 +38,9 @@
 #include <sstream>
 #include <iostream>
 #include <fstream>
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif /* __linux__ */
 
 using namespace icinga;
 
@@ -498,7 +501,78 @@ String Application::GetCrashReportFilename(void)
        return GetLocalStateDir() + "/log/icinga2/crash/report." + Convert::ToString(Utility::GetTime());
 }
 
+
 #ifndef _WIN32
+void Application::GetDebuggerBacktrace(const String& filename)
+{
+#ifdef __linux__
+       prctl(PR_SET_DUMPABLE, 1);
+#endif /* __linux __ */
+
+       String my_pid = Convert::ToString(Utility::GetPid());
+
+       pid_t pid = fork();
+
+       if (pid < 0) {
+               BOOST_THROW_EXCEPTION(posix_error()
+                   << boost::errinfo_api_function("fork")
+                   << boost::errinfo_errno(errno));
+       }
+
+       if (pid == 0) {
+               int fd = open(filename.CStr(), O_CREAT | O_RDWR | O_APPEND, 0600);
+
+               if (fd < 0) {
+                       BOOST_THROW_EXCEPTION(posix_error()
+                           << boost::errinfo_api_function("open")
+                           << boost::errinfo_errno(errno)
+                           << boost::errinfo_file_name(filename));
+               }
+
+               if (fd != 1) {
+                       /* redirect stdout to the file */
+                       dup2(fd, 1);
+                       close(fd);
+               }
+
+               /* redirect stderr to stdout */
+               if (fd != 2)
+                       close(2);
+
+               dup2(1, 2);
+
+               char *my_pid_str = strdup(my_pid.CStr());
+               const char *argv[] = {
+                       "gdb",
+                       "--batch",
+                       "-p",
+                       my_pid_str,
+                       "-ex",
+                       "thread apply all bt full",
+                       "-ex",
+                       "detach",
+                       "-ex",
+                       "quit",
+                       NULL
+               };
+               (void)execvp(argv[0], const_cast<char **>(argv));
+               perror("Failed to launch GDB");
+               free(my_pid_str);
+               _exit(0);
+       }
+
+       int status;
+       if (waitpid(pid, &status, 0) < 0) {
+               BOOST_THROW_EXCEPTION(posix_error()
+                   << boost::errinfo_api_function("waitpid")
+                   << boost::errinfo_errno(errno));
+       }
+
+#ifdef __linux__
+       prctl(PR_SET_DUMPABLE, 0);
+#endif /* __linux __ */
+}
+
 /**
  * Signal handler for SIGINT and SIGTERM. Prepares the application for cleanly
  * shutting down during the next execution of the event loop.
@@ -565,6 +639,10 @@ void Application::SigAbrtHandler(int)
        DisplayBugMessage(ofs);
 
        ofs.close();
+
+#ifndef _WIN32
+       GetDebuggerBacktrace(fname);
+#endif /* _WIN32 */
 }
 #else /* _WIN32 */
 /**
@@ -630,6 +708,10 @@ void Application::ExceptionHandler(void)
 
        ofs.close();
 
+#ifndef _WIN32
+       GetDebuggerBacktrace(fname);
+#endif /* _WIN32 */
+
        abort();
 }
 
index 6ed9c648f745109d1beae99657f309643e6c4b83..bc2b73a1ba7cfaeccb30f7d3b5fd97362f6e63ad 100644 (file)
@@ -178,6 +178,10 @@ private:
        static void ExceptionHandler(void);
 
        static String GetCrashReportFilename(void);
+
+#ifndef _WIN32
+       static void GetDebuggerBacktrace(const String& filename);
+#endif /* _WIN32 */
 };
 
 }