1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "fatal_signal.h"
10 #define BOOST_STACKTRACE_USE_ADDR2LINE
11 #include <boost/stacktrace.hpp>
12 #include <seastar/core/reactor.hh>
14 #include "common/safe_io.h"
15 #include "include/scope_guard.h"
17 FatalSignal::FatalSignal()
19 install_oneshot_signals_handler
<SIGSEGV
,
29 template <int... SigNums
>
30 void FatalSignal::install_oneshot_signals_handler()
32 (install_oneshot_signal_handler
<SigNums
>() , ...);
35 static void reraise_fatal(const int signum
)
37 // use default handler to dump core
38 ::signal(signum
, SIG_DFL
);
40 // normally, we won't get here. if we do, something is very weird.
41 if (::raise(signum
)) {
42 std::cerr
<< "reraise_fatal: failed to re-raise signal " << signum
45 std::cerr
<< "reraise_fatal: default handler for signal " << signum
46 << " didn't terminate the process?" << std::endl
;
48 std::cerr
<< std::flush
;
52 [[gnu::noinline
]] void FatalSignal::signal_entry(
54 siginfo_t
* const info
,
57 if (static std::atomic_bool handled
{false}; handled
.exchange(true)) {
61 FatalSignal::signaled(signum
, *info
);
62 reraise_fatal(signum
);
66 void FatalSignal::install_oneshot_signal_handler()
69 // it's a bad idea to use a lambda here. On GCC there are `operator()`
70 // and `_FUN()`. Controlling their inlineability is hard (impossible?).
71 sa
.sa_sigaction
= signal_entry
;
72 sigemptyset(&sa
.sa_mask
);
73 sa
.sa_flags
= SA_SIGINFO
| SA_RESTART
| SA_NODEFER
;
74 if constexpr (SigNum
== SIGSEGV
) {
75 sa
.sa_flags
|= SA_ONSTACK
;
77 [[maybe_unused
]] auto r
= ::sigaction(SigNum
, &sa
, nullptr);
82 [[gnu::noinline
]] static void print_backtrace(std::string_view cause
) {
84 if (seastar::engine_is_ready()) {
85 std::cerr
<< " on shard " << seastar::this_shard_id();
87 // nobody wants to see things like `FatalSignal::signaled()` or
88 // `print_backtrace()` in our backtraces. `+ 1` is for the extra
89 // frame created by kernel (signal trampoline, it will take care
90 // about e.g. sigreturn(2) calling; see the man page).
91 constexpr std::size_t FRAMES_TO_SKIP
= 3 + 1;
92 std::cerr
<< ".\nBacktrace:\n";
93 std::cerr
<< boost::stacktrace::stacktrace(
95 static_cast<std::size_t>(-1)/* max depth same as the default one */);
96 std::cerr
<< std::flush
;
97 // TODO: dump crash related meta data to $crash_dir
98 // see handle_fatal_signal()
101 static void print_segv_info(const siginfo_t
& siginfo
)
104 << "Dump of siginfo:" << std::endl
105 << " si_signo: " << siginfo
.si_signo
<< std::endl
106 << " si_errno: " << siginfo
.si_errno
<< std::endl
107 << " si_code: " << siginfo
.si_code
<< std::endl
108 << " si_pid: " << siginfo
.si_pid
<< std::endl
109 << " si_uid: " << siginfo
.si_uid
<< std::endl
110 << " si_status: " << siginfo
.si_status
<< std::endl
111 << " si_utime: " << siginfo
.si_utime
<< std::endl
112 << " si_stime: " << siginfo
.si_stime
<< std::endl
113 << " si_int: " << siginfo
.si_int
<< std::endl
114 << " si_ptr: " << siginfo
.si_ptr
<< std::endl
115 << " si_overrun: " << siginfo
.si_overrun
<< std::endl
116 << " si_timerid: " << siginfo
.si_timerid
<< std::endl
117 << " si_addr: " << siginfo
.si_addr
<< std::endl
118 << " si_band: " << siginfo
.si_band
<< std::endl
119 << " si_fd: " << siginfo
.si_fd
<< std::endl
120 << " si_addr_lsb: " << siginfo
.si_addr_lsb
<< std::endl
121 << " si_lower: " << siginfo
.si_lower
<< std::endl
122 << " si_upper: " << siginfo
.si_upper
<< std::endl
123 << " si_pkey: " << siginfo
.si_pkey
<< std::endl
124 << " si_call_addr: " << siginfo
.si_call_addr
<< std::endl
125 << " si_syscall: " << siginfo
.si_syscall
<< std::endl
126 << " si_arch: " << siginfo
.si_arch
<< std::endl
;
127 std::cerr
<< std::flush
;
130 static void print_proc_maps()
132 const int fd
= ::open("/proc/self/maps", O_RDONLY
);
134 std::cerr
<< "can't open /proc/self/maps. procfs not mounted?" << std::endl
;
137 const auto fd_guard
= make_scope_guard([fd
] {
140 std::cerr
<< "Content of /proc/self/maps:" << std::endl
;
142 char chunk
[4096] = {0, };
143 const ssize_t r
= safe_read(fd
, chunk
, sizeof(chunk
) - 1);
145 std::cerr
<< "error while reading /proc/self/maps: " << r
<< std::endl
;
148 std::cerr
<< chunk
<< std::flush
;
149 if (r
< static_cast<ssize_t
>(sizeof(chunk
) - 1)) {
156 [[gnu::noinline
]] void FatalSignal::signaled(const int signum
,
157 const siginfo_t
& siginfo
)
161 print_backtrace("Segmentation fault");
162 print_segv_info(siginfo
);
165 print_backtrace("Aborting");
168 print_backtrace(fmt::format("Signal {}", signum
));