summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/breakpad-client/linux/crash_generation
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/breakpad-client/linux/crash_generation')
-rw-r--r--toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h68
-rw-r--r--toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc105
-rw-r--r--toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h65
-rw-r--r--toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc378
-rw-r--r--toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h135
5 files changed, 751 insertions, 0 deletions
diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h
new file mode 100644
index 0000000000..3de2606b7b
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/client_info.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2010 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 {
+
+class CrashGenerationServer;
+
+class ClientInfo {
+ public:
+ ClientInfo(pid_t pid, CrashGenerationServer* crash_server)
+ : crash_server_(crash_server),
+ pid_(pid) {}
+
+ CrashGenerationServer* crash_server() const { return crash_server_; }
+ pid_t pid() const { return pid_; }
+ void set_error_msg(nsCString &error_msg) {
+ had_error_ = true;
+ error_msg_ = error_msg;
+ }
+
+ const nsCString* error_msg() const {
+ return &error_msg_;
+ }
+
+ bool had_error() const {
+ return had_error_;
+ }
+
+ private:
+ CrashGenerationServer* crash_server_;
+ pid_t pid_;
+ bool had_error_ = false;
+ nsCString error_msg_; // Possible error message of the minidumper in
+ // case there was an error during dumping
+};
+
+}
+
+#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc
new file mode 100644
index 0000000000..02dc66f355
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2010 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 "linux/crash_generation/crash_generation_client.h"
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <algorithm>
+
+#include "common/linux/eintr_wrapper.h"
+#include "common/linux/ignore_ret.h"
+#include "third_party/lss/linux_syscall_support.h"
+
+namespace google_breakpad {
+
+namespace {
+
+class CrashGenerationClientImpl : public CrashGenerationClient {
+ public:
+ explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {}
+ virtual ~CrashGenerationClientImpl() {}
+
+ virtual bool RequestDump(const void* blob, size_t blob_size) {
+ int fds[2];
+ if (sys_pipe(fds) < 0)
+ return false;
+ static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int));
+
+ struct kernel_iovec iov;
+ iov.iov_base = const_cast<void*>(blob);
+ iov.iov_len = blob_size;
+
+ struct kernel_msghdr msg = { 0 };
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ char cmsg[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* p = reinterpret_cast<int*>(CMSG_DATA(hdr));
+ *p = fds[1];
+
+ ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0));
+ sys_close(fds[1]);
+ if (ret < 0) {
+ sys_close(fds[0]);
+ return false;
+ }
+
+ // Wait for an ACK from the server.
+ char b;
+ IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1)));
+ sys_close(fds[0]);
+
+ return true;
+ }
+
+ private:
+ int server_fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl);
+};
+
+} // namespace
+
+// static
+CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) {
+ if (server_fd < 0)
+ return NULL;
+ return new CrashGenerationClientImpl(server_fd);
+}
+
+} // namespace google_breakpad
diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h
new file mode 100644
index 0000000000..4e68424ae8
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_client.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2010 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 "common/basictypes.h"
+
+#include <stddef.h>
+
+namespace google_breakpad {
+
+// CrashGenerationClient is an interface for implementing out-of-process crash
+// dumping. The default implementation, accessed via the TryCreate() factory,
+// works in conjunction with the CrashGenerationServer to generate a minidump
+// via a remote process.
+class CrashGenerationClient {
+ public:
+ CrashGenerationClient() {}
+ virtual ~CrashGenerationClient() {}
+
+ // Request the crash server to generate a dump. |blob| is an opaque
+ // CrashContext pointer from exception_handler.h.
+ // Returns true if the dump was successful; false otherwise.
+ virtual bool RequestDump(const void* blob, size_t blob_size) = 0;
+
+ // Returns 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:
+ DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient);
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc
new file mode 100644
index 0000000000..ee3d785385
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2010 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 <vector>
+
+#include "nsThreadUtils.h"
+
+#include "linux/crash_generation/crash_generation_server.h"
+#include "linux/crash_generation/client_info.h"
+#include "linux/handler/exception_handler.h"
+#include "linux/handler/guid_generator.h"
+#include "linux/minidump_writer/minidump_writer.h"
+#include "common/linux/eintr_wrapper.h"
+#include "common/linux/safe_readlink.h"
+
+#if defined(MOZ_OXIDIZED_BREAKPAD)
+# include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h"
+# include <sys/signalfd.h>
+# include "nsString.h"
+#endif
+
+static const char kCommandQuit = 'x';
+
+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 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);
+
+ close(control_pipe_in_);
+ close(control_pipe_out_);
+
+ 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)
+ 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 != -1)
+ close(signal_fd);
+ return true;
+ }
+
+ string minidump_filename;
+ if (!MakeMinidumpFilename(minidump_filename))
+ return true;
+
+#if defined(MOZ_OXIDIZED_BREAKPAD)
+ ExceptionHandler::CrashContext* breakpad_cc =
+ reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
+ nsCString error_msg;
+ siginfo_t& si = breakpad_cc->siginfo;
+ signalfd_siginfo signalfd_si = {};
+ signalfd_si.ssi_signo = si.si_signo;
+ signalfd_si.ssi_errno = si.si_errno;
+ signalfd_si.ssi_code = si.si_code;
+
+ switch (si.si_signo) {
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGBUS:
+ case SIGSYS:
+ signalfd_si.ssi_addr = reinterpret_cast<size_t>(si.si_addr);
+ break;
+ }
+
+ // Ignoring the return-value here for now.
+ // The function always creates an empty minidump file even in case of an
+ // error. So we'll report that as well via the callback-functions.
+ bool res = write_minidump_linux_with_context(
+ minidump_filename.c_str(), crashing_pid, &breakpad_cc->context,
+ &breakpad_cc->float_state, &signalfd_si, breakpad_cc->tid, &error_msg);
+#else
+ if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
+ crashing_pid, crash_context,
+ kCrashContextSize)) {
+ close(signal_fd);
+ return true;
+ }
+#endif
+
+ ClientInfo info(crashing_pid, this);
+#if defined(MOZ_OXIDIZED_BREAKPAD)
+ if (!res) {
+ info.set_error_msg(error_msg);
+ }
+#endif
+ if (dump_callback_) {
+ dump_callback_(dump_context_, info, minidump_filename);
+ }
+
+ // Send the done signal to the process: it can exit now.
+ // (Closing this will make the child's sys_read unblock and return 0.)
+ close(signal_fd);
+
+ if (exit_callback_) {
+ exit_callback_(exit_context_, info);
+ }
+
+ 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(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)
+{
+ NS_SetCurrentThreadName("Breakpad Server");
+ reinterpret_cast<CrashGenerationServer*>(arg)->Run();
+ return NULL;
+}
+
+} // namespace google_breakpad
diff --git a/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h
new file mode 100644
index 0000000000..83b626ab1e
--- /dev/null
+++ b/toolkit/crashreporter/breakpad-client/linux/crash_generation/crash_generation_server.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2010 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>
+
+#include "common/using_std_string.h"
+
+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 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 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(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_;
+
+ 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_