1//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines some helpful functions for dealing with the possibility of
11// Unix signals occurring while your program is running.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Unix.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/Support/Mutex.h"
18#include <vector>
19#include <algorithm>
20#if HAVE_EXECINFO_H
21# include <execinfo.h>         // For backtrace().
22#endif
23#if HAVE_SIGNAL_H
24#include <signal.h>
25#endif
26#if HAVE_SYS_STAT_H
27#include <sys/stat.h>
28#endif
29#if HAVE_DLFCN_H && __GNUG__
30#include <dlfcn.h>
31#include <cxxabi.h>
32#endif
33using namespace llvm;
34
35static RETSIGTYPE SignalHandler(int Sig);  // defined below.
36
37static SmartMutex<true> SignalsMutex;
38
39/// InterruptFunction - The function to call if ctrl-c is pressed.
40static void (*InterruptFunction)() = 0;
41
42static std::vector<sys::Path> FilesToRemove;
43static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun;
44
45// IntSigs - Signals that may interrupt the program at any time.
46static const int IntSigs[] = {
47  SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
48};
49static const int *const IntSigsEnd =
50  IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]);
51
52// KillSigs - Signals that are synchronous with the program that will cause it
53// to die.
54static const int KillSigs[] = {
55  SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV
56#ifdef SIGSYS
57  , SIGSYS
58#endif
59#ifdef SIGXCPU
60  , SIGXCPU
61#endif
62#ifdef SIGXFSZ
63  , SIGXFSZ
64#endif
65#ifdef SIGEMT
66  , SIGEMT
67#endif
68};
69static const int *const KillSigsEnd =
70  KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
71
72static unsigned NumRegisteredSignals = 0;
73static struct {
74  struct sigaction SA;
75  int SigNo;
76} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])];
77
78
79static void RegisterHandler(int Signal) {
80  assert(NumRegisteredSignals <
81         sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) &&
82         "Out of space for signal handlers!");
83
84  struct sigaction NewHandler;
85
86  NewHandler.sa_handler = SignalHandler;
87  NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND;
88  sigemptyset(&NewHandler.sa_mask);
89
90  // Install the new handler, save the old one in RegisteredSignalInfo.
91  sigaction(Signal, &NewHandler,
92            &RegisteredSignalInfo[NumRegisteredSignals].SA);
93  RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal;
94  ++NumRegisteredSignals;
95}
96
97static void RegisterHandlers() {
98  // If the handlers are already registered, we're done.
99  if (NumRegisteredSignals != 0) return;
100
101  std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
102  std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
103}
104
105static void UnregisterHandlers() {
106  // Restore all of the signal handlers to how they were before we showed up.
107  for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i)
108    sigaction(RegisteredSignalInfo[i].SigNo,
109              &RegisteredSignalInfo[i].SA, 0);
110  NumRegisteredSignals = 0;
111}
112
113
114/// RemoveFilesToRemove - Process the FilesToRemove list. This function
115/// should be called with the SignalsMutex lock held.
116static void RemoveFilesToRemove() {
117  while (!FilesToRemove.empty()) {
118    FilesToRemove.back().eraseFromDisk(true);
119    FilesToRemove.pop_back();
120  }
121}
122
123// SignalHandler - The signal handler that runs.
124static RETSIGTYPE SignalHandler(int Sig) {
125  // Restore the signal behavior to default, so that the program actually
126  // crashes when we return and the signal reissues.  This also ensures that if
127  // we crash in our signal handler that the program will terminate immediately
128  // instead of recursing in the signal handler.
129  UnregisterHandlers();
130
131  // Unmask all potentially blocked kill signals.
132  sigset_t SigMask;
133  sigfillset(&SigMask);
134  sigprocmask(SIG_UNBLOCK, &SigMask, 0);
135
136  SignalsMutex.acquire();
137  RemoveFilesToRemove();
138
139  if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
140    if (InterruptFunction) {
141      void (*IF)() = InterruptFunction;
142      SignalsMutex.release();
143      InterruptFunction = 0;
144      IF();        // run the interrupt function.
145      return;
146    }
147
148    SignalsMutex.release();
149    raise(Sig);   // Execute the default handler.
150    return;
151  }
152
153  SignalsMutex.release();
154
155  // Otherwise if it is a fault (like SEGV) run any handler.
156  for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i)
157    CallBacksToRun[i].first(CallBacksToRun[i].second);
158}
159
160void llvm::sys::RunInterruptHandlers() {
161  SignalsMutex.acquire();
162  RemoveFilesToRemove();
163  SignalsMutex.release();
164}
165
166void llvm::sys::SetInterruptFunction(void (*IF)()) {
167  SignalsMutex.acquire();
168  InterruptFunction = IF;
169  SignalsMutex.release();
170  RegisterHandlers();
171}
172
173// RemoveFileOnSignal - The public API
174bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename,
175                                   std::string* ErrMsg) {
176  SignalsMutex.acquire();
177  FilesToRemove.push_back(Filename);
178
179  SignalsMutex.release();
180
181  RegisterHandlers();
182  return false;
183}
184
185// DontRemoveFileOnSignal - The public API
186void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) {
187  SignalsMutex.acquire();
188  std::vector<sys::Path>::reverse_iterator I =
189    std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename);
190  if (I != FilesToRemove.rend())
191    FilesToRemove.erase(I.base()-1);
192  SignalsMutex.release();
193}
194
195/// AddSignalHandler - Add a function to be called when a signal is delivered
196/// to the process.  The handler can have a cookie passed to it to identify
197/// what instance of the handler it is.
198void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
199  CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie));
200  RegisterHandlers();
201}
202
203
204// PrintStackTrace - In the case of a program crash or fault, print out a stack
205// trace so that the user has an indication of why and where we died.
206//
207// On glibc systems we have the 'backtrace' function, which works nicely, but
208// doesn't demangle symbols.
209static void PrintStackTrace(void *) {
210#ifdef HAVE_BACKTRACE
211  static void* StackTrace[256];
212  // Use backtrace() to output a backtrace on Linux systems with glibc.
213  int depth = backtrace(StackTrace,
214                        static_cast<int>(array_lengthof(StackTrace)));
215#if HAVE_DLFCN_H && __GNUG__
216  int width = 0;
217  for (int i = 0; i < depth; ++i) {
218    Dl_info dlinfo;
219    dladdr(StackTrace[i], &dlinfo);
220    const char* name = strrchr(dlinfo.dli_fname, '/');
221
222    int nwidth;
223    if (name == NULL) nwidth = strlen(dlinfo.dli_fname);
224    else              nwidth = strlen(name) - 1;
225
226    if (nwidth > width) width = nwidth;
227  }
228
229  for (int i = 0; i < depth; ++i) {
230    Dl_info dlinfo;
231    dladdr(StackTrace[i], &dlinfo);
232
233    fprintf(stderr, "%-2d", i);
234
235    const char* name = strrchr(dlinfo.dli_fname, '/');
236    if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname);
237    else              fprintf(stderr, " %-*s", width, name+1);
238
239    fprintf(stderr, " %#0*lx",
240            (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]);
241
242    if (dlinfo.dli_sname != NULL) {
243      int res;
244      fputc(' ', stderr);
245      char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res);
246      if (d == NULL) fputs(dlinfo.dli_sname, stderr);
247      else           fputs(d, stderr);
248      free(d);
249
250      fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr);
251    }
252    fputc('\n', stderr);
253  }
254#else
255  backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
256#endif
257#endif
258}
259
260/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
261/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
262void llvm::sys::PrintStackTraceOnErrorSignal() {
263  AddSignalHandler(PrintStackTrace, 0);
264}
265
266
267/***/
268
269// On Darwin, raise sends a signal to the main thread instead of the current
270// thread. This has the unfortunate effect that assert() and abort() will end up
271// bypassing our crash recovery attempts. We work around this for anything in
272// the same linkage unit by just defining our own versions of the assert handler
273// and abort.
274
275#ifdef __APPLE__
276
277#include <signal.h>
278#include <pthread.h>
279
280int raise(int sig) {
281  return pthread_kill(pthread_self(), sig);
282}
283
284void __assert_rtn(const char *func,
285                  const char *file,
286                  int line,
287                  const char *expr) {
288  if (func)
289    fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n",
290            expr, func, file, line);
291  else
292    fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n",
293            expr, file, line);
294  abort();
295}
296
297void abort() {
298  raise(SIGABRT);
299  usleep(1000);
300  __builtin_trap();
301}
302
303#endif
304