From 3615716983508d49be5644ab2d6f2a43bd73ecd4 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 3 Mar 2015 13:53:11 +0100 Subject: [PATCH] Include GDB backtrace in crash reports fixes #8575 --- lib/base/application.cpp | 82 ++++++++++++++++++++++++++++++++++++++++ lib/base/application.hpp | 4 ++ 2 files changed, 86 insertions(+) diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 0bef83db3..b0a0ad4b2 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -38,6 +38,9 @@ #include #include #include +#ifdef __linux__ +#include +#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(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(); } diff --git a/lib/base/application.hpp b/lib/base/application.hpp index 6ed9c648f..bc2b73a1b 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -178,6 +178,10 @@ private: static void ExceptionHandler(void); static String GetCrashReportFilename(void); + +#ifndef _WIN32 + static void GetDebuggerBacktrace(const String& filename); +#endif /* _WIN32 */ }; }