mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-21 18:29:46 +00:00
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
This commit is contained in:
parent
4bd94f7bbe
commit
d9082dfd9a
@ -9,20 +9,29 @@
|
|||||||
|
|
||||||
#include "llvm/Support/CrashRecoveryContext.h"
|
#include "llvm/Support/CrashRecoveryContext.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
|
#include "llvm/System/ThreadLocal.h"
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
#include <cstdio>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct CrashRecoveryContextImpl;
|
struct CrashRecoveryContextImpl;
|
||||||
|
|
||||||
|
static sys::ThreadLocal<const CrashRecoveryContextImpl> CurrentContext;
|
||||||
|
|
||||||
struct CrashRecoveryContextImpl {
|
struct CrashRecoveryContextImpl {
|
||||||
std::string Backtrace;
|
std::string Backtrace;
|
||||||
::jmp_buf JumpBuffer;
|
::jmp_buf JumpBuffer;
|
||||||
volatile unsigned Failed : 1;
|
volatile unsigned Failed : 1;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CrashRecoveryContextImpl() : Failed(false) {}
|
CrashRecoveryContextImpl() : Failed(false) {
|
||||||
|
CurrentContext.set(this);
|
||||||
|
}
|
||||||
|
~CrashRecoveryContextImpl() {
|
||||||
|
CurrentContext.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
void HandleCrash() {
|
void HandleCrash() {
|
||||||
assert(!Failed && "Crash recovery context already failed!");
|
assert(!Failed && "Crash recovery context already failed!");
|
||||||
@ -44,6 +53,10 @@ CrashRecoveryContext::~CrashRecoveryContext() {
|
|||||||
delete CRCI;
|
delete CRCI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LLVM_ON_WIN32
|
||||||
|
|
||||||
|
// FIXME: No real Win32 implementation currently.
|
||||||
|
|
||||||
void CrashRecoveryContext::Enable() {
|
void CrashRecoveryContext::Enable() {
|
||||||
if (gCrashRecoveryEnabled)
|
if (gCrashRecoveryEnabled)
|
||||||
return;
|
return;
|
||||||
@ -58,6 +71,94 @@ void CrashRecoveryContext::Disable() {
|
|||||||
gCrashRecoveryEnabled = false;
|
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) {
|
bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) {
|
||||||
// If crash recovery is disabled, do nothing.
|
// If crash recovery is disabled, do nothing.
|
||||||
if (gCrashRecoveryEnabled) {
|
if (gCrashRecoveryEnabled) {
|
||||||
|
Loading…
Reference in New Issue
Block a user