PageRenderTime 46ms CodeModel.GetById 22ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/third_party/glog/src/signalhandler.cc

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