1212793Sdim//===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// 2212793Sdim// 3212793Sdim// The LLVM Compiler Infrastructure 4212793Sdim// 5212793Sdim// This file is distributed under the University of Illinois Open Source 6212793Sdim// License. See LICENSE.TXT for details. 7212793Sdim// 8212793Sdim//===----------------------------------------------------------------------===// 9212793Sdim 10212793Sdim#include "llvm/Support/CrashRecoveryContext.h" 11212793Sdim#include "llvm/ADT/SmallString.h" 12212793Sdim#include "llvm/Config/config.h" 13252723Sdim#include "llvm/Support/ErrorHandling.h" 14263509Sdim#include "llvm/Support/ManagedStatic.h" 15218893Sdim#include "llvm/Support/Mutex.h" 16218893Sdim#include "llvm/Support/ThreadLocal.h" 17252723Sdim#include <cstdio> 18212793Sdim#include <setjmp.h> 19212793Sdimusing namespace llvm; 20212793Sdim 21212793Sdimnamespace { 22212793Sdim 23212793Sdimstruct CrashRecoveryContextImpl; 24212793Sdim 25263509Sdimstatic ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; 26212793Sdim 27212793Sdimstruct CrashRecoveryContextImpl { 28212793Sdim CrashRecoveryContext *CRC; 29212793Sdim std::string Backtrace; 30212793Sdim ::jmp_buf JumpBuffer; 31212793Sdim volatile unsigned Failed : 1; 32263509Sdim unsigned SwitchedThread : 1; 33212793Sdim 34212793Sdimpublic: 35212793Sdim CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), 36263509Sdim Failed(false), 37263509Sdim SwitchedThread(false) { 38263509Sdim CurrentContext->set(this); 39212793Sdim } 40212793Sdim ~CrashRecoveryContextImpl() { 41263509Sdim if (!SwitchedThread) 42263509Sdim CurrentContext->erase(); 43212793Sdim } 44212793Sdim 45263509Sdim /// \brief Called when the separate crash-recovery thread was finished, to 46263509Sdim /// indicate that we don't need to clear the thread-local CurrentContext. 47263509Sdim void setSwitchedThread() { SwitchedThread = true; } 48263509Sdim 49212793Sdim void HandleCrash() { 50212793Sdim // Eliminate the current context entry, to avoid re-entering in case the 51212793Sdim // cleanup code crashes. 52263509Sdim CurrentContext->erase(); 53212793Sdim 54212793Sdim assert(!Failed && "Crash recovery context already failed!"); 55212793Sdim Failed = true; 56212793Sdim 57212793Sdim // FIXME: Stash the backtrace. 58212793Sdim 59212793Sdim // Jump back to the RunSafely we were called under. 60212793Sdim longjmp(JumpBuffer, 1); 61212793Sdim } 62212793Sdim}; 63212793Sdim 64212793Sdim} 65212793Sdim 66263509Sdimstatic ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; 67212793Sdimstatic bool gCrashRecoveryEnabled = false; 68212793Sdim 69263509Sdimstatic ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> > 70221345Sdim tlIsRecoveringFromCrash; 71221345Sdim 72221345SdimCrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} 73221345Sdim 74212793SdimCrashRecoveryContext::~CrashRecoveryContext() { 75221345Sdim // Reclaim registered resources. 76221345Sdim CrashRecoveryContextCleanup *i = head; 77263509Sdim tlIsRecoveringFromCrash->set(head); 78221345Sdim while (i) { 79221345Sdim CrashRecoveryContextCleanup *tmp = i; 80221345Sdim i = tmp->next; 81221345Sdim tmp->cleanupFired = true; 82221345Sdim tmp->recoverResources(); 83221345Sdim delete tmp; 84221345Sdim } 85263509Sdim tlIsRecoveringFromCrash->erase(); 86221345Sdim 87212793Sdim CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 88212793Sdim delete CRCI; 89212793Sdim} 90212793Sdim 91221345Sdimbool CrashRecoveryContext::isRecoveringFromCrash() { 92263509Sdim return tlIsRecoveringFromCrash->get() != 0; 93221345Sdim} 94221345Sdim 95212793SdimCrashRecoveryContext *CrashRecoveryContext::GetCurrent() { 96221345Sdim if (!gCrashRecoveryEnabled) 97221345Sdim return 0; 98221345Sdim 99263509Sdim const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 100212793Sdim if (!CRCI) 101212793Sdim return 0; 102212793Sdim 103212793Sdim return CRCI->CRC; 104212793Sdim} 105212793Sdim 106221345Sdimvoid CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) 107221345Sdim{ 108221345Sdim if (!cleanup) 109221345Sdim return; 110221345Sdim if (head) 111221345Sdim head->prev = cleanup; 112221345Sdim cleanup->next = head; 113221345Sdim head = cleanup; 114221345Sdim} 115221345Sdim 116221345Sdimvoid 117221345SdimCrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { 118221345Sdim if (!cleanup) 119221345Sdim return; 120221345Sdim if (cleanup == head) { 121221345Sdim head = cleanup->next; 122221345Sdim if (head) 123221345Sdim head->prev = 0; 124221345Sdim } 125221345Sdim else { 126221345Sdim cleanup->prev->next = cleanup->next; 127221345Sdim if (cleanup->next) 128221345Sdim cleanup->next->prev = cleanup->prev; 129221345Sdim } 130221345Sdim delete cleanup; 131221345Sdim} 132221345Sdim 133212793Sdim#ifdef LLVM_ON_WIN32 134212793Sdim 135226890Sdim#include "Windows/Windows.h" 136212793Sdim 137226890Sdim// On Windows, we can make use of vectored exception handling to 138226890Sdim// catch most crashing situations. Note that this does mean 139226890Sdim// we will be alerted of exceptions *before* structured exception 140226890Sdim// handling has the opportunity to catch it. But that isn't likely 141226890Sdim// to cause problems because nowhere in the project is SEH being 142226890Sdim// used. 143226890Sdim// 144226890Sdim// Vectored exception handling is built on top of SEH, and so it 145226890Sdim// works on a per-thread basis. 146226890Sdim// 147226890Sdim// The vectored exception handler functionality was added in Windows 148226890Sdim// XP, so if support for older versions of Windows is required, 149226890Sdim// it will have to be added. 150226890Sdim// 151226890Sdim// If we want to support as far back as Win2k, we could use the 152226890Sdim// SetUnhandledExceptionFilter API, but there's a risk of that 153226890Sdim// being entirely overwritten (it's not a chain). 154226890Sdim 155226890Sdimstatic LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) 156226890Sdim{ 157226890Sdim // Lookup the current thread local recovery object. 158263509Sdim const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 159226890Sdim 160226890Sdim if (!CRCI) { 161226890Sdim // Something has gone horribly wrong, so let's just tell everyone 162226890Sdim // to keep searching 163226890Sdim CrashRecoveryContext::Disable(); 164226890Sdim return EXCEPTION_CONTINUE_SEARCH; 165226890Sdim } 166226890Sdim 167226890Sdim // TODO: We can capture the stack backtrace here and store it on the 168226890Sdim // implementation if we so choose. 169226890Sdim 170226890Sdim // Handle the crash 171226890Sdim const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 172226890Sdim 173226890Sdim // Note that we don't actually get here because HandleCrash calls 174226890Sdim // longjmp, which means the HandleCrash function never returns. 175226890Sdim llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); 176226890Sdim} 177226890Sdim 178226890Sdim// Because the Enable and Disable calls are static, it means that 179226890Sdim// there may not actually be an Impl available, or even a current 180226890Sdim// CrashRecoveryContext at all. So we make use of a thread-local 181226890Sdim// exception table. The handles contained in here will either be 182226890Sdim// non-NULL, valid VEH handles, or NULL. 183226890Sdimstatic sys::ThreadLocal<const void> sCurrentExceptionHandle; 184226890Sdim 185212793Sdimvoid CrashRecoveryContext::Enable() { 186263509Sdim sys::ScopedLock L(*gCrashRecoveryContextMutex); 187212793Sdim 188212793Sdim if (gCrashRecoveryEnabled) 189212793Sdim return; 190212793Sdim 191212793Sdim gCrashRecoveryEnabled = true; 192226890Sdim 193226890Sdim // We can set up vectored exception handling now. We will install our 194226890Sdim // handler as the front of the list, though there's no assurances that 195226890Sdim // it will remain at the front (another call could install itself before 196226890Sdim // our handler). This 1) isn't likely, and 2) shouldn't cause problems. 197226890Sdim PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); 198226890Sdim sCurrentExceptionHandle.set(handle); 199212793Sdim} 200212793Sdim 201212793Sdimvoid CrashRecoveryContext::Disable() { 202263509Sdim sys::ScopedLock L(*gCrashRecoveryContextMutex); 203212793Sdim 204212793Sdim if (!gCrashRecoveryEnabled) 205212793Sdim return; 206212793Sdim 207212793Sdim gCrashRecoveryEnabled = false; 208226890Sdim 209226890Sdim PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); 210226890Sdim if (currentHandle) { 211226890Sdim // Now we can remove the vectored exception handler from the chain 212226890Sdim ::RemoveVectoredExceptionHandler(currentHandle); 213226890Sdim 214226890Sdim // Reset the handle in our thread-local set. 215226890Sdim sCurrentExceptionHandle.set(NULL); 216226890Sdim } 217212793Sdim} 218212793Sdim 219212793Sdim#else 220212793Sdim 221212793Sdim// Generic POSIX implementation. 222212793Sdim// 223212793Sdim// This implementation relies on synchronous signals being delivered to the 224212793Sdim// current thread. We use a thread local object to keep track of the active 225212793Sdim// crash recovery context, and install signal handlers to invoke HandleCrash on 226212793Sdim// the active object. 227212793Sdim// 228212793Sdim// This implementation does not to attempt to chain signal handlers in any 229212793Sdim// reliable fashion -- if we get a signal outside of a crash recovery context we 230212793Sdim// simply disable crash recovery and raise the signal again. 231212793Sdim 232212793Sdim#include <signal.h> 233212793Sdim 234245431Sdimstatic const int Signals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; 235212793Sdimstatic const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]); 236212793Sdimstatic struct sigaction PrevActions[NumSignals]; 237212793Sdim 238212793Sdimstatic void CrashRecoverySignalHandler(int Signal) { 239212793Sdim // Lookup the current thread local recovery object. 240263509Sdim const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 241212793Sdim 242212793Sdim if (!CRCI) { 243212793Sdim // We didn't find a crash recovery context -- this means either we got a 244212793Sdim // signal on a thread we didn't expect it on, the application got a signal 245212793Sdim // outside of a crash recovery context, or something else went horribly 246212793Sdim // wrong. 247212793Sdim // 248212793Sdim // Disable crash recovery and raise the signal again. The assumption here is 249212793Sdim // that the enclosing application will terminate soon, and we won't want to 250212793Sdim // attempt crash recovery again. 251212793Sdim // 252212793Sdim // This call of Disable isn't thread safe, but it doesn't actually matter. 253212793Sdim CrashRecoveryContext::Disable(); 254212793Sdim raise(Signal); 255218893Sdim 256218893Sdim // The signal will be thrown once the signal mask is restored. 257218893Sdim return; 258212793Sdim } 259212793Sdim 260212793Sdim // Unblock the signal we received. 261212793Sdim sigset_t SigMask; 262212793Sdim sigemptyset(&SigMask); 263212793Sdim sigaddset(&SigMask, Signal); 264212793Sdim sigprocmask(SIG_UNBLOCK, &SigMask, 0); 265212793Sdim 266212793Sdim if (CRCI) 267212793Sdim const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 268212793Sdim} 269212793Sdim 270212793Sdimvoid CrashRecoveryContext::Enable() { 271263509Sdim sys::ScopedLock L(*gCrashRecoveryContextMutex); 272212793Sdim 273212793Sdim if (gCrashRecoveryEnabled) 274212793Sdim return; 275212793Sdim 276212793Sdim gCrashRecoveryEnabled = true; 277212793Sdim 278212793Sdim // Setup the signal handler. 279212793Sdim struct sigaction Handler; 280212793Sdim Handler.sa_handler = CrashRecoverySignalHandler; 281212793Sdim Handler.sa_flags = 0; 282212793Sdim sigemptyset(&Handler.sa_mask); 283212793Sdim 284212793Sdim for (unsigned i = 0; i != NumSignals; ++i) { 285212793Sdim sigaction(Signals[i], &Handler, &PrevActions[i]); 286212793Sdim } 287212793Sdim} 288212793Sdim 289212793Sdimvoid CrashRecoveryContext::Disable() { 290263509Sdim sys::ScopedLock L(*gCrashRecoveryContextMutex); 291212793Sdim 292212793Sdim if (!gCrashRecoveryEnabled) 293212793Sdim return; 294212793Sdim 295212793Sdim gCrashRecoveryEnabled = false; 296212793Sdim 297212793Sdim // Restore the previous signal handlers. 298212793Sdim for (unsigned i = 0; i != NumSignals; ++i) 299212793Sdim sigaction(Signals[i], &PrevActions[i], 0); 300212793Sdim} 301212793Sdim 302212793Sdim#endif 303212793Sdim 304212793Sdimbool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) { 305212793Sdim // If crash recovery is disabled, do nothing. 306212793Sdim if (gCrashRecoveryEnabled) { 307212793Sdim assert(!Impl && "Crash recovery context already initialized!"); 308212793Sdim CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); 309212793Sdim Impl = CRCI; 310212793Sdim 311212793Sdim if (setjmp(CRCI->JumpBuffer) != 0) { 312212793Sdim return false; 313212793Sdim } 314212793Sdim } 315212793Sdim 316212793Sdim Fn(UserData); 317212793Sdim return true; 318212793Sdim} 319212793Sdim 320212793Sdimvoid CrashRecoveryContext::HandleCrash() { 321212793Sdim CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 322212793Sdim assert(CRCI && "Crash recovery context never initialized!"); 323212793Sdim CRCI->HandleCrash(); 324212793Sdim} 325212793Sdim 326212793Sdimconst std::string &CrashRecoveryContext::getBacktrace() const { 327212793Sdim CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; 328212793Sdim assert(CRC && "Crash recovery context never initialized!"); 329212793Sdim assert(CRC->Failed && "No crash was detected!"); 330212793Sdim return CRC->Backtrace; 331212793Sdim} 332218893Sdim 333218893Sdim// 334218893Sdim 335218893Sdimnamespace { 336218893Sdimstruct RunSafelyOnThreadInfo { 337218893Sdim void (*UserFn)(void*); 338218893Sdim void *UserData; 339218893Sdim CrashRecoveryContext *CRC; 340218893Sdim bool Result; 341218893Sdim}; 342218893Sdim} 343218893Sdim 344218893Sdimstatic void RunSafelyOnThread_Dispatch(void *UserData) { 345218893Sdim RunSafelyOnThreadInfo *Info = 346218893Sdim reinterpret_cast<RunSafelyOnThreadInfo*>(UserData); 347218893Sdim Info->Result = Info->CRC->RunSafely(Info->UserFn, Info->UserData); 348218893Sdim} 349218893Sdimbool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData, 350218893Sdim unsigned RequestedStackSize) { 351218893Sdim RunSafelyOnThreadInfo Info = { Fn, UserData, this, false }; 352218893Sdim llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); 353263509Sdim if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) 354263509Sdim CRC->setSwitchedThread(); 355218893Sdim return Info.Result; 356218893Sdim} 357