b1837f4044fdb69db7cc8fb6086543472e87109a
[folly.git] / folly / experimental / symbolizer / SignalHandler.cpp
1 /*
2  * Copyright 2017 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 <pthread.h>
22 #include <signal.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <algorithm>
27 #include <atomic>
28 #include <ctime>
29 #include <mutex>
30 #include <vector>
31
32 #include <glog/logging.h>
33
34 #include <folly/Conv.h>
35 #include <folly/ScopeGuard.h>
36 #include <folly/experimental/symbolizer/ElfCache.h>
37 #include <folly/experimental/symbolizer/Symbolizer.h>
38 #include <folly/portability/SysSyscall.h>
39
40 namespace folly { namespace symbolizer {
41
42 namespace {
43
44 /**
45  * Fatal signal handler registry.
46  */
47 class FatalSignalCallbackRegistry {
48  public:
49   FatalSignalCallbackRegistry();
50
51   void add(SignalCallback func);
52   void markInstalled();
53   void run();
54
55  private:
56   std::atomic<bool> installed_;
57   std::mutex mutex_;
58   std::vector<SignalCallback> handlers_;
59 };
60
61 FatalSignalCallbackRegistry::FatalSignalCallbackRegistry()
62   : installed_(false) {
63 }
64
65 void FatalSignalCallbackRegistry::add(SignalCallback func) {
66   std::lock_guard<std::mutex> lock(mutex_);
67   CHECK(!installed_)
68     << "FatalSignalCallbackRegistry::add may not be used "
69        "after installing the signal handlers.";
70   handlers_.push_back(func);
71 }
72
73 void FatalSignalCallbackRegistry::markInstalled() {
74   std::lock_guard<std::mutex> lock(mutex_);
75   CHECK(!installed_.exchange(true))
76     << "FatalSignalCallbackRegistry::markInstalled must be called "
77     << "at most once";
78 }
79
80 void FatalSignalCallbackRegistry::run() {
81   if (!installed_) {
82     return;
83   }
84
85   for (auto& fn : handlers_) {
86     fn();
87   }
88 }
89
90 // Leak it so we don't have to worry about destruction order
91 FatalSignalCallbackRegistry* gFatalSignalCallbackRegistry =
92   new FatalSignalCallbackRegistry;
93
94 struct {
95   int number;
96   const char* name;
97   struct sigaction oldAction;
98 } kFatalSignals[] = {
99   { SIGSEGV, "SIGSEGV", {} },
100   { SIGILL,  "SIGILL",  {} },
101   { SIGFPE,  "SIGFPE",  {} },
102   { SIGABRT, "SIGABRT", {} },
103   { SIGBUS,  "SIGBUS",  {} },
104   { SIGTERM, "SIGTERM", {} },
105   { 0,       nullptr,   {} }
106 };
107
108 void callPreviousSignalHandler(int signum) {
109   // Restore disposition to old disposition, then kill ourselves with the same
110   // signal. The signal will be blocked until we return from our handler,
111   // then it will invoke the default handler and abort.
112   for (auto p = kFatalSignals; p->name; ++p) {
113     if (p->number == signum) {
114       sigaction(signum, &p->oldAction, nullptr);
115       raise(signum);
116       return;
117     }
118   }
119
120   // Not one of the signals we know about. Oh well. Reset to default.
121   struct sigaction sa;
122   memset(&sa, 0, sizeof(sa));
123   sa.sa_handler = SIG_DFL;
124   sigaction(signum, &sa, nullptr);
125   raise(signum);
126 }
127
128 // Note: not thread-safe, but that's okay, as we only let one thread
129 // in our signal handler at a time.
130 //
131 // Leak it so we don't have to worry about destruction order
132 StackTracePrinter* gStackTracePrinter = new StackTracePrinter();
133
134 void printDec(uint64_t val) {
135   char buf[20];
136   uint32_t n = uint64ToBufferUnsafe(val, buf);
137   gStackTracePrinter->print(StringPiece(buf, n));
138 }
139
140 const char kHexChars[] = "0123456789abcdef";
141 void printHex(uint64_t val) {
142   // TODO(tudorb): Add this to folly/Conv.h
143   char buf[2 + 2 * sizeof(uint64_t)];  // "0x" prefix, 2 digits for each byte
144
145   char* end = buf + sizeof(buf);
146   char* p = end;
147   do {
148     *--p = kHexChars[val & 0x0f];
149     val >>= 4;
150   } while (val != 0);
151   *--p = 'x';
152   *--p = '0';
153
154   gStackTracePrinter->print(StringPiece(p, end));
155 }
156
157 void print(StringPiece sp) {
158   gStackTracePrinter->print(sp);
159 }
160
161 void flush() {
162   gStackTracePrinter->flush();
163 }
164
165 void dumpTimeInfo() {
166   SCOPE_EXIT { flush(); };
167   time_t now = time(nullptr);
168   print("*** Aborted at ");
169   printDec(now);
170   print(" (Unix time, try 'date -d @");
171   printDec(now);
172   print("') ***\n");
173 }
174
175 const char* sigill_reason(int si_code) {
176   switch (si_code) {
177     case ILL_ILLOPC:
178       return "illegal opcode";
179     case ILL_ILLOPN:
180       return "illegal operand";
181     case ILL_ILLADR:
182       return "illegal addressing mode";
183     case ILL_ILLTRP:
184       return "illegal trap";
185     case ILL_PRVOPC:
186       return "privileged opcode";
187     case ILL_PRVREG:
188       return "privileged register";
189     case ILL_COPROC:
190       return "coprocessor error";
191     case ILL_BADSTK:
192       return "internal stack error";
193
194     default:
195       return nullptr;
196   }
197 }
198
199 const char* sigfpe_reason(int si_code) {
200   switch (si_code) {
201     case FPE_INTDIV:
202       return "integer divide by zero";
203     case FPE_INTOVF:
204       return "integer overflow";
205     case FPE_FLTDIV:
206       return "floating-point divide by zero";
207     case FPE_FLTOVF:
208       return "floating-point overflow";
209     case FPE_FLTUND:
210       return "floating-point underflow";
211     case FPE_FLTRES:
212       return "floating-point inexact result";
213     case FPE_FLTINV:
214       return "floating-point invalid operation";
215     case FPE_FLTSUB:
216       return "subscript out of range";
217
218     default:
219       return nullptr;
220   }
221 }
222
223 const char* sigsegv_reason(int si_code) {
224   switch (si_code) {
225     case SEGV_MAPERR:
226       return "address not mapped to object";
227     case SEGV_ACCERR:
228       return "invalid permissions for mapped object";
229
230     default:
231       return nullptr;
232   }
233 }
234
235 const char* sigbus_reason(int si_code) {
236   switch (si_code) {
237     case BUS_ADRALN:
238       return "invalid address alignment";
239     case BUS_ADRERR:
240       return "nonexistent physical address";
241     case BUS_OBJERR:
242       return "object-specific hardware error";
243
244     // MCEERR_AR and MCEERR_AO: in sigaction(2) but not in headers.
245
246     default:
247       return nullptr;
248   }
249 }
250
251 const char* sigtrap_reason(int si_code) {
252   switch (si_code) {
253     case TRAP_BRKPT:
254       return "process breakpoint";
255     case TRAP_TRACE:
256       return "process trace trap";
257
258     // TRAP_BRANCH and TRAP_HWBKPT: in sigaction(2) but not in headers.
259
260     default:
261       return nullptr;
262   }
263 }
264
265 const char* sigchld_reason(int si_code) {
266   switch (si_code) {
267     case CLD_EXITED:
268       return "child has exited";
269     case CLD_KILLED:
270       return "child was killed";
271     case CLD_DUMPED:
272       return "child terminated abnormally";
273     case CLD_TRAPPED:
274       return "traced child has trapped";
275     case CLD_STOPPED:
276       return "child has stopped";
277     case CLD_CONTINUED:
278       return "stopped child has continued";
279
280     default:
281       return nullptr;
282   }
283 }
284
285 const char* sigio_reason(int si_code) {
286   switch (si_code) {
287     case POLL_IN:
288       return "data input available";
289     case POLL_OUT:
290       return "output buffers available";
291     case POLL_MSG:
292       return "input message available";
293     case POLL_ERR:
294       return "I/O error";
295     case POLL_PRI:
296       return "high priority input available";
297     case POLL_HUP:
298       return "device disconnected";
299
300     default:
301       return nullptr;
302   }
303 }
304
305 const char* signal_reason(int signum, int si_code) {
306   switch (signum) {
307     case SIGILL:
308       return sigill_reason(si_code);
309     case SIGFPE:
310       return sigfpe_reason(si_code);
311     case SIGSEGV:
312       return sigsegv_reason(si_code);
313     case SIGBUS:
314       return sigbus_reason(si_code);
315     case SIGTRAP:
316       return sigtrap_reason(si_code);
317     case SIGCHLD:
318       return sigchld_reason(si_code);
319     case SIGIO:
320       return sigio_reason(si_code); // aka SIGPOLL
321
322     default:
323       return nullptr;
324   }
325 }
326
327 void dumpSignalInfo(int signum, siginfo_t* siginfo) {
328   SCOPE_EXIT { flush(); };
329   // Get the signal name, if possible.
330   const char* name = nullptr;
331   for (auto p = kFatalSignals; p->name; ++p) {
332     if (p->number == signum) {
333       name = p->name;
334       break;
335     }
336   }
337
338   print("*** Signal ");
339   printDec(signum);
340   if (name) {
341     print(" (");
342     print(name);
343     print(")");
344   }
345
346   print(" (");
347   printHex(reinterpret_cast<uint64_t>(siginfo->si_addr));
348   print(") received by PID ");
349   printDec(getpid());
350   print(" (pthread TID ");
351   printHex((uint64_t)pthread_self());
352   print(") (linux TID ");
353   printDec(syscall(__NR_gettid));
354
355   // Kernel-sourced signals don't give us useful info for pid/uid.
356   if (siginfo->si_code != SI_KERNEL) {
357     print(") (maybe from PID ");
358     printDec(siginfo->si_pid);
359     print(", UID ");
360     printDec(siginfo->si_uid);
361   }
362
363   auto reason = signal_reason(signum, siginfo->si_code);
364
365   if (reason != nullptr) {
366     print(") (code: ");
367     print(reason);
368   }
369
370   print("), stack trace: ***\n");
371 }
372
373 // On Linux, pthread_t is a pointer, so 0 is an invalid value, which we
374 // take to indicate "no thread in the signal handler".
375 //
376 // POSIX defines PTHREAD_NULL for this purpose, but that's not available.
377 constexpr pthread_t kInvalidThreadId = 0;
378
379 std::atomic<pthread_t> gSignalThread(kInvalidThreadId);
380 std::atomic<bool> gInRecursiveSignalHandler(false);
381
382 // Here be dragons.
383 void innerSignalHandler(int signum, siginfo_t* info, void* /* uctx */) {
384   // First, let's only let one thread in here at a time.
385   pthread_t myId = pthread_self();
386
387   pthread_t prevSignalThread = kInvalidThreadId;
388   while (!gSignalThread.compare_exchange_strong(prevSignalThread, myId)) {
389     if (pthread_equal(prevSignalThread, myId)) {
390       // First time here. Try to dump the stack trace without symbolization.
391       // If we still fail, well, we're mightily screwed, so we do nothing the
392       // next time around.
393       if (!gInRecursiveSignalHandler.exchange(true)) {
394         print("Entered fatal signal handler recursively. We're in trouble.\n");
395         gStackTracePrinter->printStackTrace(false); // no symbolization
396       }
397       return;
398     }
399
400     // Wait a while, try again.
401     timespec ts;
402     ts.tv_sec = 0;
403     ts.tv_nsec = 100L * 1000 * 1000;  // 100ms
404     nanosleep(&ts, nullptr);
405
406     prevSignalThread = kInvalidThreadId;
407   }
408
409   dumpTimeInfo();
410   dumpSignalInfo(signum, info);
411   gStackTracePrinter->printStackTrace(true); // with symbolization
412
413   // Run user callbacks
414   gFatalSignalCallbackRegistry->run();
415 }
416
417 void signalHandler(int signum, siginfo_t* info, void* uctx) {
418   SCOPE_EXIT { flush(); };
419   innerSignalHandler(signum, info, uctx);
420
421   gSignalThread = kInvalidThreadId;
422   // Kill ourselves with the previous handler.
423   callPreviousSignalHandler(signum);
424 }
425
426 }  // namespace
427
428 void addFatalSignalCallback(SignalCallback cb) {
429   gFatalSignalCallbackRegistry->add(cb);
430 }
431
432 void installFatalSignalCallbacks() {
433   gFatalSignalCallbackRegistry->markInstalled();
434 }
435
436 namespace {
437
438 std::atomic<bool> gAlreadyInstalled;
439
440 }  // namespace
441
442 void installFatalSignalHandler() {
443   if (gAlreadyInstalled.exchange(true)) {
444     // Already done.
445     return;
446   }
447
448   struct sigaction sa;
449   memset(&sa, 0, sizeof(sa));
450   sigemptyset(&sa.sa_mask);
451   // By default signal handlers are run on the signaled thread's stack.
452   // In case of stack overflow running the SIGSEGV signal handler on
453   // the same stack leads to another SIGSEGV and crashes the program.
454   // Use SA_ONSTACK, so alternate stack is used (only if configured via
455   // sigaltstack).
456   sa.sa_flags |= SA_SIGINFO | SA_ONSTACK;
457   sa.sa_sigaction = &signalHandler;
458
459   for (auto p = kFatalSignals; p->name; ++p) {
460     CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));
461   }
462 }
463
464 }}  // namespaces