Move exception_handler into libbase. Add handler for SIGABRT.

Fixes #3590
This commit is contained in:
Gunnar Beutner 2013-01-30 11:51:15 +01:00
parent 20958d0ba8
commit ff0e6d91d2
5 changed files with 126 additions and 65 deletions

View File

@ -18,9 +18,7 @@
******************************************************************************/
#include <i2-icinga.h>
#ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h>
#endif /* HAVE_BACKTRACE_SYMBOLS */
#ifndef _WIN32
# include "icinga-version.h"
@ -31,65 +29,6 @@
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.
*
@ -99,8 +38,6 @@ static void exception_handler(void)
*/
int main(int argc, char **argv)
{
std::set_terminate(exception_handler);
#ifndef _WIN32
LTDL_SET_PRELOADED_SYMBOLS();
#endif /* _WIN32 */
@ -113,6 +50,9 @@ int main(int argc, char **argv)
* 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 */

View File

@ -297,6 +297,20 @@ void Application::SigIntHandler(int signum)
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
@ -316,6 +330,54 @@ BOOL WINAPI Application::CtrlHandler(DWORD type)
}
#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.
*
@ -335,7 +397,7 @@ int Application::Run(int argc, char **argv)
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
#else
#else /* _WIN32 */
SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE);
#endif /* _WIN32 */

View File

@ -49,6 +49,8 @@ public:
*/
virtual int Main(const vector<String>& args) = 0;
static void InstallExceptionHandlers(void);
static void RequestShutdown(void);
static void Terminate(int exitCode);
@ -89,10 +91,13 @@ private:
#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);
};

View File

@ -19,6 +19,9 @@
#include "i2-base.h"
#include <mmatch.h>
#ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h>
#endif /* HAVE_BACKTRACE_SYMBOLS */
using namespace icinga;
@ -58,6 +61,56 @@ String Utility::GetTypeName(const type_info& ti)
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.
*/

View File

@ -33,6 +33,7 @@ class I2_BASE_API Utility
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);