1
//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===//
3
// The LLVM Compiler Infrastructure
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
8
//===----------------------------------------------------------------------===//
10
// This file defines some helpful functions for dealing with the possibility of
11
// Unix signals occuring while your program is running.
13
//===----------------------------------------------------------------------===//
16
#include "llvm/ADT/STLExtras.h"
17
#include "llvm/System/Mutex.h"
21
# include <execinfo.h> // For backtrace().
29
#if HAVE_DLFCN_H && __GNUG__
35
static RETSIGTYPE SignalHandler(int Sig); // defined below.
37
static SmartMutex<true> SignalsMutex;
39
/// InterruptFunction - The function to call if ctrl-c is pressed.
40
static void (*InterruptFunction)() = 0;
42
static std::vector<sys::Path> *FilesToRemove = 0;
43
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
45
// IntSigs - Signals that may interrupt the program at any time.
46
static const int IntSigs[] = {
47
SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2
49
static const int *const IntSigsEnd =
50
IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]);
52
// KillSigs - Signals that are synchronous with the program that will cause it
54
static const int KillSigs[] = {
55
SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV
69
static const int *const KillSigsEnd =
70
KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
72
static unsigned NumRegisteredSignals = 0;
76
} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])];
79
static void RegisterHandler(int Signal) {
80
assert(NumRegisteredSignals <
81
sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) &&
82
"Out of space for signal handlers!");
84
struct sigaction NewHandler;
86
NewHandler.sa_handler = SignalHandler;
87
NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND;
88
sigemptyset(&NewHandler.sa_mask);
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;
97
static void RegisterHandlers() {
98
// If the handlers are already registered, we're done.
99
if (NumRegisteredSignals != 0) return;
101
std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
102
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
105
static 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;
115
// SignalHandler - The signal handler that runs.
116
static RETSIGTYPE SignalHandler(int Sig) {
117
// Restore the signal behavior to default, so that the program actually
118
// crashes when we return and the signal reissues. This also ensures that if
119
// we crash in our signal handler that the program will terminate immediately
120
// instead of recursing in the signal handler.
121
UnregisterHandlers();
123
// Unmask all potentially blocked kill signals.
125
sigfillset(&SigMask);
126
sigprocmask(SIG_UNBLOCK, &SigMask, 0);
128
SignalsMutex.acquire();
129
if (FilesToRemove != 0)
130
while (!FilesToRemove->empty()) {
131
FilesToRemove->back().eraseFromDisk(true);
132
FilesToRemove->pop_back();
135
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
136
if (InterruptFunction) {
137
void (*IF)() = InterruptFunction;
138
SignalsMutex.release();
139
InterruptFunction = 0;
140
IF(); // run the interrupt function.
144
SignalsMutex.release();
145
raise(Sig); // Execute the default handler.
149
SignalsMutex.release();
151
// Otherwise if it is a fault (like SEGV) run any handler.
153
for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
154
(*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
159
void llvm::sys::SetInterruptFunction(void (*IF)()) {
160
SignalsMutex.acquire();
161
InterruptFunction = IF;
162
SignalsMutex.release();
166
// RemoveFileOnSignal - The public API
167
bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename,
168
std::string* ErrMsg) {
169
SignalsMutex.acquire();
170
if (FilesToRemove == 0)
171
FilesToRemove = new std::vector<sys::Path>();
173
FilesToRemove->push_back(Filename);
175
SignalsMutex.release();
181
/// AddSignalHandler - Add a function to be called when a signal is delivered
182
/// to the process. The handler can have a cookie passed to it to identify
183
/// what instance of the handler it is.
184
void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
185
if (CallBacksToRun == 0)
186
CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >();
187
CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
192
// PrintStackTrace - In the case of a program crash or fault, print out a stack
193
// trace so that the user has an indication of why and where we died.
195
// On glibc systems we have the 'backtrace' function, which works nicely, but
196
// doesn't demangle symbols.
197
static void PrintStackTrace(void *) {
198
#ifdef HAVE_BACKTRACE
199
static void* StackTrace[256];
200
// Use backtrace() to output a backtrace on Linux systems with glibc.
201
int depth = backtrace(StackTrace,
202
static_cast<int>(array_lengthof(StackTrace)));
203
#if HAVE_DLFCN_H && __GNUG__ && 0
204
/* CLAMAV LOCAL: turn off dladdr() because we don't link -ldl */
206
for (int i = 0; i < depth; ++i) {
208
dladdr(StackTrace[i], &dlinfo);
209
const char* name = strrchr(dlinfo.dli_fname, '/');
212
if (name == NULL) nwidth = strlen(dlinfo.dli_fname);
213
else nwidth = strlen(name) - 1;
215
if (nwidth > width) width = nwidth;
218
for (int i = 0; i < depth; ++i) {
220
dladdr(StackTrace[i], &dlinfo);
222
fprintf(stderr, "%-2d", i);
224
const char* name = strrchr(dlinfo.dli_fname, '/');
225
if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname);
226
else fprintf(stderr, " %-*s", width, name+1);
228
fprintf(stderr, " %#0*lx",
229
(int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]);
231
if (dlinfo.dli_sname != NULL) {
234
char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res);
235
if (d == NULL) fputs(dlinfo.dli_sname, stderr);
236
else fputs(d, stderr);
239
fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr);
244
backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO);
249
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
250
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
251
void llvm::sys::PrintStackTraceOnErrorSignal() {
252
AddSignalHandler(PrintStackTrace, 0);