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#ifdef ENABLE_SIGNAL_OVERRIDES 99 // If the handlers are already registered, we're done. 100 if (NumRegisteredSignals != 0) return; 101 102 std::for_each(IntSigs, IntSigsEnd, RegisterHandler); 103 std::for_each(KillSigs, KillSigsEnd, RegisterHandler); 104#endif 105} 106 107static void UnregisterHandlers() { 108 // Restore all of the signal handlers to how they were before we showed up. 109 for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) 110 sigaction(RegisteredSignalInfo[i].SigNo, 111 &RegisteredSignalInfo[i].SA, 0); 112 NumRegisteredSignals = 0; 113} 114 115 116/// RemoveFilesToRemove - Process the FilesToRemove list. This function 117/// should be called with the SignalsMutex lock held. 118static void RemoveFilesToRemove() { 119 while (!FilesToRemove.empty()) { 120 FilesToRemove.back().eraseFromDisk(true); 121 FilesToRemove.pop_back(); 122 } 123} 124 125// SignalHandler - The signal handler that runs. 126static RETSIGTYPE SignalHandler(int Sig) { 127 // Restore the signal behavior to default, so that the program actually 128 // crashes when we return and the signal reissues. This also ensures that if 129 // we crash in our signal handler that the program will terminate immediately 130 // instead of recursing in the signal handler. 131 UnregisterHandlers(); 132 133 // Unmask all potentially blocked kill signals. 134 sigset_t SigMask; 135 sigfillset(&SigMask); 136 sigprocmask(SIG_UNBLOCK, &SigMask, 0); 137 138 SignalsMutex.acquire(); 139 RemoveFilesToRemove(); 140 141 if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { 142 if (InterruptFunction) { 143 void (*IF)() = InterruptFunction; 144 SignalsMutex.release(); 145 InterruptFunction = 0; 146 IF(); // run the interrupt function. 147 return; 148 } 149 150 SignalsMutex.release(); 151 raise(Sig); // Execute the default handler. 152 return; 153 } 154 155 SignalsMutex.release(); 156 157 // Otherwise if it is a fault (like SEGV) run any handler. 158 for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) 159 CallBacksToRun[i].first(CallBacksToRun[i].second); 160} 161 162void llvm::sys::RunInterruptHandlers() { 163 SignalsMutex.acquire(); 164 RemoveFilesToRemove(); 165 SignalsMutex.release(); 166} 167 168void llvm::sys::SetInterruptFunction(void (*IF)()) { 169 SignalsMutex.acquire(); 170 InterruptFunction = IF; 171 SignalsMutex.release(); 172 RegisterHandlers(); 173} 174 175// RemoveFileOnSignal - The public API 176bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, 177 std::string* ErrMsg) { 178 SignalsMutex.acquire(); 179 FilesToRemove.push_back(Filename); 180 181 SignalsMutex.release(); 182 183 RegisterHandlers(); 184 return false; 185} 186 187// DontRemoveFileOnSignal - The public API 188void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { 189 SignalsMutex.acquire(); 190 std::vector<sys::Path>::reverse_iterator I = 191 std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); 192 if (I != FilesToRemove.rend()) 193 FilesToRemove.erase(I.base()-1); 194 SignalsMutex.release(); 195} 196 197/// AddSignalHandler - Add a function to be called when a signal is delivered 198/// to the process. The handler can have a cookie passed to it to identify 199/// what instance of the handler it is. 200void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { 201 CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); 202 RegisterHandlers(); 203} 204 205 206// PrintStackTrace - In the case of a program crash or fault, print out a stack 207// trace so that the user has an indication of why and where we died. 208// 209// On glibc systems we have the 'backtrace' function, which works nicely, but 210// doesn't demangle symbols. 211static void PrintStackTrace(void *) { 212#ifdef HAVE_BACKTRACE 213 static void* StackTrace[256]; 214 // Use backtrace() to output a backtrace on Linux systems with glibc. 215 int depth = backtrace(StackTrace, 216 static_cast<int>(array_lengthof(StackTrace))); 217#if HAVE_DLFCN_H && __GNUG__ 218 int width = 0; 219 for (int i = 0; i < depth; ++i) { 220 Dl_info dlinfo; 221 dladdr(StackTrace[i], &dlinfo); 222 const char* name = strrchr(dlinfo.dli_fname, '/'); 223 224 int nwidth; 225 if (name == NULL) nwidth = strlen(dlinfo.dli_fname); 226 else nwidth = strlen(name) - 1; 227 228 if (nwidth > width) width = nwidth; 229 } 230 231 for (int i = 0; i < depth; ++i) { 232 Dl_info dlinfo; 233 dladdr(StackTrace[i], &dlinfo); 234 235 fprintf(stderr, "%-2d", i); 236 237 const char* name = strrchr(dlinfo.dli_fname, '/'); 238 if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); 239 else fprintf(stderr, " %-*s", width, name+1); 240 241 fprintf(stderr, " %#0*lx", 242 (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); 243 244 if (dlinfo.dli_sname != NULL) { 245 int res; 246 fputc(' ', stderr); 247 char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); 248 if (d == NULL) fputs(dlinfo.dli_sname, stderr); 249 else fputs(d, stderr); 250 free(d); 251 252 fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); 253 } 254 fputc('\n', stderr); 255 } 256#else 257 backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); 258#endif 259#endif 260} 261 262/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 263/// SIGSEGV) is delivered to the process, print a stack trace and then exit. 264void llvm::sys::PrintStackTraceOnErrorSignal() { 265 AddSignalHandler(PrintStackTrace, 0); 266} 267 268 269/***/ 270 271// On Darwin, raise sends a signal to the main thread instead of the current 272// thread. This has the unfortunate effect that assert() and abort() will end up 273// bypassing our crash recovery attempts. We work around this for anything in 274// the same linkage unit by just defining our own versions of the assert handler 275// and abort. 276 277#ifdef __APPLE__ 278 279#include <signal.h> 280#include <pthread.h> 281 282int raise(int sig) { 283 return pthread_kill(pthread_self(), sig); 284} 285 286void __assert_rtn(const char *func, 287 const char *file, 288 int line, 289 const char *expr) { 290 if (func) 291 fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", 292 expr, func, file, line); 293 else 294 fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", 295 expr, file, line); 296 abort(); 297} 298 299void abort() { 300 raise(SIGABRT); 301 usleep(1000); 302 __builtin_trap(); 303} 304 305#endif 306