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