Ejemplo n.º 1
0
static void bt_handler(int sig) {
  // In case we crash again in the signal hander or something
  signal(sig, SIG_DFL);

  IsCrashing = true;
  // Generating a stack dumps significant time, try to stop threads
  // from flushing bad data or generating more faults meanwhile
  if (sig==SIGQUIT || sig==SIGILL || sig==SIGSEGV || sig==SIGBUS) {
    LightProcess::Close();
    // leave running for SIGTERM SIGFPE SIGABRT
  }

  if (RuntimeOption::EvalSpinOnCrash) {
    char buf[128];
    snprintf(buf, 127,
             "Crashed. Waiting for debugger to attach pid %d\n", getpid());
    buf[127] = 0;
    write(STDERR_FILENO, buf, strlen(buf));
    for (;;) sleep(1);
  }

  // Turn on stack traces for coredumps
  StackTrace::Enabled = true;
  StackTraceNoHeap st;

  char pid[sizeof(Process::GetProcessId())*3+2]; // '-' and \0
  sprintf(pid,"%u",Process::GetProcessId());
  char tracefn[RuntimeOption::CoreDumpReportDirectory.length()
               + strlen("/stacktrace..log") + strlen(pid) + 1];
  sprintf(tracefn, "%s/stacktrace.%s.log",
          RuntimeOption::CoreDumpReportDirectory.c_str(), pid);

  int debuggerCount = RuntimeOption::EnableDebugger ?
    Eval::Debugger::CountConnectedProxy() : 0;

  st.log(strsignal(sig), tracefn, pid, kCompilerId, debuggerCount);

  int fd = ::open(tracefn, O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR);
  if (fd >= 0) {
    if (!g_context.isNull()) {
      dprintf(fd, "\nPHP Stacktrace:\n\n%s",
              debug_string_backtrace(false).data());
    }
    ::close(fd);
  }

  if (!RuntimeOption::CoreDumpEmail.empty()) {
    char format [] = "cat %s | mail -s \"Stack Trace from %s\" '%s'";
    char cmdline[strlen(format)+strlen(tracefn)
                 +strlen(Process::GetAppName().c_str())
                 +strlen(RuntimeOption::CoreDumpEmail.c_str())+1];
    sprintf(cmdline, format, tracefn, Process::GetAppName().c_str(),
            RuntimeOption::CoreDumpEmail.c_str());
    Util::ssystem(cmdline);
  }

  // Calling all of these library functions in a signal handler
  // is completely undefined behavior, but we seem to get away with it.
  // Do it last just in case

  Logger::Error("Core dumped: %s", strsignal(sig));

  // Give the debugger a chance to do extra logging if there are any attached
  // debugger clients.
  Eval::Debugger::LogShutdown(Eval::Debugger::ShutdownKind::Abnormal);

  if (!g_context.isNull()) {
    // sync up gdb Dwarf info so that gdb can do a full backtrace
    // from the core file. Do this at the very end as syncing needs
    // to allocate memory for the ELF file.
    g_vmContext->syncGdbState();
  }

  // re-raise the signal and pass it to the default handler
  // to terminate the process.
  raise(sig);
}
Ejemplo n.º 2
0
void f_debug_print_backtrace(int64_t options /* = 0 */,
                             int64_t limit /* = 0 */) {
  bool ignore_args = options & DEBUG_BACKTRACE_IGNORE_ARGS;
  echo(debug_string_backtrace(true, ignore_args, limit));
}
Ejemplo n.º 3
0
void HHVM_FUNCTION(debug_print_backtrace, int64_t options /* = 0 */,
                                          int64_t limit /* = 0 */) {
  bool ignore_args = options & k_DEBUG_BACKTRACE_IGNORE_ARGS;
  g_context->write(debug_string_backtrace(false, ignore_args, limit));
}
Ejemplo n.º 4
0
static void bt_handler(int sig) {
    // In case we crash again in the signal hander or something
    signal(sig, SIG_DFL);
    IsCrashing = true;

    // Make a stacktrace file to prove we were crashing. Do this before anything
    // else has a chance to deadlock us.
    int fd = ::open(RuntimeOption::StackTraceFilename.c_str(),
                    O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);

    if (RuntimeOption::EvalDumpRingBufferOnCrash) {
        Trace::dumpRingBuffer(RuntimeOption::EvalDumpRingBufferOnCrash);
    }

    if (RuntimeOption::EvalSpinOnCrash) {
        char buf[128];
        snprintf(buf, 127,
                 "Crashed. Waiting for debugger to attach pid %d\n", getpid());
        buf[127] = 0;
        write(STDERR_FILENO, buf, strlen(buf));
        for (;;) sleep(1);
    }

    if (fd < 0) {
        // Nothing to do if we can't write the file
        raise(sig);
        return;
    }

    // Turn on stack traces for coredumps
    StackTrace::Enabled = true;
    static const char* s_newBlacklist[] =
    {"_ZN4HPHP16StackTraceNoHeap", "_ZN4HPHPL10bt_handlerEi", "killpg"};
    StackTrace::FunctionBlacklist = s_newBlacklist;
    StackTrace::FunctionBlacklistCount = 3;
    StackTraceNoHeap st;

    int debuggerCount = RuntimeOption::EnableDebugger ?
                        Eval::Debugger::CountConnectedProxy() : 0;

    st.log(strsignal(sig), fd, kCompilerId, debuggerCount);

    // flush so if php crashes us we still have this output so far
    ::fsync(fd);

    if (fd >= 0) {
        if (!g_context.isNull()) {
            dprintf(fd, "\nPHP Stacktrace:\n\n%s",
                    debug_string_backtrace(false).data());
        }
        ::close(fd);
    }

    if (!RuntimeOption::CoreDumpEmail.empty()) {
        char format [] = "cat %s | mail -s \"Stack Trace from %s\" '%s'";
        char cmdline[strlen(format)+RuntimeOption::StackTraceFilename.length()
                     +strlen(Process::GetAppName().c_str())
                     +strlen(RuntimeOption::CoreDumpEmail.c_str())+1];
        sprintf(cmdline, format, RuntimeOption::StackTraceFilename.c_str(),
                Process::GetAppName().c_str(),
                RuntimeOption::CoreDumpEmail.c_str());
        FileUtil::ssystem(cmdline);
    }

    // Calling all of these library functions in a signal handler
    // is completely undefined behavior, but we seem to get away with it.
    // Do it last just in case

    Logger::Error("Core dumped: %s", strsignal(sig));

    // Give the debugger a chance to do extra logging if there are any attached
    // debugger clients.
    Eval::Debugger::LogShutdown(Eval::Debugger::ShutdownKind::Abnormal);

    if (!g_context.isNull()) {
        // sync up gdb Dwarf info so that gdb can do a full backtrace
        // from the core file. Do this at the very end as syncing needs
        // to allocate memory for the ELF file.
        g_context->syncGdbState();
    }

    // re-raise the signal and pass it to the default handler
    // to terminate the process.
    raise(sig);
}
Ejemplo n.º 5
0
static void bt_handler(int sig) {
  // In case we crash again in the signal hander or something
  signal(sig, SIG_DFL);

  // Generating a stack dumps significant time, try to stop threads
  // from flushing bad data or generating more faults meanwhile
  if (sig==SIGQUIT || sig==SIGILL || sig==SIGSEGV || sig==SIGBUS) {
    SegFaulting=true;
    LightProcess::Close();
    // leave running for SIGTERM SIGFPE SIGABRT
  }

  // Turn on stack traces for coredumps
  StackTrace::Enabled = true;
  StackTraceNoHeap st;

  char pid[sizeof(Process::GetProcessId())*3+2]; // '-' and \0
  sprintf(pid,"%u",Process::GetProcessId());
  char tracefn[StackTraceBase::ReportDirectory.length()
               + strlen("/stacktrace..log") + strlen(pid) + 1];
  sprintf(tracefn, "%s/stacktrace.%s.log",
          StackTraceBase::ReportDirectory.c_str(), pid);

  st.log(strsignal(sig), tracefn, pid);

  int fd = ::open(tracefn, O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR);
  if (fd >= 0) {
    if (!g_context.isNull()) {
      dprintf(fd, "\nPHP Stacktrace:\n\n%s",
              debug_string_backtrace(false).data());
    }
    ::close(fd);
  }

  if (!StackTrace::ReportEmail.empty()) {
    char format [] = "cat %s | mail -s \"Stack Trace from %s\" '%s'";
    char cmdline[strlen(format)+strlen(tracefn)
                 +strlen(Process::GetAppName().c_str())
                 +strlen(StackTrace::ReportEmail.c_str())+1];
    sprintf(cmdline, format, tracefn, Process::GetAppName().c_str(),
            StackTrace::ReportEmail.c_str());
    Util::ssystem(cmdline);
  }

  // Calling all of these library functions in a signal handler
  // is completely undefined behavior, but we seem to get away with it.
  // Do it last just in case

  Logger::Error("Core dumped: %s", strsignal(sig));

  if (hhvm && !g_context.isNull()) {
    // sync up gdb Dwarf info so that gdb can do a full backtrace
    // from the core file. Do this at the very end as syncing needs
    // to allocate memory for the ELF file.
    g_vmContext->syncGdbState();
  }

  // re-raise the signal and pass it to the default handler
  // to terminate the process.
  raise(sig);
}
Ejemplo n.º 6
0
void f_debug_print_backtrace() {
  echo(debug_string_backtrace(true));
}
Ejemplo n.º 7
0
static void bt_handler(int sig) {
  if (IsCrashing) {
    // If we re-enter bt_handler while already crashing, just abort. This
    // includes if we hit the timeout set below.
    signal(SIGABRT, SIG_DFL);
    abort();
  }

  // TSAN instruments malloc() to make sure it can't be used in signal handlers.
  // Unfortunately, we use malloc() all over the place here.  This is bad, but
  // ends up working most of the time.  Just abort so TSAN won't infinite crash
  // loop.
  if (use_tsan) {
    signal(SIGABRT, SIG_DFL);
    abort();
  }

  // In case we crash again in the signal handler or something. Do this before
  // setting up the timeout to avoid potential races.
  IsCrashing = true;
  signal(sig, SIG_DFL);

  if (RuntimeOption::StackTraceTimeout > 0) {
    signal(SIGALRM, bt_handler);
    alarm(RuntimeOption::StackTraceTimeout);
  }

  // Make a stacktrace file to prove we were crashing. Do this before anything
  // else has a chance to deadlock us.
  int fd = ::open(RuntimeOption::StackTraceFilename.c_str(),
                  O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR);

  if (RuntimeOption::EvalDumpRingBufferOnCrash) {
    Trace::dumpRingBuffer(RuntimeOption::EvalDumpRingBufferOnCrash, 0);
  }

  if (RuntimeOption::EvalSpinOnCrash) {
    char buf[128];
    snprintf(buf, 127,
             "Crashed. Waiting for debugger to attach pid %d\n", getpid());
    buf[127] = 0;
    write(STDERR_FILENO, buf, strlen(buf));
    for (;;) sleep(1);
  }

  if (fd < 0) {
    // Nothing to do if we can't write the file
    raise(sig);
    return;
  }

  // Turn on stack traces for coredumps
  StackTrace::Enabled = true;
  StackTrace::FunctionBlacklist = s_newBlacklist;
  StackTrace::FunctionBlacklistCount = 3;
  StackTraceNoHeap st;

  auto const debuggerCount = [&] {
    if (RuntimeOption::EnableDebugger) {
      return Eval::Debugger::CountConnectedProxy();
    }
    // We don't have a count of xdebug clients across all requests, so just
    // check the current request.
    if (XDebugServer::isAttached()) {
      return 1;
    }
    return 0;
  }();

  st.log(strsignal(sig), fd, compilerId().begin(), debuggerCount);

  // flush so if php crashes us we still have this output so far
  ::fsync(fd);

  if (fd >= 0) {
    // Don't attempt to determine function arguments in the PHP backtrace, as
    // that might involve re-entering the VM.
    if (!g_context.isNull()) {
      dprintf(fd, "\nPHP Stacktrace:\n\n%s",
              debug_string_backtrace(
                /*skip*/false,
                /*ignore_args*/true
              ).data());
    }
    ::close(fd);
  }

  if (jit::transdb::enabled()) {
    jit::tc::dump(true);
  }

  if (!RuntimeOption::CoreDumpEmail.empty()) {
    char format [] = "cat %s | mail -s \"Stack Trace from %s\" '%s'";
    char* cmdline = (char*)alloca(sizeof(char) *
                (strlen(format)
                 +RuntimeOption::StackTraceFilename.length()
                 +strlen(Process::GetAppName().c_str())
                 +strlen(RuntimeOption::CoreDumpEmail.c_str())+1));
    sprintf(cmdline, format, RuntimeOption::StackTraceFilename.c_str(),
            Process::GetAppName().c_str(),
            RuntimeOption::CoreDumpEmail.c_str());
    FileUtil::ssystem(cmdline);
  }

  // Calling all of these library functions in a signal handler
  // is completely undefined behavior, but we seem to get away with it.
  // Do it last just in case

  Logger::Error("Core dumped: %s", strsignal(sig));
  Logger::Error("Stack trace in %s", RuntimeOption::StackTraceFilename.c_str());

  // Flush whatever access logs are still pending
  Logger::FlushAll();
  HttpRequestHandler::GetAccessLog().flushAllWriters();

  // Give the debugger a chance to do extra logging if there are any attached
  // debugger clients.
  Eval::Debugger::LogShutdown(Eval::Debugger::ShutdownKind::Abnormal);

  if (!g_context.isNull()) {
    // sync up gdb Dwarf info so that gdb can do a full backtrace
    // from the core file. Do this at the very end as syncing needs
    // to allocate memory for the ELF file.
    g_context->syncGdbState();
  }

  // re-raise the signal and pass it to the default handler
  // to terminate the process.
  raise(sig);
}