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