From fa8ef65cd74a560ff7d14d965a3c46a558989e44 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 20 Jul 2011 09:57:29 +0000 Subject: [PATCH] * Added better handling of SIGBUS, including the error type and fault address in the dump. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1247 e378c898-3ddf-0310-93e7-cc216c733640 --- src/main.cc | 54 ++++++++++++++++++++++++++++++++++++++++++- src/signal_handler.cc | 16 +++++++++++++ src/signal_handler.h | 5 ++++ 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/main.cc b/src/main.cc index 7f714aea..67b8a7d9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef USE_EXECINFO #include @@ -73,6 +74,7 @@ #include "thread_main.h" #include "thread_worker.h" +void handle_sigbus(int signum, siginfo_t* sa, void* ptr); void do_panic(int signum); void print_help(); void initialize_commands(); @@ -178,9 +180,10 @@ main(int argc, char** argv) { SignalHandler::set_handler(SIGWINCH, sigc::mem_fun(control->display(), &display::Manager::force_redraw)); SignalHandler::set_handler(SIGSEGV, sigc::bind(sigc::ptr_fun(&do_panic), SIGSEGV)); SignalHandler::set_handler(SIGILL, sigc::bind(sigc::ptr_fun(&do_panic), SIGILL)); - SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS)); SignalHandler::set_handler(SIGFPE, sigc::bind(sigc::ptr_fun(&do_panic), SIGFPE)); + SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus); + // SIGUSR1 is used for interrupting polling, forcing that thread // to process new non-socket events. SignalHandler::set_handler(SIGUSR1, sigc::ptr_fun(&do_nothing)); @@ -877,6 +880,55 @@ main(int argc, char** argv) { return 0; } +void +handle_sigbus(int signum, siginfo_t* sa, void* ptr) { + if (signum != SIGBUS) + do_panic(signum); + + SignalHandler::set_default(signum); + display::Canvas::cleanup(); + + // Use printf here instead... + + printf("Caught SIGBUS, dumping stack:\n"); + +#ifdef USE_EXECINFO + void* stackPtrs[20]; + + // Print the stack and exit. + int stackSize = backtrace(stackPtrs, 20); + char** stackStrings = backtrace_symbols(stackPtrs, stackSize); + + for (int i = 0; i < stackSize; ++i) + printf("%i %s\n", i, stackStrings[i]); + +#else + printf("Stack dump not enabled.\n"); +#endif + + printf("\nError: %s\n", rak::error_number::error_number(sa->si_errno).c_str()); + + const char* signal_reason; + + switch (sa->si_code) { + case BUS_ADRALN: signal_reason = "Invalid address alignment."; break; + case BUS_ADRERR: signal_reason = "Non-existent physical address."; break; + case BUS_OBJERR: signal_reason = "Object specific hardware error."; break; + default: + if (sa->si_code <= 0) + signal_reason = "User-generated signal."; + else + signal_reason = "Unknown."; + + break; + }; + + printf("Signal code '%i': %s\n", sa->si_code, signal_reason); + printf("Fault address: %p.\n", sa->si_addr); + + std::abort(); +} + void do_panic(int signum) { // Use the default signal handler in the future to avoid infinit diff --git a/src/signal_handler.cc b/src/signal_handler.cc index 4b5eb55b..85be25e5 100644 --- a/src/signal_handler.cc +++ b/src/signal_handler.cc @@ -36,7 +36,9 @@ #include "config.h" +#include #include +#include "rak/error_number.h" #include "signal_handler.h" SignalHandler::Slot SignalHandler::m_handlers[HIGHEST_SIGNAL]; @@ -71,6 +73,20 @@ SignalHandler::set_handler(unsigned int signum, Slot slot) { m_handlers[signum] = slot; } +void +SignalHandler::set_sigaction_handler(unsigned int signum, handler_slot slot) { + if (signum > HIGHEST_SIGNAL) + throw std::logic_error("SignalHandler::set_handler(...) received invalid signal value."); + + struct sigaction sa; + sa.sa_sigaction = slot; + sa.sa_mask = 0; + sa.sa_flags = SA_SIGINFO; + + if (sigaction(signum, &sa, NULL) == -1) + throw std::logic_error("Could not set sigaction: " + std::string(rak::error_number::current().c_str())); +} + void SignalHandler::caught(int signum) { if ((unsigned)signum > HIGHEST_SIGNAL) diff --git a/src/signal_handler.h b/src/signal_handler.h index 5c0f4a1c..c6721d16 100644 --- a/src/signal_handler.h +++ b/src/signal_handler.h @@ -44,6 +44,9 @@ class SignalHandler { public: typedef sigc::slot0 Slot; + // typedef void (*handler_slot)(int, siginfo_t *info, ucontext_t *uap); + typedef void (*handler_slot)(int, siginfo_t*, void*); + #ifdef NSIG static const unsigned int HIGHEST_SIGNAL = NSIG; #else @@ -55,6 +58,8 @@ public: static void set_ignore(unsigned int signum); static void set_handler(unsigned int signum, Slot slot); + static void set_sigaction_handler(unsigned int signum, handler_slot slot); + static const char* as_string(unsigned int signum); private: