summaryrefslogtreecommitdiff
path: root/lib/Support
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2010-07-29 01:21:47 +0000
committerDaniel Dunbar <daniel@zuster.org>2010-07-29 01:21:47 +0000
commitd9082dfd9ab442dd33f552693fcc0f396a514bb6 (patch)
tree4730b225570962ee8132397f800742f302b95d58 /lib/Support
parent4bd94f7bbe2ed6e0d83d03b06c0d20bb346abeca (diff)
downloadllvm-d9082dfd9ab442dd33f552693fcc0f396a514bb6.tar.gz
llvm-d9082dfd9ab442dd33f552693fcc0f396a514bb6.tar.bz2
llvm-d9082dfd9ab442dd33f552693fcc0f396a514bb6.tar.xz
CrashRecoveryContext: Add a simple POSIX implementation.
- This works, but won't handle crashes on stack overflow, or signals delivered to a thread other than the one that crashed. The latter is particular annoying on Darwin, because SIGABRT tends to go to the main thread. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@109717 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support')
-rw-r--r--lib/Support/CrashRecoveryContext.cpp103
1 files changed, 102 insertions, 1 deletions
diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp
index 870221e171..c079182bd1 100644
--- a/lib/Support/CrashRecoveryContext.cpp
+++ b/lib/Support/CrashRecoveryContext.cpp
@@ -9,20 +9,29 @@
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/System/ThreadLocal.h"
#include <setjmp.h>
+#include <cstdio>
using namespace llvm;
namespace {
struct CrashRecoveryContextImpl;
+static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext;
+
struct CrashRecoveryContextImpl {
std::string Backtrace;
::jmp_buf JumpBuffer;
volatile unsigned Failed : 1;
public:
- CrashRecoveryContextImpl() : Failed(false) {}
+ CrashRecoveryContextImpl() : Failed(false) {
+ CurrentContext.set(this);
+ }
+ ~CrashRecoveryContextImpl() {
+ CurrentContext.set(0);
+ }
void HandleCrash() {
assert(!Failed && "Crash recovery context already failed!");
@@ -44,6 +53,10 @@ CrashRecoveryContext::~CrashRecoveryContext() {
delete CRCI;
}
+#ifdef LLVM_ON_WIN32
+
+// FIXME: No real Win32 implementation currently.
+
void CrashRecoveryContext::Enable() {
if (gCrashRecoveryEnabled)
return;
@@ -58,6 +71,94 @@ void CrashRecoveryContext::Disable() {
gCrashRecoveryEnabled = false;
}
+#else
+
+// Generic POSIX implementation.
+//
+// This implementation relies on synchronous signals being delivered to the
+// current thread. We use a thread local object to keep track of the active
+// crash recovery context, and install signal handlers to invoke HandleCrash on
+// the active object.
+//
+// This implementation does not to attempt to chain signal handlers in any
+// reliable fashion -- if we get a signal outside of a crash recovery context we
+// simply disable crash recovery and raise the signal again.
+
+#include <signal.h>
+
+static struct {
+ int Signal;
+ struct sigaction PrevAction;
+} SignalInfo[] = {
+ { SIGABRT, {} },
+ { SIGBUS, {} },
+ { SIGFPE, {} },
+ { SIGILL, {} },
+ { SIGSEGV, {} },
+ { SIGTRAP, {} },
+};
+static const unsigned NumSignals = sizeof(SignalInfo) / sizeof(SignalInfo[0]);
+
+static void CrashRecoverySignalHandler(int Signal) {
+ // Lookup the current thread local recovery object.
+ const CrashRecoveryContextImpl *CRCI = CurrentContext.get();
+
+ if (!CRCI) {
+ // We didn't find a crash recovery context -- this means either we got a
+ // signal on a thread we didn't expect it on, the application got a signal
+ // outside of a crash recovery context, or something else went horribly
+ // wrong.
+ //
+ // Disable crash recovery and raise the signal again. The assumption here is
+ // that the enclosing application will terminate soon, and we won't want to
+ // attempt crash recovery again.
+ //
+ // This call of Disable isn't thread safe, but it doesn't actually matter.
+ CrashRecoveryContext::Disable();
+ raise(Signal);
+ }
+
+ // Unblock the signal we received.
+ sigset_t SigMask;
+ sigemptyset(&SigMask);
+ sigaddset(&SigMask, Signal);
+ sigprocmask(SIG_UNBLOCK, &SigMask, 0);
+
+ if (CRCI)
+ const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash();
+}
+
+void CrashRecoveryContext::Enable() {
+ if (gCrashRecoveryEnabled)
+ return;
+
+ gCrashRecoveryEnabled = true;
+
+ // Setup the signal handler.
+ struct sigaction Handler;
+ Handler.sa_handler = CrashRecoverySignalHandler;
+ Handler.sa_flags = 0;
+ sigemptyset(&Handler.sa_mask);
+
+ for (unsigned i = 0; i != NumSignals; ++i) {
+ sigaction(SignalInfo[i].Signal, &Handler,
+ &SignalInfo[i].PrevAction);
+ }
+}
+
+void CrashRecoveryContext::Disable() {
+ if (!gCrashRecoveryEnabled)
+ return;
+
+ gCrashRecoveryEnabled = false;
+
+ // Restore the previous signal handlers.
+ for (unsigned i = 0; i != NumSignals; ++i)
+ sigaction(SignalInfo[i].Signal, &SignalInfo[i].PrevAction, 0);
+}
+
+#endif
+
bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
// If crash recovery is disabled, do nothing.
if (gCrashRecoveryEnabled) {