text: // 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.
  //
  // 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>
  
  // needed for building on OSX because getcontext is deprecated
  #define _XOPEN_SOURCE
  
  // #ifdef HAVE_UCONTEXT_H
  # include <ucontext.h>
  // #endif
  // #ifdef HAVE_SYS_UCONTEXT_H
  // # include <sys/ucontext.h>
  // #endif
  #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) {
  #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
    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) {
    if (write(STDERR_FILENO, data, size) < 0) {
      // Ignore errors.
    }
  }
  
  // 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;
    for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
      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()
    // returns an uint64 but in some other environments pthread_self()
    // returns a pointer.  Hence we use C-style cast here, rather than
    // reinterpret/static_cast, to support both types of environments.
    formatter.AppendUint64((uintptr_t)pthread_self(), 16);
    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());
  }
  
  // signal to use to override default signal handler
  typedef void (*override_handler_t)(int);
  override_handler_t signal_handler_override = NULL;
  
  // Invoke the default signal handler.
  void InvokeDefaultSignalHandler(int signal_number) {
    struct sigaction sig_action;
    memset(&sig_action, 0, sizeof(sig_action));
    sigemptyset(&sig_action.sa_mask);
    if( signal_handler_override ) {
      sig_action.sa_handler = signal_handler_override;
    } else {
      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
  // the first thread dump stuff and let other threads wait.
  // 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 =
        glog_internal_namespace_::sync_val_compare_and_swap(
            &g_entered_thread_id_pointer,
            static_cast<pthread_t*>(NULL),
            &my_thread_id);
    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.
    const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
    DumpSignalInfo(signal_number, signal_info);
    // Dump the stack traces.
    for (int i = 0; i < depth; ++i) {
      DumpStackFrameInfo("    ", stack[i]);
    }
  #endif
  
    // *** 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);
  
    // Kill ourself by the default signal handler.
    InvokeDefaultSignalHandler(signal_number);
  }
  
  }  // namespace
  
  //
  // stuff added for grappa
  //
  
  // replace default signal handler with raising another signal
  void OverrideDefaultSignalHandler( override_handler_t handler ) {
    signal_handler_override = handler;
  }
  
  // dump the stack trace
  void DumpStackTrace() {
    // First dump time info.
    DumpTimeInfo();
  
    // Get the program counter from ucontext.
  #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
    ucontext_t ucontext;
    getcontext( &ucontext );
    void *pc = GetPC( &ucontext );
    DumpStackFrameInfo("PC: ", pc);
  #endif
  
  #ifdef HAVE_STACKTRACE
    // Get the stack traces.
    void *stack[32];
    // +1 to exclude this function.
    const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
    //DumpSignalInfo(signal_number, signal_info);
    // Dump the stack traces.
    for (int i = 0; i < depth; ++i) {
      DumpStackFrameInfo("    ", stack[i]);
    }
  #endif
  }
  
  
  void InstallFailureSignalHandler() {
    // Build the sigaction struct.
    struct sigaction sig_action;
    memset(&sig_action, 0, sizeof(sig_action));
    sigemptyset(&sig_action.sa_mask);
    sig_action.sa_flags |= SA_SIGINFO;
    sig_action.sa_sigaction = &FailureSignalHandler;
  
    for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
      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_
  