LLVM API Documentation
00001 //===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines some helpful functions for dealing with the possibility of 00011 // Unix signals occuring while your program is running. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "Unix.h" 00016 #include "llvm/ADT/STLExtras.h" 00017 #include <vector> 00018 #include <algorithm> 00019 #if HAVE_EXECINFO_H 00020 # include <execinfo.h> // For backtrace(). 00021 #endif 00022 #if HAVE_SIGNAL_H 00023 #include <signal.h> 00024 #endif 00025 #if HAVE_SYS_STAT_H 00026 #include <sys/stat.h> 00027 #endif 00028 #if HAVE_DLFCN_H && __GNUG__ 00029 #include <dlfcn.h> 00030 #include <cxxabi.h> 00031 #endif 00032 using namespace llvm; 00033 00034 namespace { 00035 00036 static bool StackTraceRequested = false; 00037 00038 /// InterruptFunction - The function to call if ctrl-c is pressed. 00039 static void (*InterruptFunction)() = 0; 00040 00041 static std::vector<sys::Path> *FilesToRemove = 0 ; 00042 static std::vector<sys::Path> *DirectoriesToRemove = 0; 00043 00044 // IntSigs - Signals that may interrupt the program at any time. 00045 static const int IntSigs[] = { 00046 SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 00047 }; 00048 static const int *const IntSigsEnd = 00049 IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); 00050 00051 // KillSigs - Signals that are synchronous with the program that will cause it 00052 // to die. 00053 static const int KillSigs[] = { 00054 SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGXCPU, SIGXFSZ 00055 #ifdef SIGEMT 00056 , SIGEMT 00057 #endif 00058 }; 00059 static const int *const KillSigsEnd = 00060 KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); 00061 00062 #ifdef HAVE_BACKTRACE 00063 static void* StackTrace[256]; 00064 #endif 00065 00066 // PrintStackTrace - In the case of a program crash or fault, print out a stack 00067 // trace so that the user has an indication of why and where we died. 00068 // 00069 // On glibc systems we have the 'backtrace' function, which works nicely, but 00070 // doesn't demangle symbols. 00071 static void PrintStackTrace() { 00072 #ifdef HAVE_BACKTRACE 00073 // Use backtrace() to output a backtrace on Linux systems with glibc. 00074 int depth = backtrace(StackTrace, 00075 static_cast<int>(array_lengthof(StackTrace))); 00076 #if HAVE_DLFCN_H && __GNUG__ 00077 int width = 0; 00078 for (int i = 0; i < depth; ++i) { 00079 Dl_info dlinfo; 00080 dladdr(StackTrace[i], &dlinfo); 00081 const char* name = strrchr(dlinfo.dli_fname, '/'); 00082 00083 int nwidth; 00084 if (name == NULL) nwidth = strlen(dlinfo.dli_fname); 00085 else nwidth = strlen(name) - 1; 00086 00087 if (nwidth > width) width = nwidth; 00088 } 00089 00090 for (int i = 0; i < depth; ++i) { 00091 Dl_info dlinfo; 00092 dladdr(StackTrace[i], &dlinfo); 00093 00094 fprintf(stderr, "%-3d", i); 00095 00096 const char* name = strrchr(dlinfo.dli_fname, '/'); 00097 if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); 00098 else fprintf(stderr, " %-*s", width, name+1); 00099 00100 fprintf(stderr, " %#0*lx", 00101 (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); 00102 00103 if (dlinfo.dli_sname != NULL) { 00104 int res; 00105 fputc(' ', stderr); 00106 char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); 00107 if (d == NULL) fputs(dlinfo.dli_sname, stderr); 00108 else fputs(d, stderr); 00109 free(d); 00110 00111 fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); 00112 } 00113 fputc('\n', stderr); 00114 } 00115 #else 00116 backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); 00117 #endif 00118 #endif 00119 } 00120 00121 // SignalHandler - The signal handler that runs... 00122 static RETSIGTYPE SignalHandler(int Sig) { 00123 if (FilesToRemove != 0) 00124 while (!FilesToRemove->empty()) { 00125 FilesToRemove->back().eraseFromDisk(true); 00126 FilesToRemove->pop_back(); 00127 } 00128 00129 if (DirectoriesToRemove != 0) 00130 while (!DirectoriesToRemove->empty()) { 00131 DirectoriesToRemove->back().eraseFromDisk(true); 00132 DirectoriesToRemove->pop_back(); 00133 } 00134 00135 if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { 00136 if (InterruptFunction) { 00137 void (*IF)() = InterruptFunction; 00138 InterruptFunction = 0; 00139 IF(); // run the interrupt function. 00140 return; 00141 } else { 00142 exit(1); // If this is an interrupt signal, exit the program 00143 } 00144 } 00145 00146 // Otherwise if it is a fault (like SEGV) output the stacktrace to 00147 // STDERR (if we can) and reissue the signal to die... 00148 if (StackTraceRequested) 00149 PrintStackTrace(); 00150 signal(Sig, SIG_DFL); 00151 } 00152 00153 // Just call signal 00154 static void RegisterHandler(int Signal) { 00155 signal(Signal, SignalHandler); 00156 } 00157 00158 } 00159 00160 00161 void sys::SetInterruptFunction(void (*IF)()) { 00162 InterruptFunction = IF; 00163 RegisterHandler(SIGINT); 00164 } 00165 00166 // RemoveFileOnSignal - The public API 00167 bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { 00168 if (FilesToRemove == 0) 00169 FilesToRemove = new std::vector<sys::Path>; 00170 00171 FilesToRemove->push_back(Filename); 00172 00173 std::for_each(IntSigs, IntSigsEnd, RegisterHandler); 00174 std::for_each(KillSigs, KillSigsEnd, RegisterHandler); 00175 return false; 00176 } 00177 00178 // RemoveDirectoryOnSignal - The public API 00179 bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) { 00180 // Not a directory? 00181 struct stat buf; 00182 if (0 != stat(path.c_str(), &buf)) { 00183 MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file"); 00184 return true; 00185 } 00186 00187 if (!S_ISDIR(buf.st_mode)) { 00188 if (ErrMsg) 00189 *ErrMsg = path.toString() + " is not a directory"; 00190 return true; 00191 } 00192 00193 if (DirectoriesToRemove == 0) 00194 DirectoriesToRemove = new std::vector<sys::Path>; 00195 00196 DirectoriesToRemove->push_back(path); 00197 00198 std::for_each(IntSigs, IntSigsEnd, RegisterHandler); 00199 std::for_each(KillSigs, KillSigsEnd, RegisterHandler); 00200 return false; 00201 } 00202 00203 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 00204 /// SIGSEGV) is delivered to the process, print a stack trace and then exit. 00205 void sys::PrintStackTraceOnErrorSignal() { 00206 StackTraceRequested = true; 00207 std::for_each(KillSigs, KillSigsEnd, RegisterHandler); 00208 }