Bug 1538810 - Update breakpad to upstream revision 4d550cceca107f36c4bc1ea1126b7d32cc50f424 r=froydnj
authorGabriele Svelto <gsvelto@mozilla.com>
Tue, 09 Apr 2019 16:04:24 +0000
changeset 469228 98bf8629efc6d4959c293c9c46e318dae44e2114
parent 469227 c3b55b97b9ae1101c615ec2fe525fd9336bb8599
child 469229 5e05dde4f7cb57929e3427f2877156b01df5831f
push id112776
push usershindli@mozilla.com
push dateFri, 12 Apr 2019 16:20:17 +0000
treeherdermozilla-inbound@b4501ced5619 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1538810
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1538810 - Update breakpad to upstream revision 4d550cceca107f36c4bc1ea1126b7d32cc50f424 r=froydnj This includes improvements to the Linux exception handler that will provide crash addresse for a number of signals by reading the NT_SIGINFO structure and quites warnings in a number of files. This also removes an unused header. Differential Revision: https://phabricator.services.mozilla.com/D26488
toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc
toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h
toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc
toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h
toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc
toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc
toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h
toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc
toolkit/crashreporter/google-breakpad/DEPS
toolkit/crashreporter/google-breakpad/GIT-INFO
toolkit/crashreporter/google-breakpad/default.xml
toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc
toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc
toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h
toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc
toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc
toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h
toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h
toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc
toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h
toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h
toolkit/crashreporter/google-breakpad/src/third_party/linux/include/gflags/gflags_completions.h
toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc
toolkit/crashreporter/update-breakpad.sh
--- a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc
+++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.cc
@@ -211,17 +211,16 @@ pthread_mutex_t g_handler_stack_mutex_ =
 
 // sizeof(CrashContext) can be too big w.r.t the size of alternatate stack
 // for SignalHandler(). Keep the crash context as a .bss field. Exception
 // handlers are serialized by the |g_handler_stack_mutex_| and at most one at a
 // time can use |g_crash_context_|.
 ExceptionHandler::CrashContext g_crash_context_;
 
 FirstChanceHandler g_first_chance_handler_ = nullptr;
-FirstChanceHandlerDeprecated g_first_chance_handler_deprecated_ = nullptr;
 bool g_skip_sigill_ = false;
 }  // namespace
 
 // Runs before crashing: normal context.
 ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
                                    FilterCallback filter,
                                    MinidumpCallback callback,
                                    void* callback_context,
@@ -345,21 +344,16 @@ void ExceptionHandler::SignalHandler(int
   // safety in WebAssembly. This means some signals might be expected if they
   // originate from Wasm code while accessing the guard region. We give V8 the
   // chance to handle and recover from these signals first.
   if (g_first_chance_handler_ != nullptr &&
       g_first_chance_handler_(sig, info, uc)) {
     return;
   }
 
-  if (g_first_chance_handler_deprecated_ != nullptr &&
-      g_first_chance_handler_deprecated_(sig, info, uc)) {
-    return;
-  }
-
   // All the exception signals are blocked at this point.
   pthread_mutex_lock(&g_handler_stack_mutex_);
 
   // Sometimes, Breakpad runs inside a process where some other buggy code
   // saves and restores signal handlers temporarily with 'signal'
   // instead of 'sigaction'. This loses the SA_SIGINFO flag associated
   // with this function. As a consequence, the values of 'info' and 'uc'
   // become totally bogus, generally inducing a crash.
@@ -827,18 +821,12 @@ bool ExceptionHandler::WriteMinidumpForC
                                       child,
                                       child_blamed_thread))
       return false;
 
   return callback ? callback(descriptor, callback_context, true) : true;
 }
 
 void SetFirstChanceExceptionHandler(FirstChanceHandler callback) {
-  g_first_chance_handler_deprecated_ = nullptr;
   g_first_chance_handler_ = callback;
 }
 
-void SetFirstChanceExceptionHandler(FirstChanceHandlerDeprecated callback) {
-  g_first_chance_handler_ = nullptr;
-  g_first_chance_handler_deprecated_ = callback;
-}
-
 }  // namespace google_breakpad
--- a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h
+++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler.h
@@ -271,16 +271,11 @@ class ExceptionHandler {
   // Callers can request additional memory regions to be included in
   // the dump.
   AppMemoryList app_memory_list_;
 };
 
 typedef bool (*FirstChanceHandler)(int, siginfo_t*, void*);
 void SetFirstChanceExceptionHandler(FirstChanceHandler callback);
 
-typedef bool (*FirstChanceHandlerDeprecated)(int, void*, void*);
-// Deprecated. Use SetFirstChanceExceptionHandler(FirstChanceHandler callback)
-// instead.
-void SetFirstChanceExceptionHandler(FirstChanceHandlerDeprecated callback);
-
 }  // namespace google_breakpad
 
 #endif  // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
--- a/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc
+++ b/toolkit/crashreporter/breakpad-client/linux/handler/exception_handler_unittest.cc
@@ -523,42 +523,21 @@ TEST(ExceptionHandlerTest, StackedHandle
                             -1);
     CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
   }
   ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
 }
 
 namespace {
 const int kSimpleFirstChanceReturnStatus = 42;
-bool SimpleFirstChanceHandlerDeprecated(int, void*, void*) {
-  _exit(kSimpleFirstChanceReturnStatus);
-}
-
 bool SimpleFirstChanceHandler(int, siginfo_t*, void*) {
   _exit(kSimpleFirstChanceReturnStatus);
 }
 }
 
-TEST(ExceptionHandlerTest, FirstChanceHandlerRunsDeprecated) {
-  AutoTempDir temp_dir;
-
-  const pid_t child = fork();
-  if (child == 0) {
-    ExceptionHandler handler(
-        MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
-    google_breakpad::SetFirstChanceExceptionHandler(
-        SimpleFirstChanceHandlerDeprecated);
-    DoNullPointerDereference();
-  }
-  int status;
-  ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
-  ASSERT_TRUE(WIFEXITED(status));
-  ASSERT_EQ(kSimpleFirstChanceReturnStatus, WEXITSTATUS(status));
-}
-
 TEST(ExceptionHandlerTest, FirstChanceHandlerRuns) {
   AutoTempDir temp_dir;
 
   const pid_t child = fork();
   if (child == 0) {
     ExceptionHandler handler(
         MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
     google_breakpad::SetFirstChanceExceptionHandler(SimpleFirstChanceHandler);
--- a/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h
+++ b/toolkit/crashreporter/breakpad-client/linux/handler/minidump_descriptor.h
@@ -132,17 +132,17 @@ class MinidumpDescriptor {
   bool sanitize_stacks() const { return sanitize_stacks_; }
   void set_sanitize_stacks(bool sanitize_stacks) {
     sanitize_stacks_ = sanitize_stacks;
   }
 
   MicrodumpExtraInfo* microdump_extra_info() {
     assert(IsMicrodumpOnConsole());
     return &microdump_extra_info_;
-  };
+  }
 
  private:
   enum DumpMode {
     kUninitialized = 0,
     kWriteMinidumpToFile,
     kWriteMinidumpToFd,
     kWriteMicrodumpToConsole
   };
--- a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc
+++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper.cc
@@ -38,16 +38,17 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/procfs.h>
 #if defined(__mips__) && defined(__ANDROID__)
 // To get register definitions.
 #include <asm/reg.h>
 #endif
 
+#include "common/linux/elf_gnu_compat.h"
 #include "common/linux/linux_libc_support.h"
 
 namespace google_breakpad {
 
 LinuxCoreDumper::LinuxCoreDumper(pid_t pid,
                                  const char* core_path,
                                  const char* procfs_path,
                                  const char* root_prefix)
@@ -160,16 +161,17 @@ bool LinuxCoreDumper::EnumerateThreads()
     }
 
     // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are
     // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific):
     //   Thread           Name          Type
     //   -------------------------------------------------------------------
     //   1st thread       CORE          NT_PRSTATUS
     //   process-wide     CORE          NT_PRPSINFO
+    //   process-wide     CORE          NT_SIGINFO
     //   process-wide     CORE          NT_AUXV
     //   1st thread       CORE          NT_FPREGSET
     //   1st thread       LINUX         NT_PRXFPREG
     //   1st thread       LINUX         NT_386_TLS
     //
     //   2nd thread       CORE          NT_PRSTATUS
     //   2nd thread       CORE          NT_FPREGSET
     //   2nd thread       LINUX         NT_PRXFPREG
@@ -214,16 +216,57 @@ bool LinuxCoreDumper::EnumerateThreads()
           crash_signal_ = status->pr_info.si_signo;
           crash_signal_code_ = status->pr_info.si_code;
         }
         first_thread = false;
         threads_.push_back(pid);
         thread_infos_.push_back(info);
         break;
       }
+      case NT_SIGINFO: {
+        if (description.length() != sizeof(siginfo_t)) {
+          fprintf(stderr, "Found NT_SIGINFO descriptor of unexpected size\n");
+          return false;
+        }
+
+        const siginfo_t* info =
+            reinterpret_cast<const siginfo_t*>(description.data());
+
+        // Set crash_address when si_addr is valid for the signal.
+        switch (info->si_signo) {
+          case MD_EXCEPTION_CODE_LIN_SIGBUS:
+          case MD_EXCEPTION_CODE_LIN_SIGFPE:
+          case MD_EXCEPTION_CODE_LIN_SIGILL:
+          case MD_EXCEPTION_CODE_LIN_SIGSEGV:
+          case MD_EXCEPTION_CODE_LIN_SIGSYS:
+          case MD_EXCEPTION_CODE_LIN_SIGTRAP:
+            crash_address_ = reinterpret_cast<uintptr_t>(info->si_addr);
+            break;
+        }
+
+        // Set crash_exception_info for common signals.  Since exception info is
+        // unsigned, but some of these fields might be signed, we always cast.
+        switch (info->si_signo) {
+          case MD_EXCEPTION_CODE_LIN_SIGKILL:
+            set_crash_exception_info({
+              static_cast<uint64_t>(info->si_pid),
+              static_cast<uint64_t>(info->si_uid),
+            });
+            break;
+          case MD_EXCEPTION_CODE_LIN_SIGSYS:
+#ifdef si_syscall
+            set_crash_exception_info({
+              static_cast<uint64_t>(info->si_syscall),
+              static_cast<uint64_t>(info->si_arch),
+            });
+#endif
+            break;
+        }
+        break;
+      }
 #if defined(__i386) || defined(__x86_64)
       case NT_FPREGSET: {
         if (thread_infos_.empty())
           return false;
 
         ThreadInfo* info = &thread_infos_.back();
         if (description.length() != sizeof(info->fpregs)) {
           fprintf(stderr, "Found NT_FPREGSET descriptor of unexpected size\n");
--- a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc
+++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_core_dumper_unittest.cc
@@ -104,25 +104,85 @@ TEST(LinuxCoreDumperTest, VerifyDumpWith
   EXPECT_TRUE(dumper.Init());
 
   EXPECT_TRUE(dumper.IsPostMortem());
 
   // These are no-ops and should always return true.
   EXPECT_TRUE(dumper.ThreadsSuspend());
   EXPECT_TRUE(dumper.ThreadsResume());
 
-  // LinuxCoreDumper cannot determine the crash address and thus it always
+  // Linux does not set the crash address with SIGABRT, so make sure it always
   // sets the crash address to 0.
   EXPECT_EQ(0U, dumper.crash_address());
   EXPECT_EQ(kCrashSignal, dumper.crash_signal());
   EXPECT_EQ(crash_generator.GetThreadId(kCrashThread),
             dumper.crash_thread());
 
   EXPECT_EQ(kNumOfThreads, dumper.threads().size());
   for (unsigned i = 0; i < kNumOfThreads; ++i) {
     ThreadInfo info;
     EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &info));
     const void* stack;
     size_t stack_len;
     EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len, info.stack_pointer));
     EXPECT_EQ(getpid(), info.ppid);
   }
 }
+
+TEST(LinuxCoreDumperTest, VerifyExceptionDetails) {
+  CrashGenerator crash_generator;
+  if (!crash_generator.HasDefaultCorePattern()) {
+    fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test "
+            "is skipped due to non-default core pattern\n");
+    return;
+  }
+
+#ifndef si_syscall
+  fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test is "
+          "skipped due to old kernel/C library headers\n");
+  return;
+#endif
+
+  const unsigned kNumOfThreads = 2;
+  const unsigned kCrashThread = 1;
+  const int kCrashSignal = SIGSYS;
+  pid_t child_pid;
+  ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
+                                               kCrashSignal, &child_pid));
+
+  const string core_file = crash_generator.GetCoreFilePath();
+  const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy();
+
+#if defined(__ANDROID__)
+  struct stat st;
+  if (stat(core_file.c_str(), &st) != 0) {
+    fprintf(stderr, "LinuxCoreDumperTest.VerifyExceptionDetails test is "
+            "skipped due to no core file being generated");
+    return;
+  }
+#endif
+
+  LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str());
+
+  EXPECT_TRUE(dumper.Init());
+
+  EXPECT_TRUE(dumper.IsPostMortem());
+
+#if defined(__ANDROID__)
+  // TODO: For some reason, Android doesn't seem to pass this.
+  if (!dumper.crash_address()) {
+    fprintf(stderr, "LinuxCoreDumperTest.VerifyExceptionDetails test is "
+            "skipped due to missing signal details on Android");
+    return;
+  }
+#endif
+
+  // Check the exception details.
+  EXPECT_NE(0U, dumper.crash_address());
+  EXPECT_EQ(kCrashSignal, dumper.crash_signal());
+  EXPECT_EQ(crash_generator.GetThreadId(kCrashThread),
+            dumper.crash_thread());
+
+  // We check the length, but not the actual fields.  We sent SIGSYS ourselves
+  // instead of the kernel, so the extended fields are garbage.
+  const std::vector<uint64_t> info(dumper.crash_exception_info());
+  EXPECT_EQ(2U, info.size());
+}
--- a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h
+++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/linux_dumper.h
@@ -33,25 +33,28 @@
 // has been refactored to allow derived implementations supporting both
 // ptrace and core dump. A portion of the original implementation is now
 // in google_breakpad::LinuxPtraceDumper (see linux_ptrace_dumper.h for
 // details).
 
 #ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
 #define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
 
+#include <assert.h>
 #include <elf.h>
 #if defined(__ANDROID__)
 #include <link.h>
 #endif
 #include <linux/limits.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/user.h>
 
+#include <vector>
+
 #include "linux/dump_writer_common/mapping_info.h"
 #include "linux/dump_writer_common/thread_info.h"
 #include "common/linux/file_id.h"
 #include "common/memory_allocator.h"
 #include "google_breakpad/common/minidump_format.h"
 
 namespace google_breakpad {
 
@@ -179,16 +182,24 @@ class LinuxDumper {
 
   int crash_signal() const { return crash_signal_; }
   void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; }
   const char* GetCrashSignalString() const;
 
   void set_crash_signal_code(int code) { crash_signal_code_ = code; }
   int crash_signal_code() const { return crash_signal_code_; }
 
+  void set_crash_exception_info(const std::vector<uint64_t>& exception_info) {
+    assert(exception_info.size() <= MD_EXCEPTION_MAXIMUM_PARAMETERS);
+    crash_exception_info_ = exception_info;
+  }
+  const std::vector<uint64_t>& crash_exception_info() const {
+    return crash_exception_info_;
+  }
+
   pid_t crash_thread() const { return crash_thread_; }
   void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
 
   // Concatenates the |root_prefix_| and |mapping| path. Writes into |path| and
   // returns true unless the string is too long.
   bool GetMappingAbsolutePath(const MappingInfo& mapping,
                               char path[PATH_MAX]) const;
 
@@ -231,16 +242,19 @@ class LinuxDumper {
   uintptr_t crash_address_;
 
   // Signal that terminated the crashed process.
   int crash_signal_;
 
   // The code associated with |crash_signal_|.
   int crash_signal_code_;
 
+  // The additional fields associated with |crash_signal_|.
+  std::vector<uint64_t> crash_exception_info_;
+
   // ID of the crashed thread.
   pid_t crash_thread_;
 
   mutable PageAllocator allocator_;
 
   // IDs of all the threads.
   wasteful_vector<pid_t> threads_;
 
--- a/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc
+++ b/toolkit/crashreporter/breakpad-client/linux/minidump_writer/minidump_writer.cc
@@ -708,16 +708,22 @@ class MinidumpWriter {
 
     dirent->stream_type = MD_EXCEPTION_STREAM;
     dirent->location = exc.location();
 
     stream->thread_id = GetCrashThread();
     stream->exception_record.exception_code = dumper_->crash_signal();
     stream->exception_record.exception_flags = dumper_->crash_signal_code();
     stream->exception_record.exception_address = dumper_->crash_address();
+    const std::vector<uint64_t> crash_exception_info =
+        dumper_->crash_exception_info();
+    stream->exception_record.number_parameters = crash_exception_info.size();
+    memcpy(stream->exception_record.exception_information,
+           crash_exception_info.data(),
+           sizeof(uint64_t) * crash_exception_info.size());
     stream->thread_context = crashing_thread_context_;
 
     return true;
   }
 
   bool WriteSystemInfoStream(MDRawDirectory* dirent) {
     TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
     if (!si.Allocate())
--- a/toolkit/crashreporter/google-breakpad/DEPS
+++ b/toolkit/crashreporter/google-breakpad/DEPS
@@ -31,17 +31,17 @@
 # using a manually managed SVN checkout as opposed to a gclient managed checkout
 # you can still use the hooks mechanism for generating project files by calling
 # 'gclient runhooks' rather than 'gclient sync'.
 
 deps = {
   # Testing libraries and utilities.
   "src/src/testing":
     "https://github.com/google/googletest.git" +
-      "@release-1.8.0",
+      "@5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081",
 
   # Protobuf.
   "src/src/third_party/protobuf/protobuf":
     "https://github.com/google/protobuf.git" +
       "@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac",
 
   # GYP project generator.
   "src/src/tools/gyp":
--- a/toolkit/crashreporter/google-breakpad/GIT-INFO
+++ b/toolkit/crashreporter/google-breakpad/GIT-INFO
@@ -1,1 +1,1 @@
-44384d80b32a5bb361c2ec3bee667f7ccee566d7
+4d550cceca107f36c4bc1ea1126b7d32cc50f424
--- a/toolkit/crashreporter/google-breakpad/default.xml
+++ b/toolkit/crashreporter/google-breakpad/default.xml
@@ -22,17 +22,17 @@
 
   <project path='src/src/tools/gyp'
            name='external/gyp/'
            revision='324dd166b7c0b39d513026fa52d6280ac6d56770'
            remote='chromium' />
 
   <project path='src/src/testing'
            name='google/googletest.git'
-           revision='refs/tags/release-1.8.0'
+           revision='5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081'
            remote='github' />
 
   <project path='src/src/third_party/lss'
            name='linux-syscall-support/'
            revision='a89bf7903f3169e6bc7b8efc10a73a7571de21cf'
            remote='chromium' />
 
   <project path='src/src/third_party/protobuf/protobuf'
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc
@@ -742,19 +742,26 @@ bool LoadSymbols(const string& obj_file,
     // but MIPS_DWARF for regular gnu toolchains, so both need to be checked
     if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
       dwarf_section =
         FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
                                        sections, names, names_end,
                                        elf_header->e_shnum);
     }
 
-    // Parse export symbols prior to parsing DWARF data, so that any
-    // functions found via DWARF data will take precedence over the functions
-    // found via ELF.
+    if (dwarf_section) {
+      found_debug_info_section = true;
+      found_usable_info = true;
+      info->LoadedSection(".debug_info");
+      if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
+                               options.handle_inter_cu_refs, module)) {
+        fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
+                "DWARF debugging information\n", obj_file.c_str());
+      }
+    }
 
     // See if there are export symbols available.
     const Shdr* symtab_section =
         FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB,
                                        sections, names, names_end,
                                        elf_header->e_shnum);
     const Shdr* strtab_section =
         FindElfSectionByName<ElfClass>(".strtab", SHT_STRTAB,
@@ -803,27 +810,16 @@ bool LoadSymbols(const string& obj_file,
                                dynstrs,
                                dynstr_section->sh_size,
                                big_endian,
                                ElfClass::kAddrSize,
                                module);
         found_usable_info = found_usable_info || result;
       }
     }
-
-    if (dwarf_section) {
-      found_debug_info_section = true;
-      found_usable_info = true;
-      info->LoadedSection(".debug_info");
-      if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
-                               options.handle_inter_cu_refs, module)) {
-        fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
-                "DWARF debugging information\n", obj_file.c_str());
-      }
-    }
   }
 
   if (options.symbol_data != NO_CFI) {
     // Dwarf Call Frame Information (CFI) is actually independent from
     // the other DWARF debugging information, and can be used alone.
     const Shdr* dwarf_cfi_section =
         FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
                                        sections, names, names_end,
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc
@@ -80,17 +80,17 @@ class DumpSymbols : public Test {
   }
 
   vector<uint8_t> elfdata_v;
   uint8_t* elfdata;
 };
 
 typedef Types<ElfClass32, ElfClass64> ElfClasses;
 
-TYPED_TEST_CASE(DumpSymbols, ElfClasses);
+TYPED_TEST_SUITE(DumpSymbols, ElfClasses);
 
 TYPED_TEST(DumpSymbols, Invalid) {
   Elf32_Ehdr header;
   memset(&header, 0, sizeof(header));
   Module* module;
   DumpOptions options(ALL_SYMBOL_DATA, true);
   EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
                                       "foo",
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h
@@ -38,9 +38,14 @@
 
 #include <elf.h>
 
 // A note type on GNU systems corresponding to the .note.gnu.build-id section.
 #ifndef NT_GNU_BUILD_ID
 #define NT_GNU_BUILD_ID 3
 #endif
 
+// Newer Linux systems offer this.
+#ifndef NT_SIGINFO
+#define NT_SIGINFO 0x53494749
+#endif
+
 #endif  // COMMON_LINUX_ELF_GNU_COMPAT_H_
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc
@@ -133,17 +133,17 @@ public:
 
   vector<uint8_t> elfdata_v;
   uint8_t* elfdata;
   PageAllocator allocator;
 };
 
 typedef Types<ElfClass32, ElfClass64> ElfClasses;
 
-TYPED_TEST_CASE(FileIDTest, ElfClasses);
+TYPED_TEST_SUITE(FileIDTest, ElfClasses);
 
 TYPED_TEST(FileIDTest, ElfClass) {
   const char expected_identifier_string[] =
       "80808080808000000000008080808080";
   const size_t kTextSectionSize = 128;
 
   ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
   Section text(kLittleEndian);
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc
@@ -188,17 +188,17 @@ template<typename ElfClass>
 class BasicElf : public Test {};
 
 // Doesn't seem worthwhile writing the tests to be endian-independent
 // when they're unlikely to ever be run on big-endian systems.
 #if defined(__i386__) || defined(__x86_64__)
 
 typedef Types<ElfClass32, ElfClass64> ElfClasses;
 
-TYPED_TEST_CASE(BasicElf, ElfClasses);
+TYPED_TEST_SUITE(BasicElf, ElfClasses);
 
 TYPED_TEST(BasicElf, EmptyLE) {
   typedef typename TypeParam::Ehdr Ehdr;
   typedef typename TypeParam::Phdr Phdr;
   typedef typename TypeParam::Shdr Shdr;
   const size_t kStringTableSize = sizeof("\0.shstrtab");
   const size_t kStringTableAlign = 4 - kStringTableSize % 4;
   const size_t kExpectedSize = sizeof(Ehdr) +
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h
@@ -233,17 +233,17 @@ class MachMessage {
 // of a mach message being sent and being received, and adds increased type
 // safety:
 //  ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
 //  MachPortSender::SendMessage() only accepts a MachSendMessage
 
 //==============================================================================
 class MachReceiveMessage : public MachMessage {
  public:
-  MachReceiveMessage() : MachMessage() {};
+  MachReceiveMessage() : MachMessage() {}
 };
 
 //==============================================================================
 class MachSendMessage : public MachMessage {
  public:
   MachSendMessage(int32_t message_id);
 };
 
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h
@@ -37,17 +37,17 @@
 #include <limits.h>
 #include <mach/machine.h>
 
 namespace google_breakpad {
 
 class FileID {
  public:
   FileID(const char *path);
-  ~FileID() {};
+  ~FileID() {}
 
   // Load the identifier for the file path specified in the constructor into
   // |identifier|.  Return false if the identifier could not be created for the
   // file.
   // The current implementation will return the MD5 hash of the file's bytes.
   bool FileIdentifier(unsigned char identifier[16]);
 
   // Treat the file as a mach-o file that will contain one or more archicture.
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc
@@ -33,16 +33,18 @@
 // google_breakpad::Mach_O::Reader. See macho_reader.h for details.
 
 #include "common/mac/macho_reader.h"
 
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <limits>
+
 // Unfortunately, CPU_TYPE_ARM is not define for 10.4.
 #if !defined(CPU_TYPE_ARM)
 #define CPU_TYPE_ARM 12
 #endif
 
 #if !defined(CPU_TYPE_ARM_64)
 #define CPU_TYPE_ARM_64 16777228
 #endif
@@ -335,44 +337,43 @@ bool Reader::WalkLoadCommands(Reader::Lo
 
     switch (type) {
       case LC_SEGMENT:
       case LC_SEGMENT_64: {
         Segment segment;
         segment.bits_64 = (type == LC_SEGMENT_64);
         size_t word_size = segment.bits_64 ? 8 : 4;
         cursor.CString(&segment.name, 16);
-        size_t file_offset, file_size;
         cursor
             .Read(word_size, false, &segment.vmaddr)
             .Read(word_size, false, &segment.vmsize)
-            .Read(word_size, false, &file_offset)
-            .Read(word_size, false, &file_size);
+            .Read(word_size, false, &segment.fileoff)
+            .Read(word_size, false, &segment.filesize);
         cursor >> segment.maxprot
                >> segment.initprot
                >> segment.nsects
                >> segment.flags;
         if (!cursor) {
           reporter_->LoadCommandTooShort(index, type);
           return false;
         }
-        if (file_offset > buffer_.Size() ||
-            file_size > buffer_.Size() - file_offset) {
+        if (segment.fileoff > buffer_.Size() ||
+            segment.filesize > buffer_.Size() - segment.fileoff) {
           reporter_->MisplacedSegmentData(segment.name);
           return false;
         }
         // Mach-O files in .dSYM bundles have the contents of the loaded
         // segments removed, and their file offsets and file sizes zeroed
         // out. To help us handle this special case properly, give such
         // segments' contents NULL starting and ending pointers.
-        if (file_offset == 0 && file_size == 0) {
+        if (segment.fileoff == 0 && segment.filesize == 0) {
           segment.contents.start = segment.contents.end = NULL;
         } else {
-          segment.contents.start = buffer_.start + file_offset;
-          segment.contents.end = segment.contents.start + file_size;
+          segment.contents.start = buffer_.start + segment.fileoff;
+          segment.contents.end = segment.contents.start + segment.filesize;
         }
         // The section list occupies the remainder of this load command's space.
         segment.section_list.start = cursor.here();
         segment.section_list.end = command.end;
 
         if (!handler->SegmentCommand(segment))
           return false;
         break;
@@ -456,36 +457,54 @@ bool Reader::FindSegment(const string &n
 bool Reader::WalkSegmentSections(const Segment &segment,
                                  SectionHandler *handler) const {
   size_t word_size = segment.bits_64 ? 8 : 4;
   ByteCursor cursor(&segment.section_list, big_endian_);
 
   for (size_t i = 0; i < segment.nsects; i++) {
     Section section;
     section.bits_64 = segment.bits_64;
-    uint64_t size;
-    uint32_t offset, dummy32;
+    uint64_t size, offset;
+    uint32_t dummy32;
     cursor
         .CString(&section.section_name, 16)
         .CString(&section.segment_name, 16)
         .Read(word_size, false, &section.address)
         .Read(word_size, false, &size)
-        >> offset
+        .Read(sizeof(uint32_t), false, &offset)  // clears high bits of |offset|
         >> section.align
         >> dummy32
         >> dummy32
         >> section.flags
         >> dummy32
         >> dummy32;
     if (section.bits_64)
       cursor >> dummy32;
     if (!cursor) {
       reporter_->SectionsMissing(segment.name);
       return false;
     }
+
+    // Even 64-bit Mach-O isn’t a true 64-bit format in that it doesn’t handle
+    // 64-bit file offsets gracefully. Segment load commands do contain 64-bit
+    // file offsets, but sections within do not. Because segments load
+    // contiguously, recompute each section’s file offset on the basis of its
+    // containing segment’s file offset and the difference between the section’s
+    // and segment’s load addresses. If truncation is detected, honor the
+    // recomputed offset.
+    if (segment.bits_64 &&
+        segment.fileoff + segment.filesize >
+            std::numeric_limits<uint32_t>::max()) {
+      const uint64_t section_offset_recomputed =
+          segment.fileoff + section.address - segment.vmaddr;
+      if (offset == static_cast<uint32_t>(section_offset_recomputed)) {
+        offset = section_offset_recomputed;
+      }
+    }
+
     const uint32_t section_type = section.flags & SECTION_TYPE;
     if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL ||
             section_type == S_GB_ZEROFILL) {
       // Zero-fill sections have a size, but no contents.
       section.contents.start = section.contents.end = NULL;
     } else if (segment.contents.start == NULL &&
                segment.contents.end == NULL) {
       // Mach-O files in .dSYM bundles have the contents of the loaded
--- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h
+++ b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h
@@ -170,16 +170,20 @@ struct Segment {
   uint64_t vmaddr;
 
   // The size of this segment when loaded into memory. This may be larger
   // than contents.Size(), in which case the extra area will be
   // initialized with zeros. If bits_64 is false, only the bottom 32 bits
   // of this value are valid.
   uint64_t vmsize;
 
+  // The file offset and size of the segment in the Mach-O image.
+  uint64_t fileoff;
+  uint64_t filesize;
+
   // The maximum and initial VM protection of this segment's contents.
   uint32_t maxprot;
   uint32_t initprot;
 
   // The number of sections in section_list.
   uint32_t nsects;
 
   // Flags describing this segment, from SegmentFlags.
--- a/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h
+++ b/toolkit/crashreporter/google-breakpad/src/google_breakpad/processor/stack_frame.h
@@ -79,17 +79,17 @@ struct StackFrame {
         return "call frame info with scanning";
       case StackFrame::FRAME_TRUST_FP:
         return "previous frame's frame pointer";
       case StackFrame::FRAME_TRUST_SCAN:
         return "stack scanning";
       default:
         return "unknown";
     }
-  };
+  }
 
   // Return the actual return address, as saved on the stack or in a
   // register. See the comments for 'instruction', below, for details.
   virtual uint64_t ReturnAddress() const { return instruction; }
 
   // The program counter location as an absolute virtual address.
   //
   // - For the innermost called frame in a stack, this will be an exact
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/third_party/linux/include/gflags/gflags_completions.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// 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: Dave Nicponski
-//
-// Implement helpful bash-style command line flag completions
-//
-// ** Functional API:
-// HandleCommandLineCompletions() should be called early during
-// program startup, but after command line flag code has been
-// initialized, such as the beginning of HandleCommandLineHelpFlags().
-// It checks the value of the flag --tab_completion_word.  If this
-// flag is empty, nothing happens here.  If it contains a string,
-// however, then HandleCommandLineCompletions() will hijack the
-// process, attempting to identify the intention behind this
-// completion.  Regardless of the outcome of this deduction, the
-// process will be terminated, similar to --helpshort flag
-// handling.
-//
-// ** Overview of Bash completions:
-// Bash can be told to programatically determine completions for the
-// current 'cursor word'.  It does this by (in this case) invoking a
-// command with some additional arguments identifying the command
-// being executed, the word being completed, and the previous word
-// (if any).  Bash then expects a sequence of output lines to be
-// printed to stdout.  If these lines all contain a common prefix
-// longer than the cursor word, bash will replace the cursor word
-// with that common prefix, and display nothing.  If there isn't such
-// a common prefix, bash will display the lines in pages using 'more'.
-//
-// ** Strategy taken for command line completions:
-// If we can deduce either the exact flag intended, or a common flag
-// prefix, we'll output exactly that.  Otherwise, if information
-// must be displayed to the user, we'll take the opportunity to add
-// some helpful information beyond just the flag name (specifically,
-// we'll include the default flag value and as much of the flag's
-// description as can fit on a single terminal line width, as specified
-// by the flag --tab_completion_columns).  Furthermore, we'll try to
-// make bash order the output such that the most useful or relevent
-// flags are the most likely to be shown at the top.
-//
-// ** Additional features:
-// To assist in finding that one really useful flag, substring matching
-// was implemented.  Before pressing a <TAB> to get completion for the
-// current word, you can append one or more '?' to the flag to do
-// substring matching.  Here's the semantics:
-//   --foo<TAB>     Show me all flags with names prefixed by 'foo'
-//   --foo?<TAB>    Show me all flags with 'foo' somewhere in the name
-//   --foo??<TAB>   Same as prior case, but also search in module
-//                  definition path for 'foo'
-//   --foo???<TAB>  Same as prior case, but also search in flag
-//                  descriptions for 'foo'
-// Finally, we'll trim the output to a relatively small number of
-// flags to keep bash quiet about the verbosity of output.  If one
-// really wanted to see all possible matches, appending a '+' to the
-// search word will force the exhaustive list of matches to be printed.
-//
-// ** How to have bash accept completions from a binary:
-// Bash requires that it be informed about each command that programmatic
-// completion should be enabled for.  Example addition to a .bashrc
-// file would be (your path to gflags_completions.sh file may differ):
-
-/*
-$ complete -o bashdefault -o default -o nospace -C                        \
- '/usr/local/bin/gflags_completions.sh --tab_completion_columns $COLUMNS' \
-  time  env  binary_name  another_binary  [...]
-*/
-
-// This would allow the following to work:
-//   $ /path/to/binary_name --vmodule<TAB>
-// Or:
-//   $ ./bin/path/another_binary --gfs_u<TAB>
-// (etc)
-//
-// Sadly, it appears that bash gives no easy way to force this behavior for
-// all commands.  That's where the "time" in the above example comes in.
-// If you haven't specifically added a command to the list of completion
-// supported commands, you can still get completions by prefixing the
-// entire command with "env".
-//   $ env /some/brand/new/binary --vmod<TAB>
-// Assuming that "binary" is a newly compiled binary, this should still
-// produce the expected completion output.
-
-
-#ifndef GOOGLE_GFLAGS_COMPLETIONS_H_
-#define GOOGLE_GFLAGS_COMPLETIONS_H_
-
-namespace google {
-
-void HandleCommandLineCompletions(void);
-
-}
-
-#endif  // GOOGLE_GFLAGS_COMPLETIONS_H_
--- a/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
+++ b/toolkit/crashreporter/google-breakpad/src/third_party/lss/linux_syscall_support.h
@@ -1959,17 +1959,17 @@ struct kernel_statfs {
       LSS_RETURN(type,__res)
     #undef  _syscall0
     #define _syscall0(type,name)                                              \
       type LSS_NAME(name)(void) {                                             \
         long __res;                                                           \
         __asm__ volatile(LSS_ENTRYPOINT                                       \
                          : "=a" (__res)                                       \
                          : "0" (__NR_##name)                                  \
-                         : "memory");                                         \
+                         : "esp", "memory");                                  \
         LSS_RETURN(type,__res);                                               \
       }
     #undef  _syscall1
     #define _syscall1(type,name,type1,arg1)                                   \
       type LSS_NAME(name)(type1 arg1) {                                       \
         LSS_BODY(type,                                                        \
              : "=a" (__res)                                                   \
              : "0" (__NR_##name), "ri" ((long)(arg1)));                       \
@@ -2400,17 +2400,17 @@ struct kernel_statfs {
                              : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit),
                                "r"(LSS_SYSCALL_ARG(fn)),
                                "S"(LSS_SYSCALL_ARG(child_stack)),
                                "D"(LSS_SYSCALL_ARG(flags)),
                                "r"(LSS_SYSCALL_ARG(arg)),
                                "d"(LSS_SYSCALL_ARG(parent_tidptr)),
                                "r"(LSS_SYSCALL_ARG(newtls)),
                                "r"(LSS_SYSCALL_ARG(child_tidptr))
-                             : "memory", "r8", "r10", "r11", "rcx");
+                             : "rsp", "memory", "r8", "r10", "r11", "rcx");
       }
       LSS_RETURN(int, __res);
     }
     LSS_INLINE _syscall2(int, arch_prctl, int, c, void *, a)
 
     LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) {
       /* On x86-64, the kernel does not know how to return from
        * a signal handler. Instead, it relies on user space to provide a
--- a/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc
+++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc
@@ -59,14 +59,14 @@ int main(int argc, char *argv[]) {
   }
 
   const char* core_file = argv[1];
   const char* procfs_dir = argv[2];
   const char* minidump_file = argv[3];
   if (!WriteMinidumpFromCore(minidump_file,
                              core_file,
                              procfs_dir)) {
-    fprintf(stderr, "Unable to generate minidump.\n");
+    perror("core2md: Unable to generate minidump");
     return 1;
   }
 
   return 0;
 }
--- a/toolkit/crashreporter/update-breakpad.sh
+++ b/toolkit/crashreporter/update-breakpad.sh
@@ -29,16 +29,17 @@ rm -rf \
   ${crashreporter_dir}/google-breakpad/appveyor.yml \
   ${crashreporter_dir}/google-breakpad/autotools/ \
   ${crashreporter_dir}/google-breakpad/docs/ \
   ${crashreporter_dir}/google-breakpad/m4/ \
   ${crashreporter_dir}/google-breakpad/scripts/ \
   ${crashreporter_dir}/google-breakpad/src/client/ \
   ${crashreporter_dir}/google-breakpad/src/processor/testdata/ \
   ${crashreporter_dir}/google-breakpad/src/testing/ \
+  ${crashreporter_dir}/google-breakpad/src/third_party/linux \
   ${crashreporter_dir}/google-breakpad/src/third_party/protobuf \
   ${crashreporter_dir}/google-breakpad/src/tools/gyp/ \
   ${crashreporter_dir}/google-breakpad/src/tools/windows/dump_syms/testdata/ \
   ${crashreporter_dir}/google-breakpad/.github/mistaken-pull-closer.yml \
   ${crashreporter_dir}/google-breakpad/.travis.yml
 
 # restore our Makefile.ins
 hg -R ${repo} st -n | grep "Makefile\.in$" | xargs hg revert --no-backup