Copyright 2014->2015
[folly.git] / folly / experimental / symbolizer / SignalHandler.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 // This is heavily inspired by the signal handler from google-glog
18
19 #include <folly/experimental/symbolizer/SignalHandler.h>
20
21 #include <sys/types.h>
22 #include <sys/syscall.h>
23 #include <atomic>
24 #include <ctime>
25 #include <mutex>
26 #include <pthread.h>
27 #include <signal.h>
28 #include <unistd.h>
29 #include <vector>
30
31 #include <glog/logging.h>
32
33 #include <folly/Conv.h>
34 #include <folly/FileUtil.h>
35 #include <folly/Portability.h>
36 #include <folly/ScopeGuard.h>
37 #include <folly/experimental/symbolizer/Symbolizer.h>
38
39 namespace folly { namespace symbolizer {
40
41 namespace {
42
43 /**
44  * Fatal signal handler registry.
45  */
46 class FatalSignalCallbackRegistry {
47  public:
48   FatalSignalCallbackRegistry();
49
50   void add(SignalCallback func);
51   void markInstalled();
52   void run();
53
54  private:
55   std::atomic<bool> installed_;
56   std::mutex mutex_;
57   std::vector<SignalCallback> handlers_;
58 };
59
60 FatalSignalCallbackRegistry::FatalSignalCallbackRegistry()
61   : installed_(false) {
62 }
63
64 void FatalSignalCallbackRegistry::add(SignalCallback func) {
65   std::lock_guard<std::mutex> lock(mutex_);
66   CHECK(!installed_)
67     << "FatalSignalCallbackRegistry::add may not be used "
68        "after installing the signal handlers.";
69   handlers_.push_back(func);
70 }
71
72 void FatalSignalCallbackRegistry::markInstalled() {
73   std::lock_guard<std::mutex> lock(mutex_);
74   CHECK(!installed_.exchange(true))
75     << "FatalSignalCallbackRegistry::markInstalled must be called "
76     << "at most once";
77 }
78
79 void FatalSignalCallbackRegistry::run() {
80   if (!installed_) {
81     return;
82   }
83
84   for (auto& fn : handlers_) {
85     fn();
86   }
87 }
88
89 // Leak it so we don't have to worry about destruction order
90 FatalSignalCallbackRegistry* gFatalSignalCallbackRegistry =
91   new FatalSignalCallbackRegistry;
92
93 struct {
94   int number;
95   const char* name;
96   struct sigaction oldAction;
97 } kFatalSignals[] = {
98   { SIGSEGV, "SIGSEGV" },
99   { SIGILL,  "SIGILL"  },
100   { SIGFPE,  "SIGFPE"  },
101   { SIGABRT, "SIGABRT" },
102   { SIGBUS,  "SIGBUS"  },
103   { SIGTERM, "SIGTERM" },
104   { 0,       nullptr   }
105 };
106
107 void callPreviousSignalHandler(int signum) {
108   // Restore disposition to old disposition, then kill ourselves with the same
109   // signal. The signal will be blocked until we return from our handler,
110   // then it will invoke the default handler and abort.
111   for (auto p = kFatalSignals; p->name; ++p) {
112     if (p->number == signum) {
113       sigaction(signum, &p->oldAction, nullptr);
114       raise(signum);
115       return;
116     }
117   }
118
119   // Not one of the signals we know about. Oh well. Reset to default.
120   struct sigaction sa;
121   memset(&sa, 0, sizeof(sa));
122   sa.sa_handler = SIG_DFL;
123   sigaction(signum, &sa, nullptr);
124   raise(signum);
125 }
126
127 constexpr size_t kDefaultCapacity = 500;
128
129 // Note: not thread-safe, but that's okay, as we only let one thread
130 // in our signal handler at a time.
131 //
132 // Leak it so we don't have to worry about destruction order
133 auto gSignalSafeElfCache = new SignalSafeElfCache(kDefaultCapacity);
134
135 // Buffered writer (using a fixed-size buffer). We try to write only once
136 // to prevent interleaving with messages written from other threads.
137 //
138 // Leak it so we don't have to worry about destruction order.
139 auto gPrinter = new FDSymbolizePrinter(STDERR_FILENO,
140                                        SymbolizePrinter::COLOR_IF_TTY,
141                                        size_t(64) << 10);  // 64KiB
142
143 // Flush gPrinter, also fsync, in case we're about to crash again...
144 void flush() {
145   gPrinter->flush();
146   fsyncNoInt(STDERR_FILENO);
147 }
148
149 void printDec(uint64_t val) {
150   char buf[20];
151   uint32_t n = uint64ToBufferUnsafe(val, buf);
152   gPrinter->print(StringPiece(buf, n));
153 }
154
155 const char kHexChars[] = "0123456789abcdef";
156 void printHex(uint64_t val) {
157   // TODO(tudorb): Add this to folly/Conv.h
158   char buf[2 + 2 * sizeof(uint64_t)];  // "0x" prefix, 2 digits for each byte
159
160   char* end = buf + sizeof(buf);
161   char* p = end;
162   do {
163     *--p = kHexChars[val & 0x0f];
164     val >>= 4;
165   } while (val != 0);
166   *--p = 'x';
167   *--p = '0';
168
169   gPrinter->print(StringPiece(p, end));
170 }
171
172 void print(StringPiece sp) {
173   gPrinter->print(sp);
174 }
175
176 void dumpTimeInfo() {
177   SCOPE_EXIT { flush(); };
178   time_t now = time(nullptr);
179   print("*** Aborted at ");
180   printDec(now);
181   print(" (Unix time, try 'date -d @");
182   printDec(now);
183   print("') ***\n");
184 }
185
186 void dumpSignalInfo(int signum, siginfo_t* siginfo) {
187   SCOPE_EXIT { flush(); };
188   // Get the signal name, if possible.
189   const char* name = nullptr;
190   for (auto p = kFatalSignals; p->name; ++p) {
191     if (p->number == signum) {
192       name = p->name;
193       break;
194     }
195   }
196
197   print("*** Signal ");
198   printDec(signum);
199   if (name) {
200     print(" (");
201     print(name);
202     print(")");
203   }
204
205   print(" (");
206   printHex(reinterpret_cast<uint64_t>(siginfo->si_addr));
207   print(") received by PID ");
208   printDec(getpid());
209   print(" (pthread TID ");
210   printHex((uint64_t)pthread_self());
211   print(") (linux TID ");
212   printDec(syscall(__NR_gettid));
213   print("), stack trace: ***\n");
214 }
215
216 FOLLY_NOINLINE void dumpStackTrace(bool symbolize);
217
218 void dumpStackTrace(bool symbolize) {
219   SCOPE_EXIT { flush(); };
220   // Get and symbolize stack trace
221   constexpr size_t kMaxStackTraceDepth = 100;
222   FrameArray<kMaxStackTraceDepth> addresses;
223
224   // Skip the getStackTrace frame
225   if (!getStackTraceSafe(addresses)) {
226     print("(error retrieving stack trace)\n");
227   } else if (symbolize) {
228     Symbolizer symbolizer(gSignalSafeElfCache);
229     symbolizer.symbolize(addresses);
230
231     // Skip the top 2 frames:
232     // getStackTraceSafe
233     // dumpStackTrace (here)
234     //
235     // Leaving signalHandler on the stack for clarity, I think.
236     gPrinter->println(addresses, 2);
237   } else {
238     print("(safe mode, symbolizer not available)\n");
239     AddressFormatter formatter;
240     for (size_t i = 0; i < addresses.frameCount; ++i) {
241       print(formatter.format(addresses.addresses[i]));
242       print("\n");
243     }
244   }
245 }
246
247 // On Linux, pthread_t is a pointer, so 0 is an invalid value, which we
248 // take to indicate "no thread in the signal handler".
249 //
250 // POSIX defines PTHREAD_NULL for this purpose, but that's not available.
251 constexpr pthread_t kInvalidThreadId = 0;
252
253 std::atomic<pthread_t> gSignalThread(kInvalidThreadId);
254 std::atomic<bool> gInRecursiveSignalHandler(false);
255
256 // Here be dragons.
257 void innerSignalHandler(int signum, siginfo_t* info, void* uctx) {
258   // First, let's only let one thread in here at a time.
259   pthread_t myId = pthread_self();
260
261   pthread_t prevSignalThread = kInvalidThreadId;
262   while (!gSignalThread.compare_exchange_strong(prevSignalThread, myId)) {
263     if (pthread_equal(prevSignalThread, myId)) {
264       // First time here. Try to dump the stack trace without symbolization.
265       // If we still fail, well, we're mightily screwed, so we do nothing the
266       // next time around.
267       if (!gInRecursiveSignalHandler.exchange(true)) {
268         print("Entered fatal signal handler recursively. We're in trouble.\n");
269         dumpStackTrace(false);  // no symbolization
270       }
271       return;
272     }
273
274     // Wait a while, try again.
275     timespec ts;
276     ts.tv_sec = 0;
277     ts.tv_nsec = 100L * 1000 * 1000;  // 100ms
278     nanosleep(&ts, nullptr);
279
280     prevSignalThread = kInvalidThreadId;
281   }
282
283   dumpTimeInfo();
284   dumpSignalInfo(signum, info);
285   dumpStackTrace(true);  // with symbolization
286
287   // Run user callbacks
288   gFatalSignalCallbackRegistry->run();
289 }
290
291 void signalHandler(int signum, siginfo_t* info, void* uctx) {
292   SCOPE_EXIT { flush(); };
293   innerSignalHandler(signum, info, uctx);
294
295   gSignalThread = kInvalidThreadId;
296   // Kill ourselves with the previous handler.
297   callPreviousSignalHandler(signum);
298 }
299
300 }  // namespace
301
302 void addFatalSignalCallback(SignalCallback cb) {
303   gFatalSignalCallbackRegistry->add(cb);
304 }
305
306 void installFatalSignalCallbacks() {
307   gFatalSignalCallbackRegistry->markInstalled();
308 }
309
310 namespace {
311
312 std::atomic<bool> gAlreadyInstalled;
313
314 }  // namespace
315
316 void installFatalSignalHandler() {
317   if (gAlreadyInstalled.exchange(true)) {
318     // Already done.
319     return;
320   }
321
322   struct sigaction sa;
323   memset(&sa, 0, sizeof(sa));
324   sigemptyset(&sa.sa_mask);
325   sa.sa_flags |= SA_SIGINFO;
326   sa.sa_sigaction = &signalHandler;
327
328   for (auto p = kFatalSignals; p->name; ++p) {
329     CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
330   }
331 }
332
333 }}  // namespaces