From: Gunnar Beutner <gunnar@beutner.name> Date: Sat, 8 Aug 2015 07:40:16 +0000 (+0200) Subject: Implement support for attaching GDB to the Icinga process on crash X-Git-Tag: v2.4.0~441 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8f3396ae0d6015b6c1856171a2efea7faf2ea49f;p=icinga2 Implement support for attaching GDB to the Icinga process on crash fixes #9866 --- diff --git a/doc/19-language-reference.md b/doc/19-language-reference.md index a63b16e65..e7f039fbd 100644 --- a/doc/19-language-reference.md +++ b/doc/19-language-reference.md @@ -375,6 +375,7 @@ EnableHostChecks |**Read-write.** Whether active host checks are globally ena EnableServiceChecks |**Read-write.** Whether active service checks are globally enabled. Defaults to true. EnablePerfdata |**Read-write.** Whether performance data processing is globally enabled. Defaults to true. UseVfork |**Read-write.** Whether to use vfork(). Only available on *NIX. Defaults to true. +AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to false. RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index de5aeeebb..de270bc0f 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -173,6 +173,8 @@ int Main(void) ScriptGlobal::Set("UseVfork", true); #endif /* __APPLE__ */ + ScriptGlobal::Set("AttachDebugger", false); + LogSeverity logLevel = Logger::GetConsoleLogSeverity(); Logger::SetConsoleLogSeverity(LogWarning); diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 628fb5988..b32ea4fb8 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -626,9 +626,9 @@ String Application::GetCrashReportFilename(void) } -#ifndef _WIN32 -void Application::GetDebuggerBacktrace(const String& filename) +void Application::AttachDebugger(const String& filename, bool interactive) { +#ifndef _WIN32 #ifdef __linux__ prctl(PR_SET_DUMPABLE, 1); #endif /* __linux __ */ @@ -644,42 +644,58 @@ void Application::GetDebuggerBacktrace(const String& filename) } if (pid == 0) { - int fd = open(filename.CStr(), O_CREAT | O_RDWR | O_APPEND, 0600); + if (!interactive) { + 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 < 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); - if (fd != 1) { - /* redirect stdout to the file */ - dup2(fd, 1); - close(fd); + dup2(1, 2); } - /* redirect stderr to stdout */ - if (fd != 2) - close(2); + char **argv; + char *my_pid_str = strdup(my_pid.CStr()); - dup2(1, 2); + if (interactive) { + const char *uargv[] = { + "gdb", + "-p", + my_pid_str, + NULL + }; + argv = const_cast<char **>(uargv); + } else { + const char *uargv[] = { + "gdb", + "--batch", + "-p", + my_pid_str, + "-ex", + "thread apply all bt full", + "-ex", + "detach", + "-ex", + "quit", + NULL + }; + argv = const_cast<char **>(uargv); + } - 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)); + (void)execvp(argv[0], argv); perror("Failed to launch GDB"); free(my_pid_str); _exit(0); @@ -695,6 +711,9 @@ void Application::GetDebuggerBacktrace(const String& filename) #ifdef __linux__ prctl(PR_SET_DUMPABLE, 0); #endif /* __linux __ */ +#else /* _WIN32 */ + DebugBreak(); +#endif /* _WIN32 */ } /** @@ -750,30 +769,33 @@ void Application::SigAbrtHandler(int) String fname = GetCrashReportFilename(); Utility::MkDir(Utility::DirName(fname), 0750); - std::ofstream ofs; - ofs.open(fname.CStr()); + bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger")); - Log(LogCritical, "Application") - << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'" << "\n"; + if (!interactive_debugger) { + std::ofstream ofs; + ofs.open(fname.CStr()); - DisplayInfoMessage(ofs); + Log(LogCritical, "Application") + << "Icinga 2 has terminated unexpectedly. Additional information can be found in '" << fname << "'" << "\n"; - StackTrace trace; - ofs << "Stacktrace:" << "\n"; - trace.Print(ofs, 1); + DisplayInfoMessage(ofs); - DisplayBugMessage(ofs); + StackTrace trace; + ofs << "Stacktrace:" << "\n"; + trace.Print(ofs, 1); -#ifndef _WIN32 - ofs << "\n"; - ofs.close(); + DisplayBugMessage(ofs); - GetDebuggerBacktrace(fname); -#else /* _WIN32 */ - ofs.close(); -#endif /* _WIN32 */ + ofs << "\n"; + ofs.close(); + } else { + Log(LogCritical, "Application", "Icinga 2 has terminated unexpeectedly. Attaching debugger..."); + } + + AttachDebugger(fname, interactive_debugger); } -#else /* _WIN32 */ + +#ifdef _WIN32 /** * Console control handler. Prepares the application for cleanly * shutting down during the next execution of the event loop. @@ -813,35 +835,37 @@ void Application::ExceptionHandler(void) String fname = GetCrashReportFilename(); Utility::MkDir(Utility::DirName(fname), 0750); - std::ofstream ofs; - ofs.open(fname.CStr()); + bool interactive_debugger = Convert::ToBool(ScriptGlobal::Get("AttachDebugger")); - ofs << "Caught unhandled exception." << "\n" - << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n" - << "\n"; + if (interactive_debugger) { + std::ofstream ofs; + ofs.open(fname.CStr()); - DisplayInfoMessage(ofs); + ofs << "Caught unhandled exception." << "\n" + << "Current time: " << Utility::FormatDateTime("%Y-%m-%d %H:%M:%S %z", Utility::GetTime()) << "\n" + << "\n"; - try { - RethrowUncaughtException(); - } catch (const std::exception& ex) { - Log(LogCritical, "Application") - << DiagnosticInformation(ex, false) << "\n" - << "\n" - << "Additional information is available in '" << fname << "'" << "\n"; + DisplayInfoMessage(ofs); - ofs << "\n" - << DiagnosticInformation(ex) - << "\n"; - } + try { + RethrowUncaughtException(); + } catch (const std::exception& ex) { + Log(LogCritical, "Application") + << DiagnosticInformation(ex, false) << "\n" + << "\n" + << "Additional information is available in '" << fname << "'" << "\n"; + + ofs << "\n" + << DiagnosticInformation(ex) + << "\n"; + } - DisplayBugMessage(ofs); + DisplayBugMessage(ofs); - ofs.close(); + ofs.close(); + } -#ifndef _WIN32 - GetDebuggerBacktrace(fname); -#endif /* _WIN32 */ + AttachDebugger(fname, interactive_debugger); abort(); } diff --git a/lib/base/application.hpp b/lib/base/application.hpp index ffcfacefa..a874db9c0 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -175,9 +175,7 @@ private: static String GetCrashReportFilename(void); -#ifndef _WIN32 - static void GetDebuggerBacktrace(const String& filename); -#endif /* _WIN32 */ + static void AttachDebugger(const String& filename, bool interactive); }; }