signalhandler.cc 12.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
30 31 32 33 34 35 36 37 38 39 40 41 42 43
// Author: Satoru Takabayashi
//
// Implementation of InstallFailureSignalHandler().

#include "utilities.h"
#include "stacktrace.h"
#include "symbolize.h"
#include "glog/logging.h"

#include <signal.h>
#include <time.h>
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
44 45 46
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include <algorithm>

_START_GOOGLE_NAMESPACE_

namespace {

// We'll install the failure signal handler for these signals.  We could
// use strsignal() to get signal names, but we don't use it to avoid
// introducing yet another #ifdef complication.
//
// The list should be synced with the comment in signalhandler.h.
const struct {
  int number;
  const char *name;
} kFailureSignals[] = {
  { SIGSEGV, "SIGSEGV" },
  { SIGILL, "SIGILL" },
  { SIGFPE, "SIGFPE" },
  { SIGABRT, "SIGABRT" },
  { SIGBUS, "SIGBUS" },
  { SIGTERM, "SIGTERM" },
};

// Returns the program counter from signal context, NULL if unknown.
void* GetPC(void* ucontext_in_void) {
72
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
  if (ucontext_in_void != NULL) {
    ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
    return (void*)context->PC_FROM_UCONTEXT;
  }
#endif
  return NULL;
}

// The class is used for formatting error messages.  We don't use printf()
// as it's not async signal safe.
class MinimalFormatter {
 public:
  MinimalFormatter(char *buffer, int size)
      : buffer_(buffer),
        cursor_(buffer),
        end_(buffer + size) {
  }

  // Returns the number of bytes written in the buffer.
  int num_bytes_written() const { return cursor_ - buffer_; }

  // Appends string from "str" and updates the internal cursor.
  void AppendString(const char* str) {
    int i = 0;
    while (str[i] != '\0' && cursor_ + i < end_) {
      cursor_[i] = str[i];
      ++i;
    }
    cursor_ += i;
  }

  // Formats "number" in "radix" and updates the internal cursor.
  // Lowercase letters are used for 'a' - 'z'.
  void AppendUint64(uint64 number, int radix) {
    int i = 0;
    while (cursor_ + i < end_) {
      const int tmp = number % radix;
      number /= radix;
      cursor_[i] = (tmp < 10 ? '0' + tmp : 'a' + tmp - 10);
      ++i;
      if (number == 0) {
        break;
      }
    }
    // Reverse the bytes written.
    std::reverse(cursor_, cursor_ + i);
    cursor_ += i;
  }

  // Formats "number" as hexadecimal number, and updates the internal
  // cursor.  Padding will be added in front if needed.
  void AppendHexWithPadding(uint64 number, int width) {
    char* start = cursor_;
    AppendString("0x");
    AppendUint64(number, 16);
    // Move to right and add padding in front if needed.
    if (cursor_ < start + width) {
      const int64 delta = start + width - cursor_;
      std::copy(start, cursor_, start + delta);
      std::fill(start, start + delta, ' ');
      cursor_ = start + width;
    }
  }

 private:
  char *buffer_;
  char *cursor_;
  const char * const end_;
};

// Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, int size) {
145 146 147
  if (write(STDERR_FILENO, data, size) < 0) {
    // Ignore errors.
  }
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
}

// The writer function can be changed by InstallFailureWriter().
void (*g_failure_writer)(const char* data, int size) = WriteToStderr;

// Dumps time information.  We don't dump human-readable time information
// as localtime() is not guaranteed to be async signal safe.
void DumpTimeInfo() {
  time_t time_in_sec = time(NULL);
  char buf[256];  // Big enough for time info.
  MinimalFormatter formatter(buf, sizeof(buf));
  formatter.AppendString("*** Aborted at ");
  formatter.AppendUint64(time_in_sec, 10);
  formatter.AppendString(" (unix time)");
  formatter.AppendString(" try \"date -d @");
  formatter.AppendUint64(time_in_sec, 10);
  formatter.AppendString("\" if you are using GNU date ***\n");
  g_failure_writer(buf, formatter.num_bytes_written());
}

// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
  // Get the signal name.
  const char* signal_name = NULL;
172
  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    if (signal_number == kFailureSignals[i].number) {
      signal_name = kFailureSignals[i].name;
    }
  }

  char buf[256];  // Big enough for signal info.
  MinimalFormatter formatter(buf, sizeof(buf));

  formatter.AppendString("*** ");
  if (signal_name) {
    formatter.AppendString(signal_name);
  } else {
    // Use the signal number if the name is unknown.  The signal name
    // should be known, but just in case.
    formatter.AppendString("Signal ");
    formatter.AppendUint64(signal_number, 10);
  }
  formatter.AppendString(" (@0x");
  formatter.AppendUint64(reinterpret_cast<uintptr_t>(siginfo->si_addr), 16);
  formatter.AppendString(")");
  formatter.AppendString(" received by PID ");
  formatter.AppendUint64(getpid(), 10);
  formatter.AppendString(" (TID 0x");
  // We assume pthread_t is an integral number or a pointer, rather
  // than a complex struct.  In some environments, pthread_self()
198
  // returns an uint64 but in some other environments pthread_self()
199 200
  // returns a pointer.  Hence we use C-style cast here, rather than
  // reinterpret/static_cast, to support both types of environments.
201
  formatter.AppendUint64((uintptr_t)pthread_self(), 16);
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  formatter.AppendString(") ");
  // Only linux has the PID of the signal sender in si_pid.
#ifdef OS_LINUX
  formatter.AppendString("from PID ");
  formatter.AppendUint64(siginfo->si_pid, 10);
  formatter.AppendString("; ");
#endif
  formatter.AppendString("stack trace: ***\n");
  g_failure_writer(buf, formatter.num_bytes_written());
}

// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
  // Get the symbol name.
  const char *symbol = "(unknown)";
  char symbolized[1024];  // Big enough for a sane symbol.
  // Symbolizes the previous address of pc because pc may be in the
  // next function.
  if (Symbolize(reinterpret_cast<char *>(pc) - 1,
                symbolized, sizeof(symbolized))) {
    symbol = symbolized;
  }

  char buf[1024];  // Big enough for stack frame info.
  MinimalFormatter formatter(buf, sizeof(buf));

  formatter.AppendString(prefix);
  formatter.AppendString("@ ");
  const int width = 2 * sizeof(void*) + 2;  // + 2  for "0x".
  formatter.AppendHexWithPadding(reinterpret_cast<uintptr_t>(pc), width);
  formatter.AppendString(" ");
  formatter.AppendString(symbol);
  formatter.AppendString("\n");
  g_failure_writer(buf, formatter.num_bytes_written());
}

// Invoke the default signal handler.
void InvokeDefaultSignalHandler(int signal_number) {
240 241
  struct sigaction sig_action;
  memset(&sig_action, 0, sizeof(sig_action));
242 243 244 245 246 247 248 249
  sigemptyset(&sig_action.sa_mask);
  sig_action.sa_handler = SIG_DFL;
  sigaction(signal_number, &sig_action, NULL);
  kill(getpid(), signal_number);
}

// This variable is used for protecting FailureSignalHandler() from
// 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 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
// See also comments in FailureSignalHandler().
static pthread_t* g_entered_thread_id_pointer = NULL;

// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
void FailureSignalHandler(int signal_number,
                          siginfo_t *signal_info,
                          void *ucontext) {
  // First check if we've already entered the function.  We use an atomic
  // compare and swap operation for platforms that support it.  For other
  // platforms, we use a naive method that could lead to a subtle race.

  // We assume pthread_self() is async signal safe, though it's not
  // officially guaranteed.
  pthread_t my_thread_id = pthread_self();
  // NOTE: We could simply use pthread_t rather than pthread_t* for this,
  // if pthread_self() is guaranteed to return non-zero value for thread
  // ids, but there is no such guarantee.  We need to distinguish if the
  // old value (value returned from __sync_val_compare_and_swap) is
  // different from the original value (in this case NULL).
  pthread_t* old_thread_id_pointer =
272 273 274 275
      glog_internal_namespace_::sync_val_compare_and_swap(
          &g_entered_thread_id_pointer,
          static_cast<pthread_t*>(NULL),
          &my_thread_id);
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
  if (old_thread_id_pointer != NULL) {
    // We've already entered the signal handler.  What should we do?
    if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
      // It looks the current thread is reentering the signal handler.
      // Something must be going wrong (maybe we are reentering by another
      // type of signal?).  Kill ourself by the default signal handler.
      InvokeDefaultSignalHandler(signal_number);
    }
    // Another thread is dumping stuff.  Let's wait until that thread
    // finishes the job and kills the process.
    while (true) {
      sleep(1);
    }
  }
  // This is the first time we enter the signal handler.  We are going to
  // do some interesting stuff from here.
  // TODO(satorux): We might want to set timeout here using alarm(), but
  // mixing alarm() and sleep() can be a bad idea.

  // First dump time info.
  DumpTimeInfo();

  // Get the program counter from ucontext.
  void *pc = GetPC(ucontext);
  DumpStackFrameInfo("PC: ", pc);

#ifdef HAVE_STACKTRACE
  // Get the stack traces.
  void *stack[32];
  // +1 to exclude this function.
306
  const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
307 308 309 310 311 312
  DumpSignalInfo(signal_number, signal_info);
  // Dump the stack traces.
  for (int i = 0; i < depth; ++i) {
    DumpStackFrameInfo("    ", stack[i]);
  }
#endif
313 314 315 316 317 318 319 320 321 322 323 324 325 326

  // *** TRANSITION ***
  //
  // BEFORE this point, all code must be async-termination-safe!
  // (See WARNING above.)
  //
  // AFTER this point, we do unsafe things, like using LOG()!
  // The process could be terminated or hung at any time.  We try to
  // do more useful things first and riskier things later.

  // Flush the logs before we do anything in case 'anything'
  // causes problems.
  FlushLogFilesUnsafe(0);

327 328 329 330 331 332 333 334
  // Kill ourself by the default signal handler.
  InvokeDefaultSignalHandler(signal_number);
}

}  // namespace

void InstallFailureSignalHandler() {
  // Build the sigaction struct.
335 336
  struct sigaction sig_action;
  memset(&sig_action, 0, sizeof(sig_action));
337 338 339 340
  sigemptyset(&sig_action.sa_mask);
  sig_action.sa_flags |= SA_SIGINFO;
  sig_action.sa_sigaction = &FailureSignalHandler;

341
  for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
342 343 344 345 346 347 348 349 350
    CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL));
  }
}

void InstallFailureWriter(void (*writer)(const char* data, int size)) {
  g_failure_writer = writer;
}

_END_GOOGLE_NAMESPACE_