Bug 516759: Implement Linux client/server for OOP minidump generation requests. r=luser
authorChris Jones <jones.chris.g@gmail.com>
Tue, 12 Jan 2010 15:14:37 -0600
changeset 37202 832fb29e91ddd5281238a3c07f7c55a9be7af69e
parent 37201 d52fb4c91f3f91befe81cce9275ea49aee61bd21
child 37203 854866e02b61f1d3d375f146137a9f0300c3d646
push idunknown
push userunknown
push dateunknown
reviewersluser
bugs516759
milestone1.9.3a1pre
Bug 516759: Implement Linux client/server for OOP minidump generation requests. r=luser
toolkit/crashreporter/Makefile.in
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/Makefile.in
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc
toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h
toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc
toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc
toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h
toolkit/xre/Makefile.in
--- a/toolkit/crashreporter/Makefile.in
+++ b/toolkit/crashreporter/Makefile.in
@@ -72,16 +72,17 @@ endif
 
 ifeq ($(OS_ARCH),Linux)
 # there's no define for this normally
 DEFINES += -DXP_LINUX
 DIRS += \
   google-breakpad/src/common \
   google-breakpad/src/common/linux \
   google-breakpad/src/client \
+  google-breakpad/src/client/linux/crash_generation \
   google-breakpad/src/client/linux/handler \
   google-breakpad/src/client/linux/minidump_writer \
   google-breakpad/src/tools/linux/dump_syms \
   $(NULL)
 endif
 
 ifeq ($(OS_ARCH),SunOS)
 # there's no define for this normally
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/Makefile.in
@@ -0,0 +1,64 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Breakpad integration
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Chris Jones <jones.chris.g@gmail.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../../../../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE		= crash_generation
+LIBRARY_NAME	= crash_generation_s
+
+LOCAL_INCLUDES 	= -I$(topsrcdir)/toolkit/crashreporter/google-breakpad/src
+
+CPPSRCS		=				\
+  crash_generation_client.cc			\
+  crash_generation_server.cc			\
+  $(NULL)
+
+# need static lib
+FORCE_STATIC_LIB = 1
+FORCE_USE_PIC = 1
+
+include $(topsrcdir)/config/rules.mk
+ifeq ($(OS_ARCH),Linux)
+include $(topsrcdir)/config/config.mk
+# need this to suppress errors when compiling common/linux/eintr_wrapper.h
+OS_CXXFLAGS := $(filter-out -pedantic,$(OS_CXXFLAGS))
+endif
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2009, 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.
+
+#ifndef CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
+#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
+
+namespace google_breakpad {
+
+struct ClientInfo {
+  CrashGenerationServer* crash_server_;
+  pid_t pid_;
+};
+
+}
+
+#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2009, 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.
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <algorithm>
+
+#include "client/linux/crash_generation/crash_generation_client.h"
+#include "common/linux/eintr_wrapper.h"
+#include "common/linux/linux_libc_support.h"
+#include "common/linux/linux_syscall_support.h"
+
+namespace google_breakpad {
+
+bool
+CrashGenerationClient::RequestDump(const void* blob, size_t blob_size)
+{
+  int fds[2];
+  sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+  static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int));
+
+  struct kernel_msghdr msg;
+  my_memset(&msg, 0, sizeof(struct kernel_msghdr));
+  struct kernel_iovec iov[1];
+  iov[0].iov_base = const_cast<void*>(blob);
+  iov[0].iov_len = blob_size;
+
+  msg.msg_iov = iov;
+  msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
+  char cmsg[kControlMsgSize];
+  my_memset(cmsg, 0, kControlMsgSize);
+  msg.msg_control = cmsg;
+  msg.msg_controllen = sizeof(cmsg);
+
+  struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg);
+  hdr->cmsg_level = SOL_SOCKET;
+  hdr->cmsg_type = SCM_RIGHTS;
+  hdr->cmsg_len = CMSG_LEN(sizeof(int));
+  *((int*) CMSG_DATA(hdr)) = fds[1];
+
+  HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
+  sys_close(fds[1]);
+
+  // wait for an ACK from the server
+  char b;
+  HANDLE_EINTR(sys_read(fds[0], &b, 1));
+
+  return true;
+}
+
+//static
+CrashGenerationClient*
+CrashGenerationClient::TryCreate(int server_fd)
+{
+  if (0 > server_fd)
+    return NULL;
+  return new CrashGenerationClient(server_fd);
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2009, 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.
+
+#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
+#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
+
+#include <stddef.h>
+
+namespace google_breakpad {
+
+class CrashGenerationClient {
+public:
+  ~CrashGenerationClient()
+  {
+  }
+
+  // Request the crash server to generate a dump.  |blob| is a hack,
+  // see exception_handler.h and minidump_writer.h
+  //
+  // Return true if the dump was successful; false otherwise.
+  bool RequestDump(const void* blob, size_t blob_size);
+
+  // Return a new CrashGenerationClient if |server_fd| is valid and
+  // connects to a CrashGenerationServer.  Otherwise, return NULL.
+  // The returned CrashGenerationClient* is owned by the caller of
+  // this function.
+  static CrashGenerationClient* TryCreate(int server_fd);
+
+private:
+  CrashGenerationClient(int server_fd) : server_fd_(server_fd)
+  {
+  }
+
+  int server_fd_;
+
+  // prevent copy construction and assignment
+  CrashGenerationClient(const CrashGenerationClient&);
+  CrashGenerationClient& operator=(const CrashGenerationClient&);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc
@@ -0,0 +1,466 @@
+// Copyright (c) 2009, 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.
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "client/linux/crash_generation/crash_generation_server.h"
+#include "client/linux/crash_generation/client_info.h"
+#include "client/linux/handler/exception_handler.h"
+#include "client/linux/minidump_writer/minidump_writer.h"
+#include "common/linux/eintr_wrapper.h"
+#include "common/linux/guid_creator.h"
+
+static const char kCommandQuit = 'x';
+
+static bool
+GetInodeForFileDescriptor(ino_t* inode_out, int fd)
+{
+  assert(inode_out);
+
+  struct stat buf;
+  if (fstat(fd, &buf) < 0)
+    return false;
+
+  if (!S_ISSOCK(buf.st_mode))
+    return false;
+
+  *inode_out = buf.st_ino;
+  return true;
+}
+
+// expected prefix of the target of the /proc/self/fd/%d link for a socket
+static const char kSocketLinkPrefix[] = "socket:[";
+
+// Parse a symlink in /proc/pid/fd/$x and return the inode number of the
+// socket.
+//   inode_out: (output) set to the inode number on success
+//   path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
+static bool
+GetInodeForProcPath(ino_t* inode_out, const char* path)
+{
+  assert(inode_out);
+  assert(path);
+
+  char buf[256];
+  const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
+  if (n == -1) {
+    return false;
+  }
+  buf[n] = 0;
+
+  if (0 != memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
+    return false;
+  }
+
+  char* endptr;
+  const u_int64_t inode_ul =
+      strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10);
+  if (*endptr != ']')
+    return false;
+
+  if (inode_ul == ULLONG_MAX) {
+    return false;
+  }
+
+  *inode_out = inode_ul;
+  return true;
+}
+
+static bool
+FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode)
+{
+  assert(pid_out);
+  bool already_found = false;
+
+  DIR* proc = opendir("/proc");
+  if (!proc) {
+    return false;
+  }
+
+  std::vector<pid_t> pids;
+
+  struct dirent* dent;
+  while ((dent = readdir(proc))) {
+    char* endptr;
+    const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10);
+    if (pid_ul == ULONG_MAX || '\0' != *endptr)
+      continue;
+    pids.push_back(pid_ul);
+  }
+  closedir(proc);
+
+  for (std::vector<pid_t>::const_iterator
+       i = pids.begin(); i != pids.end(); ++i) {
+    const pid_t current_pid = *i;
+    char buf[256];
+    snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid);
+    DIR* fd = opendir(buf);
+    if (!fd)
+      continue;
+
+    while ((dent = readdir(fd))) {
+      if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid,
+                   dent->d_name) >= static_cast<int>(sizeof(buf))) {
+        continue;
+      }
+
+      ino_t fd_inode;
+      if (GetInodeForProcPath(&fd_inode, buf)
+	  && fd_inode == socket_inode) {
+	if (already_found) {
+	  closedir(fd);
+	  return false;
+	}
+
+	already_found = true;
+	*pid_out = current_pid;
+	break;
+      }
+    }
+
+    closedir(fd);
+  }
+
+  return already_found;
+}
+
+namespace google_breakpad {
+
+CrashGenerationServer::CrashGenerationServer(
+  const int listen_fd,
+  OnClientDumpRequestCallback dump_callback,
+  void* dump_context,
+  OnClientExitingCallback exit_callback,
+  void* exit_context,
+  bool generate_dumps,
+  const std::string* dump_path) :
+    server_fd_(listen_fd),
+    dump_callback_(dump_callback),
+    dump_context_(dump_context),
+    exit_callback_(exit_callback),
+    exit_context_(exit_context),
+    generate_dumps_(generate_dumps),
+    started_(false)
+{
+  if (dump_path)
+    dump_dir_ = *dump_path;
+  else
+    dump_dir_ = "/tmp";
+}
+
+CrashGenerationServer::~CrashGenerationServer()
+{
+  if (started_)
+    Stop();
+}
+
+bool
+CrashGenerationServer::Start()
+{
+  if (started_ || 0 > server_fd_)
+    return false;
+
+  int control_pipe[2];
+  if (pipe(control_pipe))
+    return false;
+
+  if (fcntl(control_pipe[0], F_SETFD, FD_CLOEXEC))
+    return false;
+  if (fcntl(control_pipe[1], F_SETFD, FD_CLOEXEC))
+    return false;
+
+  if (fcntl(control_pipe[0], F_SETFL, O_NONBLOCK))
+    return false;
+
+  control_pipe_in_ = control_pipe[0];
+  control_pipe_out_ = control_pipe[1];
+
+  if (pthread_create(&thread_, NULL,
+                     ThreadMain, reinterpret_cast<void*>(this)))
+    return false;
+
+  started_ = true;
+  return true;
+}
+
+void
+CrashGenerationServer::Stop()
+{
+  assert(pthread_self() != thread_);
+
+ if (!started_)
+   return;
+
+  HANDLE_EINTR(write(control_pipe_out_, &kCommandQuit, 1));
+  
+  void* dummy;
+  pthread_join(thread_, &dummy);
+
+  started_ = false;
+}
+
+//static
+bool
+CrashGenerationServer::CreateReportChannel(int* server_fd, int* client_fd)
+{
+  int fds[2];
+
+  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds))
+    return false;
+
+  static const int on = 1;
+  // Enable passcred on the server end of the socket
+  if (setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)))
+    return false;
+
+  if (fcntl(fds[1], F_SETFL, O_NONBLOCK))
+    return false;
+  if (fcntl(fds[1], F_SETFD, FD_CLOEXEC))
+    return false;
+
+  *client_fd = fds[0];
+  *server_fd = fds[1];
+  return true;
+}
+
+// The following methods/functions execute on the server thread
+
+void
+CrashGenerationServer::Run()
+{
+  struct pollfd pollfds[2];
+  memset(&pollfds, 0, sizeof(pollfds));
+
+  pollfds[0].fd = server_fd_;
+  pollfds[0].events = POLLIN;
+
+  pollfds[1].fd = control_pipe_in_;
+  pollfds[1].events = POLLIN;
+
+  while (true) {
+    // infinite timeout
+    int nevents = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1);
+    if (-1 == nevents) {
+      if (EINTR == errno) {
+        continue;
+      } else {
+	return;
+      }
+    }
+
+    if (pollfds[0].revents && !ClientEvent(pollfds[0].revents))
+      return;
+
+    if (pollfds[1].revents && !ControlEvent(pollfds[1].revents))
+      return;
+  }
+}
+
+bool
+CrashGenerationServer::ClientEvent(short revents)
+{
+  if (POLLHUP & revents)
+    return false;
+  assert(POLLIN & revents);
+
+  // A process has crashed and has signaled us by writing a datagram
+  // to the death signal socket. The datagram contains the crash context needed
+  // for writing the minidump as well as a file descriptor and a credentials
+  // block so that they can't lie about their pid.
+
+  // The length of the control message:
+  static const unsigned kControlMsgSize =
+      CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
+  // The length of the regular payload:
+  static const unsigned kCrashContextSize =
+      sizeof(google_breakpad::ExceptionHandler::CrashContext);
+
+  struct msghdr msg = {0};
+  struct iovec iov[1];
+  char crash_context[kCrashContextSize];
+  char control[kControlMsgSize];
+  const ssize_t expected_msg_size = sizeof(crash_context);
+
+  iov[0].iov_base = crash_context;
+  iov[0].iov_len = sizeof(crash_context);
+  msg.msg_iov = iov;
+  msg.msg_iovlen = sizeof(iov)/sizeof(iov[0]);
+  msg.msg_control = control;
+  msg.msg_controllen = kControlMsgSize;
+
+  const ssize_t msg_size = HANDLE_EINTR(recvmsg(server_fd_, &msg, 0));
+  if (msg_size != expected_msg_size)
+    return true;
+
+  if (msg.msg_controllen != kControlMsgSize ||
+      msg.msg_flags & ~MSG_TRUNC)
+    return true;
+
+  // Walk the control payload and extract the file descriptor and validated pid.
+  pid_t crashing_pid = -1;
+  int signal_fd = -1;
+  for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
+       hdr = CMSG_NXTHDR(&msg, hdr)) {
+    if (hdr->cmsg_level != SOL_SOCKET)
+      continue;
+    if (hdr->cmsg_type == SCM_RIGHTS) {
+      const unsigned len = hdr->cmsg_len -
+          (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
+      assert(len % sizeof(int) == 0u);
+      const unsigned num_fds = len / sizeof(int);
+      if (num_fds > 1 || num_fds == 0) {
+        // A nasty process could try and send us too many descriptors and
+        // force a leak.
+        for (unsigned i = 0; i < num_fds; ++i)
+          HANDLE_EINTR(close(reinterpret_cast<int*>(CMSG_DATA(hdr))[i]));
+        return true;
+      } else {
+        signal_fd = reinterpret_cast<int*>(CMSG_DATA(hdr))[0];
+      }
+    } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
+      const struct ucred *cred =
+          reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
+      crashing_pid = cred->pid;
+    }
+  }
+
+  if (crashing_pid == -1 || signal_fd == -1) {
+    if (signal_fd)
+      HANDLE_EINTR(close(signal_fd));
+    return true;
+  }
+
+  // Kernel bug workaround (broken in 2.6.30 at least):
+  // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
+  // namespaces. Thus |crashing_pid| might be garbage from our point of view.
+  // In the future we can remove this workaround, but we have to wait a couple
+  // of years to be sure that it's worked its way out into the world.
+
+  ino_t inode_number;
+  if (!GetInodeForFileDescriptor(&inode_number, signal_fd)) {
+    HANDLE_EINTR(close(signal_fd));
+    return true;
+  }
+
+  if (!FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) {
+    HANDLE_EINTR(close(signal_fd));
+    return true;
+  }
+
+  std::string minidump_filename;
+  if (!MakeMinidumpFilename(minidump_filename))
+    return true;
+
+  if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
+                                      crashing_pid, crash_context,
+                                      kCrashContextSize)) {
+    HANDLE_EINTR(close(signal_fd));
+    return true;
+  }
+
+  if (dump_callback_) {
+    ClientInfo info;
+
+    info.crash_server_ = this;
+    info.pid_ = crashing_pid;
+
+    dump_callback_(dump_context_, &info, &minidump_filename);
+  }
+
+  // Send the done signal to the process: it can exit now.
+  memset(&msg, 0, sizeof(msg));
+  struct iovec done_iov;
+  done_iov.iov_base = const_cast<char*>("\x42");
+  done_iov.iov_len = 1;
+  msg.msg_iov = &done_iov;
+  msg.msg_iovlen = 1;
+
+  HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
+  HANDLE_EINTR(close(signal_fd));
+
+  return true;
+}
+
+bool
+CrashGenerationServer::ControlEvent(short revents)
+{
+  if (POLLHUP & revents)
+    return false;
+  assert(POLLIN & revents);
+
+  char command;
+  if (read(control_pipe_in_, &command, 1))
+    return false;
+
+  switch (command) {
+  case kCommandQuit:
+    return false;
+  default:
+    assert(0);
+  }
+
+  return true;
+}
+
+bool
+CrashGenerationServer::MakeMinidumpFilename(std::string& outFilename)
+{
+  GUID guid;
+  char guidString[kGUIDStringLength+1];
+
+  if (!(CreateGUID(&guid)
+        && GUIDToString(&guid, guidString, sizeof(guidString))))
+    return false;
+
+  char path[PATH_MAX];
+  snprintf(path, sizeof(path), "%s/%s.dmp", dump_dir_.c_str(), guidString);
+
+  outFilename = path;
+  return true;
+}
+
+// static
+void*
+CrashGenerationServer::ThreadMain(void *arg)
+{
+  reinterpret_cast<CrashGenerationServer*>(arg)->Run();
+  return NULL;
+}
+
+} // namespace google_breakpad
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2009, 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.
+
+#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
+#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
+
+#include <pthread.h>
+
+#include <string>
+
+namespace google_breakpad {
+
+class ClientInfo;
+
+class CrashGenerationServer {
+public:
+  // WARNING: callbacks may be invoked on a different thread
+  // than that which creates the CrashGenerationServer.  They must
+  // be thread safe.
+  typedef void (*OnClientDumpRequestCallback)(void* context,
+                                              const ClientInfo* client_info,
+                                              const std::string* file_path);
+
+  typedef void (*OnClientExitingCallback)(void* context,
+                                          const ClientInfo* client_info);
+
+  // Create an instance with the given parameters.
+  //
+  // Parameter listen_fd: The server fd created by CreateReportChannel().
+  // Parameter dump_callback: Callback for a client crash dump request.
+  // Parameter dump_context: Context for client crash dump request callback.
+  // Parameter exit_callback: Callback for client process exit.
+  // Parameter exit_context: Context for client exit callback.
+  // Parameter generate_dumps: Whether to automatically generate dumps.
+  //     Client code of this class might want to generate dumps explicitly
+  //     in the crash dump request callback. In that case, false can be
+  //     passed for this parameter.
+  // Parameter dump_path: Path for generating dumps; required only if true is
+  //     passed for generateDumps parameter; NULL can be passed otherwise.
+  CrashGenerationServer(const int listen_fd,
+                        OnClientDumpRequestCallback dump_callback,
+                        void* dump_context,
+                        OnClientExitingCallback exit_callback,
+                        void* exit_context,
+                        bool generate_dumps,
+                        const std::string* dump_path);
+
+  ~CrashGenerationServer();
+
+  // Perform initialization steps needed to start listening to clients.
+  //
+  // Return true if initialization is successful; false otherwise.
+  bool Start();
+
+  // Stop the server.
+  void Stop();
+
+  // Create a "channel" that can be used by clients to report crashes
+  // to a CrashGenerationServer.  |*server_fd| should be passed to
+  // this class's constructor, and |*client_fd| should be passed to
+  // the ExceptionHandler constructor in the client process.
+  static bool CreateReportChannel(int* server_fd, int* client_fd);
+
+private:
+  // Run the server's event loop
+  void Run();
+
+  // Invoked when an child process (client) event occurs
+  // Returning true => "keep running", false => "exit loop"
+  bool ClientEvent(short revents);
+
+  // Invoked when the controlling thread (main) event occurs
+  // Returning true => "keep running", false => "exit loop"
+  bool ControlEvent(short revents);
+
+  // Return a unique filename at which a minidump can be written
+  bool MakeMinidumpFilename(std::string& outFilename);
+
+  // Trampoline to |Run()|
+  static void* ThreadMain(void* arg);
+
+  int server_fd_;
+
+  OnClientDumpRequestCallback dump_callback_;
+  void* dump_context_;
+
+  OnClientExitingCallback exit_callback_;
+  void* exit_context_;
+
+  bool generate_dumps_;
+
+  std::string dump_dir_;
+
+  bool started_;
+
+  pthread_t thread_;
+  int control_pipe_in_;
+  int control_pipe_out_;
+
+  // disable these
+  CrashGenerationServer(const CrashGenerationServer&);
+  CrashGenerationServer& operator=(const CrashGenerationServer&);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_SERVER_H_
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
@@ -109,40 +109,65 @@ pthread_mutex_t ExceptionHandler::handle
     PTHREAD_MUTEX_INITIALIZER;
 
 // Runs before crashing: normal context.
 ExceptionHandler::ExceptionHandler(const std::string &dump_path,
                                    FilterCallback filter,
                                    MinidumpCallback callback,
                                    void *callback_context,
                                    bool install_handler)
-    : filter_(filter),
-      callback_(callback),
-      callback_context_(callback_context),
-      dump_path_(),
-      handler_installed_(install_handler),
-      crash_handler_(NULL) {
-  set_dump_path(dump_path);
+  : filter_(filter),
+    callback_(callback),
+    callback_context_(callback_context),
+    handler_installed_(install_handler)
+{
+  Init(dump_path, -1);
+}
 
-  if (install_handler) {
-    InstallHandlers();
-
-    pthread_mutex_lock(&handler_stack_mutex_);
-      if (handler_stack_ == NULL)
-        handler_stack_ = new std::vector<ExceptionHandler *>;
-      handler_stack_->push_back(this);
-    pthread_mutex_unlock(&handler_stack_mutex_);
-  }
+ExceptionHandler::ExceptionHandler(const std::string &dump_path,
+                                   FilterCallback filter,
+                                   MinidumpCallback callback,
+                                   void* callback_context,
+                                   bool install_handler,
+                                   const int server_fd)
+  : filter_(filter),
+    callback_(callback),
+    callback_context_(callback_context),
+    handler_installed_(install_handler)
+{
+  Init(dump_path, server_fd);
 }
 
 // Runs before crashing: normal context.
 ExceptionHandler::~ExceptionHandler() {
   UninstallHandlers();
 }
 
+void ExceptionHandler::Init(const std::string &dump_path,
+                            const int server_fd)
+{
+  crash_handler_ = NULL;
+
+  if (0 <= server_fd)
+    crash_generation_client_
+      .reset(CrashGenerationClient::TryCreate(server_fd));
+
+  if (handler_installed_)
+    InstallHandlers();
+
+  if (!IsOutOfProcess())
+    set_dump_path(dump_path);
+
+  pthread_mutex_lock(&handler_stack_mutex_);
+  if (handler_stack_ == NULL)
+    handler_stack_ = new std::vector<ExceptionHandler *>;
+  handler_stack_->push_back(this);
+  pthread_mutex_unlock(&handler_stack_mutex_);
+}
+
 // Runs before crashing: normal context.
 bool ExceptionHandler::InstallHandlers() {
   // We run the signal handlers on an alternative stack because we might have
   // crashed because of a stack overflow.
 
   // We use this value rather than SIGSTKSZ because we would end up overrunning
   // such a small stack.
   static const unsigned kSigStackSize = 8192;
@@ -275,16 +300,19 @@ bool ExceptionHandler::HandleSignal(int 
                                        callback_context_))
     return true;
 
   return GenerateDump(&context);
 }
 
 // This function may run in a compromised context: see the top of the file.
 bool ExceptionHandler::GenerateDump(CrashContext *context) {
+  if (IsOutOfProcess())
+    return crash_generation_client_->RequestDump(context, sizeof(*context));
+
   static const unsigned kChildStackSize = 8000;
   PageAllocator allocator;
   uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
   if (!stack)
     return false;
   // clone() needs the top-most address. (scrub just to be safe)
   stack += kChildStackSize;
   my_memset(stack - 16, 0, 16);
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
@@ -30,16 +30,21 @@
 #ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
 #define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
 
 #include <vector>
 #include <string>
 
 #include <signal.h>
 
+#include "client/linux/crash_generation/crash_generation_client.h"
+#include "processor/scoped_ptr.h"
+
+struct sigaction;
+
 namespace google_breakpad {
 
 // ExceptionHandler
 //
 // ExceptionHandler can write a minidump file when an exception occurs,
 // or when WriteMinidump() is called explicitly by your program.
 //
 // To have the exception handler write minidumps when an uncaught exception
@@ -111,16 +116,28 @@ class ExceptionHandler {
   // callback is called after writing the dump file, as described above.
   // If install_handler is true, then a minidump will be written whenever
   // an unhandled exception occurs.  If it is false, minidumps will only
   // be written when WriteMinidump is called.
   ExceptionHandler(const std::string &dump_path,
                    FilterCallback filter, MinidumpCallback callback,
                    void *callback_context,
                    bool install_handler);
+
+  // Creates a new ExceptionHandler instance that can attempt to
+  // perform out-of-process dump generation if server_fd is valid. If
+  // server_fd is invalid, in-process dump generation will be
+  // used. See the above ctor for a description of the other
+  // parameters.
+  ExceptionHandler(const std::string& dump_path,
+                   FilterCallback filter, MinidumpCallback callback,
+                   void* callback_context,
+                   bool install_handler,
+                   const int server_fd);
+
   ~ExceptionHandler();
 
   // Get and set the minidump path.
   std::string dump_path() const { return dump_path_; }
   void set_dump_path(const std::string &dump_path) {
     dump_path_ = dump_path;
     dump_path_c_ = dump_path_.c_str();
     UpdateNextID();
@@ -144,33 +161,42 @@ class ExceptionHandler {
   // blob. It shouldn't be needed in any user code.
   struct CrashContext {
     siginfo_t siginfo;
     pid_t tid;  // the crashing thread.
     struct ucontext context;
     struct _libc_fpstate float_state;
   };
 
+  // Returns whether out-of-process dump generation is used or not.
+  bool IsOutOfProcess() const {
+      return crash_generation_client_.get() != NULL;
+  }
+
  private:
+  void Init(const std::string &dump_path,
+            const int server_fd);
   bool InstallHandlers();
   void UninstallHandlers();
   void PreresolveSymbols();
   bool GenerateDump(CrashContext *context);
 
   void UpdateNextID();
   static void SignalHandler(int sig, siginfo_t* info, void* uc);
   bool HandleSignal(int sig, siginfo_t* info, void* uc);
   static int ThreadEntry(void* arg);
   bool DoDump(pid_t crashing_process, const void* context,
               size_t context_size);
 
   const FilterCallback filter_;
   const MinidumpCallback callback_;
   void* const callback_context_;
 
+  scoped_ptr<CrashGenerationClient> crash_generation_client_;
+
   std::string dump_path_;
   std::string next_minidump_path_;
   std::string next_minidump_id_;
 
   // Pointers to C-string representations of the above. These are set
   // when the above are set so we can avoid calling c_str during
   // an exception.
   const char* dump_path_c_;
@@ -184,16 +210,15 @@ class ExceptionHandler {
   // The global exception handler stack. This is need becuase there may exist
   // multiple ExceptionHandler instances in a process. Each will have itself
   // registered in this stack.
   static std::vector<ExceptionHandler*> *handler_stack_;
   // The index of the handler that should handle the next exception.
   static unsigned handler_stack_index_;
   static pthread_mutex_t handler_stack_mutex_;
 
-  // A vector of the old signal handlers. The void* is a pointer to a newly
-  // allocated sigaction structure to avoid pulling in too many includes.
-  std::vector<std::pair<int, void *> > old_handlers_;
+  // A vector of the old signal handlers.
+  std::vector<std::pair<int, struct sigaction *> > old_handlers_;
 };
 
 }  // namespace google_breakpad
 
 #endif  // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc
@@ -33,30 +33,21 @@
 #include <unistd.h>
 #include <signal.h>
 #include <sys/poll.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
 
 #include "client/linux/handler//exception_handler.h"
 #include "client/linux/minidump_writer/minidump_writer.h"
+#include "common/linux/eintr_wrapper.h"
 #include "common/linux/linux_libc_support.h"
 #include "common/linux/linux_syscall_support.h"
 #include "breakpad_googletest_includes.h"
 
-// This provides a wrapper around system calls which may be
-// interrupted by a signal and return EINTR. See man 7 signal.
-#define HANDLE_EINTR(x) ({ \
-  typeof(x) __eintr_result__; \
-  do { \
-    __eintr_result__ = x; \
-  } while (__eintr_result__ == -1 && errno == EINTR); \
-  __eintr_result__;\
-})
-
 using namespace google_breakpad;
 
 static void sigchld_handler(int signo) { }
 
 class ExceptionHandlerTest : public ::testing::Test {
  protected:
   void SetUp() {
     // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc
@@ -27,30 +27,21 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <unistd.h>
 #include <sys/syscall.h>
 
 #include "client/linux/handler/exception_handler.h"
 #include "client/linux/minidump_writer/minidump_writer.h"
+#include "common/linux/eintr_wrapper.h"
 #include "breakpad_googletest_includes.h"
 
 using namespace google_breakpad;
 
-// This provides a wrapper around system calls which may be
-// interrupted by a signal and return EINTR. See man 7 signal.
-#define HANDLE_EINTR(x) ({ \
-  typeof(x) __eintr_result__; \
-  do { \
-    __eintr_result__ = x; \
-  } while (__eintr_result__ == -1 && errno == EINTR); \
-  __eintr_result__;\
-})
-
 namespace {
 typedef testing::Test MinidumpWriterTest;
 }
 
 TEST(MinidumpWriterTest, Setup) {
   int fds[2];
   ASSERT_NE(-1, pipe(fds));
 
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2009, 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.
+
+#ifndef COMMON_LINUX_EINTR_WRAPPER_H_
+#define COMMON_LINUX_EINTR_WRAPPER_H_
+
+#include <errno.h>
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+//
+
+#define HANDLE_EINTR(x) ({ \
+  typeof(x) __eintr_result__; \
+  do { \
+    __eintr_result__ = x; \
+  } while (__eintr_result__ == -1 && errno == EINTR); \
+  __eintr_result__;\
+})
+
+#endif // ifndef COMMON_LINUX_EINTR_WRAPPER_H_
--- a/toolkit/xre/Makefile.in
+++ b/toolkit/xre/Makefile.in
@@ -142,16 +142,17 @@ SHARED_LIBRARY_LIBS += \
 	$(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/$(LIB_PREFIX)minidump_file_writer_s.$(LIB_SUFFIX) \
 	$(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/mac/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
 	$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/$(LIB_PREFIX)breakpad_common_s.$(LIB_SUFFIX) \
 	$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/mac/$(LIB_PREFIX)breakpad_mac_common_s.$(LIB_SUFFIX)
 endif
 
 ifeq ($(OS_ARCH),Linux)
 SHARED_LIBRARY_LIBS += \
+  $(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/$(LIB_PREFIX)crash_generation_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/linux/handler/$(LIB_PREFIX)exception_handler_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/$(LIB_PREFIX)minidump_writer_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/client/$(LIB_PREFIX)minidump_file_writer_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/$(LIB_PREFIX)breakpad_common_s.$(LIB_SUFFIX) \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/linux/$(LIB_PREFIX)breakpad_linux_common_s.$(LIB_SUFFIX) \
   $(NULL)
 endif