| Index: third_party/crashpad/crashpad/handler/handler_main.cc | 
| diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc | 
| index 3ada8c3e50567990378061214fe03252783f5edf..9433a6af5186ec33ebf6c68fb17948adb227381d 100644 | 
| --- a/third_party/crashpad/crashpad/handler/handler_main.cc | 
| +++ b/third_party/crashpad/crashpad/handler/handler_main.cc | 
| @@ -14,9 +14,11 @@ | 
|  | 
| #include "handler/handler_main.h" | 
|  | 
| +#include <errno.h> | 
| #include <getopt.h> | 
| #include <stdint.h> | 
| #include <stdlib.h> | 
| +#include <sys/types.h> | 
|  | 
| #include <map> | 
| #include <memory> | 
| @@ -38,6 +40,8 @@ | 
| #include "handler/prune_crash_reports_thread.h" | 
| #include "tools/tool_support.h" | 
| #include "util/file/file_io.h" | 
| +#include "util/misc/metrics.h" | 
| +#include "util/numeric/in_range_cast.h" | 
| #include "util/stdlib/map_insert.h" | 
| #include "util/stdlib/string_number_conversion.h" | 
| #include "util/string/split_string.h" | 
| @@ -105,6 +109,122 @@ void Usage(const base::FilePath& me) { | 
|  | 
| #if defined(OS_MACOSX) | 
|  | 
| +struct sigaction g_original_crash_sigaction[NSIG]; | 
| + | 
| +void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 
| +  // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not | 
| +  // useful, signals generated asynchronously such as by kill() or raise()) and | 
| +  // small positive numbers (useful, signal generated via a hardware fault). The | 
| +  // standard specifies these other constants, and while xnu never uses them, | 
| +  // they are intended to denote signals generated asynchronously and are | 
| +  // included here. Additionally, existing practice on other systems | 
| +  // (acknowledged by the standard) is for negative numbers to indicate that a | 
| +  // signal was generated asynchronously. Although xnu does not do this, allow | 
| +  // for the possibility for completeness. | 
| +  bool si_code_valid = !(siginfo->si_code <= 0 || | 
| +                         siginfo->si_code == SI_USER || | 
| +                         siginfo->si_code == SI_QUEUE || | 
| +                         siginfo->si_code == SI_TIMER || | 
| +                         siginfo->si_code == SI_ASYNCIO || | 
| +                         siginfo->si_code == SI_MESGQ); | 
| + | 
| +  // 0x5343 = 'SC', signifying “signal and code”, disambiguates from the schema | 
| +  // used by ExceptionCodeForMetrics(). That system primarily uses Mach | 
| +  // exception types and codes, which are not available to a POSIX signal | 
| +  // handler. It does provide a way to encode only signal numbers, but does so | 
| +  // with the understanding that certain “raw” signals would not be encountered | 
| +  // without a Mach exception. Furthermore, it does not allow siginfo->si_code | 
| +  // to be encoded, because that’s not available to Mach exception handlers. It | 
| +  // would be a shame to lose that information available to a POSIX signal | 
| +  // handler. | 
| +  int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8); | 
| +  if (si_code_valid) { | 
| +    metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff); | 
| +  } | 
| +  Metrics::HandlerCrashed(metrics_code); | 
| + | 
| +  // Restore the previous signal handler. | 
| +  DCHECK_GT(sig, 0); | 
| +  DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | 
| +  struct sigaction* osa = &g_original_crash_sigaction[sig]; | 
| +  int rv = sigaction(sig, osa, nullptr); | 
| +  DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; | 
| + | 
| +  // If the signal was received synchronously resulting from a hardware fault, | 
| +  // returning from the signal handler will cause the kernel to re-raise it, | 
| +  // because this handler hasn’t done anything to alleviate the condition that | 
| +  // caused the signal to be raised in the first place. With the old signal | 
| +  // handler in place (expected to be SIG_DFL), it will cause the same behavior | 
| +  // to be taken as though this signal handler had never been installed at all | 
| +  // (expected to be a crash). This is ideal, because the signal is re-raised | 
| +  // with the same properties and from the same context that initially triggered | 
| +  // it, providing the best debugging experience. | 
| + | 
| +  if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || | 
| +      !si_code_valid) { | 
| +    // Signals received other than via hardware faults, such as those raised | 
| +    // asynchronously via kill() and raise(), and those arising via hardware | 
| +    // traps such as int3 (resulting in SIGTRAP but advancing the instruction | 
| +    // pointer), will not reoccur on their own when returning from the signal | 
| +    // handler. Re-raise them or call to the previous signal handler as | 
| +    // appropriate. | 
| +    // | 
| +    // Unfortunately, when SIGBUS is received asynchronously via kill(), | 
| +    // siginfo->si_code makes it appear as though it was actually received via a | 
| +    // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c | 
| +    // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed | 
| +    // metric to be logged but will not cause the process to terminate. This | 
| +    // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The | 
| +    // alternative, to re-raise here on any SIGBUS, is a bad idea because it | 
| +    // would lose properties associated with the the original signal, which are | 
| +    // very valuable for debugging and are visible to a Mach exception handler. | 
| +    // Since SIGBUS is normally received synchronously in response to a hardware | 
| +    // fault, don’t sweat the unexpected asynchronous case. | 
| +    if (osa->sa_handler == SIG_DFL) { | 
| +      // Because this signal handler executes with the signal blocked, this | 
| +      // raise() cannot immediately deliver the signal. Delivery is deferred | 
| +      // until this signal handler returns and the signal becomes unblocked. The | 
| +      // re-raised signal will appear with the same context as where it was | 
| +      // initially triggered. | 
| +      rv = raise(sig); | 
| +      DPLOG_IF(ERROR, rv != 0) << "raise"; | 
| +    } else if (osa->sa_handler != SIG_IGN) { | 
| +      if (osa->sa_flags & SA_SIGINFO) { | 
| +        osa->sa_sigaction(sig, siginfo, context); | 
| +      } else { | 
| +        osa->sa_handler(sig); | 
| +      } | 
| +    } | 
| +  } | 
| +} | 
| + | 
| +void InstallCrashHandler() { | 
| +  struct sigaction sa = {}; | 
| +  sigemptyset(&sa.sa_mask); | 
| +  sa.sa_flags = SA_SIGINFO; | 
| +  sa.sa_sigaction = HandleCrashSignal; | 
| + | 
| +  // These are the core-generating signals from 10.12.3 | 
| +  // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the | 
| +  // set. | 
| +  const int kSignals[] = {SIGQUIT, | 
| +                          SIGILL, | 
| +                          SIGTRAP, | 
| +                          SIGABRT, | 
| +                          SIGEMT, | 
| +                          SIGFPE, | 
| +                          SIGBUS, | 
| +                          SIGSEGV, | 
| +                          SIGSYS}; | 
| + | 
| +  for (int sig : kSignals) { | 
| +    DCHECK_GT(sig, 0); | 
| +    DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | 
| +    int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); | 
| +    PCHECK(rv == 0) << "sigaction " << sig; | 
| +  } | 
| +} | 
| + | 
| struct ResetSIGTERMTraits { | 
| static struct sigaction* InvalidValue() { | 
| return nullptr; | 
| @@ -126,9 +246,8 @@ void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { | 
| g_exception_handler_server->Stop(); | 
| } | 
|  | 
| -#endif  // OS_MACOSX | 
| +#elif defined(OS_WIN) | 
|  | 
| -#if defined(OS_WIN) | 
| LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; | 
|  | 
| LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 
| @@ -139,15 +258,18 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 
| else | 
| return EXCEPTION_CONTINUE_SEARCH; | 
| } | 
| -#endif  // OS_WIN | 
| + | 
| +void InstallCrashHandler() { | 
| +  g_original_exception_filter = | 
| +      SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 
| +} | 
| + | 
| +#endif  // OS_MACOSX | 
|  | 
| }  // namespace | 
|  | 
| int HandlerMain(int argc, char* argv[]) { | 
| -#if defined(OS_WIN) | 
| -  g_original_exception_filter = | 
| -      SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 
| -#endif | 
| +  InstallCrashHandler(); | 
|  | 
| const base::FilePath argv0( | 
| ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); | 
|  |