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