blob: 961ee965196ebb2dc115d9f2c0eb8ff1725bdb84 [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"
37#include "glog/logging.h"
38
39#include <signal.h>
40#include <time.h>
41#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
49_START_GOOGLE_NAMESPACE_
50
51namespace {
52
53// We'll install the failure signal handler for these signals. We could
54// use strsignal() to get signal names, but we don't use it to avoid
55// introducing yet another #ifdef complication.
56//
57// The list should be synced with the comment in signalhandler.h.
58const struct {
59 int number;
60 const char *name;
61} kFailureSignals[] = {
62 { SIGSEGV, "SIGSEGV" },
63 { SIGILL, "SIGILL" },
64 { SIGFPE, "SIGFPE" },
65 { SIGABRT, "SIGABRT" },
66#if !defined(OS_WINDOWS)
67 { SIGBUS, "SIGBUS" },
68#endif
69 { SIGTERM, "SIGTERM" },
70};
71
72static bool kFailureSignalHandlerInstalled = false;
73
74// Returns the program counter from signal context, NULL if unknown.
75void* GetPC(void* ucontext_in_void) {
76#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
77 if (ucontext_in_void != NULL) {
78 ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
79 return (void*)context->PC_FROM_UCONTEXT;
80 }
81#endif
82 return NULL;
83}
84
85// The class is used for formatting error messages. We don't use printf()
86// as it's not async signal safe.
87class MinimalFormatter {
88 public:
89 MinimalFormatter(char *buffer, int size)
90 : buffer_(buffer),
91 cursor_(buffer),
92 end_(buffer + size) {
93 }
94
95 // Returns the number of bytes written in the buffer.
96 int num_bytes_written() const { return (int) (cursor_ - buffer_); }
97
98 // Appends string from "str" and updates the internal cursor.
99 void AppendString(const char* str) {
100 int i = 0;
101 while (str[i] != '\0' && cursor_ + i < end_) {
102 cursor_[i] = str[i];
103 ++i;
104 }
105 cursor_ += i;
106 }
107
108 // Formats "number" in "radix" and updates the internal cursor.
109 // Lowercase letters are used for 'a' - 'z'.
110 void AppendUint64(uint64 number, int radix) {
111 int i = 0;
112 while (cursor_ + i < end_) {
113 const int tmp = number % radix;
114 number /= radix;
115 cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
116 ++i;
117 if (number == 0) {
118 break;
119 }
120 }
121 // Reverse the bytes written.
122 std::reverse(cursor_, cursor_ + i);
123 cursor_ += i;
124 }
125
126 // Formats "number" as hexadecimal number, and updates the internal
127 // cursor. Padding will be added in front if needed.
128 void AppendHexWithPadding(uint64 number, int width) {
129 char* start = cursor_;
130 AppendString("0x");
131 AppendUint64(number, 16);
132 // Move to right and add padding in front if needed.
133 if (cursor_ < start + width) {
134 const int64 delta = start + width - cursor_;
135 std::copy(start, cursor_, start + delta);
136 std::fill(start, start + delta, ' ');
137 cursor_ = start + width;
138 }
139 }
140
141 private:
142 char *buffer_;
143 char *cursor_;
144 const char * const end_;
145};
146
147// Writes the given data with the size to the standard error.
148void WriteToStderr(const char* data, int size) {
149 if (write(STDERR_FILENO, data, size) < 0) {
150 // Ignore errors.
151 }
152}
153
154// The writer function can be changed by InstallFailureWriter().
155void (*g_failure_writer)(const char* data, int size) = WriteToStderr;
156
157// Dumps time information. We don't dump human-readable time information
158// as localtime() is not guaranteed to be async signal safe.
159void DumpTimeInfo() {
160 time_t time_in_sec = time(NULL);
161 char buf[256]; // Big enough for time info.
162 MinimalFormatter formatter(buf, sizeof(buf));
163 formatter.AppendString("*** Aborted at ");
164 formatter.AppendUint64(time_in_sec, 10);
165 formatter.AppendString(" (unix time)");
166 formatter.AppendString(" try \"date -d @");
167 formatter.AppendUint64(time_in_sec, 10);
168 formatter.AppendString("\" if you are using GNU date ***\n");
169 g_failure_writer(buf, formatter.num_bytes_written());
170}
171
172// TOOD(hamaji): Use signal instead of sigaction?
173#ifdef HAVE_SIGACTION
174
175// Dumps information about the signal to STDERR.
176void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
177 // Get the signal name.
178 const char* signal_name = NULL;
179 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
180 if (signal_number == kFailureSignals[i].number) {
181 signal_name = kFailureSignals[i].name;
182 }
183 }
184
185 char buf[256]; // Big enough for signal info.
186 MinimalFormatter formatter(buf, sizeof(buf));
187
188 formatter.AppendString("*** ");
189 if (signal_name) {
190 formatter.AppendString(signal_name);
191 } else {
192 // Use the signal number if the name is unknown. The signal name
193 // should be known, but just in case.
194 formatter.AppendString("Signal ");
195 formatter.AppendUint64(signal_number, 10);
196 }
197 formatter.AppendString(" (@0x");
198 formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
199 formatter.AppendString(")");
200 formatter.AppendString(" received by PID ");
201 formatter.AppendUint64(getpid(), 10);
202 formatter.AppendString(" (TID 0x");
203 // We assume pthread_t is an integral number or a pointer, rather
204 // than a complex struct. In some environments, pthread_self()
205 // returns an uint64 but in some other environments pthread_self()
206 // returns a pointer. Hence we use C-style cast here, rather than
207 // reinterpret/static_cast, to support both types of environments.
208 formatter.AppendUint64((uintptr_t)pthread_self(), 16);
209 formatter.AppendString(") ");
210 // Only linux has the PID of the signal sender in si_pid.
211#ifdef OS_LINUX
212 formatter.AppendString("from PID ");
213 formatter.AppendUint64(siginfo->si_pid, 10);
214 formatter.AppendString("; ");
215#endif
216 formatter.AppendString("stack trace: ***\n");
217 g_failure_writer(buf, formatter.num_bytes_written());
218}
219
220#endif // HAVE_SIGACTION
221
222// Dumps information about the stack frame to STDERR.
223void DumpStackFrameInfo(const char* prefix, void* pc) {
224 // Get the symbol name.
225 const char *symbol = "(unknown)";
226 char symbolized[1024]; // Big enough for a sane symbol.
227 // Symbolizes the previous address of pc because pc may be in the
228 // next function.
229 if (Symbolize(reinterpret_cast<char *>(pc) - 1,
230 symbolized, sizeof(symbolized))) {
231 symbol = symbolized;
232 }
233
234 char buf[1024]; // Big enough for stack frame info.
235 MinimalFormatter formatter(buf, sizeof(buf));
236
237 formatter.AppendString(prefix);
238 formatter.AppendString("@ ");
239 const int width = 2 * sizeof(void*) + 2; // + 2 for "0x".
240 formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
241 formatter.AppendString(" ");
242 formatter.AppendString(symbol);
243 formatter.AppendString("\n");
244 g_failure_writer(buf, formatter.num_bytes_written());
245}
246
247// Invoke the default signal handler.
248void InvokeDefaultSignalHandler(int signal_number) {
249#ifdef HAVE_SIGACTION
250 struct sigaction sig_action;
251 memset(&sig_action, 0, sizeof(sig_action));
252 sigemptyset(&sig_action.sa_mask);
253 sig_action.sa_handler = SIG_DFL;
254 sigaction(signal_number, &sig_action, NULL);
255 kill(getpid(), signal_number);
256#elif defined(OS_WINDOWS)
257 signal(signal_number, SIG_DFL);
258 raise(signal_number);
259#endif
260}
261
262// This variable is used for protecting FailureSignalHandler() from
263// dumping stuff while another thread is doing it. Our policy is to let
264// the first thread dump stuff and let other threads wait.
265// See also comments in FailureSignalHandler().
266static pthread_t* g_entered_thread_id_pointer = NULL;
267
268// Dumps signal and stack frame information, and invokes the default
269// signal handler once our job is done.
270#if defined(OS_WINDOWS)
271void FailureSignalHandler(int signal_number)
272#else
273void FailureSignalHandler(int signal_number,
274 siginfo_t *signal_info,
275 void *ucontext)
276#endif
277{
278 // First check if we've already entered the function. We use an atomic
279 // compare and swap operation for platforms that support it. For other
280 // platforms, we use a naive method that could lead to a subtle race.
281
282 // We assume pthread_self() is async signal safe, though it's not
283 // officially guaranteed.
284 pthread_t my_thread_id = pthread_self();
285 // NOTE: We could simply use pthread_t rather than pthread_t* for this,
286 // if pthread_self() is guaranteed to return non-zero value for thread
287 // ids, but there is no such guarantee. We need to distinguish if the
288 // old value (value returned from __sync_val_compare_and_swap) is
289 // different from the original value (in this case NULL).
290 pthread_t* old_thread_id_pointer =
291 glog_internal_namespace_::sync_val_compare_and_swap(
292 &g_entered_thread_id_pointer,
293 static_cast<pthread_t*>(NULL),
294 &my_thread_id);
295 if (old_thread_id_pointer != NULL) {
296 // We've already entered the signal handler. What should we do?
297 if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
298 // It looks the current thread is reentering the signal handler.
299 // Something must be going wrong (maybe we are reentering by another
300 // type of signal?). Kill ourself by the default signal handler.
301 InvokeDefaultSignalHandler(signal_number);
302 }
303 // Another thread is dumping stuff. Let's wait until that thread
304 // finishes the job and kills the process.
305 while (true) {
306 sleep(1);
307 }
308 }
309 // This is the first time we enter the signal handler. We are going to
310 // do some interesting stuff from here.
311 // TODO(satorux): We might want to set timeout here using alarm(), but
312 // mixing alarm() and sleep() can be a bad idea.
313
314 // First dump time info.
315 DumpTimeInfo();
316
317#if !defined(OS_WINDOWS)
318 // Get the program counter from ucontext.
319 void *pc = GetPC(ucontext);
320 DumpStackFrameInfo("PC: ", pc);
321#endif
322
323#ifdef HAVE_STACKTRACE
324 // Get the stack traces.
325 void *stack[32];
326 // +1 to exclude this function.
327 const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
328# ifdef HAVE_SIGACTION
329 DumpSignalInfo(signal_number, signal_info);
330# endif
331 // Dump the stack traces.
332 for (int i = 0; i < depth; ++i) {
333 DumpStackFrameInfo(" ", stack[i]);
334 }
335#endif
336
337 // *** TRANSITION ***
338 //
339 // BEFORE this point, all code must be async-termination-safe!
340 // (See WARNING above.)
341 //
342 // AFTER this point, we do unsafe things, like using LOG()!
343 // The process could be terminated or hung at any time. We try to
344 // do more useful things first and riskier things later.
345
346 // Flush the logs before we do anything in case 'anything'
347 // causes problems.
348 FlushLogFilesUnsafe(0);
349
350 // Kill ourself by the default signal handler.
351 InvokeDefaultSignalHandler(signal_number);
352}
353
354} // namespace
355
356namespace glog_internal_namespace_ {
357
358bool IsFailureSignalHandlerInstalled() {
359#ifdef HAVE_SIGACTION
360 // TODO(andschwa): Return kFailureSignalHandlerInstalled?
361 struct sigaction sig_action;
362 memset(&sig_action, 0, sizeof(sig_action));
363 sigemptyset(&sig_action.sa_mask);
364 sigaction(SIGABRT, NULL, &sig_action);
365 if (sig_action.sa_sigaction == &FailureSignalHandler)
366 return true;
367#elif defined(OS_WINDOWS)
368 return kFailureSignalHandlerInstalled;
369#endif // HAVE_SIGACTION
370 return false;
371}
372
373} // namespace glog_internal_namespace_
374
375void InstallFailureSignalHandler() {
376#ifdef HAVE_SIGACTION
377 // Build the sigaction struct.
378 struct sigaction sig_action;
379 memset(&sig_action, 0, sizeof(sig_action));
380 sigemptyset(&sig_action.sa_mask);
381 sig_action.sa_flags |= SA_SIGINFO;
382 sig_action.sa_sigaction = &FailureSignalHandler;
383
384 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
385 CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
386 }
387 kFailureSignalHandlerInstalled = true;
388#elif defined(OS_WINDOWS)
389 for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
390 CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
391 SIG_ERR);
392 }
393 kFailureSignalHandlerInstalled = true;
394#endif // HAVE_SIGACTION
395}
396
397void InstallFailureWriter(void (*writer)(const char* data, int size)) {
398#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS)
399 g_failure_writer = writer;
400#endif // HAVE_SIGACTION
401}
402
403_END_GOOGLE_NAMESPACE_