blob: 5e43fa31b30a7ebec5dcf4a37faee3838e0f03ca [file] [log] [blame]
Austin Schuh906616c2019-01-21 20:25:11 -08001// Copyright (c) 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Author: Satoru Takabayashi
31//
32// Implementation of InstallFailureSignalHandler().
33
34#include "utilities.h"
35#include "stacktrace.h"
36#include "symbolize.h"
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070037#include <glog/logging.h>
Austin Schuh906616c2019-01-21 20:25:11 -080038
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070039#include <csignal>
40#include <ctime>
Austin Schuh906616c2019-01-21 20:25:11 -080041#ifdef HAVE_UCONTEXT_H
42# include <ucontext.h>
43#endif
44#ifdef HAVE_SYS_UCONTEXT_H
45# include <sys/ucontext.h>
46#endif
47#include <algorithm>
48
Austin Schuh77f3f222022-06-10 16:49:21 -070049namespace aos {
50void FatalUnsetRealtimePriority() __attribute__((weak));
51}
52
Austin Schuh906616c2019-01-21 20:25:11 -080053_START_GOOGLE_NAMESPACE_
54
55namespace {
56
Austin Schuh77f3f222022-06-10 16:49:21 -070057void MaybeUnsetRealtime() {
58 if (&aos::FatalUnsetRealtimePriority != nullptr) {
59 aos::FatalUnsetRealtimePriority();
60 }
61}
62
Austin Schuh906616c2019-01-21 20:25:11 -080063// We'll install the failure signal handler for these signals. We could
64// use strsignal() to get signal names, but we don't use it to avoid
65// introducing yet another #ifdef complication.
66//
67// The list should be synced with the comment in signalhandler.h.
68const struct {
69 int number;
70 const char *name;
71} kFailureSignals[] = {
72 { SIGSEGV, "SIGSEGV" },
73 { SIGILL, "SIGILL" },
74 { SIGFPE, "SIGFPE" },
75 { SIGABRT, "SIGABRT" },
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070076#if !defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -080077 { SIGBUS, "SIGBUS" },
78#endif
79 { SIGTERM, "SIGTERM" },
80};
81
82static bool kFailureSignalHandlerInstalled = false;
83
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070084#if !defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -080085// Returns the program counter from signal context, NULL if unknown.
86void* GetPC(void* ucontext_in_void) {
87#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
88 if (ucontext_in_void != NULL) {
89 ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
90 return (void*)context->PC_FROM_UCONTEXT;
91 }
Austin Schuh10358f22019-01-21 20:25:11 -080092#else
93 (void)ucontext_in_void;
Austin Schuh906616c2019-01-21 20:25:11 -080094#endif
95 return NULL;
96}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070097#endif
Austin Schuh906616c2019-01-21 20:25:11 -080098
99// The class is used for formatting error messages. We don't use printf()
100// as it's not async signal safe.
101class MinimalFormatter {
102 public:
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700103 MinimalFormatter(char *buffer, size_t size)
Austin Schuh906616c2019-01-21 20:25:11 -0800104 : buffer_(buffer),
105 cursor_(buffer),
106 end_(buffer + size) {
107 }
108
109 // Returns the number of bytes written in the buffer.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700110 std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
Austin Schuh906616c2019-01-21 20:25:11 -0800111
112 // Appends string from "str" and updates the internal cursor.
113 void AppendString(const char* str) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700114 ptrdiff_t i = 0;
Austin Schuh906616c2019-01-21 20:25:11 -0800115 while (str[i] != '\0' && cursor_ + i < end_) {
116 cursor_[i] = str[i];
117 ++i;
118 }
119 cursor_ += i;
120 }
121
122 // Formats "number" in "radix" and updates the internal cursor.
123 // Lowercase letters are used for 'a' - 'z'.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700124 void AppendUint64(uint64 number, unsigned radix) {
125 unsigned i = 0;
Austin Schuh906616c2019-01-21 20:25:11 -0800126 while (cursor_ + i < end_) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700127 const uint64 tmp = number % radix;
Austin Schuh906616c2019-01-21 20:25:11 -0800128 number /= radix;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700129 cursor_[i] = static_cast<char>(tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800130 ++i;
131 if (number == 0) {
132 break;
133 }
134 }
135 // Reverse the bytes written.
136 std::reverse(cursor_, cursor_ + i);
137 cursor_ += i;
138 }
139
140 // Formats "number" as hexadecimal number, and updates the internal
141 // cursor. Padding will be added in front if needed.
142 void AppendHexWithPadding(uint64 number, int width) {
143 char* start = cursor_;
144 AppendString("0x");
145 AppendUint64(number, 16);
146 // Move to right and add padding in front if needed.
147 if (cursor_ < start + width) {
148 const int64 delta = start + width - cursor_;
149 std::copy(start, cursor_, start + delta);
150 std::fill(start, start + delta, ' ');
151 cursor_ = start + width;
152 }
153 }
154
155 private:
156 char *buffer_;
157 char *cursor_;
158 const char * const end_;
159};
160
161// Writes the given data with the size to the standard error.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700162void WriteToStderr(const char* data, size_t size) {
Austin Schuh906616c2019-01-21 20:25:11 -0800163 if (write(STDERR_FILENO, data, size) < 0) {
164 // Ignore errors.
165 }
166}
167
168// The writer function can be changed by InstallFailureWriter().
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700169void (*g_failure_writer)(const char* data, size_t size) = WriteToStderr;
Austin Schuh906616c2019-01-21 20:25:11 -0800170
171// Dumps time information. We don't dump human-readable time information
172// as localtime() is not guaranteed to be async signal safe.
173void DumpTimeInfo() {
174 time_t time_in_sec = time(NULL);
175 char buf[256]; // Big enough for time info.
176 MinimalFormatter formatter(buf, sizeof(buf));
177 formatter.AppendString("*** Aborted at ");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700178 formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800179 formatter.AppendString(" (unix time)");
180 formatter.AppendString(" try \"date -d @");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700181 formatter.AppendUint64(static_cast<uint64>(time_in_sec), 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800182 formatter.AppendString("\" if you are using GNU date ***\n");
183 g_failure_writer(buf, formatter.num_bytes_written());
184}
185
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700186// TODO(hamaji): Use signal instead of sigaction?
187#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
Austin Schuh906616c2019-01-21 20:25:11 -0800188
189// Dumps information about the signal to STDERR.
190void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
191 // Get the signal name.
192 const char* signal_name = NULL;
193 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
194 if (signal_number == kFailureSignals[i].number) {
195 signal_name = kFailureSignals[i].name;
196 }
197 }
198
199 char buf[256]; // Big enough for signal info.
200 MinimalFormatter formatter(buf, sizeof(buf));
201
202 formatter.AppendString("*** ");
203 if (signal_name) {
204 formatter.AppendString(signal_name);
205 } else {
206 // Use the signal number if the name is unknown. The signal name
207 // should be known, but just in case.
208 formatter.AppendString("Signal ");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700209 formatter.AppendUint64(static_cast<uint64>(signal_number), 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800210 }
211 formatter.AppendString(" (@0x");
212 formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
213 formatter.AppendString(")");
214 formatter.AppendString(" received by PID ");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700215 formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800216 formatter.AppendString(" (TID 0x");
217 // We assume pthread_t is an integral number or a pointer, rather
218 // than a complex struct. In some environments, pthread_self()
219 // returns an uint64 but in some other environments pthread_self()
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700220 // returns a pointer.
221 pthread_t id = pthread_self();
222 formatter.AppendUint64(
223 reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
Austin Schuh906616c2019-01-21 20:25:11 -0800224 formatter.AppendString(") ");
225 // Only linux has the PID of the signal sender in si_pid.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700226#ifdef GLOG_OS_LINUX
Austin Schuh906616c2019-01-21 20:25:11 -0800227 formatter.AppendString("from PID ");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700228 formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
Austin Schuh906616c2019-01-21 20:25:11 -0800229 formatter.AppendString("; ");
230#endif
231 formatter.AppendString("stack trace: ***\n");
232 g_failure_writer(buf, formatter.num_bytes_written());
233}
234
235#endif // HAVE_SIGACTION
236
237// Dumps information about the stack frame to STDERR.
238void DumpStackFrameInfo(const char* prefix, void* pc) {
239 // Get the symbol name.
240 const char *symbol = "(unknown)";
241 char symbolized[1024]; // Big enough for a sane symbol.
242 // Symbolizes the previous address of pc because pc may be in the
243 // next function.
244 if (Symbolize(reinterpret_cast<char *>(pc) - 1,
245 symbolized, sizeof(symbolized))) {
246 symbol = symbolized;
247 }
248
249 char buf[1024]; // Big enough for stack frame info.
250 MinimalFormatter formatter(buf, sizeof(buf));
251
252 formatter.AppendString(prefix);
253 formatter.AppendString("@ ");
254 const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
255 formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
256 formatter.AppendString(" ");
257 formatter.AppendString(symbol);
258 formatter.AppendString("\n");
259 g_failure_writer(buf, formatter.num_bytes_written());
260}
261
262// Invoke the default signal handler.
263void InvokeDefaultSignalHandler(int signal_number) {
264#ifdef HAVE_SIGACTION
265 struct sigaction sig_action;
266 memset(&sig_action, 0, sizeof(sig_action));
267 sigemptyset(&sig_action.sa_mask);
268 sig_action.sa_handler = SIG_DFL;
269 sigaction(signal_number, &sig_action, NULL);
270 kill(getpid(), signal_number);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700271#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800272 signal(signal_number, SIG_DFL);
273 raise(signal_number);
274#endif
275}
276
277// This variable is used for protecting FailureSignalHandler() from
278// dumping stuff while another thread is doing it. Our policy is to let
279// the first thread dump stuff and let other threads wait.
280// See also comments in FailureSignalHandler().
281static pthread_t* g_entered_thread_id_pointer = NULL;
282
283// Dumps signal and stack frame information, and invokes the default
284// signal handler once our job is done.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700285#if defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800286void FailureSignalHandler(int signal_number)
287#else
288void FailureSignalHandler(int signal_number,
289 siginfo_t *signal_info,
290 void *ucontext)
291#endif
292{
293 // First check if we've already entered the function. We use an atomic
294 // compare and swap operation for platforms that support it. For other
295 // platforms, we use a naive method that could lead to a subtle race.
296
297 // We assume pthread_self() is async signal safe, though it's not
298 // officially guaranteed.
299 pthread_t my_thread_id = pthread_self();
300 // NOTE: We could simply use pthread_t rather than pthread_t* for this,
301 // if pthread_self() is guaranteed to return non-zero value for thread
302 // ids, but there is no such guarantee. We need to distinguish if the
303 // old value (value returned from __sync_val_compare_and_swap) is
304 // different from the original value (in this case NULL).
305 pthread_t* old_thread_id_pointer =
306 glog_internal_namespace_::sync_val_compare_and_swap(
307 &g_entered_thread_id_pointer,
308 static_cast<pthread_t*>(NULL),
309 &my_thread_id);
310 if (old_thread_id_pointer != NULL) {
311 // We've already entered the signal handler. What should we do?
312 if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
313 // It looks the current thread is reentering the signal handler.
314 // Something must be going wrong (maybe we are reentering by another
315 // type of signal?). Kill ourself by the default signal handler.
316 InvokeDefaultSignalHandler(signal_number);
317 }
318 // Another thread is dumping stuff. Let's wait until that thread
319 // finishes the job and kills the process.
320 while (true) {
321 sleep(1);
322 }
323 }
Austin Schuh77f3f222022-06-10 16:49:21 -0700324 MaybeUnsetRealtime();
Austin Schuha8faf282020-03-08 14:49:53 -0700325
Austin Schuh906616c2019-01-21 20:25:11 -0800326 // This is the first time we enter the signal handler. We are going to
327 // do some interesting stuff from here.
328 // TODO(satorux): We might want to set timeout here using alarm(), but
329 // mixing alarm() and sleep() can be a bad idea.
330
331 // First dump time info.
332 DumpTimeInfo();
333
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700334#if !defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800335 // Get the program counter from ucontext.
336 void *pc = GetPC(ucontext);
337 DumpStackFrameInfo("PC: ", pc);
Austin Schuh10358f22019-01-21 20:25:11 -0800338#else
339 (void)ucontext;
Austin Schuh906616c2019-01-21 20:25:11 -0800340#endif
341
342#ifdef HAVE_STACKTRACE
343 // Get the stack traces.
344 void *stack[32];
345 // +1 to exclude this function.
346 const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
347# ifdef HAVE_SIGACTION
348 DumpSignalInfo(signal_number, signal_info);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700349#elif !defined(GLOG_OS_WINDOWS)
Austin Schuh10358f22019-01-21 20:25:11 -0800350 (void)signal_info;
Austin Schuh906616c2019-01-21 20:25:11 -0800351# endif
352 // Dump the stack traces.
353 for (int i = 0; i < depth; ++i) {
354 DumpStackFrameInfo(" ", stack[i]);
355 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700356#elif !defined(GLOG_OS_WINDOWS)
Austin Schuh10358f22019-01-21 20:25:11 -0800357 (void)signal_info;
Austin Schuh906616c2019-01-21 20:25:11 -0800358#endif
359
360 // *** TRANSITION ***
361 //
362 // BEFORE this point, all code must be async-termination-safe!
363 // (See WARNING above.)
364 //
365 // AFTER this point, we do unsafe things, like using LOG()!
366 // The process could be terminated or hung at any time. We try to
367 // do more useful things first and riskier things later.
368
369 // Flush the logs before we do anything in case 'anything'
370 // causes problems.
371 FlushLogFilesUnsafe(0);
372
373 // Kill ourself by the default signal handler.
374 InvokeDefaultSignalHandler(signal_number);
375}
376
377} // namespace
378
379namespace glog_internal_namespace_ {
380
381bool IsFailureSignalHandlerInstalled() {
382#ifdef HAVE_SIGACTION
383 // TODO(andschwa): Return kFailureSignalHandlerInstalled?
384 struct sigaction sig_action;
385 memset(&sig_action, 0, sizeof(sig_action));
386 sigemptyset(&sig_action.sa_mask);
387 sigaction(SIGABRT, NULL, &sig_action);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700388 if (sig_action.sa_sigaction == &FailureSignalHandler) {
Austin Schuh906616c2019-01-21 20:25:11 -0800389 return true;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700390 }
391#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800392 return kFailureSignalHandlerInstalled;
393#endif // HAVE_SIGACTION
394 return false;
395}
396
397} // namespace glog_internal_namespace_
398
399void InstallFailureSignalHandler() {
400#ifdef HAVE_SIGACTION
401 // Build the sigaction struct.
402 struct sigaction sig_action;
403 memset(&sig_action, 0, sizeof(sig_action));
404 sigemptyset(&sig_action.sa_mask);
405 sig_action.sa_flags |= SA_SIGINFO;
406 sig_action.sa_sigaction = &FailureSignalHandler;
407
408 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
409 CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
410 }
411 kFailureSignalHandlerInstalled = true;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700412#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800413 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
414 CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
415 SIG_ERR);
416 }
417 kFailureSignalHandlerInstalled = true;
418#endif // HAVE_SIGACTION
419}
420
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700421void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
422#if defined(HAVE_SIGACTION) || defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800423 g_failure_writer = writer;
424#endif // HAVE_SIGACTION
425}
426
427_END_GOOGLE_NAMESPACE_