2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // This is heavily inspired by the signal handler from google-glog
19 #include <folly/experimental/symbolizer/SignalHandler.h>
23 #include <sys/types.h>
32 #include <glog/logging.h>
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>
40 namespace folly { namespace symbolizer {
45 * Fatal signal handler registry.
47 class FatalSignalCallbackRegistry {
49 FatalSignalCallbackRegistry();
51 void add(SignalCallback func);
56 std::atomic<bool> installed_;
58 std::vector<SignalCallback> handlers_;
61 FatalSignalCallbackRegistry::FatalSignalCallbackRegistry()
65 void FatalSignalCallbackRegistry::add(SignalCallback func) {
66 std::lock_guard<std::mutex> lock(mutex_);
68 << "FatalSignalCallbackRegistry::add may not be used "
69 "after installing the signal handlers.";
70 handlers_.push_back(func);
73 void FatalSignalCallbackRegistry::markInstalled() {
74 std::lock_guard<std::mutex> lock(mutex_);
75 CHECK(!installed_.exchange(true))
76 << "FatalSignalCallbackRegistry::markInstalled must be called "
80 void FatalSignalCallbackRegistry::run() {
85 for (auto& fn : handlers_) {
90 // Leak it so we don't have to worry about destruction order
91 FatalSignalCallbackRegistry* gFatalSignalCallbackRegistry =
92 new FatalSignalCallbackRegistry;
97 struct sigaction oldAction;
99 { SIGSEGV, "SIGSEGV", {} },
100 { SIGILL, "SIGILL", {} },
101 { SIGFPE, "SIGFPE", {} },
102 { SIGABRT, "SIGABRT", {} },
103 { SIGBUS, "SIGBUS", {} },
104 { SIGTERM, "SIGTERM", {} },
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);
120 // Not one of the signals we know about. Oh well. Reset to default.
122 memset(&sa, 0, sizeof(sa));
123 sa.sa_handler = SIG_DFL;
124 sigaction(signum, &sa, nullptr);
128 // Note: not thread-safe, but that's okay, as we only let one thread
129 // in our signal handler at a time.
131 // Leak it so we don't have to worry about destruction order
132 StackTracePrinter* gStackTracePrinter = new StackTracePrinter();
134 void printDec(uint64_t val) {
136 uint32_t n = uint64ToBufferUnsafe(val, buf);
137 gStackTracePrinter->print(StringPiece(buf, n));
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
145 char* end = buf + sizeof(buf);
148 *--p = kHexChars[val & 0x0f];
154 gStackTracePrinter->print(StringPiece(p, end));
157 void print(StringPiece sp) {
158 gStackTracePrinter->print(sp);
162 gStackTracePrinter->flush();
165 void dumpTimeInfo() {
166 SCOPE_EXIT { flush(); };
167 time_t now = time(nullptr);
168 print("*** Aborted at ");
170 print(" (Unix time, try 'date -d @");
175 const char* sigill_reason(int si_code) {
178 return "illegal opcode";
180 return "illegal operand";
182 return "illegal addressing mode";
184 return "illegal trap";
186 return "privileged opcode";
188 return "privileged register";
190 return "coprocessor error";
192 return "internal stack error";
199 const char* sigfpe_reason(int si_code) {
202 return "integer divide by zero";
204 return "integer overflow";
206 return "floating-point divide by zero";
208 return "floating-point overflow";
210 return "floating-point underflow";
212 return "floating-point inexact result";
214 return "floating-point invalid operation";
216 return "subscript out of range";
223 const char* sigsegv_reason(int si_code) {
226 return "address not mapped to object";
228 return "invalid permissions for mapped object";
235 const char* sigbus_reason(int si_code) {
238 return "invalid address alignment";
240 return "nonexistent physical address";
242 return "object-specific hardware error";
244 // MCEERR_AR and MCEERR_AO: in sigaction(2) but not in headers.
251 const char* sigtrap_reason(int si_code) {
254 return "process breakpoint";
256 return "process trace trap";
258 // TRAP_BRANCH and TRAP_HWBKPT: in sigaction(2) but not in headers.
265 const char* sigchld_reason(int si_code) {
268 return "child has exited";
270 return "child was killed";
272 return "child terminated abnormally";
274 return "traced child has trapped";
276 return "child has stopped";
278 return "stopped child has continued";
285 const char* sigio_reason(int si_code) {
288 return "data input available";
290 return "output buffers available";
292 return "input message available";
296 return "high priority input available";
298 return "device disconnected";
305 const char* signal_reason(int signum, int si_code) {
308 return sigill_reason(si_code);
310 return sigfpe_reason(si_code);
312 return sigsegv_reason(si_code);
314 return sigbus_reason(si_code);
316 return sigtrap_reason(si_code);
318 return sigchld_reason(si_code);
320 return sigio_reason(si_code); // aka SIGPOLL
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) {
338 print("*** Signal ");
347 printHex(reinterpret_cast<uint64_t>(siginfo->si_addr));
348 print(") received by PID ");
350 print(" (pthread TID ");
351 printHex((uint64_t)pthread_self());
352 print(") (linux TID ");
353 printDec(syscall(__NR_gettid));
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);
360 printDec(siginfo->si_uid);
363 auto reason = signal_reason(signum, siginfo->si_code);
365 if (reason != nullptr) {
370 print("), stack trace: ***\n");
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".
376 // POSIX defines PTHREAD_NULL for this purpose, but that's not available.
377 constexpr pthread_t kInvalidThreadId = 0;
379 std::atomic<pthread_t> gSignalThread(kInvalidThreadId);
380 std::atomic<bool> gInRecursiveSignalHandler(false);
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();
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
393 if (!gInRecursiveSignalHandler.exchange(true)) {
394 print("Entered fatal signal handler recursively. We're in trouble.\n");
395 gStackTracePrinter->printStackTrace(false); // no symbolization
400 // Wait a while, try again.
403 ts.tv_nsec = 100L * 1000 * 1000; // 100ms
404 nanosleep(&ts, nullptr);
406 prevSignalThread = kInvalidThreadId;
410 dumpSignalInfo(signum, info);
411 gStackTracePrinter->printStackTrace(true); // with symbolization
413 // Run user callbacks
414 gFatalSignalCallbackRegistry->run();
417 void signalHandler(int signum, siginfo_t* info, void* uctx) {
418 SCOPE_EXIT { flush(); };
419 innerSignalHandler(signum, info, uctx);
421 gSignalThread = kInvalidThreadId;
422 // Kill ourselves with the previous handler.
423 callPreviousSignalHandler(signum);
428 void addFatalSignalCallback(SignalCallback cb) {
429 gFatalSignalCallbackRegistry->add(cb);
432 void installFatalSignalCallbacks() {
433 gFatalSignalCallbackRegistry->markInstalled();
438 std::atomic<bool> gAlreadyInstalled;
442 void installFatalSignalHandler() {
443 if (gAlreadyInstalled.exchange(true)) {
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
456 sa.sa_flags |= SA_SIGINFO | SA_ONSTACK;
457 sa.sa_sigaction = &signalHandler;
459 for (auto p = kFatalSignals; p->name; ++p) {
460 CHECK_ERR(sigaction(p->number, &sa, &p->oldAction));