1a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// 2a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 3a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// The LLVM Compiler Infrastructure 4a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 5a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// This file is distributed under the University of Illinois Open Source 6a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// License. See LICENSE.TXT for details. 7a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar// 8a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar//===----------------------------------------------------------------------===// 9a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 10a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar#include "llvm/Support/CrashRecoveryContext.h" 11dade28ee4eeaa9d22dac986666de4005e1309a06Daniel Dunbar#include "llvm/Config/config.h" 12d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/ErrorHandling.h" 1363fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo#include "llvm/Support/ManagedStatic.h" 141f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/Mutex.h" 151f6efa3996dd1929fbc129203ce5009b620e6969Michael J. Spencer#include "llvm/Support/ThreadLocal.h" 16d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include <setjmp.h> 17a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarusing namespace llvm; 18a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 19a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarnamespace { 20a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 21a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarstruct CrashRecoveryContextImpl; 22a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 23c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesstatic ManagedStatic< 24c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines sys::ThreadLocal<const CrashRecoveryContextImpl> > CurrentContext; 25d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 26a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarstruct CrashRecoveryContextImpl { 27a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar CrashRecoveryContext *CRC; 28a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar std::string Backtrace; 29a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar ::jmp_buf JumpBuffer; 30a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar volatile unsigned Failed : 1; 314e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis unsigned SwitchedThread : 1; 32a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 33a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarpublic: 34a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), 354e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis Failed(false), 364e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis SwitchedThread(false) { 3763fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo CurrentContext->set(this); 38d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar } 39d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar ~CrashRecoveryContextImpl() { 404e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis if (!SwitchedThread) 4163fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo CurrentContext->erase(); 42d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar } 43a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 444e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis /// \brief Called when the separate crash-recovery thread was finished, to 454e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis /// indicate that we don't need to clear the thread-local CurrentContext. 464e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis void setSwitchedThread() { SwitchedThread = true; } 474e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis 48a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar void HandleCrash() { 49ebe7eb884e30c8e9e9f44f499d75ee39cc6c6d6eDaniel Dunbar // Eliminate the current context entry, to avoid re-entering in case the 50ebe7eb884e30c8e9e9f44f499d75ee39cc6c6d6eDaniel Dunbar // cleanup code crashes. 5163fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo CurrentContext->erase(); 52ebe7eb884e30c8e9e9f44f499d75ee39cc6c6d6eDaniel Dunbar 53a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar assert(!Failed && "Crash recovery context already failed!"); 54a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar Failed = true; 55a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 56a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar // FIXME: Stash the backtrace. 57a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 58a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar // Jump back to the RunSafely we were called under. 59a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar longjmp(JumpBuffer, 1); 60a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar } 61a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar}; 62a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 63a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 64a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 6563fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlostatic ManagedStatic<sys::Mutex> gCrashRecoveryContextMutex; 66a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarstatic bool gCrashRecoveryEnabled = false; 67a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 6863fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlostatic ManagedStatic<sys::ThreadLocal<const CrashRecoveryContextCleanup> > 69b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek tlIsRecoveringFromCrash; 70b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek 71a4f983970133c934d6af66dc8dc50fbf908c31ddTed KremenekCrashRecoveryContextCleanup::~CrashRecoveryContextCleanup() {} 72a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 73a309dac868e591d7254f570b950a50f640c009f8Daniel DunbarCrashRecoveryContext::~CrashRecoveryContext() { 74a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek // Reclaim registered resources. 75a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *i = head; 7663fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo tlIsRecoveringFromCrash->set(head); 77a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek while (i) { 78a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek CrashRecoveryContextCleanup *tmp = i; 79a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek i = tmp->next; 801a06d5721acb9a2b69217fc8872ed5b14a482104Ted Kremenek tmp->cleanupFired = true; 813311d951e22b133207ed6f8e384d80f0970a7fb3Ted Kremenek tmp->recoverResources(); 82a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek delete tmp; 83a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 8463fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo tlIsRecoveringFromCrash->erase(); 85a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 86a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 87a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar delete CRCI; 88a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 89a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 90b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenekbool CrashRecoveryContext::isRecoveringFromCrash() { 91dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return tlIsRecoveringFromCrash->get() != nullptr; 92b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek} 93b52fde4185cd724f51aae4018b0f8278732379c7Ted Kremenek 94a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel DunbarCrashRecoveryContext *CrashRecoveryContext::GetCurrent() { 95fb200e30a48c3e682742174453d9550d1dc589d5Ted Kremenek if (!gCrashRecoveryEnabled) 96dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return nullptr; 97fb200e30a48c3e682742174453d9550d1dc589d5Ted Kremenek 9863fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 99a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar if (!CRCI) 100dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines return nullptr; 101a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar 102a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar return CRCI->CRC; 103a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar} 104a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar 105a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekvoid CrashRecoveryContext::registerCleanup(CrashRecoveryContextCleanup *cleanup) 106a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek{ 107a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (!cleanup) 108a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek return; 109a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (head) 110a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek head->prev = cleanup; 111a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek cleanup->next = head; 112a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek head = cleanup; 113a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek} 114a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 115a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenekvoid 116a4f983970133c934d6af66dc8dc50fbf908c31ddTed KremenekCrashRecoveryContext::unregisterCleanup(CrashRecoveryContextCleanup *cleanup) { 117a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (!cleanup) 118a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek return; 119a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (cleanup == head) { 120a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek head = cleanup->next; 121a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (head) 122dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines head->prev = nullptr; 123a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 124a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek else { 125a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek cleanup->prev->next = cleanup->next; 126a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek if (cleanup->next) 127a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek cleanup->next->prev = cleanup->prev; 128a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek } 129a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek delete cleanup; 130a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek} 131a4f983970133c934d6af66dc8dc50fbf908c31ddTed Kremenek 132d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar#ifdef LLVM_ON_WIN32 133d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 13436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "Windows/WindowsSupport.h" 13577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 13677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// On Windows, we can make use of vectored exception handling to 13777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// catch most crashing situations. Note that this does mean 13877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// we will be alerted of exceptions *before* structured exception 13977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// handling has the opportunity to catch it. But that isn't likely 14077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// to cause problems because nowhere in the project is SEH being 14177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// used. 14277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// 14377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// Vectored exception handling is built on top of SEH, and so it 14477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// works on a per-thread basis. 14577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// 14677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// The vectored exception handler functionality was added in Windows 14777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// XP, so if support for older versions of Windows is required, 14877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// it will have to be added. 14977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// 15077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// If we want to support as far back as Win2k, we could use the 15177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// SetUnhandledExceptionFilter API, but there's a risk of that 15277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// being entirely overwritten (it's not a chain). 15377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 15477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumistatic LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) 15577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi{ 15677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Lookup the current thread local recovery object. 15763fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 15877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 15977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi if (!CRCI) { 16077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Something has gone horribly wrong, so let's just tell everyone 16177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // to keep searching 16277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi CrashRecoveryContext::Disable(); 16377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi return EXCEPTION_CONTINUE_SEARCH; 16477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi } 16577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 16677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // TODO: We can capture the stack backtrace here and store it on the 16777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // implementation if we so choose. 16877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 16977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Handle the crash 17077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 17177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 17277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Note that we don't actually get here because HandleCrash calls 17377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // longjmp, which means the HandleCrash function never returns. 17477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi llvm_unreachable("Handled the crash, should have longjmp'ed out of here"); 17577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi} 17677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 17777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// Because the Enable and Disable calls are static, it means that 17877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// there may not actually be an Impl available, or even a current 17977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// CrashRecoveryContext at all. So we make use of a thread-local 18077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// exception table. The handles contained in here will either be 18177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi// non-NULL, valid VEH handles, or NULL. 18277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumistatic sys::ThreadLocal<const void> sCurrentExceptionHandle; 183d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 184a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarvoid CrashRecoveryContext::Enable() { 18563fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo sys::ScopedLock L(*gCrashRecoveryContextMutex); 186c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar 187a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar if (gCrashRecoveryEnabled) 188a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar return; 189a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 190a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar gCrashRecoveryEnabled = true; 19177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 19277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // We can set up vectored exception handling now. We will install our 19377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // handler as the front of the list, though there's no assurances that 19477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // it will remain at the front (another call could install itself before 19577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // our handler). This 1) isn't likely, and 2) shouldn't cause problems. 19677c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi PVOID handle = ::AddVectoredExceptionHandler(1, ExceptionHandler); 19777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi sCurrentExceptionHandle.set(handle); 198a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 199a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 200a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarvoid CrashRecoveryContext::Disable() { 20163fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo sys::ScopedLock L(*gCrashRecoveryContextMutex); 202c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar 203a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar if (!gCrashRecoveryEnabled) 204a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar return; 205a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 206a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar gCrashRecoveryEnabled = false; 20777c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 20877c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi PVOID currentHandle = const_cast<PVOID>(sCurrentExceptionHandle.get()); 20977c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi if (currentHandle) { 21077c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Now we can remove the vectored exception handler from the chain 21177c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi ::RemoveVectoredExceptionHandler(currentHandle); 21277c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi 21377c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi // Reset the handle in our thread-local set. 21477c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi sCurrentExceptionHandle.set(NULL); 21577c108241aae7d19d9d620b10ced8e783c7c8202NAKAMURA Takumi } 216a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 217a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 218d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar#else 219d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 220d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// Generic POSIX implementation. 221d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// 222d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// This implementation relies on synchronous signals being delivered to the 223d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// current thread. We use a thread local object to keep track of the active 224d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// crash recovery context, and install signal handlers to invoke HandleCrash on 225d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// the active object. 226d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// 227d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// This implementation does not to attempt to chain signal handlers in any 228d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// reliable fashion -- if we get a signal outside of a crash recovery context we 229d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar// simply disable crash recovery and raise the signal again. 230d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 231d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar#include <signal.h> 232d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 233c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesstatic const int Signals[] = 234c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; 23563cc2e1982bd02b6484bba3fc0103c688f13711bDaniel Dunbarstatic const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]); 23663cc2e1982bd02b6484bba3fc0103c688f13711bDaniel Dunbarstatic struct sigaction PrevActions[NumSignals]; 237d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 238d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbarstatic void CrashRecoverySignalHandler(int Signal) { 239d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // Lookup the current thread local recovery object. 24063fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo const CrashRecoveryContextImpl *CRCI = CurrentContext->get(); 241d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 242d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar if (!CRCI) { 243d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // We didn't find a crash recovery context -- this means either we got a 244d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // signal on a thread we didn't expect it on, the application got a signal 245d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // outside of a crash recovery context, or something else went horribly 246d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // wrong. 247d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // 248d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // Disable crash recovery and raise the signal again. The assumption here is 249d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // that the enclosing application will terminate soon, and we won't want to 250d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // attempt crash recovery again. 251d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // 252d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // This call of Disable isn't thread safe, but it doesn't actually matter. 253d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar CrashRecoveryContext::Disable(); 254d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar raise(Signal); 255d49e2aa5b89758b3b8841fa427e3c9e90f2e30b2Daniel Dunbar 256d49e2aa5b89758b3b8841fa427e3c9e90f2e30b2Daniel Dunbar // The signal will be thrown once the signal mask is restored. 257d49e2aa5b89758b3b8841fa427e3c9e90f2e30b2Daniel Dunbar return; 258d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar } 259d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 260d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // Unblock the signal we received. 261d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar sigset_t SigMask; 262d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar sigemptyset(&SigMask); 263d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar sigaddset(&SigMask, Signal); 264dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines sigprocmask(SIG_UNBLOCK, &SigMask, nullptr); 265d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 266d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar if (CRCI) 267d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar const_cast<CrashRecoveryContextImpl*>(CRCI)->HandleCrash(); 268d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar} 269d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 270d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbarvoid CrashRecoveryContext::Enable() { 27163fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo sys::ScopedLock L(*gCrashRecoveryContextMutex); 272c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar 273d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar if (gCrashRecoveryEnabled) 274d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar return; 275d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 276d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar gCrashRecoveryEnabled = true; 277d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 278d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // Setup the signal handler. 279d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar struct sigaction Handler; 280d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar Handler.sa_handler = CrashRecoverySignalHandler; 281d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar Handler.sa_flags = 0; 282d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar sigemptyset(&Handler.sa_mask); 283d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 284d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar for (unsigned i = 0; i != NumSignals; ++i) { 28563cc2e1982bd02b6484bba3fc0103c688f13711bDaniel Dunbar sigaction(Signals[i], &Handler, &PrevActions[i]); 286d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar } 287d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar} 288d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 289d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbarvoid CrashRecoveryContext::Disable() { 29063fe0669ad5005aacd89f57855d30f905a7dbd92Filip Pizlo sys::ScopedLock L(*gCrashRecoveryContextMutex); 291c0c815e887d72414894930b62221acc32488c2d0Daniel Dunbar 292d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar if (!gCrashRecoveryEnabled) 293d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar return; 294d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 295d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar gCrashRecoveryEnabled = false; 296d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 297d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar // Restore the previous signal handlers. 298d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar for (unsigned i = 0; i != NumSignals; ++i) 299dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines sigaction(Signals[i], &PrevActions[i], nullptr); 300d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar} 301d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 302d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar#endif 303d9082dfd9ab442dd33f552693fcc0f396a514bb6Daniel Dunbar 304dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesbool CrashRecoveryContext::RunSafely(function_ref<void()> Fn) { 305a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar // If crash recovery is disabled, do nothing. 306a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar if (gCrashRecoveryEnabled) { 307a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar assert(!Impl && "Crash recovery context already initialized!"); 308a8fa798246503c726b02b415bb1f1b26bc0b0159Daniel Dunbar CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); 309a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar Impl = CRCI; 310a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 311a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar if (setjmp(CRCI->JumpBuffer) != 0) { 312a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar return false; 313a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar } 314a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar } 315a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 316dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines Fn(); 317a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar return true; 318a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 319a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 320a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarvoid CrashRecoveryContext::HandleCrash() { 321a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; 322a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar assert(CRCI && "Crash recovery context never initialized!"); 323a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar CRCI->HandleCrash(); 324a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 325a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar 326a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbarconst std::string &CrashRecoveryContext::getBacktrace() const { 327a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; 328a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar assert(CRC && "Crash recovery context never initialized!"); 329a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar assert(CRC->Failed && "No crash was detected!"); 330a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar return CRC->Backtrace; 331a309dac868e591d7254f570b950a50f640c009f8Daniel Dunbar} 332f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar 333c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines// FIXME: Portability. 334c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesstatic void setThreadBackgroundPriority() { 335c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#ifdef __APPLE__ 336c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); 337c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#endif 338c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines} 339c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 340c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hinesstatic bool hasThreadBackgroundPriority() { 341c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#ifdef __APPLE__ 342c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return getpriority(PRIO_DARWIN_THREAD, 0) == 1; 343c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#else 344c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines return false; 345c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines#endif 346c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines} 347f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar 348f8254d647352f8f194b4753a25d582758289e497Daniel Dunbarnamespace { 349f8254d647352f8f194b4753a25d582758289e497Daniel Dunbarstruct RunSafelyOnThreadInfo { 350dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines function_ref<void()> Fn; 351f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar CrashRecoveryContext *CRC; 352c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines bool UseBackgroundPriority; 353f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar bool Result; 354f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar}; 355f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar} 356f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar 357f8254d647352f8f194b4753a25d582758289e497Daniel Dunbarstatic void RunSafelyOnThread_Dispatch(void *UserData) { 358f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar RunSafelyOnThreadInfo *Info = 359f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar reinterpret_cast<RunSafelyOnThreadInfo*>(UserData); 360c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 361c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines if (Info->UseBackgroundPriority) 362c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines setThreadBackgroundPriority(); 363c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines 364dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines Info->Result = Info->CRC->RunSafely(Info->Fn); 365f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar} 366dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesbool CrashRecoveryContext::RunSafelyOnThread(function_ref<void()> Fn, 367f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar unsigned RequestedStackSize) { 368c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines bool UseBackgroundPriority = hasThreadBackgroundPriority(); 369c6a4f5e819217e1e12c458aed8e7b122e23a3a58Stephen Hines RunSafelyOnThreadInfo Info = { Fn, this, UseBackgroundPriority, false }; 370f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); 3714e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis if (CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *)Impl) 3724e91fa3834008778b10d6770f9872c50e1e75659Argyrios Kyrtzidis CRC->setSwitchedThread(); 373f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar return Info.Result; 374f8254d647352f8f194b4753a25d582758289e497Daniel Dunbar} 375