summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/client/linux
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/linux')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h53
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc105
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h65
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc333
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h135
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym3
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym3
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/mapping_info.h61
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h53
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc305
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.h91
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc259
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.h64
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc789
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h278
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc1179
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/microdump_extra_info.h52
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.cc87
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.h149
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/log/log.cc84
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/log/log.h55
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.cc609
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.h65
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc257
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set.h144
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc164
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h106
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc78
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h131
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc169
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc258
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.h125
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc128
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc776
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h265
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc94
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc355
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h92
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc470
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc1376
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h124
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc775
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc66
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h49
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h130
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc199
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/moz.build35
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc104
48 files changed, 0 insertions, 11347 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h
deleted file mode 100644
index d0a184a63..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/client_info.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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_; }
-
- private:
- CrashGenerationServer* crash_server_;
- pid_t pid_;
-};
-
-}
-
-#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc
deleted file mode 100644
index d8bfbbad2..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// 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 "client/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/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h
deleted file mode 100644
index 4e68424ae..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_client.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc
deleted file mode 100644
index 1d7d93b99..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-// 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 "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"
-#include "common/linux/safe_readlink.h"
-
-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)
- close(signal_fd);
- return true;
- }
-
- string minidump_filename;
- if (!MakeMinidumpFilename(minidump_filename))
- return true;
-
- if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
- crashing_pid, crash_context,
- kCrashContextSize)) {
- close(signal_fd);
- return true;
- }
-
- if (dump_callback_) {
- ClientInfo info(crashing_pid, this);
-
- 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);
-
- 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)
-{
- reinterpret_cast<CrashGenerationServer*>(arg)->Run();
- return NULL;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h b/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h
deleted file mode 100644
index 483fb709b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/crash_generation/crash_generation_server.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym b/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym
deleted file mode 100644
index e042a5ec4..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym
+++ /dev/null
@@ -1,3 +0,0 @@
-MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so
-PUBLIC 400 0 __kernel_vsyscall
-STACK WIN 4 400 100 1 1 0 0 0 0 0 1
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym b/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym
deleted file mode 100644
index c209c2375..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym
+++ /dev/null
@@ -1,3 +0,0 @@
-MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so
-PUBLIC 400 0 __kernel_vsyscall
-STACK WIN 4 400 200 3 3 0 0 0 0 0 1 \ No newline at end of file
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/mapping_info.h b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/mapping_info.h
deleted file mode 100644
index 5f247cfd4..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/mapping_info.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2014, 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_DUMP_WRITER_COMMON_MAPPING_INFO_H_
-#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
-
-#include <limits.h>
-#include <list>
-#include <stdint.h>
-
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-// One of these is produced for each mapping in the process (i.e. line in
-// /proc/$x/maps).
-struct MappingInfo {
- uintptr_t start_addr;
- size_t size;
- size_t offset; // offset into the backed file.
- bool exec; // true if the mapping has the execute bit set.
- char name[NAME_MAX];
-};
-
-struct MappingEntry {
- MappingInfo first;
- uint8_t second[sizeof(MDGUID)];
-};
-
-// A list of <MappingInfo, GUID>
-typedef std::list<MappingEntry> MappingList;
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h
deleted file mode 100644
index e2ef45df5..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/raw_context_cpu.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2014, 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_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
-#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
-
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-#if defined(__i386__)
-typedef MDRawContextX86 RawContextCPU;
-#elif defined(__x86_64)
-typedef MDRawContextAMD64 RawContextCPU;
-#elif defined(__ARM_EABI__)
-typedef MDRawContextARM RawContextCPU;
-#elif defined(__aarch64__)
-typedef MDRawContextARM64 RawContextCPU;
-#elif defined(__mips__)
-typedef MDRawContextMIPS RawContextCPU;
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc
deleted file mode 100644
index 0a1041d62..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.cc
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright (c) 2014, 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 "client/linux/dump_writer_common/thread_info.h"
-
-#include <string.h>
-#include <assert.h>
-
-#include "common/linux/linux_libc_support.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace {
-
-#if defined(__i386__)
-// Write a uint16_t to memory
-// out: memory location to write to
-// v: value to write.
-void U16(void* out, uint16_t v) {
- my_memcpy(out, &v, sizeof(v));
-}
-
-// Write a uint32_t to memory
-// out: memory location to write to
-// v: value to write.
-void U32(void* out, uint32_t v) {
- my_memcpy(out, &v, sizeof(v));
-}
-#endif
-
-}
-
-namespace google_breakpad {
-
-#if defined(__i386__)
-
-uintptr_t ThreadInfo::GetInstructionPointer() const {
- return regs.eip;
-}
-
-void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
- out->context_flags = MD_CONTEXT_X86_ALL;
-
- out->dr0 = dregs[0];
- out->dr1 = dregs[1];
- out->dr2 = dregs[2];
- out->dr3 = dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = dregs[6];
- out->dr7 = dregs[7];
-
- out->gs = regs.xgs;
- out->fs = regs.xfs;
- out->es = regs.xes;
- out->ds = regs.xds;
-
- out->edi = regs.edi;
- out->esi = regs.esi;
- out->ebx = regs.ebx;
- out->edx = regs.edx;
- out->ecx = regs.ecx;
- out->eax = regs.eax;
-
- out->ebp = regs.ebp;
- out->eip = regs.eip;
- out->cs = regs.xcs;
- out->eflags = regs.eflags;
- out->esp = regs.esp;
- out->ss = regs.xss;
-
- out->float_save.control_word = fpregs.cwd;
- out->float_save.status_word = fpregs.swd;
- out->float_save.tag_word = fpregs.twd;
- out->float_save.error_offset = fpregs.fip;
- out->float_save.error_selector = fpregs.fcs;
- out->float_save.data_offset = fpregs.foo;
- out->float_save.data_selector = fpregs.fos;
-
- // 8 registers * 10 bytes per register.
- my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8);
-
- // This matches the Intel fpsave format.
- U16(out->extended_registers + 0, fpregs.cwd);
- U16(out->extended_registers + 2, fpregs.swd);
- U16(out->extended_registers + 4, fpregs.twd);
- U16(out->extended_registers + 6, fpxregs.fop);
- U32(out->extended_registers + 8, fpxregs.fip);
- U16(out->extended_registers + 12, fpxregs.fcs);
- U32(out->extended_registers + 16, fpregs.foo);
- U16(out->extended_registers + 20, fpregs.fos);
- U32(out->extended_registers + 24, fpxregs.mxcsr);
-
- my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128);
- my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128);
-}
-
-#elif defined(__x86_64)
-
-uintptr_t ThreadInfo::GetInstructionPointer() const {
- return regs.rip;
-}
-
-void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
- out->context_flags = MD_CONTEXT_AMD64_FULL |
- MD_CONTEXT_AMD64_SEGMENTS;
-
- out->cs = regs.cs;
-
- out->ds = regs.ds;
- out->es = regs.es;
- out->fs = regs.fs;
- out->gs = regs.gs;
-
- out->ss = regs.ss;
- out->eflags = regs.eflags;
-
- out->dr0 = dregs[0];
- out->dr1 = dregs[1];
- out->dr2 = dregs[2];
- out->dr3 = dregs[3];
- // 4 and 5 deliberatly omitted because they aren't included in the minidump
- // format.
- out->dr6 = dregs[6];
- out->dr7 = dregs[7];
-
- out->rax = regs.rax;
- out->rcx = regs.rcx;
- out->rdx = regs.rdx;
- out->rbx = regs.rbx;
-
- out->rsp = regs.rsp;
-
- out->rbp = regs.rbp;
- out->rsi = regs.rsi;
- out->rdi = regs.rdi;
- out->r8 = regs.r8;
- out->r9 = regs.r9;
- out->r10 = regs.r10;
- out->r11 = regs.r11;
- out->r12 = regs.r12;
- out->r13 = regs.r13;
- out->r14 = regs.r14;
- out->r15 = regs.r15;
-
- out->rip = regs.rip;
-
- out->flt_save.control_word = fpregs.cwd;
- out->flt_save.status_word = fpregs.swd;
- out->flt_save.tag_word = fpregs.ftw;
- out->flt_save.error_opcode = fpregs.fop;
- out->flt_save.error_offset = fpregs.rip;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_offset = fpregs.rdp;
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = fpregs.mxcsr;
- out->flt_save.mx_csr_mask = fpregs.mxcr_mask;
-
- my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16);
- my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16);
-}
-
-#elif defined(__ARM_EABI__)
-
-uintptr_t ThreadInfo::GetInstructionPointer() const {
- return regs.uregs[15];
-}
-
-void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
- out->context_flags = MD_CONTEXT_ARM_FULL;
-
- for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
- out->iregs[i] = regs.uregs[i];
- // No CPSR register in ThreadInfo(it's not accessible via ptrace)
- out->cpsr = 0;
-#if !defined(__ANDROID__)
- out->float_save.fpscr = fpregs.fpsr |
- (static_cast<uint64_t>(fpregs.fpcr) << 32);
- // TODO: sort this out, actually collect floating point registers
- my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
- my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
-#endif
-}
-
-#elif defined(__aarch64__)
-
-uintptr_t ThreadInfo::GetInstructionPointer() const {
- return regs.pc;
-}
-
-void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
- out->context_flags = MD_CONTEXT_ARM64_FULL;
-
- out->cpsr = static_cast<uint32_t>(regs.pstate);
- for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
- out->iregs[i] = regs.regs[i];
- out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp;
- out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc;
-
- out->float_save.fpsr = fpregs.fpsr;
- out->float_save.fpcr = fpregs.fpcr;
- my_memcpy(&out->float_save.regs, &fpregs.vregs,
- MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
-}
-
-#elif defined(__mips__)
-
-uintptr_t ThreadInfo::GetInstructionPointer() const {
- return mcontext.pc;
-}
-
-void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
-#if _MIPS_SIM == _ABI64
- out->context_flags = MD_CONTEXT_MIPS64_FULL;
-#elif _MIPS_SIM == _ABIO32
- out->context_flags = MD_CONTEXT_MIPS_FULL;
-#else
-# error "This mips ABI is currently not supported (n32)"
-#endif
-
- for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
- out->iregs[i] = mcontext.gregs[i];
-
- out->mdhi = mcontext.mdhi;
- out->mdlo = mcontext.mdlo;
- out->dsp_control = mcontext.dsp;
-
- out->hi[0] = mcontext.hi1;
- out->lo[0] = mcontext.lo1;
- out->hi[1] = mcontext.hi2;
- out->lo[1] = mcontext.lo2;
- out->hi[2] = mcontext.hi3;
- out->lo[2] = mcontext.lo3;
-
- out->epc = mcontext.pc;
- out->badvaddr = 0; // Not stored in mcontext
- out->status = 0; // Not stored in mcontext
- out->cause = 0; // Not stored in mcontext
-
- for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
- out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs;
-
- out->float_save.fpcsr = mcontext.fpc_csr;
-#if _MIPS_SIM == _ABIO32
- out->float_save.fir = mcontext.fpc_eir;
-#endif
-}
-#endif // __mips__
-
-void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) {
- assert(gp_regs || size);
-#if defined(__mips__)
- if (gp_regs)
- *gp_regs = mcontext.gregs;
- if (size)
- *size = sizeof(mcontext.gregs);
-#else
- if (gp_regs)
- *gp_regs = &regs;
- if (size)
- *size = sizeof(regs);
-#endif
-}
-
-void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) {
- assert(fp_regs || size);
-#if defined(__mips__)
- if (fp_regs)
- *fp_regs = &mcontext.fpregs;
- if (size)
- *size = sizeof(mcontext.fpregs);
-#else
- if (fp_regs)
- *fp_regs = &fpregs;
- if (size)
- *size = sizeof(fpregs);
-#endif
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.h b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.h
deleted file mode 100644
index 99093d2e0..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/thread_info.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2014, 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_DUMP_WRITER_COMMON_THREAD_INFO_H_
-#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
-
-#include <sys/ucontext.h>
-#include <sys/user.h>
-
-#include "client/linux/dump_writer_common/raw_context_cpu.h"
-#include "common/memory.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-#if defined(__i386) || defined(__x86_64)
-typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t;
-#endif
-
-// We produce one of these structures for each thread in the crashed process.
-struct ThreadInfo {
- pid_t tgid; // thread group id
- pid_t ppid; // parent process
-
- uintptr_t stack_pointer; // thread stack pointer
-
-
-#if defined(__i386) || defined(__x86_64)
- user_regs_struct regs;
- user_fpregs_struct fpregs;
- static const unsigned kNumDebugRegisters = 8;
- debugreg_t dregs[8];
-#if defined(__i386)
- user_fpxregs_struct fpxregs;
-#endif // defined(__i386)
-
-#elif defined(__ARM_EABI__)
- // Mimicking how strace does this(see syscall.c, search for GETREGS)
- struct user_regs regs;
- struct user_fpregs fpregs;
-#elif defined(__aarch64__)
- // Use the structures defined in <sys/user.h>
- struct user_regs_struct regs;
- struct user_fpsimd_struct fpregs;
-#elif defined(__mips__)
- // Use the structure defined in <sys/ucontext.h>.
- mcontext_t mcontext;
-#endif
-
- // Returns the instruction pointer (platform-dependent impl.).
- uintptr_t GetInstructionPointer() const;
-
- // Fills a RawContextCPU using the context in the ThreadInfo object.
- void FillCPUContext(RawContextCPU* out) const;
-
- // Returns the pointer and size of general purpose register area.
- void GetGeneralPurposeRegisters(void** gp_regs, size_t* size);
-
- // Returns the pointer and size of float point register area.
- void GetFloatingPointRegisters(void** fp_regs, size_t* size);
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
deleted file mode 100644
index 93b4d9f85..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright (c) 2014, 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 "client/linux/dump_writer_common/ucontext_reader.h"
-
-#include "common/linux/linux_libc_support.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-// Minidump defines register structures which are different from the raw
-// structures which we get from the kernel. These are platform specific
-// functions to juggle the ucontext and user structures into minidump format.
-
-#if defined(__i386__)
-
-uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.gregs[REG_ESP];
-}
-
-uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.gregs[REG_EIP];
-}
-
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
- const struct _libc_fpstate* fp) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_X86_FULL |
- MD_CONTEXT_X86_FLOATING_POINT;
-
- out->gs = regs[REG_GS];
- out->fs = regs[REG_FS];
- out->es = regs[REG_ES];
- out->ds = regs[REG_DS];
-
- out->edi = regs[REG_EDI];
- out->esi = regs[REG_ESI];
- out->ebx = regs[REG_EBX];
- out->edx = regs[REG_EDX];
- out->ecx = regs[REG_ECX];
- out->eax = regs[REG_EAX];
-
- out->ebp = regs[REG_EBP];
- out->eip = regs[REG_EIP];
- out->cs = regs[REG_CS];
- out->eflags = regs[REG_EFL];
- out->esp = regs[REG_UESP];
- out->ss = regs[REG_SS];
-
- out->float_save.control_word = fp->cw;
- out->float_save.status_word = fp->sw;
- out->float_save.tag_word = fp->tag;
- out->float_save.error_offset = fp->ipoff;
- out->float_save.error_selector = fp->cssel;
- out->float_save.data_offset = fp->dataoff;
- out->float_save.data_selector = fp->datasel;
-
- // 8 registers * 10 bytes per register.
- my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
-}
-
-#elif defined(__x86_64)
-
-uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.gregs[REG_RSP];
-}
-
-uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.gregs[REG_RIP];
-}
-
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
- const struct _libc_fpstate* fpregs) {
- const greg_t* regs = uc->uc_mcontext.gregs;
-
- out->context_flags = MD_CONTEXT_AMD64_FULL;
-
- out->cs = regs[REG_CSGSFS] & 0xffff;
-
- out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
- out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
-
- out->eflags = regs[REG_EFL];
-
- out->rax = regs[REG_RAX];
- out->rcx = regs[REG_RCX];
- out->rdx = regs[REG_RDX];
- out->rbx = regs[REG_RBX];
-
- out->rsp = regs[REG_RSP];
- out->rbp = regs[REG_RBP];
- out->rsi = regs[REG_RSI];
- out->rdi = regs[REG_RDI];
- out->r8 = regs[REG_R8];
- out->r9 = regs[REG_R9];
- out->r10 = regs[REG_R10];
- out->r11 = regs[REG_R11];
- out->r12 = regs[REG_R12];
- out->r13 = regs[REG_R13];
- out->r14 = regs[REG_R14];
- out->r15 = regs[REG_R15];
-
- out->rip = regs[REG_RIP];
-
- out->flt_save.control_word = fpregs->cwd;
- out->flt_save.status_word = fpregs->swd;
- out->flt_save.tag_word = fpregs->ftw;
- out->flt_save.error_opcode = fpregs->fop;
- out->flt_save.error_offset = fpregs->rip;
- out->flt_save.data_offset = fpregs->rdp;
- out->flt_save.error_selector = 0; // We don't have this.
- out->flt_save.data_selector = 0; // We don't have this.
- out->flt_save.mx_csr = fpregs->mxcsr;
- out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
- my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
- my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
-}
-
-#elif defined(__ARM_EABI__)
-
-uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.arm_sp;
-}
-
-uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.arm_pc;
-}
-
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
- out->context_flags = MD_CONTEXT_ARM_FULL;
-
- out->iregs[0] = uc->uc_mcontext.arm_r0;
- out->iregs[1] = uc->uc_mcontext.arm_r1;
- out->iregs[2] = uc->uc_mcontext.arm_r2;
- out->iregs[3] = uc->uc_mcontext.arm_r3;
- out->iregs[4] = uc->uc_mcontext.arm_r4;
- out->iregs[5] = uc->uc_mcontext.arm_r5;
- out->iregs[6] = uc->uc_mcontext.arm_r6;
- out->iregs[7] = uc->uc_mcontext.arm_r7;
- out->iregs[8] = uc->uc_mcontext.arm_r8;
- out->iregs[9] = uc->uc_mcontext.arm_r9;
- out->iregs[10] = uc->uc_mcontext.arm_r10;
-
- out->iregs[11] = uc->uc_mcontext.arm_fp;
- out->iregs[12] = uc->uc_mcontext.arm_ip;
- out->iregs[13] = uc->uc_mcontext.arm_sp;
- out->iregs[14] = uc->uc_mcontext.arm_lr;
- out->iregs[15] = uc->uc_mcontext.arm_pc;
-
- out->cpsr = uc->uc_mcontext.arm_cpsr;
-
- // TODO: fix this after fixing ExceptionHandler
- out->float_save.fpscr = 0;
- my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
- my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
-}
-
-#elif defined(__aarch64__)
-
-uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.sp;
-}
-
-uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.pc;
-}
-
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
- const struct fpsimd_context* fpregs) {
- out->context_flags = MD_CONTEXT_ARM64_FULL;
-
- out->cpsr = static_cast<uint32_t>(uc->uc_mcontext.pstate);
- for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i)
- out->iregs[i] = uc->uc_mcontext.regs[i];
- out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp;
- out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc;
-
- out->float_save.fpsr = fpregs->fpsr;
- out->float_save.fpcr = fpregs->fpcr;
- my_memcpy(&out->float_save.regs, &fpregs->vregs,
- MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16);
-}
-
-#elif defined(__mips__)
-
-uintptr_t UContextReader::GetStackPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP];
-}
-
-uintptr_t UContextReader::GetInstructionPointer(const ucontext_t* uc) {
- return uc->uc_mcontext.pc;
-}
-
-void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext_t *uc) {
-#if _MIPS_SIM == _ABI64
- out->context_flags = MD_CONTEXT_MIPS64_FULL;
-#elif _MIPS_SIM == _ABIO32
- out->context_flags = MD_CONTEXT_MIPS_FULL;
-#else
-#error "This mips ABI is currently not supported (n32)"
-#endif
-
- for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
- out->iregs[i] = uc->uc_mcontext.gregs[i];
-
- out->mdhi = uc->uc_mcontext.mdhi;
- out->mdlo = uc->uc_mcontext.mdlo;
-
- out->hi[0] = uc->uc_mcontext.hi1;
- out->hi[1] = uc->uc_mcontext.hi2;
- out->hi[2] = uc->uc_mcontext.hi3;
- out->lo[0] = uc->uc_mcontext.lo1;
- out->lo[1] = uc->uc_mcontext.lo2;
- out->lo[2] = uc->uc_mcontext.lo3;
- out->dsp_control = uc->uc_mcontext.dsp;
-
- out->epc = uc->uc_mcontext.pc;
- out->badvaddr = 0; // Not reported in signal context.
- out->status = 0; // Not reported in signal context.
- out->cause = 0; // Not reported in signal context.
-
- for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
- out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i];
-
- out->float_save.fpcsr = uc->uc_mcontext.fpc_csr;
-#if _MIPS_SIM == _ABIO32
- out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused.
-#endif
-}
-#endif
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.h b/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.h
deleted file mode 100644
index 2369a9ad3..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/dump_writer_common/ucontext_reader.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2014, 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_DUMP_WRITER_COMMON_UCONTEXT_READER_H
-#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
-
-#include <sys/ucontext.h>
-#include <sys/user.h>
-
-#include "client/linux/dump_writer_common/raw_context_cpu.h"
-#include "common/memory.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-// Wraps platform-dependent implementations of accessors to ucontext structs.
-struct UContextReader {
- static uintptr_t GetStackPointer(const ucontext_t* uc);
-
- static uintptr_t GetInstructionPointer(const ucontext_t* uc);
-
- // Juggle a arch-specific ucontext into a minidump format
- // out: the minidump structure
- // info: the collection of register structures.
-#if defined(__i386__) || defined(__x86_64)
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
- const struct _libc_fpstate* fp);
-#elif defined(__aarch64__)
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc,
- const struct fpsimd_context* fpregs);
-#else
- static void FillCPUContext(RawContextCPU *out, const ucontext_t *uc);
-#endif
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
deleted file mode 100644
index 288e0bb69..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
+++ /dev/null
@@ -1,789 +0,0 @@
-// 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.
-
-// The ExceptionHandler object installs signal handlers for a number of
-// signals. We rely on the signal handler running on the thread which crashed
-// in order to identify it. This is true of the synchronous signals (SEGV etc),
-// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
-// uses ExceptionHandler, you need to use tgkill to direct it to the current
-// thread.
-//
-// The signal flow looks like this:
-//
-// SignalHandler (uses a global stack of ExceptionHandler objects to find
-// | one to handle the signal. If the first rejects it, try
-// | the second etc...)
-// V
-// HandleSignal ----------------------------| (clones a new process which
-// | | shares an address space with
-// (wait for cloned | the crashed process. This
-// process) | allows us to ptrace the crashed
-// | | process)
-// V V
-// (set signal handler to ThreadEntry (static function to bounce
-// SIG_DFL and rethrow, | back into the object)
-// killing the crashed |
-// process) V
-// DoDump (writes minidump)
-// |
-// V
-// sys_exit
-//
-
-// This code is a little fragmented. Different functions of the ExceptionHandler
-// class run in a number of different contexts. Some of them run in a normal
-// context and are easy to code, others run in a compromised context and the
-// restrictions at the top of minidump_writer.cc apply: no libc and use the
-// alternative malloc. Each function should have comment above it detailing the
-// context which it runs in.
-
-#include "client/linux/handler/exception_handler.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/limits.h>
-#include <pthread.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <sys/signal.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <ucontext.h>
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#include "common/basictypes.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/memory.h"
-#include "client/linux/log/log.h"
-#include "client/linux/microdump_writer/microdump_writer.h"
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "common/linux/eintr_wrapper.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-#if defined(__ANDROID__)
-#include "linux/sched.h"
-#endif
-
-#ifndef PR_SET_PTRACER
-#define PR_SET_PTRACER 0x59616d61
-#endif
-
-// A wrapper for the tgkill syscall: send a signal to a specific thread.
-static int tgkill(pid_t tgid, pid_t tid, int sig) {
- return syscall(__NR_tgkill, tgid, tid, sig);
- return 0;
-}
-
-namespace google_breakpad {
-
-namespace {
-// The list of signals which we consider to be crashes. The default action for
-// all these signals must be Core (see man 7 signal) because we rethrow the
-// signal after handling it and expect that it'll be fatal.
-const int kExceptionSignals[] = {
- SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGTRAP
-};
-const int kNumHandledSignals =
- sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]);
-struct sigaction old_handlers[kNumHandledSignals];
-bool handlers_installed = false;
-
-// InstallAlternateStackLocked will store the newly installed stack in new_stack
-// and (if it exists) the previously installed stack in old_stack.
-stack_t old_stack;
-stack_t new_stack;
-bool stack_installed = false;
-
-// Create an alternative stack to run the signal handlers on. This is done since
-// the signal might have been caused by a stack overflow.
-// Runs before crashing: normal context.
-void InstallAlternateStackLocked() {
- if (stack_installed)
- return;
-
- memset(&old_stack, 0, sizeof(old_stack));
- memset(&new_stack, 0, sizeof(new_stack));
-
- // SIGSTKSZ may be too small to prevent the signal handlers from overrunning
- // the alternative stack. Ensure that the size of the alternative stack is
- // large enough.
- static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ);
-
- // Only set an alternative stack if there isn't already one, or if the current
- // one is too small.
- if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp ||
- old_stack.ss_size < kSigStackSize) {
- new_stack.ss_sp = calloc(1, kSigStackSize);
- new_stack.ss_size = kSigStackSize;
-
- if (sys_sigaltstack(&new_stack, NULL) == -1) {
- free(new_stack.ss_sp);
- return;
- }
- stack_installed = true;
- }
-}
-
-// Runs before crashing: normal context.
-void RestoreAlternateStackLocked() {
- if (!stack_installed)
- return;
-
- stack_t current_stack;
- if (sys_sigaltstack(NULL, &current_stack) == -1)
- return;
-
- // Only restore the old_stack if the current alternative stack is the one
- // installed by the call to InstallAlternateStackLocked.
- if (current_stack.ss_sp == new_stack.ss_sp) {
- if (old_stack.ss_sp) {
- if (sys_sigaltstack(&old_stack, NULL) == -1)
- return;
- } else {
- stack_t disable_stack;
- disable_stack.ss_flags = SS_DISABLE;
- if (sys_sigaltstack(&disable_stack, NULL) == -1)
- return;
- }
- }
-
- free(new_stack.ss_sp);
- stack_installed = false;
-}
-
-void InstallDefaultHandler(int sig) {
-#if defined(__ANDROID__)
- // Android L+ expose signal and sigaction symbols that override the system
- // ones. There is a bug in these functions where a request to set the handler
- // to SIG_DFL is ignored. In that case, an infinite loop is entered as the
- // signal is repeatedly sent to breakpad's signal handler.
- // To work around this, directly call the system's sigaction.
- struct kernel_sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sys_sigemptyset(&sa.sa_mask);
- sa.sa_handler_ = SIG_DFL;
- sa.sa_flags = SA_RESTART;
- sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t));
-#else
- signal(sig, SIG_DFL);
-#endif
-}
-
-// The global exception handler stack. This is needed because there may exist
-// multiple ExceptionHandler instances in a process. Each will have itself
-// registered in this stack.
-std::vector<ExceptionHandler*>* g_handler_stack_ = NULL;
-pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-
-// 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_;
-
-} // namespace
-
-// Runs before crashing: normal context.
-ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor,
- FilterCallback filter,
- MinidumpCallback callback,
- void* callback_context,
- bool install_handler,
- const int server_fd)
- : filter_(filter),
- callback_(callback),
- callback_context_(callback_context),
- minidump_descriptor_(descriptor),
- crash_handler_(NULL) {
- if (server_fd >= 0)
- crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd));
-
- if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() &&
- !minidump_descriptor_.IsMicrodumpOnConsole())
- minidump_descriptor_.UpdatePath();
-
-#if defined(__ANDROID__)
- if (minidump_descriptor_.IsMicrodumpOnConsole())
- logger::initializeCrashLogWriter();
-#endif
-
- pthread_mutex_lock(&g_handler_stack_mutex_);
-
- // Pre-fault the crash context struct. This is to avoid failing due to OOM
- // if handling an exception when the process ran out of virtual memory.
- memset(&g_crash_context_, 0, sizeof(g_crash_context_));
-
- if (!g_handler_stack_)
- g_handler_stack_ = new std::vector<ExceptionHandler*>;
- if (install_handler) {
- InstallAlternateStackLocked();
- InstallHandlersLocked();
- }
- g_handler_stack_->push_back(this);
- pthread_mutex_unlock(&g_handler_stack_mutex_);
-}
-
-// Runs before crashing: normal context.
-ExceptionHandler::~ExceptionHandler() {
- pthread_mutex_lock(&g_handler_stack_mutex_);
- std::vector<ExceptionHandler*>::iterator handler =
- std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this);
- g_handler_stack_->erase(handler);
- if (g_handler_stack_->empty()) {
- delete g_handler_stack_;
- g_handler_stack_ = NULL;
- RestoreAlternateStackLocked();
- RestoreHandlersLocked();
- }
- pthread_mutex_unlock(&g_handler_stack_mutex_);
-}
-
-// Runs before crashing: normal context.
-// static
-bool ExceptionHandler::InstallHandlersLocked() {
- if (handlers_installed)
- return false;
-
- // Fail if unable to store all the old handlers.
- for (int i = 0; i < kNumHandledSignals; ++i) {
- if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1)
- return false;
- }
-
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sigemptyset(&sa.sa_mask);
-
- // Mask all exception signals when we're handling one of them.
- for (int i = 0; i < kNumHandledSignals; ++i)
- sigaddset(&sa.sa_mask, kExceptionSignals[i]);
-
- sa.sa_sigaction = SignalHandler;
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
-
- for (int i = 0; i < kNumHandledSignals; ++i) {
- if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) {
- // At this point it is impractical to back out changes, and so failure to
- // install a signal is intentionally ignored.
- }
- }
- handlers_installed = true;
- return true;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-// static
-void ExceptionHandler::RestoreHandlersLocked() {
- if (!handlers_installed)
- return;
-
- for (int i = 0; i < kNumHandledSignals; ++i) {
- if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
- InstallDefaultHandler(kExceptionSignals[i]);
- }
- }
- handlers_installed = false;
-}
-
-// void ExceptionHandler::set_crash_handler(HandlerCallback callback) {
-// crash_handler_ = callback;
-// }
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-// static
-void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
- // 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.
- //
- // The following code tries to detect this case. When it does, it
- // resets the signal handlers with sigaction + SA_SIGINFO and returns.
- // This forces the signal to be thrown again, but this time the kernel
- // will call the function with the right arguments.
- struct sigaction cur_handler;
- if (sigaction(sig, NULL, &cur_handler) == 0 &&
- (cur_handler.sa_flags & SA_SIGINFO) == 0) {
- // Reset signal handler with the right flags.
- sigemptyset(&cur_handler.sa_mask);
- sigaddset(&cur_handler.sa_mask, sig);
-
- cur_handler.sa_sigaction = SignalHandler;
- cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO;
-
- if (sigaction(sig, &cur_handler, NULL) == -1) {
- // When resetting the handler fails, try to reset the
- // default one to avoid an infinite loop here.
- InstallDefaultHandler(sig);
- }
- pthread_mutex_unlock(&g_handler_stack_mutex_);
- return;
- }
-
- bool handled = false;
- for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) {
- handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc);
- }
-
- // Upon returning from this signal handler, sig will become unmasked and then
- // it will be retriggered. If one of the ExceptionHandlers handled it
- // successfully, restore the default handler. Otherwise, restore the
- // previously installed handler. Then, when the signal is retriggered, it will
- // be delivered to the appropriate handler.
- if (handled) {
- InstallDefaultHandler(sig);
- } else {
- RestoreHandlersLocked();
- }
-
- pthread_mutex_unlock(&g_handler_stack_mutex_);
-
- // info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise).
- if (info->si_code <= 0 || sig == SIGABRT) {
- // This signal was triggered by somebody sending us the signal with kill().
- // In order to retrigger it, we have to queue a new signal by calling
- // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is
- // due to the kernel sending a SIGABRT from a user request via SysRQ.
- if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) {
- // If we failed to kill ourselves (e.g. because a sandbox disallows us
- // to do so), we instead resort to terminating our process. This will
- // result in an incorrect exit code.
- _exit(1);
- }
- } else {
- // This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV).
- // No need to reissue the signal. It will automatically trigger again,
- // when we return from the signal handler.
- }
-}
-
-struct ThreadArgument {
- pid_t pid; // the crashing process
- const MinidumpDescriptor* minidump_descriptor;
- ExceptionHandler* handler;
- const void* context; // a CrashContext structure
- size_t context_size;
-};
-
-// This is the entry function for the cloned process. We are in a compromised
-// context here: see the top of the file.
-// static
-int ExceptionHandler::ThreadEntry(void *arg) {
- const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
-
- // Block here until the crashing process unblocks us when
- // we're allowed to use ptrace
- thread_arg->handler->WaitForContinueSignal();
-
- return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
- thread_arg->context_size) == false;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
- if (filter_ && !filter_(callback_context_))
- return false;
-
- // Allow ourselves to be dumped if the signal is trusted.
- bool signal_trusted = info->si_code > 0;
- bool signal_pid_trusted = info->si_code == SI_USER ||
- info->si_code == SI_TKILL;
- if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) {
- sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
- }
-
- // Fill in all the holes in the struct to make Valgrind happy.
- memset(&g_crash_context_, 0, sizeof(g_crash_context_));
- memcpy(&g_crash_context_.siginfo, info, sizeof(siginfo_t));
- memcpy(&g_crash_context_.context, uc, sizeof(ucontext_t));
-#if defined(__aarch64__)
- ucontext_t* uc_ptr = (ucontext_t*)uc;
- struct fpsimd_context* fp_ptr =
- (struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved;
- if (fp_ptr->head.magic == FPSIMD_MAGIC) {
- memcpy(&g_crash_context_.float_state, fp_ptr,
- sizeof(g_crash_context_.float_state));
- }
-#elif !defined(__ARM_EABI__) && !defined(__mips__)
- // FP state is not part of user ABI on ARM Linux.
- // In case of MIPS Linux FP state is already part of ucontext_t
- // and 'float_state' is not a member of CrashContext.
- ucontext_t* uc_ptr = (ucontext_t*)uc;
- if (uc_ptr->uc_mcontext.fpregs) {
- memcpy(&g_crash_context_.float_state, uc_ptr->uc_mcontext.fpregs,
- sizeof(g_crash_context_.float_state));
- }
-#endif
- g_crash_context_.tid = syscall(__NR_gettid);
- if (crash_handler_ != NULL) {
- if (crash_handler_(&g_crash_context_, sizeof(g_crash_context_),
- callback_context_)) {
- return true;
- }
- }
- return GenerateDump(&g_crash_context_);
-}
-
-// This is a public interface to HandleSignal that allows the client to
-// generate a crash dump. This function may run in a compromised context.
-bool ExceptionHandler::SimulateSignalDelivery(int sig) {
- siginfo_t siginfo = {};
- // Mimic a trusted signal to allow tracing the process (see
- // ExceptionHandler::HandleSignal().
- siginfo.si_code = SI_USER;
- siginfo.si_pid = getpid();
- ucontext_t context;
- getcontext(&context);
- return HandleSignal(sig, &siginfo, &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));
-
- // Allocating too much stack isn't a problem, and better to err on the side
- // of caution than smash it into random locations.
- static const unsigned kChildStackSize = 16000;
- PageAllocator allocator;
- uint8_t* stack = reinterpret_cast<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);
-
- ThreadArgument thread_arg;
- thread_arg.handler = this;
- thread_arg.minidump_descriptor = &minidump_descriptor_;
- thread_arg.pid = getpid();
- thread_arg.context = context;
- thread_arg.context_size = sizeof(*context);
-
- // We need to explicitly enable ptrace of parent processes on some
- // kernels, but we need to know the PID of the cloned process before we
- // can do this. Create a pipe here which we can use to block the
- // cloned process after creating it, until we have explicitly enabled ptrace
- if (sys_pipe(fdes) == -1) {
- // Creating the pipe failed. We'll log an error but carry on anyway,
- // as we'll probably still get a useful crash report. All that will happen
- // is the write() and read() calls will fail with EBADF
- static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump "
- "sys_pipe failed:";
- logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1);
- logger::write(strerror(errno), strlen(strerror(errno)));
- logger::write("\n", 1);
-
- // Ensure fdes[0] and fdes[1] are invalid file descriptors.
- fdes[0] = fdes[1] = -1;
- }
-
- const pid_t child = sys_clone(
- ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
- &thread_arg, NULL, NULL, NULL);
- if (child == -1) {
- sys_close(fdes[0]);
- sys_close(fdes[1]);
- return false;
- }
-
- if (child != 0) {
- static const char clonedMsg[] =
- "ExceptionHandler::GenerateDump cloned child ";
- char pidMsg[32];
-
- unsigned int pidLen = my_uint_len(child);
- my_uitos(pidMsg, child, pidLen);
-
- logger::write(clonedMsg, my_strlen(clonedMsg));
- logger::write(pidMsg, pidLen);
- logger::write("\n", 1);
- } else {
- static const char childMsg[] =
- "ExceptionHandler::GenerateDump I'm the child\n";
- logger::write(childMsg, my_strlen(childMsg));
- }
-
- // Allow the child to ptrace us
- sys_prctl(PR_SET_PTRACER, child, 0, 0, 0);
- SendContinueSignalToChild();
- int status;
- const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL));
-
- sys_close(fdes[0]);
- sys_close(fdes[1]);
-
- if (r == -1) {
- static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:";
- logger::write(msg, sizeof(msg) - 1);
- logger::write(strerror(errno), strlen(strerror(errno)));
- logger::write("\n", 1);
- }
-
- bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
- if (callback_)
- success = callback_(minidump_descriptor_, callback_context_, success);
- return success;
-}
-
-// This function runs in a compromised context: see the top of the file.
-void ExceptionHandler::SendContinueSignalToChild() {
- static const char okToContinueMessage = 'a';
- int r;
- r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char)));
- if (r == -1) {
- static const char msg[] = "ExceptionHandler::SendContinueSignalToChild "
- "sys_write failed:";
- logger::write(msg, sizeof(msg) - 1);
- logger::write(strerror(errno), strlen(strerror(errno)));
- logger::write("\n", 1);
- }
-
- const char* msg = "ExceptionHandler::SendContinueSignalToChild sent continue signal to child\n";
- logger::write(msg, my_strlen(msg));
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the cloned process.
-void ExceptionHandler::WaitForContinueSignal() {
- int r;
- char receivedMessage;
-
- const char* waitMsg = "ExceptionHandler::WaitForContinueSignal waiting for continue signal...\n";
- logger::write(waitMsg, my_strlen(waitMsg));
-
- r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char)));
- if (r == -1) {
- static const char msg[] = "ExceptionHandler::WaitForContinueSignal "
- "sys_read failed:";
- logger::write(msg, sizeof(msg) - 1);
- logger::write(strerror(errno), strlen(strerror(errno)));
- logger::write("\n", 1);
- }
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the cloned process.
-bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
- size_t context_size) {
- if (minidump_descriptor_.IsMicrodumpOnConsole()) {
- return google_breakpad::WriteMicrodump(
- crashing_process,
- context,
- context_size,
- mapping_list_,
- *minidump_descriptor_.microdump_extra_info());
- }
- if (minidump_descriptor_.IsFD()) {
- return google_breakpad::WriteMinidump(minidump_descriptor_.fd(),
- minidump_descriptor_.size_limit(),
- crashing_process,
- context,
- context_size,
- mapping_list_,
- app_memory_list_);
- }
- return google_breakpad::WriteMinidump(minidump_descriptor_.path(),
- minidump_descriptor_.size_limit(),
- crashing_process,
- context,
- context_size,
- mapping_list_,
- app_memory_list_);
-}
-
-// static
-bool ExceptionHandler::WriteMinidump(const string& dump_path,
- MinidumpCallback callback,
- void* callback_context) {
- MinidumpDescriptor descriptor(dump_path);
- ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1);
- return eh.WriteMinidump();
-}
-
-// In order to making using EBP to calculate the desired value for ESP
-// a valid operation, ensure that this function is compiled with a
-// frame pointer using the following attribute. This attribute
-// is supported on GCC but not on clang.
-#if defined(__i386__) && defined(__GNUC__) && !defined(__clang__)
-__attribute__((optimize("no-omit-frame-pointer")))
-#endif
-bool ExceptionHandler::WriteMinidump() {
- if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() &&
- !minidump_descriptor_.IsMicrodumpOnConsole()) {
- // Update the path of the minidump so that this can be called multiple times
- // and new files are created for each minidump. This is done before the
- // generation happens, as clients may want to access the MinidumpDescriptor
- // after this call to find the exact path to the minidump file.
- minidump_descriptor_.UpdatePath();
- } else if (minidump_descriptor_.IsFD()) {
- // Reposition the FD to its beginning and resize it to get rid of the
- // previous minidump info.
- lseek(minidump_descriptor_.fd(), 0, SEEK_SET);
- ignore_result(ftruncate(minidump_descriptor_.fd(), 0));
- }
-
- // Allow this process to be dumped.
- sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
-
- CrashContext context;
- int getcontext_result = getcontext(&context.context);
- if (getcontext_result)
- return false;
-
-#if defined(__i386__)
- // In CPUFillFromUContext in minidumpwriter.cc the stack pointer is retrieved
- // from REG_UESP instead of from REG_ESP. REG_UESP is the user stack pointer
- // and it only makes sense when running in kernel mode with a different stack
- // pointer. When WriteMiniDump is called during normal processing REG_UESP is
- // zero which leads to bad minidump files.
- if (!context.context.uc_mcontext.gregs[REG_UESP]) {
- // If REG_UESP is set to REG_ESP then that includes the stack space for the
- // CrashContext object in this function, which is about 128 KB. Since the
- // Linux dumper only records 32 KB of stack this would mean that nothing
- // useful would be recorded. A better option is to set REG_UESP to REG_EBP,
- // perhaps with a small negative offset in case there is any code that
- // objects to them being equal.
- context.context.uc_mcontext.gregs[REG_UESP] =
- context.context.uc_mcontext.gregs[REG_EBP] - 16;
- // The stack saving is based off of REG_ESP so it must be set to match the
- // new REG_UESP.
- context.context.uc_mcontext.gregs[REG_ESP] =
- context.context.uc_mcontext.gregs[REG_UESP];
- }
-#endif
-
-#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__)
- // FPU state is not part of ARM EABI ucontext_t.
- memcpy(&context.float_state, context.context.uc_mcontext.fpregs,
- sizeof(context.float_state));
-#endif
- context.tid = sys_gettid();
-
- // Add an exception stream to the minidump for better reporting.
- memset(&context.siginfo, 0, sizeof(context.siginfo));
- context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED;
-#if defined(__i386__)
- context.siginfo.si_addr =
- reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_EIP]);
-#elif defined(__x86_64__)
- context.siginfo.si_addr =
- reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_RIP]);
-#elif defined(__arm__)
- context.siginfo.si_addr =
- reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc);
-#elif defined(__aarch64__)
- context.siginfo.si_addr =
- reinterpret_cast<void*>(context.context.uc_mcontext.pc);
-#elif defined(__mips__)
- context.siginfo.si_addr =
- reinterpret_cast<void*>(context.context.uc_mcontext.pc);
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
- return GenerateDump(&context);
-}
-
-void ExceptionHandler::AddMappingInfo(const string& name,
- const uint8_t identifier[sizeof(MDGUID)],
- uintptr_t start_address,
- size_t mapping_size,
- size_t file_offset) {
- MappingInfo info;
- info.start_addr = start_address;
- info.size = mapping_size;
- info.offset = file_offset;
- strncpy(info.name, name.c_str(), sizeof(info.name) - 1);
- info.name[sizeof(info.name) - 1] = '\0';
-
- MappingEntry mapping;
- mapping.first = info;
- memcpy(mapping.second, identifier, sizeof(MDGUID));
- mapping_list_.push_back(mapping);
-}
-
-void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
- AppMemoryList::iterator iter =
- std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
- if (iter != app_memory_list_.end()) {
- // Don't allow registering the same pointer twice.
- return;
- }
-
- AppMemory app_memory;
- app_memory.ptr = ptr;
- app_memory.length = length;
- app_memory_list_.push_back(app_memory);
-}
-
-void ExceptionHandler::UnregisterAppMemory(void* ptr) {
- AppMemoryList::iterator iter =
- std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
- if (iter != app_memory_list_.end()) {
- app_memory_list_.erase(iter);
- }
-}
-
-// static
-bool ExceptionHandler::WriteMinidumpForChild(pid_t child,
- pid_t child_blamed_thread,
- const string& dump_path,
- MinidumpCallback callback,
- void* callback_context) {
- // This function is not run in a compromised context.
- MinidumpDescriptor descriptor(dump_path);
- descriptor.UpdatePath();
- if (!google_breakpad::WriteMinidump(descriptor.path(),
- child,
- child_blamed_thread))
- return false;
-
- return callback ? callback(descriptor, callback_context, true) : true;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
deleted file mode 100644
index 846df772f..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
+++ /dev/null
@@ -1,278 +0,0 @@
-// 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_HANDLER_EXCEPTION_HANDLER_H_
-#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
-
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/ucontext.h>
-
-#include <string>
-
-#include "client/linux/crash_generation/crash_generation_client.h"
-#include "client/linux/handler/minidump_descriptor.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "common/scoped_ptr.h"
-#include "common/using_std_string.h"
-#include "google_breakpad/common/minidump_format.h"
-
-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
-// (crash) occurs, you should create an instance early in the execution
-// of your program, and keep it around for the entire time you want to
-// have crash handling active (typically, until shutdown).
-// (NOTE): There should be only be one this kind of exception handler
-// object per process.
-//
-// If you want to write minidumps without installing the exception handler,
-// you can create an ExceptionHandler with install_handler set to false,
-// then call WriteMinidump. You can also use this technique if you want to
-// use different minidump callbacks for different call sites.
-//
-// In either case, a callback function is called when a minidump is written,
-// which receives the full path or file descriptor of the minidump. The
-// caller can collect and write additional application state to that minidump,
-// and launch an external crash-reporting application.
-//
-// Caller should try to make the callbacks as crash-friendly as possible,
-// it should avoid use heap memory allocation as much as possible.
-
-class ExceptionHandler {
- public:
- // A callback function to run before Breakpad performs any substantial
- // processing of an exception. A FilterCallback is called before writing
- // a minidump. |context| is the parameter supplied by the user as
- // callback_context when the handler was created.
- //
- // If a FilterCallback returns true, Breakpad will continue processing,
- // attempting to write a minidump. If a FilterCallback returns false,
- // Breakpad will immediately report the exception as unhandled without
- // writing a minidump, allowing another handler the opportunity to handle it.
- typedef bool (*FilterCallback)(void *context);
-
- // A callback function to run after the minidump has been written.
- // |descriptor| contains the file descriptor or file path containing the
- // minidump. |context| is the parameter supplied by the user as
- // callback_context when the handler was created. |succeeded| indicates
- // whether a minidump file was successfully written.
- //
- // If an exception occurred and the callback returns true, Breakpad will
- // treat the exception as fully-handled, suppressing any other handlers from
- // being notified of the exception. If the callback returns false, Breakpad
- // will treat the exception as unhandled, and allow another handler to handle
- // it. If there are no other handlers, Breakpad will report the exception to
- // the system as unhandled, allowing a debugger or native crash dialog the
- // opportunity to handle the exception. Most callback implementations
- // should normally return the value of |succeeded|, or when they wish to
- // not report an exception of handled, false. Callbacks will rarely want to
- // return true directly (unless |succeeded| is true).
- typedef bool (*MinidumpCallback)(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded);
-
- // In certain cases, a user may wish to handle the generation of the minidump
- // themselves. In this case, they can install a handler callback which is
- // called when a crash has occurred. If this function returns true, no other
- // processing of occurs and the process will shortly be crashed. If this
- // returns false, the normal processing continues.
- typedef bool (*HandlerCallback)(const void* crash_context,
- size_t crash_context_size,
- void* context);
-
- // Creates a new ExceptionHandler instance to handle writing minidumps.
- // Before writing a minidump, the optional |filter| callback will be called.
- // Its return value determines whether or not Breakpad should write a
- // minidump. The minidump content will be written to the file path or file
- // descriptor from |descriptor|, and the optional |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.
- // If |server_fd| is valid, the minidump is generated out-of-process. If it
- // is -1, in-process generation will always be used.
- ExceptionHandler(const MinidumpDescriptor& descriptor,
- FilterCallback filter,
- MinidumpCallback callback,
- void* callback_context,
- bool install_handler,
- const int server_fd);
- ~ExceptionHandler();
-
- const MinidumpDescriptor& minidump_descriptor() const {
- return minidump_descriptor_;
- }
-
- void set_minidump_descriptor(const MinidumpDescriptor& descriptor) {
- minidump_descriptor_ = descriptor;
- }
-
- void set_crash_handler(HandlerCallback callback) {
- crash_handler_ = callback;
- }
-
- void set_crash_generation_client(CrashGenerationClient* client) {
- crash_generation_client_.reset(client);
- }
-
- // Writes a minidump immediately. This can be used to capture the execution
- // state independently of a crash.
- // Returns true on success.
- // If the ExceptionHandler has been created with a path, a new file is
- // generated for each minidump. The file path can be retrieved in the
- // MinidumpDescriptor passed to the MinidumpCallback or by accessing the
- // MinidumpDescriptor directly from the ExceptionHandler (with
- // minidump_descriptor()).
- // If the ExceptionHandler has been created with a file descriptor, the file
- // descriptor is repositioned to its beginning and the previous generated
- // minidump is overwritten.
- // Note that this method is not supposed to be called from a compromised
- // context as it uses the heap.
- bool WriteMinidump();
-
- // Convenience form of WriteMinidump which does not require an
- // ExceptionHandler instance.
- static bool WriteMinidump(const string& dump_path,
- MinidumpCallback callback,
- void* callback_context);
-
- // Write a minidump of |child| immediately. This can be used to
- // capture the execution state of |child| independently of a crash.
- // Pass a meaningful |child_blamed_thread| to make that thread in
- // the child process the one from which a crash signature is
- // extracted.
- //
- // WARNING: the return of this function *must* happen before
- // the code that will eventually reap |child| executes.
- // Otherwise there's a pernicious race condition in which |child|
- // exits, is reaped, another process created with its pid, then that
- // new process dumped.
- static bool WriteMinidumpForChild(pid_t child,
- pid_t child_blamed_thread,
- const string& dump_path,
- MinidumpCallback callback,
- void* callback_context);
-
- // This structure is passed to minidump_writer.h:WriteMinidump via an opaque
- // blob. It shouldn't be needed in any user code.
- struct CrashContext {
- siginfo_t siginfo;
- pid_t tid; // the crashing thread.
- ucontext_t context;
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- // #ifdef this out because FP state is not part of user ABI for Linux ARM.
- // In case of MIPS Linux FP state is already part of struct
- // ucontext so 'float_state' is not required.
- fpstate_t float_state;
-#endif
- };
-
- // Returns whether out-of-process dump generation is used or not.
- bool IsOutOfProcess() const {
- return crash_generation_client_.get() != NULL;
- }
-
- // Add information about a memory mapping. This can be used if
- // a custom library loader is used that maps things in a way
- // that the linux dumper can't handle by reading the maps file.
- void AddMappingInfo(const string& name,
- const uint8_t identifier[sizeof(MDGUID)],
- uintptr_t start_address,
- size_t mapping_size,
- size_t file_offset);
-
- // Register a block of memory of length bytes starting at address ptr
- // to be copied to the minidump when a crash happens.
- void RegisterAppMemory(void* ptr, size_t length);
-
- // Unregister a block of memory that was registered with RegisterAppMemory.
- void UnregisterAppMemory(void* ptr);
-
- // Force signal handling for the specified signal.
- bool SimulateSignalDelivery(int sig);
-
- // Report a crash signal from an SA_SIGINFO signal handler.
- bool HandleSignal(int sig, siginfo_t* info, void* uc);
-
- private:
- // Save the old signal handlers and install new ones.
- static bool InstallHandlersLocked();
- // Restore the old signal handlers.
- static void RestoreHandlersLocked();
-
- void PreresolveSymbols();
- bool GenerateDump(CrashContext *context);
- void SendContinueSignalToChild();
- void WaitForContinueSignal();
-
- static void SignalHandler(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_;
-
- MinidumpDescriptor minidump_descriptor_;
-
- // Must be volatile. The compiler is unaware of the code which runs in
- // the signal handler which reads this variable. Without volatile the
- // compiler is free to optimise away writes to this variable which it
- // believes are never read.
- volatile HandlerCallback crash_handler_;
-
- // We need to explicitly enable ptrace of parent processes on some
- // kernels, but we need to know the PID of the cloned process before we
- // can do this. We create a pipe which we can use to block the
- // cloned process after creating it, until we have explicitly enabled
- // ptrace. This is used to store the file descriptors for the pipe
- int fdes[2];
-
- // Callers can add extra info about mappings for cases where the
- // dumper code cannot extract enough information from /proc/<pid>/maps.
- MappingList mapping_list_;
-
- // Callers can request additional memory regions to be included in
- // the dump.
- AppMemoryList app_memory_list_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
diff --git 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
deleted file mode 100644
index 17d84cf7b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc
+++ /dev/null
@@ -1,1179 +0,0 @@
-// 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 <stdint.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#if defined(__mips__)
-#include <sys/cachectl.h>
-#endif
-
-#include <string>
-
-#include "breakpad_googletest_includes.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/ignore_ret.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/tests/auto_tempdir.h"
-#include "common/using_std_string.h"
-#include "third_party/lss/linux_syscall_support.h"
-#include "google_breakpad/processor/minidump.h"
-
-using namespace google_breakpad;
-
-namespace {
-
-// Flush the instruction cache for a given memory range.
-// Only required on ARM and mips.
-void FlushInstructionCache(const char* memory, uint32_t memory_size) {
-#if defined(__arm__)
- long begin = reinterpret_cast<long>(memory);
- long end = begin + static_cast<long>(memory_size);
-# if defined(__ANDROID__)
- // Provided by Android's <unistd.h>
- cacheflush(begin, end, 0);
-# elif defined(__linux__)
- // GLibc/ARM doesn't provide a wrapper for it, do a direct syscall.
-# ifndef __ARM_NR_cacheflush
-# define __ARM_NR_cacheflush 0xf0002
-# endif
- syscall(__ARM_NR_cacheflush, begin, end, 0);
-# else
-# error "Your operating system is not supported yet"
-# endif
-#elif defined(__mips__)
-# if defined(__ANDROID__)
- // Provided by Android's <unistd.h>
- long begin = reinterpret_cast<long>(memory);
- long end = begin + static_cast<long>(memory_size);
-#if _MIPS_SIM == _ABIO32
- cacheflush(begin, end, 0);
-#else
- syscall(__NR_cacheflush, begin, end, ICACHE);
-#endif
-# elif defined(__linux__)
- // See http://www.linux-mips.org/wiki/Cacheflush_Syscall.
- cacheflush(const_cast<char*>(memory), memory_size, ICACHE);
-# else
-# error "Your operating system is not supported yet"
-# endif
-#endif
-}
-
-void sigchld_handler(int signo) { }
-
-int CreateTMPFile(const string& dir, string* path) {
- string file = dir + "/exception-handler-unittest.XXXXXX";
- const char* c_file = file.c_str();
- // Copy that string, mkstemp needs a C string it can modify.
- char* c_path = strdup(c_file);
- const int fd = mkstemp(c_path);
- if (fd >= 0)
- *path = c_path;
- free(c_path);
- return fd;
-}
-
-class ExceptionHandlerTest : public ::testing::Test {
- protected:
- void SetUp() {
- // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = sigchld_handler;
- ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
- }
-
- void TearDown() {
- sigaction(SIGCHLD, &old_action, NULL);
- }
-
- struct sigaction old_action;
-};
-
-
-void WaitForProcessToTerminate(pid_t process_id, int expected_status) {
- int status;
- ASSERT_NE(HANDLE_EINTR(waitpid(process_id, &status, 0)), -1);
- ASSERT_TRUE(WIFSIGNALED(status));
- ASSERT_EQ(expected_status, WTERMSIG(status));
-}
-
-// Reads the minidump path sent over the pipe |fd| and sets it in |path|.
-void ReadMinidumpPathFromPipe(int fd, string* path) {
- struct pollfd pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = fd;
- pfd.events = POLLIN | POLLERR;
-
- const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
- ASSERT_EQ(1, r);
- ASSERT_TRUE(pfd.revents & POLLIN);
-
- int32_t len;
- ASSERT_EQ(static_cast<ssize_t>(sizeof(len)), read(fd, &len, sizeof(len)));
- ASSERT_LT(len, 2048);
- char* filename = static_cast<char*>(malloc(len + 1));
- ASSERT_EQ(len, read(fd, filename, len));
- filename[len] = 0;
- close(fd);
- *path = filename;
- free(filename);
-}
-
-} // namespace
-
-TEST(ExceptionHandlerTest, SimpleWithPath) {
- AutoTempDir temp_dir;
- ExceptionHandler handler(
- MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
- EXPECT_EQ(temp_dir.path(), handler.minidump_descriptor().directory());
- string temp_subdir = temp_dir.path() + "/subdir";
- handler.set_minidump_descriptor(MinidumpDescriptor(temp_subdir));
- EXPECT_EQ(temp_subdir, handler.minidump_descriptor().directory());
-}
-
-TEST(ExceptionHandlerTest, SimpleWithFD) {
- AutoTempDir temp_dir;
- string path;
- const int fd = CreateTMPFile(temp_dir.path(), &path);
- ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1);
- close(fd);
-}
-
-static bool DoneCallback(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded) {
- if (!succeeded)
- return false;
-
- if (!descriptor.IsFD()) {
- int fd = reinterpret_cast<intptr_t>(context);
- uint32_t len = 0;
- len = my_strlen(descriptor.path());
- IGNORE_RET(HANDLE_EINTR(sys_write(fd, &len, sizeof(len))));
- IGNORE_RET(HANDLE_EINTR(sys_write(fd, descriptor.path(), len)));
- }
- return true;
-}
-
-#ifndef ADDRESS_SANITIZER
-
-// This is a replacement for "*reinterpret_cast<volatile int*>(NULL) = 0;"
-// It is needed because GCC is allowed to assume that the program will
-// not execute any undefined behavior (UB) operation. Further, when GCC
-// observes that UB statement is reached, it can assume that all statements
-// leading to the UB one are never executed either, and can completely
-// optimize them out. In the case of ExceptionHandlerTest::ExternalDumper,
-// GCC-4.9 optimized out the entire set up of ExceptionHandler, causing
-// test failure.
-volatile int *p_null; // external linkage, so GCC can't tell that it
- // remains NULL. Volatile just for a good measure.
-static void DoNullPointerDereference() {
- *p_null = 1;
-}
-
-void ChildCrash(bool use_fd) {
- AutoTempDir temp_dir;
- int fds[2] = {0};
- int minidump_fd = -1;
- string minidump_path;
- if (use_fd) {
- minidump_fd = CreateTMPFile(temp_dir.path(), &minidump_path);
- } else {
- ASSERT_NE(pipe(fds), -1);
- }
-
- const pid_t child = fork();
- if (child == 0) {
- {
- google_breakpad::scoped_ptr<ExceptionHandler> handler;
- if (use_fd) {
- handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd),
- NULL, NULL, NULL, true, -1));
- } else {
- close(fds[0]); // Close the reading end.
- void* fd_param = reinterpret_cast<void*>(fds[1]);
- handler.reset(new ExceptionHandler(MinidumpDescriptor(temp_dir.path()),
- NULL, DoneCallback, fd_param,
- true, -1));
- }
- // Crash with the exception handler in scope.
- DoNullPointerDereference();
- }
- }
- if (!use_fd)
- close(fds[1]); // Close the writting end.
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-
- if (!use_fd)
- ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
-
- struct stat st;
- ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
- unlink(minidump_path.c_str());
-}
-
-TEST(ExceptionHandlerTest, ChildCrashWithPath) {
- ASSERT_NO_FATAL_FAILURE(ChildCrash(false));
-}
-
-TEST(ExceptionHandlerTest, ChildCrashWithFD) {
- ASSERT_NO_FATAL_FAILURE(ChildCrash(true));
-}
-
-static bool DoneCallbackReturnFalse(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded) {
- return false;
-}
-
-static bool DoneCallbackReturnTrue(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded) {
- return true;
-}
-
-static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded) {
- raise(SIGKILL);
- return true;
-}
-
-static bool FilterCallbackReturnFalse(void* context) {
- return false;
-}
-
-static bool FilterCallbackReturnTrue(void* context) {
- return true;
-}
-
-// SIGKILL cannot be blocked and a handler cannot be installed for it. In the
-// following tests, if the child dies with signal SIGKILL, then the signal was
-// redelivered to this handler. If the child dies with SIGSEGV then it wasn't.
-static void RaiseSIGKILL(int sig) {
- raise(SIGKILL);
-}
-
-static bool InstallRaiseSIGKILL() {
- struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = RaiseSIGKILL;
- return sigaction(SIGSEGV, &sa, NULL) != -1;
-}
-
-static void CrashWithCallbacks(ExceptionHandler::FilterCallback filter,
- ExceptionHandler::MinidumpCallback done,
- string path) {
- ExceptionHandler handler(
- MinidumpDescriptor(path), filter, done, NULL, true, -1);
- // Crash with the exception handler in scope.
- DoNullPointerDereference();
-}
-
-TEST(ExceptionHandlerTest, RedeliveryOnFilterCallbackFalse) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ASSERT_TRUE(InstallRaiseSIGKILL());
- CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
- }
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-TEST(ExceptionHandlerTest, RedeliveryOnDoneCallbackFalse) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ASSERT_TRUE(InstallRaiseSIGKILL());
- CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
- }
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-TEST(ExceptionHandlerTest, NoRedeliveryOnDoneCallbackTrue) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ASSERT_TRUE(InstallRaiseSIGKILL());
- CrashWithCallbacks(NULL, DoneCallbackReturnTrue, temp_dir.path());
- }
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-}
-
-TEST(ExceptionHandlerTest, NoRedeliveryOnFilterCallbackTrue) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ASSERT_TRUE(InstallRaiseSIGKILL());
- CrashWithCallbacks(FilterCallbackReturnTrue, NULL, temp_dir.path());
- }
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-}
-
-TEST(ExceptionHandlerTest, RedeliveryToDefaultHandler) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
- }
-
- // As RaiseSIGKILL wasn't installed, the redelivery should just kill the child
- // with SIGSEGV.
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-}
-
-// Check that saving and restoring the signal handler with 'signal'
-// instead of 'sigaction' doesn't make the Breakpad signal handler
-// crash. See comments in ExceptionHandler::SignalHandler for full
-// details.
-TEST(ExceptionHandlerTest, RedeliveryOnBadSignalHandlerFlag) {
- AutoTempDir temp_dir;
- const pid_t child = fork();
- if (child == 0) {
- // Install the RaiseSIGKILL handler for SIGSEGV.
- ASSERT_TRUE(InstallRaiseSIGKILL());
-
- // Create a new exception handler, this installs a new SIGSEGV
- // handler, after saving the old one.
- ExceptionHandler handler(
- MinidumpDescriptor(temp_dir.path()), NULL,
- DoneCallbackReturnFalse, NULL, true, -1);
-
- // Install the default SIGSEGV handler, saving the current one.
- // Then re-install the current one with 'signal', this loses the
- // SA_SIGINFO flag associated with the Breakpad handler.
- sighandler_t old_handler = signal(SIGSEGV, SIG_DFL);
- ASSERT_NE(reinterpret_cast<void*>(old_handler),
- reinterpret_cast<void*>(SIG_ERR));
- ASSERT_NE(reinterpret_cast<void*>(signal(SIGSEGV, old_handler)),
- reinterpret_cast<void*>(SIG_ERR));
-
- // Crash with the exception handler in scope.
- DoNullPointerDereference();
- }
- // SIGKILL means Breakpad's signal handler didn't crash.
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-TEST(ExceptionHandlerTest, StackedHandlersDeliveredToTop) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
- NULL,
- NULL,
- NULL,
- true,
- -1);
- CrashWithCallbacks(NULL, DoneCallbackRaiseSIGKILL, temp_dir.path());
- }
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-TEST(ExceptionHandlerTest, StackedHandlersNotDeliveredToBottom) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
- NULL,
- DoneCallbackRaiseSIGKILL,
- NULL,
- true,
- -1);
- CrashWithCallbacks(NULL, NULL, temp_dir.path());
- }
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-}
-
-TEST(ExceptionHandlerTest, StackedHandlersFilteredToBottom) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
- NULL,
- DoneCallbackRaiseSIGKILL,
- NULL,
- true,
- -1);
- CrashWithCallbacks(FilterCallbackReturnFalse, NULL, temp_dir.path());
- }
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-TEST(ExceptionHandlerTest, StackedHandlersUnhandledToBottom) {
- AutoTempDir temp_dir;
-
- const pid_t child = fork();
- if (child == 0) {
- ExceptionHandler bottom(MinidumpDescriptor(temp_dir.path()),
- NULL,
- DoneCallbackRaiseSIGKILL,
- NULL,
- true,
- -1);
- CrashWithCallbacks(NULL, DoneCallbackReturnFalse, temp_dir.path());
- }
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGKILL));
-}
-
-#endif // !ADDRESS_SANITIZER
-
-const unsigned char kIllegalInstruction[] = {
-#if defined(__mips__)
- // mfc2 zero,Impl - usually illegal in userspace.
- 0x48, 0x00, 0x00, 0x48
-#else
- // This crashes with SIGILL on x86/x86-64/arm.
- 0xff, 0xff, 0xff, 0xff
-#endif
-};
-
-// Test that memory around the instruction pointer is written
-// to the dump as a MinidumpMemoryRegion.
-TEST(ExceptionHandlerTest, InstructionPointerMemory) {
- AutoTempDir temp_dir;
- int fds[2];
- ASSERT_NE(pipe(fds), -1);
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const uint32_t kMemorySize = 256; // bytes
- const int kOffset = kMemorySize / 2;
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
- DoneCallback, reinterpret_cast<void*>(fds[1]),
- true, -1);
- // Get some executable memory.
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- kMemorySize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0));
- if (!memory)
- exit(0);
-
- // Write some instructions that will crash. Put them in the middle
- // of the block of memory, because the minidump should contain 128
- // bytes on either side of the instruction pointer.
- memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
- FlushInstructionCache(memory, kMemorySize);
-
- // Now execute the instructions, which should crash.
- typedef void (*void_function)(void);
- void_function memory_function =
- reinterpret_cast<void_function>(memory + kOffset);
- memory_function();
- }
- close(fds[1]);
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
-
- string minidump_path;
- ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
-
- struct stat st;
- ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- // Read the minidump. Locate the exception record and the
- // memory list, and then ensure that there is a memory region
- // in the memory list that covers the instruction pointer from
- // the exception record.
- Minidump minidump(minidump_path);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpException* exception = minidump.GetException();
- MinidumpMemoryList* memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(exception);
- ASSERT_TRUE(memory_list);
- ASSERT_LT(0U, memory_list->region_count());
-
- MinidumpContext* context = exception->GetContext();
- ASSERT_TRUE(context);
-
- uint64_t instruction_pointer;
- ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
-
- MinidumpMemoryRegion* region =
- memory_list->GetMemoryRegionForAddress(instruction_pointer);
- ASSERT_TRUE(region);
-
- EXPECT_EQ(kMemorySize, region->GetSize());
- const uint8_t* bytes = region->GetMemory();
- ASSERT_TRUE(bytes);
-
- uint8_t prefix_bytes[kOffset];
- uint8_t suffix_bytes[kMemorySize - kOffset - sizeof(kIllegalInstruction)];
- memset(prefix_bytes, 0, sizeof(prefix_bytes));
- memset(suffix_bytes, 0, sizeof(suffix_bytes));
- EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
- EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
- sizeof(kIllegalInstruction)) == 0);
- EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
- suffix_bytes, sizeof(suffix_bytes)) == 0);
-
- unlink(minidump_path.c_str());
-}
-
-// Test that the memory region around the instruction pointer is
-// bounded correctly on the low end.
-TEST(ExceptionHandlerTest, InstructionPointerMemoryMinBound) {
- AutoTempDir temp_dir;
- int fds[2];
- ASSERT_NE(pipe(fds), -1);
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const uint32_t kMemorySize = 256; // bytes
- const int kOffset = 0;
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
- DoneCallback, reinterpret_cast<void*>(fds[1]),
- true, -1);
- // Get some executable memory.
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- kMemorySize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0));
- if (!memory)
- exit(0);
-
- // Write some instructions that will crash. Put them in the middle
- // of the block of memory, because the minidump should contain 128
- // bytes on either side of the instruction pointer.
- memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
- FlushInstructionCache(memory, kMemorySize);
-
- // Now execute the instructions, which should crash.
- typedef void (*void_function)(void);
- void_function memory_function =
- reinterpret_cast<void_function>(memory + kOffset);
- memory_function();
- }
- close(fds[1]);
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
-
- string minidump_path;
- ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
-
- struct stat st;
- ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- // Read the minidump. Locate the exception record and the
- // memory list, and then ensure that there is a memory region
- // in the memory list that covers the instruction pointer from
- // the exception record.
- Minidump minidump(minidump_path);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpException* exception = minidump.GetException();
- MinidumpMemoryList* memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(exception);
- ASSERT_TRUE(memory_list);
- ASSERT_LT(0U, memory_list->region_count());
-
- MinidumpContext* context = exception->GetContext();
- ASSERT_TRUE(context);
-
- uint64_t instruction_pointer;
- ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
-
- MinidumpMemoryRegion* region =
- memory_list->GetMemoryRegionForAddress(instruction_pointer);
- ASSERT_TRUE(region);
-
- EXPECT_EQ(kMemorySize / 2, region->GetSize());
- const uint8_t* bytes = region->GetMemory();
- ASSERT_TRUE(bytes);
-
- uint8_t suffix_bytes[kMemorySize / 2 - sizeof(kIllegalInstruction)];
- memset(suffix_bytes, 0, sizeof(suffix_bytes));
- EXPECT_TRUE(memcmp(bytes + kOffset, kIllegalInstruction,
- sizeof(kIllegalInstruction)) == 0);
- EXPECT_TRUE(memcmp(bytes + kOffset + sizeof(kIllegalInstruction),
- suffix_bytes, sizeof(suffix_bytes)) == 0);
- unlink(minidump_path.c_str());
-}
-
-// Test that the memory region around the instruction pointer is
-// bounded correctly on the high end.
-TEST(ExceptionHandlerTest, InstructionPointerMemoryMaxBound) {
- AutoTempDir temp_dir;
- int fds[2];
- ASSERT_NE(pipe(fds), -1);
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- // Use 4k here because the OS will hand out a single page even
- // if a smaller size is requested, and this test wants to
- // test the upper bound of the memory range.
- const uint32_t kMemorySize = 4096; // bytes
- const int kOffset = kMemorySize - sizeof(kIllegalInstruction);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
- DoneCallback, reinterpret_cast<void*>(fds[1]),
- true, -1);
- // Get some executable memory.
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- kMemorySize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0));
- if (!memory)
- exit(0);
-
- // Write some instructions that will crash. Put them in the middle
- // of the block of memory, because the minidump should contain 128
- // bytes on either side of the instruction pointer.
- memcpy(memory + kOffset, kIllegalInstruction, sizeof(kIllegalInstruction));
- FlushInstructionCache(memory, kMemorySize);
-
- // Now execute the instructions, which should crash.
- typedef void (*void_function)(void);
- void_function memory_function =
- reinterpret_cast<void_function>(memory + kOffset);
- memory_function();
- }
- close(fds[1]);
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGILL));
-
- string minidump_path;
- ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
-
- struct stat st;
- ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- // Read the minidump. Locate the exception record and the memory list, and
- // then ensure that there is a memory region in the memory list that covers
- // the instruction pointer from the exception record.
- Minidump minidump(minidump_path);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpException* exception = minidump.GetException();
- MinidumpMemoryList* memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(exception);
- ASSERT_TRUE(memory_list);
- ASSERT_LT(0U, memory_list->region_count());
-
- MinidumpContext* context = exception->GetContext();
- ASSERT_TRUE(context);
-
- uint64_t instruction_pointer;
- ASSERT_TRUE(context->GetInstructionPointer(&instruction_pointer));
-
- MinidumpMemoryRegion* region =
- memory_list->GetMemoryRegionForAddress(instruction_pointer);
- ASSERT_TRUE(region);
-
- const size_t kPrefixSize = 128; // bytes
- EXPECT_EQ(kPrefixSize + sizeof(kIllegalInstruction), region->GetSize());
- const uint8_t* bytes = region->GetMemory();
- ASSERT_TRUE(bytes);
-
- uint8_t prefix_bytes[kPrefixSize];
- memset(prefix_bytes, 0, sizeof(prefix_bytes));
- EXPECT_TRUE(memcmp(bytes, prefix_bytes, sizeof(prefix_bytes)) == 0);
- EXPECT_TRUE(memcmp(bytes + kPrefixSize,
- kIllegalInstruction, sizeof(kIllegalInstruction)) == 0);
-
- unlink(minidump_path.c_str());
-}
-
-#ifndef ADDRESS_SANITIZER
-
-// Ensure that an extra memory block doesn't get added when the instruction
-// pointer is not in mapped memory.
-TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
- AutoTempDir temp_dir;
- int fds[2];
- ASSERT_NE(pipe(fds), -1);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL,
- DoneCallback, reinterpret_cast<void*>(fds[1]),
- true, -1);
- // Try calling a NULL pointer.
- typedef void (*void_function)(void);
- // Volatile markings are needed to keep Clang from generating invalid
- // opcodes. See http://crbug.com/498354 for details.
- volatile void_function memory_function =
- reinterpret_cast<void_function>(NULL);
- memory_function();
- // not reached
- exit(1);
- }
- close(fds[1]);
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-
- string minidump_path;
- ASSERT_NO_FATAL_FAILURE(ReadMinidumpPathFromPipe(fds[0], &minidump_path));
-
- struct stat st;
- ASSERT_EQ(0, stat(minidump_path.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- // Read the minidump. Locate the exception record and the
- // memory list, and then ensure that there is a memory region
- // in the memory list that covers the instruction pointer from
- // the exception record.
- Minidump minidump(minidump_path);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpException* exception = minidump.GetException();
- MinidumpMemoryList* memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(exception);
- ASSERT_TRUE(memory_list);
- ASSERT_EQ(static_cast<unsigned int>(1), memory_list->region_count());
-
- unlink(minidump_path.c_str());
-}
-
-#endif // !ADDRESS_SANITIZER
-
-// Test that anonymous memory maps can be annotated with names and IDs.
-TEST(ExceptionHandlerTest, ModuleInfo) {
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
- const char* kMemoryName = "a fake module";
- const uint8_t kModuleGUID[sizeof(MDGUID)] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
- };
- const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
-
- // Get some memory.
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- kMemorySize,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0));
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
-
- AutoTempDir temp_dir;
- ExceptionHandler handler(
- MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
-
- // Add info about the anonymous memory mapping.
- handler.AddMappingInfo(kMemoryName,
- kModuleGUID,
- kMemoryAddress,
- kMemorySize,
- 0);
- ASSERT_TRUE(handler.WriteMinidump());
-
- const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
- // Read the minidump. Load the module list, and ensure that the mmap'ed
- // |memory| is listed with the given module name and debug ID.
- Minidump minidump(minidump_desc.path());
- ASSERT_TRUE(minidump.Read());
-
- MinidumpModuleList* module_list = minidump.GetModuleList();
- ASSERT_TRUE(module_list);
- const MinidumpModule* module =
- module_list->GetModuleForAddress(kMemoryAddress);
- ASSERT_TRUE(module);
-
- EXPECT_EQ(kMemoryAddress, module->base_address());
- EXPECT_EQ(kMemorySize, module->size());
- EXPECT_EQ(kMemoryName, module->code_file());
- EXPECT_EQ(module_identifier, module->debug_identifier());
-
- unlink(minidump_desc.path());
-}
-
-#ifndef ADDRESS_SANITIZER
-
-static const unsigned kControlMsgSize =
- CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
-
-static bool
-CrashHandler(const void* crash_context, size_t crash_context_size,
- void* context) {
- const int fd = (intptr_t) context;
- int fds[2];
- if (pipe(fds) == -1) {
- // There doesn't seem to be any way to reliably handle
- // this failure without the parent process hanging
- // At least make sure that this process doesn't access
- // unexpected file descriptors
- fds[0] = -1;
- fds[1] = -1;
- }
- struct kernel_msghdr msg = {0};
- struct kernel_iovec iov;
- iov.iov_base = const_cast<void*>(crash_context);
- iov.iov_len = crash_context_size;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- char cmsg[kControlMsgSize];
- 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];
- hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
- hdr->cmsg_level = SOL_SOCKET;
- hdr->cmsg_type = SCM_CREDENTIALS;
- hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
- struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
- cred->uid = getuid();
- cred->gid = getgid();
- cred->pid = getpid();
-
- ssize_t ret = HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
- sys_close(fds[1]);
- if (ret <= 0)
- return false;
-
- char b;
- IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1)));
-
- return true;
-}
-
-TEST(ExceptionHandlerTest, ExternalDumper) {
- int fds[2];
- ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
- static const int on = 1;
- setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[0]);
- ExceptionHandler handler(MinidumpDescriptor("/tmp1"), NULL, NULL,
- reinterpret_cast<void*>(fds[1]), true, -1);
- handler.set_crash_handler(CrashHandler);
- DoNullPointerDereference();
- }
- close(fds[1]);
- struct msghdr msg = {0};
- struct iovec iov;
- static const unsigned kCrashContextSize =
- sizeof(ExceptionHandler::CrashContext);
- char context[kCrashContextSize];
- char control[kControlMsgSize];
- iov.iov_base = context;
- iov.iov_len = kCrashContextSize;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = control;
- msg.msg_controllen = kControlMsgSize;
-
- const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
- ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n);
- ASSERT_EQ(kControlMsgSize, msg.msg_controllen);
- ASSERT_EQ(static_cast<__typeof__(msg.msg_flags)>(0), msg.msg_flags);
- ASSERT_EQ(0, close(fds[0]));
-
- 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_EQ(sizeof(int), len);
- signal_fd = *(reinterpret_cast<int*>(CMSG_DATA(hdr)));
- } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
- const struct ucred *cred =
- reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
- crashing_pid = cred->pid;
- }
- }
-
- ASSERT_NE(crashing_pid, -1);
- ASSERT_NE(signal_fd, -1);
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + "/exception-handler-unittest";
- ASSERT_TRUE(WriteMinidump(templ.c_str(), crashing_pid, context,
- kCrashContextSize));
- static const char b = 0;
- ASSERT_EQ(1, (HANDLE_EINTR(write(signal_fd, &b, 1))));
- ASSERT_EQ(0, close(signal_fd));
-
- ASSERT_NO_FATAL_FAILURE(WaitForProcessToTerminate(child, SIGSEGV));
-
- struct stat st;
- ASSERT_EQ(0, stat(templ.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
- unlink(templ.c_str());
-}
-
-#endif // !ADDRESS_SANITIZER
-
-TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) {
- AutoTempDir temp_dir;
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
- NULL, false, -1);
- ASSERT_TRUE(handler.WriteMinidump());
-
- string minidump_path = handler.minidump_descriptor().path();
-
- // Read the minidump and check the exception stream.
- Minidump minidump(minidump_path);
- ASSERT_TRUE(minidump.Read());
- MinidumpException* exception = minidump.GetException();
- ASSERT_TRUE(exception);
- const MDRawExceptionStream* raw = exception->exception();
- ASSERT_TRUE(raw);
- EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
- raw->exception_record.exception_code);
-}
-
-TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) {
- AutoTempDir temp_dir;
- string path;
- const int fd = CreateTMPFile(temp_dir.path(), &path);
- ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1);
- ASSERT_TRUE(handler.WriteMinidump());
- // Check by the size of the data written to the FD that a minidump was
- // generated.
- off_t size = lseek(fd, 0, SEEK_CUR);
- ASSERT_GT(size, 0);
-
- // Generate another minidump.
- ASSERT_TRUE(handler.WriteMinidump());
- size = lseek(fd, 0, SEEK_CUR);
- ASSERT_GT(size, 0);
-}
-
-TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
- AutoTempDir temp_dir;
- ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
- NULL, false, -1);
- ASSERT_TRUE(handler.WriteMinidump());
-
- const MinidumpDescriptor& minidump_1 = handler.minidump_descriptor();
- struct stat st;
- ASSERT_EQ(0, stat(minidump_1.path(), &st));
- ASSERT_GT(st.st_size, 0);
- string minidump_1_path(minidump_1.path());
- // Check it is a valid minidump.
- Minidump minidump1(minidump_1_path);
- ASSERT_TRUE(minidump1.Read());
- unlink(minidump_1.path());
-
- // Generate another minidump, it should go to a different file.
- ASSERT_TRUE(handler.WriteMinidump());
- const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor();
- ASSERT_EQ(0, stat(minidump_2.path(), &st));
- ASSERT_GT(st.st_size, 0);
- string minidump_2_path(minidump_2.path());
- // Check it is a valid minidump.
- Minidump minidump2(minidump_2_path);
- ASSERT_TRUE(minidump2.Read());
- unlink(minidump_2.path());
-
- // 2 distinct files should be produced.
- ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str());
-}
-
-// Test that an additional memory region can be added to the minidump.
-TEST(ExceptionHandlerTest, AdditionalMemory) {
- const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
-
- // Get some heap memory.
- uint8_t* memory = new uint8_t[kMemorySize];
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
-
- // Stick some data into the memory so the contents can be verified.
- for (uint32_t i = 0; i < kMemorySize; ++i) {
- memory[i] = i % 255;
- }
-
- AutoTempDir temp_dir;
- ExceptionHandler handler(
- MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
-
- // Add the memory region to the list of memory to be included.
- handler.RegisterAppMemory(memory, kMemorySize);
- handler.WriteMinidump();
-
- const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
-
- // Read the minidump. Ensure that the memory region is present
- Minidump minidump(minidump_desc.path());
- ASSERT_TRUE(minidump.Read());
-
- MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(dump_memory_list);
- const MinidumpMemoryRegion* region =
- dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
- ASSERT_TRUE(region);
-
- EXPECT_EQ(kMemoryAddress, region->GetBase());
- EXPECT_EQ(kMemorySize, region->GetSize());
-
- // Verify memory contents.
- EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
-
- delete[] memory;
-}
-
-// Test that a memory region that was previously registered
-// can be unregistered.
-TEST(ExceptionHandlerTest, AdditionalMemoryRemove) {
- const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
-
- // Get some heap memory.
- uint8_t* memory = new uint8_t[kMemorySize];
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
-
- AutoTempDir temp_dir;
- ExceptionHandler handler(
- MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
-
- // Add the memory region to the list of memory to be included.
- handler.RegisterAppMemory(memory, kMemorySize);
-
- // ...and then remove it
- handler.UnregisterAppMemory(memory);
- handler.WriteMinidump();
-
- const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
-
- // Read the minidump. Ensure that the memory region is not present.
- Minidump minidump(minidump_desc.path());
- ASSERT_TRUE(minidump.Read());
-
- MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(dump_memory_list);
- const MinidumpMemoryRegion* region =
- dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
- EXPECT_FALSE(region);
-
- delete[] memory;
-}
-
-static bool SimpleCallback(const MinidumpDescriptor& descriptor,
- void* context,
- bool succeeded) {
- string* filename = reinterpret_cast<string*>(context);
- *filename = descriptor.path();
- return true;
-}
-
-TEST(ExceptionHandlerTest, WriteMinidumpForChild) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- AutoTempDir temp_dir;
- string minidump_filename;
- ASSERT_TRUE(
- ExceptionHandler::WriteMinidumpForChild(child, child,
- temp_dir.path(), SimpleCallback,
- (void*)&minidump_filename));
-
- Minidump minidump(minidump_filename);
- ASSERT_TRUE(minidump.Read());
- // Check that the crashing thread is the main thread of |child|
- MinidumpException* exception = minidump.GetException();
- ASSERT_TRUE(exception);
- uint32_t thread_id;
- ASSERT_TRUE(exception->GetThreadID(&thread_id));
- EXPECT_EQ(child, static_cast<int32_t>(thread_id));
-
- const MDRawExceptionStream* raw = exception->exception();
- ASSERT_TRUE(raw);
- EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
- raw->exception_record.exception_code);
-
- close(fds[1]);
- unlink(minidump_filename.c_str());
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/microdump_extra_info.h b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/microdump_extra_info.h
deleted file mode 100644
index bf01f0c7b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/microdump_extra_info.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2015 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_HANDLER_MICRODUMP_EXTRA_INFO_H_
-#define CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
-
-namespace google_breakpad {
-
-struct MicrodumpExtraInfo {
- // Strings pointed to by this struct are not copied, and are
- // expected to remain valid for the lifetime of the process.
- const char* build_fingerprint;
- const char* product_info;
- const char* gpu_fingerprint;
- const char* process_type;
-
- MicrodumpExtraInfo()
- : build_fingerprint(NULL),
- product_info(NULL),
- gpu_fingerprint(NULL),
- process_type(NULL) {}
-};
-
-}
-
-#endif // CLIENT_LINUX_HANDLER_MICRODUMP_EXTRA_INFO_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.cc
deleted file mode 100644
index ce09153dd..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright (c) 2012 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 <stdio.h>
-
-#include "client/linux/handler/minidump_descriptor.h"
-
-#include "common/linux/guid_creator.h"
-
-namespace google_breakpad {
-
-//static
-const MinidumpDescriptor::MicrodumpOnConsole
- MinidumpDescriptor::kMicrodumpOnConsole = {};
-
-MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor)
- : mode_(descriptor.mode_),
- fd_(descriptor.fd_),
- directory_(descriptor.directory_),
- c_path_(NULL),
- size_limit_(descriptor.size_limit_),
- microdump_extra_info_(descriptor.microdump_extra_info_) {
- // The copy constructor is not allowed to be called on a MinidumpDescriptor
- // with a valid path_, as getting its c_path_ would require the heap which
- // can cause problems in compromised environments.
- assert(descriptor.path_.empty());
-}
-
-MinidumpDescriptor& MinidumpDescriptor::operator=(
- const MinidumpDescriptor& descriptor) {
- assert(descriptor.path_.empty());
-
- mode_ = descriptor.mode_;
- fd_ = descriptor.fd_;
- directory_ = descriptor.directory_;
- path_.clear();
- if (c_path_) {
- // This descriptor already had a path set, so generate a new one.
- c_path_ = NULL;
- UpdatePath();
- }
- size_limit_ = descriptor.size_limit_;
- microdump_extra_info_ = descriptor.microdump_extra_info_;
- return *this;
-}
-
-void MinidumpDescriptor::UpdatePath() {
- assert(mode_ == kWriteMinidumpToFile && !directory_.empty());
-
- GUID guid;
- char guid_str[kGUIDStringLength + 1];
- if (!CreateGUID(&guid) || !GUIDToString(&guid, guid_str, sizeof(guid_str))) {
- assert(false);
- }
-
- path_.clear();
- path_ = directory_ + "/" + guid_str + ".dmp";
- c_path_ = path_.c_str();
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.h b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.h
deleted file mode 100644
index 782a60a4e..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_descriptor.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2012 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_HANDLER_MINIDUMP_DESCRIPTOR_H_
-#define CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_
-
-#include <assert.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "client/linux/handler/microdump_extra_info.h"
-#include "common/using_std_string.h"
-
-// This class describes how a crash dump should be generated, either:
-// - Writing a full minidump to a file in a given directory (the actual path,
-// inside the directory, is determined by this class).
-// - Writing a full minidump to a given fd.
-// - Writing a reduced microdump to the console (logcat on Android).
-namespace google_breakpad {
-
-class MinidumpDescriptor {
- public:
- struct MicrodumpOnConsole {};
- static const MicrodumpOnConsole kMicrodumpOnConsole;
-
- MinidumpDescriptor()
- : mode_(kUninitialized),
- fd_(-1),
- size_limit_(-1) {}
-
- explicit MinidumpDescriptor(const string& directory)
- : mode_(kWriteMinidumpToFile),
- fd_(-1),
- directory_(directory),
- c_path_(NULL),
- size_limit_(-1) {
- assert(!directory.empty());
- }
-
- explicit MinidumpDescriptor(int fd)
- : mode_(kWriteMinidumpToFd),
- fd_(fd),
- c_path_(NULL),
- size_limit_(-1) {
- assert(fd != -1);
- }
-
- explicit MinidumpDescriptor(const MicrodumpOnConsole&)
- : mode_(kWriteMicrodumpToConsole),
- fd_(-1),
- size_limit_(-1) {}
-
- explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor);
- MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor);
-
- static MinidumpDescriptor getMicrodumpDescriptor();
-
- bool IsFD() const { return mode_ == kWriteMinidumpToFd; }
-
- int fd() const { return fd_; }
-
- string directory() const { return directory_; }
-
- const char* path() const { return c_path_; }
-
- bool IsMicrodumpOnConsole() const {
- return mode_ == kWriteMicrodumpToConsole;
- }
-
- // Updates the path so it is unique.
- // Should be called from a normal context: this methods uses the heap.
- void UpdatePath();
-
- off_t size_limit() const { return size_limit_; }
- void set_size_limit(off_t limit) { size_limit_ = limit; }
-
- MicrodumpExtraInfo* microdump_extra_info() {
- assert(IsMicrodumpOnConsole());
- return &microdump_extra_info_;
- };
-
- private:
- enum DumpMode {
- kUninitialized = 0,
- kWriteMinidumpToFile,
- kWriteMinidumpToFd,
- kWriteMicrodumpToConsole
- };
-
- // Specifies the dump mode (see DumpMode).
- DumpMode mode_;
-
- // The file descriptor where the minidump is generated.
- int fd_;
-
- // The directory where the minidump should be generated.
- string directory_;
-
- // The full path to the generated minidump.
- string path_;
-
- // The C string of |path_|. Precomputed so it can be access from a compromised
- // context.
- const char* c_path_;
-
- off_t size_limit_;
-
- // The extra microdump data (e.g. product name/version, build
- // fingerprint, gpu fingerprint) that should be appended to the dump
- // (microdump only). Microdumps don't have the ability of appending
- // extra metadata after the dump is generated (as opposite to
- // minidumps MIME fields), therefore the extra data must be provided
- // upfront. Any memory pointed to by members of the
- // MicrodumpExtraInfo struct must be valid for the lifetime of the
- // process (read: the caller has to guarantee that it is stored in
- // global static storage.)
- MicrodumpExtraInfo microdump_extra_info_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.cc
deleted file mode 100644
index fc23aa6d5..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012 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 "client/linux/log/log.h"
-
-#if defined(__ANDROID__)
-#include <android/log.h>
-#include <dlfcn.h>
-#else
-#include "third_party/lss/linux_syscall_support.h"
-#endif
-
-namespace logger {
-
-#if defined(__ANDROID__)
-namespace {
-
-// __android_log_buf_write() is not exported in the NDK and is being used by
-// dynamic runtime linking. Its declaration is taken from Android's
-// system/core/include/log/log.h.
-using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag,
- const char *text);
-const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h.
-const char kAndroidLogTag[] = "google-breakpad";
-
-bool g_crash_log_initialized = false;
-AndroidLogBufferWriteFunc g_android_log_buf_write = nullptr;
-
-} // namespace
-
-void initializeCrashLogWriter() {
- if (g_crash_log_initialized)
- return;
- g_android_log_buf_write = reinterpret_cast<AndroidLogBufferWriteFunc>(
- dlsym(RTLD_DEFAULT, "__android_log_buf_write"));
- g_crash_log_initialized = true;
-}
-
-int writeToCrashLog(const char* buf) {
- // Try writing to the crash log ring buffer. If not available, fall back to
- // the standard log buffer.
- if (g_android_log_buf_write) {
- return g_android_log_buf_write(kAndroidCrashLogId, ANDROID_LOG_FATAL,
- kAndroidLogTag, buf);
- }
- return __android_log_write(ANDROID_LOG_FATAL, kAndroidLogTag, buf);
-}
-#endif
-
-int write(const char* buf, size_t nbytes) {
-#if defined(__ANDROID__)
- return __android_log_write(ANDROID_LOG_WARN, kAndroidLogTag, buf);
-#else
- return sys_write(2, buf, nbytes);
-#endif
-}
-
-} // namespace logger
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.h b/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.h
deleted file mode 100644
index f94bbd5fb..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/log/log.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012, 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_LOG_LOG_H_
-#define CLIENT_LINUX_LOG_LOG_H_
-
-#include <stddef.h>
-
-namespace logger {
-
-int write(const char* buf, size_t nbytes);
-
-// In the case of Android the log can be written to the default system log
-// (default behavior of write() above, or to the crash log (see
-// writeToCrashLog() below).
-#if defined(__ANDROID__)
-
-// The logger must be initialized in a non-compromised context.
-void initializeCrashLogWriter();
-
-// Once initialized, writeToCrashLog is safe to use in a compromised context,
-// even if the initialization failed, in which case this will silently fall
-// back on write().
-int writeToCrashLog(const char* buf);
-#endif
-
-} // namespace logger
-
-#endif // CLIENT_LINUX_LOG_LOG_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.cc
deleted file mode 100644
index a508667a0..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.cc
+++ /dev/null
@@ -1,609 +0,0 @@
-// Copyright (c) 2014, 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.
-
-// This translation unit generates microdumps into the console (logcat on
-// Android). See crbug.com/410294 for more info and design docs.
-
-#include "client/linux/microdump_writer/microdump_writer.h"
-
-#include <limits>
-
-#include <sys/utsname.h>
-
-#include "client/linux/dump_writer_common/thread_info.h"
-#include "client/linux/dump_writer_common/ucontext_reader.h"
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/handler/microdump_extra_info.h"
-#include "client/linux/log/log.h"
-#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
-#include "common/linux/file_id.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/memory.h"
-
-namespace {
-
-using google_breakpad::auto_wasteful_vector;
-using google_breakpad::ExceptionHandler;
-using google_breakpad::kDefaultBuildIdSize;
-using google_breakpad::LinuxDumper;
-using google_breakpad::LinuxPtraceDumper;
-using google_breakpad::MappingInfo;
-using google_breakpad::MappingList;
-using google_breakpad::MicrodumpExtraInfo;
-using google_breakpad::RawContextCPU;
-using google_breakpad::ThreadInfo;
-using google_breakpad::UContextReader;
-
-const size_t kLineBufferSize = 2048;
-
-#if !defined(__LP64__)
-// The following are only used by DumpFreeSpace, so need to be compiled
-// in conditionally in the same way.
-
-template <typename Dst, typename Src>
-Dst saturated_cast(Src src) {
- if (src >= std::numeric_limits<Dst>::max())
- return std::numeric_limits<Dst>::max();
- if (src <= std::numeric_limits<Dst>::min())
- return std::numeric_limits<Dst>::min();
- return static_cast<Dst>(src);
-}
-
-int Log2Floor(uint64_t n) {
- // Copied from chromium src/base/bits.h
- if (n == 0)
- return -1;
- int log = 0;
- uint64_t value = n;
- for (int i = 5; i >= 0; --i) {
- int shift = (1 << i);
- uint64_t x = value >> shift;
- if (x != 0) {
- value = x;
- log += shift;
- }
- }
- assert(value == 1u);
- return log;
-}
-
-bool MappingsAreAdjacent(const MappingInfo& a, const MappingInfo& b) {
- // Because of load biasing, we can end up with a situation where two
- // mappings actually overlap. So we will define adjacency to also include a
- // b start address that lies within a's address range (including starting
- // immediately after a).
- // Because load biasing only ever moves the start address backwards, the end
- // address should still increase.
- return a.start_addr <= b.start_addr && a.start_addr + a.size >= b.start_addr;
-}
-
-bool MappingLessThan(const MappingInfo* a, const MappingInfo* b) {
- // Return true if mapping a is before mapping b.
- // For the same reason (load biasing) we compare end addresses, which - unlike
- // start addresses - will not have been modified.
- return a->start_addr + a->size < b->start_addr + b->size;
-}
-
-size_t NextOrderedMapping(
- const google_breakpad::wasteful_vector<MappingInfo*>& mappings,
- size_t curr) {
- // Find the mapping that directly follows mappings[curr].
- // If no such mapping exists, return |invalid| to indicate this.
- const size_t invalid = std::numeric_limits<size_t>::max();
- size_t best = invalid;
- for (size_t next = 0; next < mappings.size(); ++next) {
- if (MappingLessThan(mappings[curr], mappings[next]) &&
- (best == invalid || MappingLessThan(mappings[next], mappings[best]))) {
- best = next;
- }
- }
- return best;
-}
-
-#endif // !__LP64__
-
-class MicrodumpWriter {
- public:
- MicrodumpWriter(const ExceptionHandler::CrashContext* context,
- const MappingList& mappings,
- const MicrodumpExtraInfo& microdump_extra_info,
- LinuxDumper* dumper)
- : ucontext_(context ? &context->context : NULL),
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- float_state_(context ? &context->float_state : NULL),
-#endif
- dumper_(dumper),
- mapping_list_(mappings),
- microdump_extra_info_(microdump_extra_info),
- log_line_(NULL) {
- log_line_ = reinterpret_cast<char*>(Alloc(kLineBufferSize));
- if (log_line_)
- log_line_[0] = '\0'; // Clear out the log line buffer.
- }
-
- ~MicrodumpWriter() { dumper_->ThreadsResume(); }
-
- bool Init() {
- // In the exceptional case where the system was out of memory and there
- // wasn't even room to allocate the line buffer, bail out. There is nothing
- // useful we can possibly achieve without the ability to Log. At least let's
- // try to not crash.
- if (!dumper_->Init() || !log_line_)
- return false;
- return dumper_->ThreadsSuspend() && dumper_->LateInit();
- }
-
- bool Dump() {
- bool success;
- LogLine("-----BEGIN BREAKPAD MICRODUMP-----");
- DumpProductInformation();
- DumpOSInformation();
- DumpProcessType();
- DumpGPUInformation();
-#if !defined(__LP64__)
- DumpFreeSpace();
-#endif
- success = DumpCrashingThread();
- if (success)
- success = DumpMappings();
- LogLine("-----END BREAKPAD MICRODUMP-----");
- dumper_->ThreadsResume();
- return success;
- }
-
- private:
- // Writes one line to the system log.
- void LogLine(const char* msg) {
-#if defined(__ANDROID__)
- logger::writeToCrashLog(msg);
-#else
- logger::write(msg, my_strlen(msg));
- logger::write("\n", 1);
-#endif
- }
-
- // Stages the given string in the current line buffer.
- void LogAppend(const char* str) {
- my_strlcat(log_line_, str, kLineBufferSize);
- }
-
- // As above (required to take precedence over template specialization below).
- void LogAppend(char* str) {
- LogAppend(const_cast<const char*>(str));
- }
-
- // Stages the hex repr. of the given int type in the current line buffer.
- template<typename T>
- void LogAppend(T value) {
- // Make enough room to hex encode the largest int type + NUL.
- static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F'};
- char hexstr[sizeof(T) * 2 + 1];
- for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4)
- hexstr[i] = HEX[static_cast<uint8_t>(value) & 0x0F];
- hexstr[sizeof(T) * 2] = '\0';
- LogAppend(hexstr);
- }
-
- // Stages the buffer content hex-encoded in the current line buffer.
- void LogAppend(const void* buf, size_t length) {
- const uint8_t* ptr = reinterpret_cast<const uint8_t*>(buf);
- for (size_t i = 0; i < length; ++i, ++ptr)
- LogAppend(*ptr);
- }
-
- // Writes out the current line buffer on the system log.
- void LogCommitLine() {
- LogLine(log_line_);
- my_strlcpy(log_line_, "", kLineBufferSize);
- }
-
- void DumpProductInformation() {
- LogAppend("V ");
- if (microdump_extra_info_.product_info) {
- LogAppend(microdump_extra_info_.product_info);
- } else {
- LogAppend("UNKNOWN:0.0.0.0");
- }
- LogCommitLine();
- }
-
- void DumpProcessType() {
- LogAppend("P ");
- if (microdump_extra_info_.process_type) {
- LogAppend(microdump_extra_info_.process_type);
- } else {
- LogAppend("UNKNOWN");
- }
- LogCommitLine();
- }
-
- void DumpOSInformation() {
- const uint8_t n_cpus = static_cast<uint8_t>(sysconf(_SC_NPROCESSORS_CONF));
-
-#if defined(__ANDROID__)
- const char kOSId[] = "A";
-#else
- const char kOSId[] = "L";
-#endif
-
-// Dump the runtime architecture. On multiarch devices it might not match the
-// hw architecture (the one returned by uname()), for instance in the case of
-// a 32-bit app running on a aarch64 device.
-#if defined(__aarch64__)
- const char kArch[] = "arm64";
-#elif defined(__ARMEL__)
- const char kArch[] = "arm";
-#elif defined(__x86_64__)
- const char kArch[] = "x86_64";
-#elif defined(__i386__)
- const char kArch[] = "x86";
-#elif defined(__mips__)
-# if _MIPS_SIM == _ABIO32
- const char kArch[] = "mips";
-# elif _MIPS_SIM == _ABI64
- const char kArch[] = "mips64";
-# else
-# error "This mips ABI is currently not supported (n32)"
-#endif
-#else
-#error "This code has not been ported to your platform yet"
-#endif
-
- LogAppend("O ");
- LogAppend(kOSId);
- LogAppend(" ");
- LogAppend(kArch);
- LogAppend(" ");
- LogAppend(n_cpus);
- LogAppend(" ");
-
- // Dump the HW architecture (e.g., armv7l, aarch64).
- struct utsname uts;
- const bool has_uts_info = (uname(&uts) == 0);
- const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch";
- LogAppend(hwArch);
- LogAppend(" ");
-
- // If the client has attached a build fingerprint to the MinidumpDescriptor
- // use that one. Otherwise try to get some basic info from uname().
- if (microdump_extra_info_.build_fingerprint) {
- LogAppend(microdump_extra_info_.build_fingerprint);
- } else if (has_uts_info) {
- LogAppend(uts.release);
- LogAppend(" ");
- LogAppend(uts.version);
- } else {
- LogAppend("no build fingerprint available");
- }
- LogCommitLine();
- }
-
- void DumpGPUInformation() {
- LogAppend("G ");
- if (microdump_extra_info_.gpu_fingerprint) {
- LogAppend(microdump_extra_info_.gpu_fingerprint);
- } else {
- LogAppend("UNKNOWN");
- }
- LogCommitLine();
- }
-
- bool DumpThreadStack(uint32_t thread_id,
- uintptr_t stack_pointer,
- int max_stack_len,
- uint8_t** stack_copy) {
- *stack_copy = NULL;
- const void* stack;
- size_t stack_len;
-
- if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
- // The stack pointer might not be available. In this case we don't hard
- // fail, just produce a (almost useless) microdump w/o a stack section.
- return true;
- }
-
- LogAppend("S 0 ");
- LogAppend(stack_pointer);
- LogAppend(" ");
- LogAppend(reinterpret_cast<uintptr_t>(stack));
- LogAppend(" ");
- LogAppend(stack_len);
- LogCommitLine();
-
- if (max_stack_len >= 0 &&
- stack_len > static_cast<unsigned int>(max_stack_len)) {
- stack_len = max_stack_len;
- }
-
- *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
- dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len);
-
- // Dump the content of the stack, splicing it into chunks which size is
- // compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD).
- const size_t STACK_DUMP_CHUNK_SIZE = 384;
- for (size_t stack_off = 0; stack_off < stack_len;
- stack_off += STACK_DUMP_CHUNK_SIZE) {
- LogAppend("S ");
- LogAppend(reinterpret_cast<uintptr_t>(stack) + stack_off);
- LogAppend(" ");
- LogAppend(*stack_copy + stack_off,
- std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off));
- LogCommitLine();
- }
- return true;
- }
-
- // Write information about the crashing thread.
- bool DumpCrashingThread() {
- const unsigned num_threads = dumper_->threads().size();
-
- for (unsigned i = 0; i < num_threads; ++i) {
- MDRawThread thread;
- my_memset(&thread, 0, sizeof(thread));
- thread.thread_id = dumper_->threads()[i];
-
- // Dump only the crashing thread.
- if (static_cast<pid_t>(thread.thread_id) != dumper_->crash_thread())
- continue;
-
- assert(ucontext_);
- assert(!dumper_->IsPostMortem());
-
- uint8_t* stack_copy;
- const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
- if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy))
- return false;
-
- RawContextCPU cpu;
- my_memset(&cpu, 0, sizeof(RawContextCPU));
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- UContextReader::FillCPUContext(&cpu, ucontext_, float_state_);
-#else
- UContextReader::FillCPUContext(&cpu, ucontext_);
-#endif
- DumpCPUState(&cpu);
- }
- return true;
- }
-
- void DumpCPUState(RawContextCPU* cpu) {
- LogAppend("C ");
- LogAppend(cpu, sizeof(*cpu));
- LogCommitLine();
- }
-
- // If there is caller-provided information about this mapping
- // in the mapping_list_ list, return true. Otherwise, return false.
- bool HaveMappingInfo(const MappingInfo& mapping) {
- for (MappingList::const_iterator iter = mapping_list_.begin();
- iter != mapping_list_.end();
- ++iter) {
- // Ignore any mappings that are wholly contained within
- // mappings in the mapping_info_ list.
- if (mapping.start_addr >= iter->first.start_addr &&
- (mapping.start_addr + mapping.size) <=
- (iter->first.start_addr + iter->first.size)) {
- return true;
- }
- }
- return false;
- }
-
- // Dump information about the provided |mapping|. If |identifier| is non-NULL,
- // use it instead of calculating a file ID from the mapping.
- void DumpModule(const MappingInfo& mapping,
- bool member,
- unsigned int mapping_id,
- const uint8_t* identifier) {
-
- auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
- dumper_->allocator());
-
- if (identifier) {
- // GUID was provided by caller.
- identifier_bytes.insert(identifier_bytes.end(),
- identifier,
- identifier + sizeof(MDGUID));
- } else {
- dumper_->ElfFileIdentifierForMapping(
- mapping,
- member,
- mapping_id,
- identifier_bytes);
- }
-
- // Copy as many bytes of |identifier| as will fit into a MDGUID
- MDGUID module_identifier = {0};
- memcpy(&module_identifier, &identifier_bytes[0],
- std::min(sizeof(MDGUID), identifier_bytes.size()));
-
- char file_name[NAME_MAX];
- char file_path[NAME_MAX];
- dumper_->GetMappingEffectiveNameAndPath(
- mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
-
- LogAppend("M ");
- LogAppend(static_cast<uintptr_t>(mapping.start_addr));
- LogAppend(" ");
- LogAppend(mapping.offset);
- LogAppend(" ");
- LogAppend(mapping.size);
- LogAppend(" ");
- LogAppend(module_identifier.data1);
- LogAppend(module_identifier.data2);
- LogAppend(module_identifier.data3);
- LogAppend(module_identifier.data4[0]);
- LogAppend(module_identifier.data4[1]);
- LogAppend(module_identifier.data4[2]);
- LogAppend(module_identifier.data4[3]);
- LogAppend(module_identifier.data4[4]);
- LogAppend(module_identifier.data4[5]);
- LogAppend(module_identifier.data4[6]);
- LogAppend(module_identifier.data4[7]);
- LogAppend("0 "); // Age is always 0 on Linux.
- LogAppend(file_name);
- LogCommitLine();
- }
-
-#if !defined(__LP64__)
- void DumpFreeSpace() {
- const google_breakpad::wasteful_vector<MappingInfo*>& mappings =
- dumper_->mappings();
- if (mappings.size() == 0) return;
-
- // This is complicated by the fact that mappings is not in order. It should
- // be mostly in order, however the mapping that contains the entry point for
- // the process is always at the front of the vector.
-
- static const int HBITS = sizeof(size_t) * 8;
- size_t hole_histogram[HBITS];
- my_memset(hole_histogram, 0, sizeof(hole_histogram));
-
- // Find the lowest address mapping.
- size_t curr = 0;
- for (size_t i = 1; i < mappings.size(); ++i) {
- if (mappings[i]->start_addr < mappings[curr]->start_addr) curr = i;
- }
-
- uintptr_t lo_addr = mappings[curr]->start_addr;
-
- size_t hole_cnt = 0;
- size_t hole_max = 0;
- size_t hole_sum = 0;
-
- while (true) {
- // Skip to the end of an adjacent run of mappings. This is an optimization
- // for the fact that mappings is mostly sorted.
- while (curr != mappings.size() - 1 &&
- MappingsAreAdjacent(*mappings[curr], *mappings[curr + 1])) {
- ++curr;
- }
-
- size_t next = NextOrderedMapping(mappings, curr);
- if (next == std::numeric_limits<size_t>::max())
- break;
-
- uintptr_t hole_lo = mappings[curr]->start_addr + mappings[curr]->size;
- uintptr_t hole_hi = mappings[next]->start_addr;
-
- if (hole_hi > hole_lo) {
- size_t hole_sz = hole_hi - hole_lo;
- hole_sum += hole_sz;
- hole_max = std::max(hole_sz, hole_max);
- ++hole_cnt;
- ++hole_histogram[Log2Floor(hole_sz)];
- }
- curr = next;
- }
-
- uintptr_t hi_addr = mappings[curr]->start_addr + mappings[curr]->size;
-
- LogAppend("H ");
- LogAppend(lo_addr);
- LogAppend(" ");
- LogAppend(hi_addr);
- LogAppend(" ");
- LogAppend(saturated_cast<uint16_t>(hole_cnt));
- LogAppend(" ");
- LogAppend(hole_max);
- LogAppend(" ");
- LogAppend(hole_sum);
- for (unsigned int i = 0; i < HBITS; ++i) {
- if (!hole_histogram[i]) continue;
- LogAppend(" ");
- LogAppend(saturated_cast<uint8_t>(i));
- LogAppend(":");
- LogAppend(saturated_cast<uint8_t>(hole_histogram[i]));
- }
- LogCommitLine();
- }
-#endif
-
- // Write information about the mappings in effect.
- bool DumpMappings() {
- // First write all the mappings from the dumper
- for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
- const MappingInfo& mapping = *dumper_->mappings()[i];
- if (mapping.name[0] == 0 || // only want modules with filenames.
- !mapping.exec || // only want executable mappings.
- mapping.size < 4096 || // too small to get a signature for.
- HaveMappingInfo(mapping)) {
- continue;
- }
-
- DumpModule(mapping, true, i, NULL);
- }
- // Next write all the mappings provided by the caller
- for (MappingList::const_iterator iter = mapping_list_.begin();
- iter != mapping_list_.end();
- ++iter) {
- DumpModule(iter->first, false, 0, iter->second);
- }
- return true;
- }
-
- void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); }
-
- const ucontext_t* const ucontext_;
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- const google_breakpad::fpstate_t* const float_state_;
-#endif
- LinuxDumper* dumper_;
- const MappingList& mapping_list_;
- const MicrodumpExtraInfo microdump_extra_info_;
- char* log_line_;
-};
-} // namespace
-
-namespace google_breakpad {
-
-bool WriteMicrodump(pid_t crashing_process,
- const void* blob,
- size_t blob_size,
- const MappingList& mappings,
- const MicrodumpExtraInfo& microdump_extra_info) {
- LinuxPtraceDumper dumper(crashing_process);
- const ExceptionHandler::CrashContext* context = NULL;
- if (blob) {
- if (blob_size != sizeof(ExceptionHandler::CrashContext))
- return false;
- context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
- dumper.set_crash_address(
- reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
- dumper.set_crash_signal(context->siginfo.si_signo);
- dumper.set_crash_thread(context->tid);
- }
- MicrodumpWriter writer(context, mappings, microdump_extra_info, &dumper);
- if (!writer.Init())
- return false;
- return writer.Dump();
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.h b/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.h
deleted file mode 100644
index 7c742761d..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2014, 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_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "client/linux/dump_writer_common/mapping_info.h"
-
-namespace google_breakpad {
-
-struct MicrodumpExtraInfo;
-
-// Writes a microdump (a reduced dump containing only the state of the crashing
-// thread) on the console (logcat on Android). These functions do not malloc nor
-// use libc functions which may. Thus, it can be used in contexts where the
-// state of the heap may be corrupt.
-// Args:
-// crashing_process: the pid of the crashing process. This must be trusted.
-// blob: a blob of data from the crashing process. See exception_handler.h
-// blob_size: the length of |blob| in bytes.
-// mappings: a list of additional mappings provided by the application.
-// build_fingerprint: a (optional) C string which determines the OS
-// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys).
-// product_info: a (optional) C string which determines the product name and
-// version (e.g., WebView:42.0.2311.136).
-//
-// Returns true iff successful.
-bool WriteMicrodump(pid_t crashing_process,
- const void* blob,
- size_t blob_size,
- const MappingList& mappings,
- const MicrodumpExtraInfo& microdump_extra_info);
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc
deleted file mode 100644
index 58a731188..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/microdump_writer/microdump_writer_unittest.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright (c) 2014 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 <ctype.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <sstream>
-#include <string>
-
-#include "breakpad_googletest_includes.h"
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/handler/microdump_extra_info.h"
-#include "client/linux/microdump_writer/microdump_writer.h"
-#include "common/linux/eintr_wrapper.h"
-#include "common/linux/ignore_ret.h"
-#include "common/scoped_ptr.h"
-#include "common/tests/auto_tempdir.h"
-#include "common/using_std_string.h"
-
-using namespace google_breakpad;
-
-namespace {
-
-typedef testing::Test MicrodumpWriterTest;
-
-MicrodumpExtraInfo MakeMicrodumpExtraInfo(
- const char* build_fingerprint,
- const char* product_info,
- const char* gpu_fingerprint) {
- MicrodumpExtraInfo info;
- info.build_fingerprint = build_fingerprint;
- info.product_info = product_info;
- info.gpu_fingerprint = gpu_fingerprint;
- return info;
-}
-
-void CrashAndGetMicrodump(
- const MappingList& mappings,
- const MicrodumpExtraInfo& microdump_extra_info,
- scoped_array<char>* buf) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- AutoTempDir temp_dir;
- string stderr_file = temp_dir.path() + "/stderr.log";
- int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
- ASSERT_NE(-1, err_fd);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
-
- // Set a non-zero tid to avoid tripping asserts.
- context.tid = child;
-
- // Redirect temporarily stderr to the stderr.log file.
- int save_err = dup(STDERR_FILENO);
- ASSERT_NE(-1, save_err);
- ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO));
-
- ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings,
- microdump_extra_info));
-
- // Revert stderr back to the console.
- dup2(save_err, STDERR_FILENO);
- close(save_err);
-
- // Read back the stderr file and check for the microdump marker.
- fsync(err_fd);
- lseek(err_fd, 0, SEEK_SET);
- const size_t kBufSize = 64 * 1024;
- buf->reset(new char[kBufSize]);
- ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0);
-
- close(err_fd);
- close(fds[1]);
-
- ASSERT_NE(static_cast<char*>(0), strstr(
- buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----"));
- ASSERT_NE(static_cast<char*>(0), strstr(
- buf->get(), "-----END BREAKPAD MICRODUMP-----"));
-}
-
-void CheckMicrodumpContents(const string& microdump_content,
- const MicrodumpExtraInfo& expected_info) {
- std::istringstream iss(microdump_content);
- bool did_find_os_info = false;
- bool did_find_product_info = false;
- bool did_find_gpu_info = false;
- for (string line; std::getline(iss, line);) {
- if (line.find("O ") == 0) {
- std::istringstream os_info_tokens(line);
- string token;
- os_info_tokens.ignore(2); // Ignore the "O " preamble.
- // Check the OS descriptor char (L=Linux, A=Android).
- os_info_tokens >> token;
- ASSERT_TRUE(token == "L" || token == "A");
-
- os_info_tokens >> token; // HW architecture.
- os_info_tokens >> token; // Number of cpus.
- for (size_t i = 0; i < token.size(); ++i)
- ASSERT_TRUE(isxdigit(token[i]));
- os_info_tokens >> token; // SW architecture.
-
- // Check that the build fingerprint is in the right place.
- os_info_tokens >> token;
- if (expected_info.build_fingerprint)
- ASSERT_EQ(expected_info.build_fingerprint, token);
- did_find_os_info = true;
- } else if (line.find("V ") == 0) {
- if (expected_info.product_info)
- ASSERT_EQ(string("V ") + expected_info.product_info, line);
- did_find_product_info = true;
- } else if (line.find("G ") == 0) {
- if (expected_info.gpu_fingerprint)
- ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line);
- did_find_gpu_info = true;
- }
- }
- ASSERT_TRUE(did_find_os_info);
- ASSERT_TRUE(did_find_product_info);
- ASSERT_TRUE(did_find_gpu_info);
-}
-
-void CheckMicrodumpContents(const string& microdump_content,
- const string& expected_fingerprint,
- const string& expected_product_info,
- const string& expected_gpu_fingerprint) {
- CheckMicrodumpContents(
- microdump_content,
- MakeMicrodumpExtraInfo(expected_fingerprint.c_str(),
- expected_product_info.c_str(),
- expected_gpu_fingerprint.c_str()));
-}
-
-TEST(MicrodumpWriterTest, BasicWithMappings) {
- // Push some extra mapping to check the MappingList logic.
- const uint32_t memory_size = sysconf(_SC_PAGESIZE);
- const char* kMemoryName = "libfoo.so";
- const uint8_t kModuleGUID[sizeof(MDGUID)] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
- };
-
- MappingInfo info;
- info.start_addr = memory_size;
- info.size = memory_size;
- info.offset = 42;
- strcpy(info.name, kMemoryName);
-
- MappingList mappings;
- MappingEntry mapping;
- mapping.first = info;
- memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
- mappings.push_back(mapping);
-
- scoped_array<char> buf;
- CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf);
-
-#ifdef __LP64__
- ASSERT_NE(static_cast<char*>(0), strstr(
- buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 "
- "33221100554477668899AABBCCDDEEFF0 libfoo.so"));
-#else
- ASSERT_NE(static_cast<char*>(0), strstr(
- buf.get(), "M 00001000 0000002A 00001000 "
- "33221100554477668899AABBCCDDEEFF0 libfoo.so"));
-#endif
-
- // In absence of a product info in the minidump, the writer should just write
- // an unknown marker.
- ASSERT_NE(static_cast<char*>(0), strstr(
- buf.get(), "V UNKNOWN:0.0.0.0"));
-}
-
-// Ensure that the product info and build fingerprint metadata show up in the
-// final microdump if present.
-TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) {
- const char kProductInfo[] = "MockProduct:42.0.2311.99";
- const char kBuildFingerprint[] =
- "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys";
- const char kGPUFingerprint[] =
- "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)";
- const MicrodumpExtraInfo kMicrodumpExtraInfo(
- MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint));
- scoped_array<char> buf;
- MappingList no_mappings;
-
- CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf);
- CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo);
-}
-
-TEST(MicrodumpWriterTest, NoProductInfo) {
- const char kBuildFingerprint[] = "foobar";
- const char kGPUFingerprint[] = "bazqux";
- scoped_array<char> buf;
- MappingList no_mappings;
-
- const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo(
- MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint));
-
- CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf);
- CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
- "UNKNOWN:0.0.0.0", kGPUFingerprint);
-}
-
-TEST(MicrodumpWriterTest, NoGPUInfo) {
- const char kProductInfo[] = "bazqux";
- const char kBuildFingerprint[] = "foobar";
- scoped_array<char> buf;
- MappingList no_mappings;
-
- const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo(
- MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL));
-
- CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf);
- CheckMicrodumpContents(string(buf.get()), kBuildFingerprint,
- kProductInfo, "UNKNOWN");
-}
-} // namespace
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set.h
deleted file mode 100644
index 1cca9aa5a..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2013, 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_MINIDUMP_WRITER_CPU_SET_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_
-
-#include <stdint.h>
-#include <assert.h>
-#include <string.h>
-
-#include "common/linux/linux_libc_support.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// Helper class used to model a set of CPUs, as read from sysfs
-// files like /sys/devices/system/cpu/present
-// See See http://www.kernel.org/doc/Documentation/cputopology.txt
-class CpuSet {
-public:
- // The maximum number of supported CPUs.
- static const size_t kMaxCpus = 1024;
-
- CpuSet() {
- my_memset(mask_, 0, sizeof(mask_));
- }
-
- // Parse a sysfs file to extract the corresponding CPU set.
- bool ParseSysFile(int fd) {
- char buffer[512];
- int ret = sys_read(fd, buffer, sizeof(buffer)-1);
- if (ret < 0)
- return false;
-
- buffer[ret] = '\0';
-
- // Expected format: comma-separated list of items, where each
- // item can be a decimal integer, or two decimal integers separated
- // by a dash.
- // E.g.:
- // 0
- // 0,1,2,3
- // 0-3
- // 1,10-23
- const char* p = buffer;
- const char* p_end = p + ret;
- while (p < p_end) {
- // Skip leading space, if any
- while (p < p_end && my_isspace(*p))
- p++;
-
- // Find start and size of current item.
- const char* item = p;
- size_t item_len = static_cast<size_t>(p_end - p);
- const char* item_next =
- static_cast<const char*>(my_memchr(p, ',', item_len));
- if (item_next != NULL) {
- p = item_next + 1;
- item_len = static_cast<size_t>(item_next - item);
- } else {
- p = p_end;
- item_next = p_end;
- }
-
- // Ignore trailing spaces.
- while (item_next > item && my_isspace(item_next[-1]))
- item_next--;
-
- // skip empty items.
- if (item_next == item)
- continue;
-
- // read first decimal value.
- uintptr_t start = 0;
- const char* next = my_read_decimal_ptr(&start, item);
- uintptr_t end = start;
- if (*next == '-')
- my_read_decimal_ptr(&end, next+1);
-
- while (start <= end)
- SetBit(start++);
- }
- return true;
- }
-
- // Intersect this CPU set with another one.
- void IntersectWith(const CpuSet& other) {
- for (size_t nn = 0; nn < kMaskWordCount; ++nn)
- mask_[nn] &= other.mask_[nn];
- }
-
- // Return the number of CPUs in this set.
- int GetCount() {
- int result = 0;
- for (size_t nn = 0; nn < kMaskWordCount; ++nn) {
- result += __builtin_popcount(mask_[nn]);
- }
- return result;
- }
-
-private:
- void SetBit(uintptr_t index) {
- size_t nn = static_cast<size_t>(index);
- if (nn < kMaxCpus)
- mask_[nn / kMaskWordBits] |= (1U << (nn % kMaskWordBits));
- }
-
- typedef uint32_t MaskWordType;
- static const size_t kMaskWordBits = 8*sizeof(MaskWordType);
- static const size_t kMaskWordCount =
- (kMaxCpus + kMaskWordBits - 1) / kMaskWordBits;
-
- MaskWordType mask_[kMaskWordCount];
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc
deleted file mode 100644
index e2274bd17..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/cpu_set_unittest.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2013, 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 <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-
-#include "breakpad_googletest_includes.h"
-#include "client/linux/minidump_writer/cpu_set.h"
-#include "common/linux/tests/auto_testfile.h"
-
-using namespace google_breakpad;
-
-namespace {
-
-typedef testing::Test CpuSetTest;
-
-// Helper class to write test text file to a temporary file and return
-// its file descriptor.
-class ScopedTestFile : public AutoTestFile {
-public:
- explicit ScopedTestFile(const char* text)
- : AutoTestFile("cpu_set", text) {
- }
-};
-
-}
-
-TEST(CpuSetTest, EmptyCount) {
- CpuSet set;
- ASSERT_EQ(0, set.GetCount());
-}
-
-TEST(CpuSetTest, OneCpu) {
- ScopedTestFile file("10");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(1, set.GetCount());
-}
-
-TEST(CpuSetTest, OneCpuTerminated) {
- ScopedTestFile file("10\n");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(1, set.GetCount());
-}
-
-TEST(CpuSetTest, TwoCpusWithComma) {
- ScopedTestFile file("1,10");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(2, set.GetCount());
-}
-
-TEST(CpuSetTest, TwoCpusWithRange) {
- ScopedTestFile file("1-2");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(2, set.GetCount());
-}
-
-TEST(CpuSetTest, TenCpusWithRange) {
- ScopedTestFile file("9-18");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(10, set.GetCount());
-}
-
-TEST(CpuSetTest, MultiItems) {
- ScopedTestFile file("0, 2-4, 128");
- ASSERT_TRUE(file.IsOk());
-
- CpuSet set;
- ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
- ASSERT_EQ(5, set.GetCount());
-}
-
-TEST(CpuSetTest, IntersectWith) {
- ScopedTestFile file1("9-19");
- ASSERT_TRUE(file1.IsOk());
- CpuSet set1;
- ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
- ASSERT_EQ(11, set1.GetCount());
-
- ScopedTestFile file2("16-24");
- ASSERT_TRUE(file2.IsOk());
- CpuSet set2;
- ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
- ASSERT_EQ(9, set2.GetCount());
-
- set1.IntersectWith(set2);
- ASSERT_EQ(4, set1.GetCount());
- ASSERT_EQ(9, set2.GetCount());
-}
-
-TEST(CpuSetTest, SelfIntersection) {
- ScopedTestFile file1("9-19");
- ASSERT_TRUE(file1.IsOk());
- CpuSet set1;
- ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
- ASSERT_EQ(11, set1.GetCount());
-
- set1.IntersectWith(set1);
- ASSERT_EQ(11, set1.GetCount());
-}
-
-TEST(CpuSetTest, EmptyIntersection) {
- ScopedTestFile file1("0-19");
- ASSERT_TRUE(file1.IsOk());
- CpuSet set1;
- ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
- ASSERT_EQ(20, set1.GetCount());
-
- ScopedTestFile file2("20-39");
- ASSERT_TRUE(file2.IsOk());
- CpuSet set2;
- ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
- ASSERT_EQ(20, set2.GetCount());
-
- set1.IntersectWith(set2);
- ASSERT_EQ(0, set1.GetCount());
-
- ASSERT_EQ(20, set2.GetCount());
-}
-
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h
deleted file mode 100644
index a4bde1803..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// 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_MINIDUMP_WRITER_DIRECTORY_READER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
-
-#include <stdint.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "common/linux/linux_libc_support.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for enumerating a directory without using diropen/readdir or other
-// functions which may allocate memory.
-class DirectoryReader {
- public:
- DirectoryReader(int fd)
- : fd_(fd),
- buf_used_(0) {
- }
-
- // Return the next entry from the directory
- // name: (output) the NUL terminated entry name
- //
- // Returns true iff successful (false on EOF).
- //
- // After calling this, one must call |PopEntry| otherwise you'll get the same
- // entry over and over.
- bool GetNextEntry(const char** name) {
- struct kernel_dirent* const dent =
- reinterpret_cast<kernel_dirent*>(buf_);
-
- if (buf_used_ == 0) {
- // need to read more entries.
- const int n = sys_getdents(fd_, dent, sizeof(buf_));
- if (n < 0) {
- return false;
- } else if (n == 0) {
- hit_eof_ = true;
- } else {
- buf_used_ += n;
- }
- }
-
- if (buf_used_ == 0 && hit_eof_)
- return false;
-
- assert(buf_used_ > 0);
-
- *name = dent->d_name;
- return true;
- }
-
- void PopEntry() {
- if (!buf_used_)
- return;
-
- const struct kernel_dirent* const dent =
- reinterpret_cast<kernel_dirent*>(buf_);
-
- buf_used_ -= dent->d_reclen;
- my_memmove(buf_, buf_ + dent->d_reclen, buf_used_);
- }
-
- private:
- const int fd_;
- bool hit_eof_;
- unsigned buf_used_;
- uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc
deleted file mode 100644
index 326f9e36b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 <set>
-#include <string>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/types.h>
-
-#include "client/linux/minidump_writer/directory_reader.h"
-#include "common/using_std_string.h"
-#include "breakpad_googletest_includes.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test DirectoryReaderTest;
-}
-
-TEST(DirectoryReaderTest, CompareResults) {
- std::set<string> dent_set;
-
- DIR *const dir = opendir("/proc/self");
- ASSERT_TRUE(dir != NULL);
-
- struct dirent* dent;
- while ((dent = readdir(dir)))
- dent_set.insert(dent->d_name);
-
- closedir(dir);
-
- const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY);
- ASSERT_GE(fd, 0);
-
- DirectoryReader dir_reader(fd);
- unsigned seen = 0;
-
- const char* name;
- while (dir_reader.GetNextEntry(&name)) {
- ASSERT_TRUE(dent_set.find(name) != dent_set.end());
- seen++;
- dir_reader.PopEntry();
- }
-
- ASSERT_TRUE(dent_set.find("status") != dent_set.end());
- ASSERT_TRUE(dent_set.find("stat") != dent_set.end());
- ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end());
-
- ASSERT_EQ(dent_set.size(), seen);
- close(fd);
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h
deleted file mode 100644
index 779cfeb60..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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_MINIDUMP_WRITER_LINE_READER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
-
-#include <stdint.h>
-#include <assert.h>
-#include <string.h>
-
-#include "common/linux/linux_libc_support.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for reading a file, line by line, without using fopen/fgets or other
-// functions which may allocate memory.
-class LineReader {
- public:
- LineReader(int fd)
- : fd_(fd),
- hit_eof_(false),
- buf_used_(0) {
- }
-
- // The maximum length of a line.
- static const size_t kMaxLineLen = 512;
-
- // Return the next line from the file.
- // line: (output) a pointer to the start of the line. The line is NUL
- // terminated.
- // len: (output) the length of the line (not inc the NUL byte)
- //
- // Returns true iff successful (false on EOF).
- //
- // One must call |PopLine| after this function, otherwise you'll continue to
- // get the same line over and over.
- bool GetNextLine(const char **line, unsigned *len) {
- for (;;) {
- if (buf_used_ == 0 && hit_eof_)
- return false;
-
- for (unsigned i = 0; i < buf_used_; ++i) {
- if (buf_[i] == '\n' || buf_[i] == 0) {
- buf_[i] = 0;
- *len = i;
- *line = buf_;
- return true;
- }
- }
-
- if (buf_used_ == sizeof(buf_)) {
- // we scanned the whole buffer and didn't find an end-of-line marker.
- // This line is too long to process.
- return false;
- }
-
- // We didn't find any end-of-line terminators in the buffer. However, if
- // this is the last line in the file it might not have one:
- if (hit_eof_) {
- assert(buf_used_);
- // There's room for the NUL because of the buf_used_ == sizeof(buf_)
- // check above.
- buf_[buf_used_] = 0;
- *len = buf_used_;
- buf_used_ += 1; // since we appended the NUL.
- *line = buf_;
- return true;
- }
-
- // Otherwise, we should pull in more data from the file
- const ssize_t n = sys_read(fd_, buf_ + buf_used_,
- sizeof(buf_) - buf_used_);
- if (n < 0) {
- return false;
- } else if (n == 0) {
- hit_eof_ = true;
- } else {
- buf_used_ += n;
- }
-
- // At this point, we have either set the hit_eof_ flag, or we have more
- // data to process...
- }
- }
-
- void PopLine(unsigned len) {
- // len doesn't include the NUL byte at the end.
-
- assert(buf_used_ >= len + 1);
- buf_used_ -= len + 1;
- my_memmove(buf_, buf_ + len + 1, buf_used_);
- }
-
- private:
- const int fd_;
-
- bool hit_eof_;
- unsigned buf_used_;
- char buf_[kMaxLineLen];
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc
deleted file mode 100644
index 29686f04a..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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 <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "client/linux/minidump_writer/line_reader.h"
-#include "breakpad_googletest_includes.h"
-#include "common/linux/tests/auto_testfile.h"
-
-using namespace google_breakpad;
-
-namespace {
-
-typedef testing::Test LineReaderTest;
-
-class ScopedTestFile : public AutoTestFile {
-public:
- explicit ScopedTestFile(const char* text)
- : AutoTestFile("line_reader", text) {
- }
-
- ScopedTestFile(const char* text, size_t text_len)
- : AutoTestFile("line_reader", text, text_len) {
- }
-};
-
-}
-
-TEST(LineReaderTest, EmptyFile) {
- ScopedTestFile file("");
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
-
-TEST(LineReaderTest, OneLineTerminated) {
- ScopedTestFile file("a\n");
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned int len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned int)1, len);
- ASSERT_EQ('a', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
-
-TEST(LineReaderTest, OneLine) {
- ScopedTestFile file("a");
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned)1, len);
- ASSERT_EQ('a', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
-
-TEST(LineReaderTest, TwoLinesTerminated) {
- ScopedTestFile file("a\nb\n");
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned)1, len);
- ASSERT_EQ('a', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned)1, len);
- ASSERT_EQ('b', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
-
-TEST(LineReaderTest, TwoLines) {
- ScopedTestFile file("a\nb");
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned)1, len);
- ASSERT_EQ('a', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ((unsigned)1, len);
- ASSERT_EQ('b', line[0]);
- ASSERT_EQ('\0', line[1]);
- reader.PopLine(len);
-
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
-
-TEST(LineReaderTest, MaxLength) {
- char l[LineReader::kMaxLineLen-1];
- memset(l, 'a', sizeof(l));
- ScopedTestFile file(l, sizeof(l));
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_TRUE(reader.GetNextLine(&line, &len));
- ASSERT_EQ(sizeof(l), len);
- ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0);
- ASSERT_EQ('\0', line[len]);
-}
-
-TEST(LineReaderTest, TooLong) {
- // Note: this writes kMaxLineLen 'a' chars in the test file.
- char l[LineReader::kMaxLineLen];
- memset(l, 'a', sizeof(l));
- ScopedTestFile file(l, sizeof(l));
- ASSERT_TRUE(file.IsOk());
- LineReader reader(file.GetFd());
-
- const char *line;
- unsigned len;
- ASSERT_FALSE(reader.GetNextLine(&line, &len));
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc
deleted file mode 100644
index 622f05069..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper.
-// See linux_core_dumper.h for details.
-
-#include "client/linux/minidump_writer/linux_core_dumper.h"
-
-#include <asm/ptrace.h>
-#include <assert.h>
-#include <elf.h>
-#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/linux_libc_support.h"
-
-namespace google_breakpad {
-
-LinuxCoreDumper::LinuxCoreDumper(pid_t pid,
- const char* core_path,
- const char* procfs_path,
- const char* root_prefix)
- : LinuxDumper(pid, root_prefix),
- core_path_(core_path),
- procfs_path_(procfs_path),
- thread_infos_(&allocator_, 8) {
- assert(core_path_);
-}
-
-bool LinuxCoreDumper::BuildProcPath(char* path, pid_t pid,
- const char* node) const {
- if (!path || !node)
- return false;
-
- size_t node_len = my_strlen(node);
- if (node_len == 0)
- return false;
-
- size_t procfs_path_len = my_strlen(procfs_path_);
- size_t total_length = procfs_path_len + 1 + node_len;
- if (total_length >= NAME_MAX)
- return false;
-
- memcpy(path, procfs_path_, procfs_path_len);
- path[procfs_path_len] = '/';
- memcpy(path + procfs_path_len + 1, node, node_len);
- path[total_length] = '\0';
- return true;
-}
-
-bool LinuxCoreDumper::CopyFromProcess(void* dest, pid_t child,
- const void* src, size_t length) {
- ElfCoreDump::Addr virtual_address = reinterpret_cast<ElfCoreDump::Addr>(src);
- // TODO(benchan): Investigate whether the data to be copied could span
- // across multiple segments in the core dump file. ElfCoreDump::CopyData
- // and this method do not handle that case yet.
- if (!core_.CopyData(dest, virtual_address, length)) {
- // If the data segment is not found in the core dump, fill the result
- // with marker characters.
- memset(dest, 0xab, length);
- return false;
- }
- return true;
-}
-
-bool LinuxCoreDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
- if (index >= thread_infos_.size())
- return false;
-
- *info = thread_infos_[index];
- const uint8_t* stack_pointer;
-#if defined(__i386)
- memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
-#elif defined(__x86_64)
- memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
-#elif defined(__ARM_EABI__)
- memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
-#elif defined(__aarch64__)
- memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
-#elif defined(__mips__)
- stack_pointer =
- reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
-#else
-#error "This code hasn't been ported to your platform yet."
-#endif
- info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
- return true;
-}
-
-bool LinuxCoreDumper::IsPostMortem() const {
- return true;
-}
-
-bool LinuxCoreDumper::ThreadsSuspend() {
- return true;
-}
-
-bool LinuxCoreDumper::ThreadsResume() {
- return true;
-}
-
-bool LinuxCoreDumper::EnumerateThreads() {
- if (!mapped_core_file_.Map(core_path_, 0)) {
- fprintf(stderr, "Could not map core dump file into memory\n");
- return false;
- }
-
- core_.SetContent(mapped_core_file_.content());
- if (!core_.IsValid()) {
- fprintf(stderr, "Invalid core dump file\n");
- return false;
- }
-
- ElfCoreDump::Note note = core_.GetFirstNote();
- if (!note.IsValid()) {
- fprintf(stderr, "PT_NOTE section not found\n");
- return false;
- }
-
- bool first_thread = true;
- do {
- ElfCoreDump::Word type = note.GetType();
- MemoryRange name = note.GetName();
- MemoryRange description = note.GetDescription();
-
- if (type == 0 || name.IsEmpty() || description.IsEmpty()) {
- fprintf(stderr, "Could not found a valid PT_NOTE.\n");
- return false;
- }
-
- // 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_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
- // 2nd thread LINUX NT_386_TLS
- //
- // 3rd thread CORE NT_PRSTATUS
- // 3rd thread CORE NT_FPREGSET
- // 3rd thread LINUX NT_PRXFPREG
- // 3rd thread LINUX NT_386_TLS
- //
- // The following code only works if notes are ordered as expected.
- switch (type) {
- case NT_PRSTATUS: {
- if (description.length() != sizeof(elf_prstatus)) {
- fprintf(stderr, "Found NT_PRSTATUS descriptor of unexpected size\n");
- return false;
- }
-
- const elf_prstatus* status =
- reinterpret_cast<const elf_prstatus*>(description.data());
- pid_t pid = status->pr_pid;
- ThreadInfo info;
- memset(&info, 0, sizeof(ThreadInfo));
- info.tgid = status->pr_pgrp;
- info.ppid = status->pr_ppid;
-#if defined(__mips__)
-#if defined(__ANDROID__)
- for (int i = EF_R0; i <= EF_R31; i++)
- info.mcontext.gregs[i - EF_R0] = status->pr_reg[i];
-#else // __ANDROID__
- for (int i = EF_REG0; i <= EF_REG31; i++)
- info.mcontext.gregs[i - EF_REG0] = status->pr_reg[i];
-#endif // __ANDROID__
- info.mcontext.mdlo = status->pr_reg[EF_LO];
- info.mcontext.mdhi = status->pr_reg[EF_HI];
- info.mcontext.pc = status->pr_reg[EF_CP0_EPC];
-#else // __mips__
- memcpy(&info.regs, status->pr_reg, sizeof(info.regs));
-#endif // __mips__
- if (first_thread) {
- crash_thread_ = pid;
- crash_signal_ = status->pr_info.si_signo;
- }
- first_thread = false;
- threads_.push_back(pid);
- thread_infos_.push_back(info);
- 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");
- return false;
- }
-
- memcpy(&info->fpregs, description.data(), sizeof(info->fpregs));
- break;
- }
-#endif
-#if defined(__i386)
- case NT_PRXFPREG: {
- if (thread_infos_.empty())
- return false;
-
- ThreadInfo* info = &thread_infos_.back();
- if (description.length() != sizeof(info->fpxregs)) {
- fprintf(stderr, "Found NT_PRXFPREG descriptor of unexpected size\n");
- return false;
- }
-
- memcpy(&info->fpxregs, description.data(), sizeof(info->fpxregs));
- break;
- }
-#endif
- }
- note = note.GetNextNote();
- } while (note.IsValid());
-
- return true;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.h
deleted file mode 100644
index 8a7c924b6..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper.h
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// linux_core_dumper.h: Define the google_breakpad::LinuxCoreDumper
-// class, which is derived from google_breakpad::LinuxDumper to extract
-// information from a crashed process via its core dump and proc files.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_CORE_DUMPER_H_
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "common/linux/elf_core_dump.h"
-#include "common/linux/memory_mapped_file.h"
-
-namespace google_breakpad {
-
-class LinuxCoreDumper : public LinuxDumper {
- public:
- // Constructs a dumper for extracting information of a given process
- // with a process ID of |pid| via its core dump file at |core_path| and
- // its proc files at |procfs_path|. If |procfs_path| is a copy of
- // /proc/<pid>, it should contain the following files:
- // auxv, cmdline, environ, exe, maps, status
- // See LinuxDumper for the purpose of |root_prefix|.
- LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path,
- const char* root_prefix = "");
-
- // Implements LinuxDumper::BuildProcPath().
- // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
- // |path| is a character array of at least NAME_MAX bytes to return the
- // result.|node| is the final node without any slashes. Return true on
- // success.
- //
- // As this dumper performs a post-mortem dump and makes use of a copy
- // of the proc files of the crashed process, this derived method does
- // not actually make use of |pid| and always returns a subpath of
- // |procfs_path_| regardless of whether |pid| corresponds to the main
- // process or a thread of the process, i.e. assuming both the main process
- // and its threads have the following proc files with the same content:
- // auxv, cmdline, environ, exe, maps, status
- virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const;
-
- // Implements LinuxDumper::CopyFromProcess().
- // Copies content of |length| bytes from a given process |child|,
- // starting from |src|, into |dest|. This method extracts the content
- // the core dump and fills |dest| with a sequence of marker bytes
- // if the expected data is not found in the core dump. Returns true if
- // the expected data is found in the core dump.
- virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length);
-
- // Implements LinuxDumper::GetThreadInfoByIndex().
- // Reads information about the |index|-th thread of |threads_|.
- // Returns true on success. One must have called |ThreadsSuspend| first.
- virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
-
- // Implements LinuxDumper::IsPostMortem().
- // Always returns true to indicate that this dumper performs a
- // post-mortem dump of a crashed process via a core dump file.
- virtual bool IsPostMortem() const;
-
- // Implements LinuxDumper::ThreadsSuspend().
- // As the dumper performs a post-mortem dump via a core dump file,
- // there is no threads to suspend. This method does nothing and
- // always returns true.
- virtual bool ThreadsSuspend();
-
- // Implements LinuxDumper::ThreadsResume().
- // As the dumper performs a post-mortem dump via a core dump file,
- // there is no threads to resume. This method does nothing and
- // always returns true.
- virtual bool ThreadsResume();
-
- protected:
- // Implements LinuxDumper::EnumerateThreads().
- // Enumerates all threads of the given process into |threads_|.
- virtual bool EnumerateThreads();
-
- private:
- // Path of the core dump file.
- const char* core_path_;
-
- // Path of the directory containing the proc files of the given process,
- // which is usually a copy of /proc/<pid>.
- const char* procfs_path_;
-
- // Memory-mapped core dump file at |core_path_|.
- MemoryMappedFile mapped_core_file_;
-
- // Content of the core dump file.
- ElfCoreDump core_;
-
- // Thread info found in the core dump file.
- wasteful_vector<ThreadInfo> thread_infos_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_LINUX_CORE_DUMPER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
deleted file mode 100644
index ae0c965b3..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// linux_core_dumper_unittest.cc:
-// Unit tests for google_breakpad::LinuxCoreDumoer.
-
-#include <string>
-
-#include "breakpad_googletest_includes.h"
-#include "client/linux/minidump_writer/linux_core_dumper.h"
-#include "common/linux/tests/crash_generator.h"
-#include "common/using_std_string.h"
-
-using namespace google_breakpad;
-
-TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) {
- const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root");
- const MappingInfo mapping = { 0, 0, 0, false, "/usr/lib/libc.so" };
-
- char path[PATH_MAX];
- dumper.GetMappingAbsolutePath(mapping, path);
-
- EXPECT_STREQ("/mnt/root/usr/lib/libc.so", path);
-}
-
-TEST(LinuxCoreDumperTest, BuildProcPath) {
- const pid_t pid = getpid();
- const char procfs_path[] = "/procfs_copy";
- LinuxCoreDumper dumper(getpid(), "core_file", procfs_path);
-
- char maps_path[NAME_MAX] = "";
- char maps_path_expected[NAME_MAX];
- snprintf(maps_path_expected, sizeof(maps_path_expected),
- "%s/maps", procfs_path);
- EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps"));
- EXPECT_STREQ(maps_path_expected, maps_path);
-
- EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps"));
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, ""));
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL));
-
- char long_node[NAME_MAX];
- size_t long_node_len = NAME_MAX - strlen(procfs_path) - 1;
- memset(long_node, 'a', long_node_len);
- long_node[long_node_len] = '\0';
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, long_node));
-}
-
-TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) {
- CrashGenerator crash_generator;
- if (!crash_generator.HasDefaultCorePattern()) {
- fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test "
- "is skipped due to non-default core pattern\n");
- return;
- }
-
- const unsigned kNumOfThreads = 3;
- const unsigned kCrashThread = 1;
- const int kCrashSignal = SIGABRT;
- 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.VerifyDumpWithMultipleThreads 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());
-
- // 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
- // 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);
- }
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc
deleted file mode 100644
index bdbdc6507..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc
+++ /dev/null
@@ -1,776 +0,0 @@
-// 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.
-
-// linux_dumper.cc: Implement google_breakpad::LinuxDumper.
-// See linux_dumper.h for details.
-
-// This code deals with the mechanics of getting information about a crashed
-// process. Since this code may run in a compromised address space, the same
-// rules apply as detailed at the top of minidump_writer.h: no libc calls and
-// use the alternative allocator.
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-
-#include <assert.h>
-#include <elf.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stddef.h>
-#include <string.h>
-
-#include "client/linux/minidump_writer/line_reader.h"
-#include "common/linux/elfutils.h"
-#include "common/linux/file_id.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/linux/memory_mapped_file.h"
-#include "common/linux/safe_readlink.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-#if defined(__ANDROID__)
-
-// Android packed relocations definitions are not yet available from the
-// NDK header files, so we have to provide them manually here.
-#ifndef DT_LOOS
-#define DT_LOOS 0x6000000d
-#endif
-#ifndef DT_ANDROID_REL
-static const int DT_ANDROID_REL = DT_LOOS + 2;
-#endif
-#ifndef DT_ANDROID_RELA
-static const int DT_ANDROID_RELA = DT_LOOS + 4;
-#endif
-
-#endif // __ANDROID __
-
-static const char kMappedFileUnsafePrefix[] = "/dev/";
-static const char kDeletedSuffix[] = " (deleted)";
-static const char kReservedFlags[] = " ---p";
-
-inline static bool IsMappedFileOpenUnsafe(
- const google_breakpad::MappingInfo& mapping) {
- // It is unsafe to attempt to open a mapped file that lives under /dev,
- // because the semantics of the open may be driver-specific so we'd risk
- // hanging the crash dumper. And a file in /dev/ almost certainly has no
- // ELF file identifier anyways.
- return my_strncmp(mapping.name,
- kMappedFileUnsafePrefix,
- sizeof(kMappedFileUnsafePrefix) - 1) == 0;
-}
-
-namespace google_breakpad {
-
-#if defined(__CHROMEOS__)
-
-namespace {
-
-// Recover memory mappings before writing dump on ChromeOS
-//
-// On Linux, breakpad relies on /proc/[pid]/maps to associate symbols from
-// addresses. ChromeOS' hugepage implementation replaces some segments with
-// anonymous private pages, which is a restriction of current implementation
-// in Linux kernel at the time of writing. Thus, breakpad can no longer
-// symbolize addresses from those text segments replaced with hugepages.
-//
-// This postprocess tries to recover the mappings. Because hugepages are always
-// inserted in between some .text sections, it tries to infer the names and
-// offsets of the segments, by looking at segments immediately precede and
-// succeed them.
-//
-// For example, a text segment before hugepage optimization
-// 02001000-03002000 r-xp /opt/google/chrome/chrome
-//
-// can be broken into
-// 02001000-02200000 r-xp /opt/google/chrome/chrome
-// 02200000-03000000 r-xp
-// 03000000-03002000 r-xp /opt/google/chrome/chrome
-//
-// For more details, see:
-// crbug.com/628040 ChromeOS' use of hugepages confuses crash symbolization
-
-// Copied from CrOS' hugepage implementation, which is unlikely to change.
-// The hugepage size is 2M.
-const unsigned int kHpageShift = 21;
-const size_t kHpageSize = (1 << kHpageShift);
-const size_t kHpageMask = (~(kHpageSize - 1));
-
-// Find and merge anonymous r-xp segments with surrounding named segments.
-// There are two cases:
-
-// Case 1: curr, next
-// curr is anonymous
-// curr is r-xp
-// curr.size >= 2M
-// curr.size is a multiple of 2M.
-// next is backed by some file.
-// curr and next are contiguous.
-// offset(next) == sizeof(curr)
-void TryRecoverMappings(MappingInfo *curr, MappingInfo *next) {
- // Merged segments are marked with size = 0.
- if (curr->size == 0 || next->size == 0)
- return;
-
- if (curr->size >= kHpageSize &&
- curr->exec &&
- (curr->size & kHpageMask) == curr->size &&
- (curr->start_addr & kHpageMask) == curr->start_addr &&
- curr->name[0] == '\0' &&
- next->name[0] != '\0' &&
- curr->start_addr + curr->size == next->start_addr &&
- curr->size == next->offset) {
-
- // matched
- my_strlcpy(curr->name, next->name, NAME_MAX);
- if (next->exec) {
- // (curr, next)
- curr->size += next->size;
- next->size = 0;
- }
- }
-}
-
-// Case 2: prev, curr, next
-// curr is anonymous
-// curr is r-xp
-// curr.size >= 2M
-// curr.size is a multiple of 2M.
-// next and prev are backed by the same file.
-// prev, curr and next are contiguous.
-// offset(next) == offset(prev) + sizeof(prev) + sizeof(curr)
-void TryRecoverMappings(MappingInfo *prev, MappingInfo *curr,
- MappingInfo *next) {
- // Merged segments are marked with size = 0.
- if (prev->size == 0 || curr->size == 0 || next->size == 0)
- return;
-
- if (curr->size >= kHpageSize &&
- curr->exec &&
- (curr->size & kHpageMask) == curr->size &&
- (curr->start_addr & kHpageMask) == curr->start_addr &&
- curr->name[0] == '\0' &&
- next->name[0] != '\0' &&
- curr->start_addr + curr->size == next->start_addr &&
- prev->start_addr + prev->size == curr->start_addr &&
- my_strncmp(prev->name, next->name, NAME_MAX) == 0 &&
- next->offset == prev->offset + prev->size + curr->size) {
-
- // matched
- my_strlcpy(curr->name, prev->name, NAME_MAX);
- if (prev->exec) {
- curr->offset = prev->offset;
- curr->start_addr = prev->start_addr;
- if (next->exec) {
- // (prev, curr, next)
- curr->size += prev->size + next->size;
- prev->size = 0;
- next->size = 0;
- } else {
- // (prev, curr), next
- curr->size += prev->size;
- prev->size = 0;
- }
- } else {
- curr->offset = prev->offset + prev->size;
- if (next->exec) {
- // prev, (curr, next)
- curr->size += next->size;
- next->size = 0;
- } else {
- // prev, curr, next
- }
- }
- }
-}
-
-// mappings_ is sorted excepted for the first entry.
-// This function tries to merge segemnts into the first entry,
-// then check for other sorted entries.
-// See LinuxDumper::EnumerateMappings().
-void CrOSPostProcessMappings(wasteful_vector<MappingInfo*>& mappings) {
- // Find the candidate "next" to first segment, which is the only one that
- // could be out-of-order.
- size_t l = 1;
- size_t r = mappings.size();
- size_t next = mappings.size();
- while (l < r) {
- int m = (l + r) / 2;
- if (mappings[m]->start_addr > mappings[0]->start_addr)
- r = next = m;
- else
- l = m + 1;
- }
-
- // Try to merge segments into the first.
- if (next < mappings.size()) {
- TryRecoverMappings(mappings[0], mappings[next]);
- if (next - 1 > 0)
- TryRecoverMappings(mappings[next - 1], mappings[0], mappings[next]);
- }
-
- // Iterate through normal, sorted cases.
- // Normal case 1.
- for (size_t i = 1; i < mappings.size() - 1; i++)
- TryRecoverMappings(mappings[i], mappings[i + 1]);
-
- // Normal case 2.
- for (size_t i = 1; i < mappings.size() - 2; i++)
- TryRecoverMappings(mappings[i], mappings[i + 1], mappings[i + 2]);
-
- // Collect merged (size == 0) segments.
- size_t f, e;
- for (f = e = 0; e < mappings.size(); e++)
- if (mappings[e]->size > 0)
- mappings[f++] = mappings[e];
- mappings.resize(f);
-}
-
-} // namespace
-#endif // __CHROMEOS__
-
-// All interesting auvx entry types are below AT_SYSINFO_EHDR
-#define AT_MAX AT_SYSINFO_EHDR
-
-LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix)
- : pid_(pid),
- root_prefix_(root_prefix),
- crash_address_(0),
- crash_signal_(0),
- crash_thread_(pid),
- threads_(&allocator_, 8),
- mappings_(&allocator_),
- auxv_(&allocator_, AT_MAX + 1) {
- assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX);
- // The passed-in size to the constructor (above) is only a hint.
- // Must call .resize() to do actual initialization of the elements.
- auxv_.resize(AT_MAX + 1);
-}
-
-LinuxDumper::~LinuxDumper() {
-}
-
-bool LinuxDumper::Init() {
- return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
-}
-
-bool LinuxDumper::LateInit() {
-#if defined(__ANDROID__)
- LatePostprocessMappings();
-#endif
-
-#if defined(__CHROMEOS__)
- CrOSPostProcessMappings(mappings_);
-#endif
-
- return true;
-}
-
-bool
-LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
- bool member,
- unsigned int mapping_id,
- wasteful_vector<uint8_t>& identifier) {
- assert(!member || mapping_id < mappings_.size());
- if (IsMappedFileOpenUnsafe(mapping))
- return false;
-
- // Special-case linux-gate because it's not a real file.
- if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
- void* linux_gate = NULL;
- if (pid_ == sys_getpid()) {
- linux_gate = reinterpret_cast<void*>(mapping.start_addr);
- } else {
- linux_gate = allocator_.Alloc(mapping.size);
- CopyFromProcess(linux_gate, pid_,
- reinterpret_cast<const void*>(mapping.start_addr),
- mapping.size);
- }
- return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
- }
-
- char filename[PATH_MAX];
- if (!GetMappingAbsolutePath(mapping, filename))
- return false;
- bool filename_modified = HandleDeletedFileInMapping(filename);
-
- MemoryMappedFile mapped_file(filename, mapping.offset);
- if (!mapped_file.data() || mapped_file.size() < SELFMAG)
- return false;
-
- bool success =
- FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
- if (success && member && filename_modified) {
- mappings_[mapping_id]->name[my_strlen(mapping.name) -
- sizeof(kDeletedSuffix) + 1] = '\0';
- }
-
- return success;
-}
-
-bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
- char path[PATH_MAX]) const {
- return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX &&
- my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX;
-}
-
-namespace {
-bool ElfFileSoNameFromMappedFile(
- const void* elf_base, char* soname, size_t soname_size) {
- if (!IsValidElf(elf_base)) {
- // Not ELF
- return false;
- }
-
- const void* segment_start;
- size_t segment_size;
- int elf_class;
- if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC,
- &segment_start, &segment_size, &elf_class)) {
- // No dynamic section
- return false;
- }
-
- const void* dynstr_start;
- size_t dynstr_size;
- if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB,
- &dynstr_start, &dynstr_size, &elf_class)) {
- // No dynstr section
- return false;
- }
-
- const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
- size_t dcount = segment_size / sizeof(ElfW(Dyn));
- for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
- if (dyn->d_tag == DT_SONAME) {
- const char* dynstr = static_cast<const char*>(dynstr_start);
- if (dyn->d_un.d_val >= dynstr_size) {
- // Beyond the end of the dynstr section
- return false;
- }
- const char* str = dynstr + dyn->d_un.d_val;
- const size_t maxsize = dynstr_size - dyn->d_un.d_val;
- my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
- return true;
- }
- }
-
- // Did not find SONAME
- return false;
-}
-
-// Find the shared object name (SONAME) by examining the ELF information
-// for |mapping|. If the SONAME is found copy it into the passed buffer
-// |soname| and return true. The size of the buffer is |soname_size|.
-// The SONAME will be truncated if it is too long to fit in the buffer.
-bool ElfFileSoName(const LinuxDumper& dumper,
- const MappingInfo& mapping, char* soname, size_t soname_size) {
- if (IsMappedFileOpenUnsafe(mapping)) {
- // Not safe
- return false;
- }
-
- char filename[PATH_MAX];
- if (!dumper.GetMappingAbsolutePath(mapping, filename))
- return false;
-
- MemoryMappedFile mapped_file(filename, mapping.offset);
- if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
- // mmap failed
- return false;
- }
-
- return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
-}
-
-} // namespace
-
-
-void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
- char* file_path,
- size_t file_path_size,
- char* file_name,
- size_t file_name_size) {
- my_strlcpy(file_path, mapping.name, file_path_size);
-
- // If an executable is mapped from a non-zero offset, this is likely because
- // the executable was loaded directly from inside an archive file (e.g., an
- // apk on Android). We try to find the name of the shared object (SONAME) by
- // looking in the file for ELF sections.
- bool mapped_from_archive = false;
- if (mapping.exec && mapping.offset != 0) {
- mapped_from_archive =
- ElfFileSoName(*this, mapping, file_name, file_name_size);
- }
-
- if (mapped_from_archive) {
- // Some tools (e.g., stackwalk) extract the basename from the pathname. In
- // this case, we append the file_name to the mapped archive path as follows:
- // file_name := libname.so
- // file_path := /path/to/ARCHIVE.APK/libname.so
- if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
- my_strlcat(file_path, "/", file_path_size);
- my_strlcat(file_path, file_name, file_path_size);
- }
- } else {
- // Common case:
- // file_path := /path/to/libname.so
- // file_name := libname.so
- const char* basename = my_strrchr(file_path, '/');
- basename = basename == NULL ? file_path : (basename + 1);
- my_strlcpy(file_name, basename, file_name_size);
- }
-}
-
-bool LinuxDumper::ReadAuxv() {
- char auxv_path[NAME_MAX];
- if (!BuildProcPath(auxv_path, pid_, "auxv")) {
- return false;
- }
-
- int fd = sys_open(auxv_path, O_RDONLY, 0);
- if (fd < 0) {
- return false;
- }
-
- elf_aux_entry one_aux_entry;
- bool res = false;
- while (sys_read(fd,
- &one_aux_entry,
- sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
- one_aux_entry.a_type != AT_NULL) {
- if (one_aux_entry.a_type <= AT_MAX) {
- auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val;
- res = true;
- }
- }
- sys_close(fd);
- return res;
-}
-
-bool LinuxDumper::EnumerateMappings() {
- char maps_path[NAME_MAX];
- if (!BuildProcPath(maps_path, pid_, "maps"))
- return false;
-
- // linux_gate_loc is the beginning of the kernel's mapping of
- // linux-gate.so in the process. It doesn't actually show up in the
- // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR
- // aux vector entry, which gives the information necessary to special
- // case its entry when creating the list of mappings.
- // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
- // information.
- const void* linux_gate_loc =
- reinterpret_cast<void *>(auxv_[AT_SYSINFO_EHDR]);
- // Although the initial executable is usually the first mapping, it's not
- // guaranteed (see http://crosbug.com/25355); therefore, try to use the
- // actual entry point to find the mapping.
- const void* entry_point_loc = reinterpret_cast<void *>(auxv_[AT_ENTRY]);
-
- const int fd = sys_open(maps_path, O_RDONLY, 0);
- if (fd < 0)
- return false;
- LineReader* const line_reader = new(allocator_) LineReader(fd);
-
- const char* line;
- unsigned line_len;
- while (line_reader->GetNextLine(&line, &line_len)) {
- uintptr_t start_addr, end_addr, offset;
-
- const char* i1 = my_read_hex_ptr(&start_addr, line);
- if (*i1 == '-') {
- const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
- if (*i2 == ' ') {
- bool exec = (*(i2 + 3) == 'x');
- const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
- if (*i3 == ' ') {
- const char* name = NULL;
- // Only copy name if the name is a valid path name, or if
- // it's the VDSO image.
- if (((name = my_strchr(line, '/')) == NULL) &&
- linux_gate_loc &&
- reinterpret_cast<void*>(start_addr) == linux_gate_loc) {
- name = kLinuxGateLibraryName;
- offset = 0;
- }
- // Merge adjacent mappings with the same name into one module,
- // assuming they're a single library mapped by the dynamic linker
- if (name && !mappings_.empty()) {
- MappingInfo* module = mappings_.back();
- if ((start_addr == module->start_addr + module->size) &&
- (my_strlen(name) == my_strlen(module->name)) &&
- (my_strncmp(name, module->name, my_strlen(name)) == 0)) {
- module->size = end_addr - module->start_addr;
- line_reader->PopLine(line_len);
- continue;
- }
- }
- // Also merge mappings that result from address ranges that the
- // linker reserved but which a loaded library did not use. These
- // appear as an anonymous private mapping with no access flags set
- // and which directly follow an executable mapping.
- if (!name && !mappings_.empty()) {
- MappingInfo* module = mappings_.back();
- if ((start_addr == module->start_addr + module->size) &&
- module->exec &&
- module->name[0] == '/' &&
- offset == 0 && my_strncmp(i2,
- kReservedFlags,
- sizeof(kReservedFlags) - 1) == 0) {
- module->size = end_addr - module->start_addr;
- line_reader->PopLine(line_len);
- continue;
- }
- }
- MappingInfo* const module = new(allocator_) MappingInfo;
- my_memset(module, 0, sizeof(MappingInfo));
- module->start_addr = start_addr;
- module->size = end_addr - start_addr;
- module->offset = offset;
- module->exec = exec;
- if (name != NULL) {
- const unsigned l = my_strlen(name);
- if (l < sizeof(module->name))
- my_memcpy(module->name, name, l);
- }
- // If this is the entry-point mapping, and it's not already the
- // first one, then we need to make it be first. This is because
- // the minidump format assumes the first module is the one that
- // corresponds to the main executable (as codified in
- // processor/minidump.cc:MinidumpModuleList::GetMainModule()).
- if (entry_point_loc &&
- (entry_point_loc >=
- reinterpret_cast<void*>(module->start_addr)) &&
- (entry_point_loc <
- reinterpret_cast<void*>(module->start_addr+module->size)) &&
- !mappings_.empty()) {
- // push the module onto the front of the list.
- mappings_.resize(mappings_.size() + 1);
- for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
- mappings_[idx] = mappings_[idx - 1];
- mappings_[0] = module;
- } else {
- mappings_.push_back(module);
- }
- }
- }
- }
- line_reader->PopLine(line_len);
- }
-
- sys_close(fd);
-
- return !mappings_.empty();
-}
-
-#if defined(__ANDROID__)
-
-bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
- CopyFromProcess(ehdr, pid_,
- reinterpret_cast<const void*>(start_addr),
- sizeof(*ehdr));
- return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0;
-}
-
-void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
- uintptr_t start_addr,
- uintptr_t* min_vaddr_ptr,
- uintptr_t* dyn_vaddr_ptr,
- size_t* dyn_count_ptr) {
- uintptr_t phdr_addr = start_addr + ehdr->e_phoff;
-
- const uintptr_t max_addr = UINTPTR_MAX;
- uintptr_t min_vaddr = max_addr;
- uintptr_t dyn_vaddr = 0;
- size_t dyn_count = 0;
-
- for (size_t i = 0; i < ehdr->e_phnum; ++i) {
- ElfW(Phdr) phdr;
- CopyFromProcess(&phdr, pid_,
- reinterpret_cast<const void*>(phdr_addr),
- sizeof(phdr));
- if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) {
- min_vaddr = phdr.p_vaddr;
- }
- if (phdr.p_type == PT_DYNAMIC) {
- dyn_vaddr = phdr.p_vaddr;
- dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn));
- }
- phdr_addr += sizeof(phdr);
- }
-
- *min_vaddr_ptr = min_vaddr;
- *dyn_vaddr_ptr = dyn_vaddr;
- *dyn_count_ptr = dyn_count;
-}
-
-bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
- uintptr_t dyn_vaddr,
- size_t dyn_count) {
- uintptr_t dyn_addr = load_bias + dyn_vaddr;
- for (size_t i = 0; i < dyn_count; ++i) {
- ElfW(Dyn) dyn;
- CopyFromProcess(&dyn, pid_,
- reinterpret_cast<const void*>(dyn_addr),
- sizeof(dyn));
- if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) {
- return true;
- }
- dyn_addr += sizeof(dyn);
- }
- return false;
-}
-
-uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr,
- uintptr_t start_addr) {
- uintptr_t min_vaddr = 0;
- uintptr_t dyn_vaddr = 0;
- size_t dyn_count = 0;
- ParseLoadedElfProgramHeaders(ehdr, start_addr,
- &min_vaddr, &dyn_vaddr, &dyn_count);
- // If |min_vaddr| is non-zero and we find Android packed relocation tags,
- // return the effective load bias.
- if (min_vaddr != 0) {
- const uintptr_t load_bias = start_addr - min_vaddr;
- if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) {
- return load_bias;
- }
- }
- // Either |min_vaddr| is zero, or it is non-zero but we did not find the
- // expected Android packed relocations tags.
- return start_addr;
-}
-
-void LinuxDumper::LatePostprocessMappings() {
- for (size_t i = 0; i < mappings_.size(); ++i) {
- // Only consider exec mappings that indicate a file path was mapped, and
- // where the ELF header indicates a mapped shared library.
- MappingInfo* mapping = mappings_[i];
- if (!(mapping->exec && mapping->name[0] == '/')) {
- continue;
- }
- ElfW(Ehdr) ehdr;
- if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
- continue;
- }
- if (ehdr.e_type == ET_DYN) {
- // Compute the effective load bias for this mapped library, and update
- // the mapping to hold that rather than |start_addr|, at the same time
- // adjusting |size| to account for the change in |start_addr|. Where
- // the library does not contain Android packed relocations,
- // GetEffectiveLoadBias() returns |start_addr| and the mapping entry
- // is not changed.
- const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr,
- mapping->start_addr);
- mapping->size += mapping->start_addr - load_bias;
- mapping->start_addr = load_bias;
- }
- }
-}
-
-#endif // __ANDROID__
-
-// Get information about the stack, given the stack pointer. We don't try to
-// walk the stack since we might not have all the information needed to do
-// unwind. So we just grab, up to, 32k of stack.
-bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
- uintptr_t int_stack_pointer) {
- // Move the stack pointer to the bottom of the page that it's in.
- const uintptr_t page_size = getpagesize();
-
- uint8_t* const stack_pointer =
- reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
-
- // The number of bytes of stack which we try to capture.
- static const ptrdiff_t kStackToCapture = 32 * 1024;
-
- const MappingInfo* mapping = FindMapping(stack_pointer);
- if (!mapping)
- return false;
- const ptrdiff_t offset = stack_pointer -
- reinterpret_cast<uint8_t*>(mapping->start_addr);
- const ptrdiff_t distance_to_end =
- static_cast<ptrdiff_t>(mapping->size) - offset;
- *stack_len = distance_to_end > kStackToCapture ?
- kStackToCapture : distance_to_end;
- *stack = stack_pointer;
- return true;
-}
-
-// Find the mapping which the given memory address falls in.
-const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
- const uintptr_t addr = (uintptr_t) address;
-
- for (size_t i = 0; i < mappings_.size(); ++i) {
- const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
- if (addr >= start && addr - start < mappings_[i]->size)
- return mappings_[i];
- }
-
- return NULL;
-}
-
-bool LinuxDumper::HandleDeletedFileInMapping(char* path) const {
- static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
-
- // Check for ' (deleted)' in |path|.
- // |path| has to be at least as long as "/x (deleted)".
- const size_t path_len = my_strlen(path);
- if (path_len < kDeletedSuffixLen + 2)
- return false;
- if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
- kDeletedSuffixLen) != 0) {
- return false;
- }
-
- // Check |path| against the /proc/pid/exe 'symlink'.
- char exe_link[NAME_MAX];
- if (!BuildProcPath(exe_link, pid_, "exe"))
- return false;
- MappingInfo new_mapping = {0};
- if (!SafeReadLink(exe_link, new_mapping.name))
- return false;
- char new_path[PATH_MAX];
- if (!GetMappingAbsolutePath(new_mapping, new_path))
- return false;
- if (my_strcmp(path, new_path) != 0)
- return false;
-
- // Check to see if someone actually named their executable 'foo (deleted)'.
- struct kernel_stat exe_stat;
- struct kernel_stat new_path_stat;
- if (sys_stat(exe_link, &exe_stat) == 0 &&
- sys_stat(new_path, &new_path_stat) == 0 &&
- exe_stat.st_dev == new_path_stat.st_dev &&
- exe_stat.st_ino == new_path_stat.st_ino) {
- return false;
- }
-
- my_memcpy(path, exe_link, NAME_MAX);
- return true;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h
deleted file mode 100644
index c3c799267..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h
+++ /dev/null
@@ -1,265 +0,0 @@
-// 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.
-
-// linux_dumper.h: Define the google_breakpad::LinuxDumper class, which
-// is a base class for extracting information of a crashed process. It
-// was originally a complete implementation using the ptrace API, but
-// 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 <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 "client/linux/dump_writer_common/mapping_info.h"
-#include "client/linux/dump_writer_common/thread_info.h"
-#include "common/linux/file_id.h"
-#include "common/memory.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
-#if defined(__i386) || defined(__ARM_EABI__) || \
- (defined(__mips__) && _MIPS_SIM == _ABIO32)
-typedef Elf32_auxv_t elf_aux_entry;
-#elif defined(__x86_64) || defined(__aarch64__) || \
- (defined(__mips__) && _MIPS_SIM != _ABIO32)
-typedef Elf64_auxv_t elf_aux_entry;
-#endif
-
-typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t;
-
-// When we find the VDSO mapping in the process's address space, this
-// is the name we use for it when writing it to the minidump.
-// This should always be less than NAME_MAX!
-const char kLinuxGateLibraryName[] = "linux-gate.so";
-
-class LinuxDumper {
- public:
- // The |root_prefix| is prepended to mapping paths before opening them, which
- // is useful if the crash originates from a chroot.
- explicit LinuxDumper(pid_t pid, const char* root_prefix = "");
-
- virtual ~LinuxDumper();
-
- // Parse the data for |threads| and |mappings|.
- virtual bool Init();
-
- // Take any actions that could not be taken in Init(). LateInit() is
- // called after all other caller's initialization is complete, and in
- // particular after it has called ThreadsSuspend(), so that ptrace is
- // available.
- virtual bool LateInit();
-
- // Return true if the dumper performs a post-mortem dump.
- virtual bool IsPostMortem() const = 0;
-
- // Suspend/resume all threads in the given process.
- virtual bool ThreadsSuspend() = 0;
- virtual bool ThreadsResume() = 0;
-
- // Read information about the |index|-th thread of |threads_|.
- // Returns true on success. One must have called |ThreadsSuspend| first.
- virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0;
-
- // These are only valid after a call to |Init|.
- const wasteful_vector<pid_t> &threads() { return threads_; }
- const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
- const MappingInfo* FindMapping(const void* address) const;
- const wasteful_vector<elf_aux_val_t>& auxv() { return auxv_; }
-
- // Find a block of memory to take as the stack given the top of stack pointer.
- // stack: (output) the lowest address in the memory area
- // stack_len: (output) the length of the memory area
- // stack_top: the current top of the stack
- bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
-
- PageAllocator* allocator() { return &allocator_; }
-
- // Copy content of |length| bytes from a given process |child|,
- // starting from |src|, into |dest|. Returns true on success.
- virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length) = 0;
-
- // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
- // |path| is a character array of at least NAME_MAX bytes to return the
- // result.|node| is the final node without any slashes. Returns true on
- // success.
- virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0;
-
- // Generate a File ID from the .text section of a mapped entry.
- // If not a member, mapping_id is ignored. This method can also manipulate the
- // |mapping|.name to truncate "(deleted)" from the file name if necessary.
- bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
- bool member,
- unsigned int mapping_id,
- wasteful_vector<uint8_t>& identifier);
-
- uintptr_t crash_address() const { return crash_address_; }
- void set_crash_address(uintptr_t crash_address) {
- crash_address_ = crash_address;
- }
-
- int crash_signal() const { return crash_signal_; }
- void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; }
-
- 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;
-
- // Extracts the effective path and file name of from |mapping|. In most cases
- // the effective name/path are just the mapping's path and basename. In some
- // other cases, however, a library can be mapped from an archive (e.g., when
- // loading .so libs from an apk on Android) and this method is able to
- // reconstruct the original file name.
- void GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
- char* file_path,
- size_t file_path_size,
- char* file_name,
- size_t file_name_size);
-
- protected:
- bool ReadAuxv();
-
- virtual bool EnumerateMappings();
-
- virtual bool EnumerateThreads() = 0;
-
- // For the case where a running program has been deleted, it'll show up in
- // /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
- // see if '/path/to/program (deleted)' matches /proc/pid/exe and return
- // /proc/pid/exe in |path| so ELF identifier generation works correctly. This
- // also checks to see if '/path/to/program (deleted)' exists, so it does not
- // get fooled by a poorly named binary.
- // For programs that don't end with ' (deleted)', this is a no-op.
- // This assumes |path| is a buffer with length NAME_MAX.
- // Returns true if |path| is modified.
- bool HandleDeletedFileInMapping(char* path) const;
-
- // ID of the crashed process.
- const pid_t pid_;
-
- // Path of the root directory to which mapping paths are relative.
- const char* const root_prefix_;
-
- // Virtual address at which the process crashed.
- uintptr_t crash_address_;
-
- // Signal that terminated the crashed process.
- int crash_signal_;
-
- // ID of the crashed thread.
- pid_t crash_thread_;
-
- mutable PageAllocator allocator_;
-
- // IDs of all the threads.
- wasteful_vector<pid_t> threads_;
-
- // Info from /proc/<pid>/maps.
- wasteful_vector<MappingInfo*> mappings_;
-
- // Info from /proc/<pid>/auxv
- wasteful_vector<elf_aux_val_t> auxv_;
-
-#if defined(__ANDROID__)
- private:
- // Android M and later support packed ELF relocations in shared libraries.
- // Packing relocations changes the vaddr of the LOAD segments, such that
- // the effective load bias is no longer the same as the start address of
- // the memory mapping containing the executable parts of the library. The
- // packing is applied to the stripped library run on the target, but not to
- // any other library, and in particular not to the library used to generate
- // breakpad symbols. As a result, we need to adjust the |start_addr| for
- // any mapping that results from a shared library that contains Android
- // packed relocations, so that it properly represents the effective library
- // load bias. The following functions support this adjustment.
-
- // Check that a given mapping at |start_addr| is for an ELF shared library.
- // If it is, place the ELF header in |ehdr| and return true.
- // The first LOAD segment in an ELF shared library has offset zero, so the
- // ELF file header is at the start of this map entry, and in already mapped
- // memory.
- bool GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr);
-
- // For the ELF file mapped at |start_addr|, iterate ELF program headers to
- // find the min vaddr of all program header LOAD segments, the vaddr for
- // the DYNAMIC segment, and a count of DYNAMIC entries. Return values in
- // |min_vaddr_ptr|, |dyn_vaddr_ptr|, and |dyn_count_ptr|.
- // The program header table is also in already mapped memory.
- void ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
- uintptr_t start_addr,
- uintptr_t* min_vaddr_ptr,
- uintptr_t* dyn_vaddr_ptr,
- size_t* dyn_count_ptr);
-
- // Search the DYNAMIC tags for the ELF file with the given |load_bias|, and
- // return true if the tags indicate that the file contains Android packed
- // relocations. Dynamic tags are found at |dyn_vaddr| past the |load_bias|.
- bool HasAndroidPackedRelocations(uintptr_t load_bias,
- uintptr_t dyn_vaddr,
- size_t dyn_count);
-
- // If the ELF file mapped at |start_addr| contained Android packed
- // relocations, return the load bias that the system linker (or Chromium
- // crazy linker) will have used. If the file did not contain Android
- // packed relocations, returns |start_addr|, indicating that no adjustment
- // is necessary.
- // The effective load bias is |start_addr| adjusted downwards by the
- // min vaddr in the library LOAD segments.
- uintptr_t GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, uintptr_t start_addr);
-
- // Called from LateInit(). Iterates |mappings_| and rewrites the |start_addr|
- // field of any that represent ELF shared libraries with Android packed
- // relocations, so that |start_addr| is the load bias that the system linker
- // (or Chromium crazy linker) used. This value matches the addresses produced
- // when the non-relocation-packed library is used for breakpad symbol
- // generation.
- void LatePostprocessMappings();
-#endif // __ANDROID__
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
deleted file mode 100644
index 4ccb7201f..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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.
-//
-// Helper program for the linux_dumper class, which creates a bunch of
-// threads. The first word of each thread's stack is set to the thread
-// id.
-
-#include <pthread.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "common/scoped_ptr.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-#if defined(__ARM_EABI__)
-#define TID_PTR_REGISTER "r3"
-#elif defined(__aarch64__)
-#define TID_PTR_REGISTER "x3"
-#elif defined(__i386)
-#define TID_PTR_REGISTER "ecx"
-#elif defined(__x86_64)
-#define TID_PTR_REGISTER "rcx"
-#elif defined(__mips__)
-#define TID_PTR_REGISTER "$1"
-#else
-#error This test has not been ported to this platform.
-#endif
-
-void *thread_function(void *data) {
- int pipefd = *static_cast<int *>(data);
- volatile pid_t thread_id = syscall(__NR_gettid);
- // Signal parent that a thread has started.
- uint8_t byte = 1;
- if (write(pipefd, &byte, sizeof(byte)) != sizeof(byte)) {
- perror("ERROR: parent notification failed");
- return NULL;
- }
- register volatile pid_t *thread_id_ptr asm(TID_PTR_REGISTER) = &thread_id;
- while (true)
- asm volatile ("" : : "r" (thread_id_ptr));
- return NULL;
-}
-
-int main(int argc, char *argv[]) {
- if (argc < 3) {
- fprintf(stderr,
- "usage: linux_dumper_unittest_helper <pipe fd> <# of threads>\n");
- return 1;
- }
- int pipefd = atoi(argv[1]);
- int num_threads = atoi(argv[2]);
- if (num_threads < 1) {
- fprintf(stderr, "ERROR: number of threads is 0");
- return 1;
- }
- google_breakpad::scoped_array<pthread_t> threads(new pthread_t[num_threads]);
- pthread_attr_t thread_attributes;
- pthread_attr_init(&thread_attributes);
- pthread_attr_setdetachstate(&thread_attributes, PTHREAD_CREATE_DETACHED);
- for (int i = 1; i < num_threads; i++) {
- pthread_create(&threads[i], &thread_attributes, &thread_function, &pipefd);
- }
- thread_function(&pipefd);
- return 0;
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
deleted file mode 100644
index c35e0e958..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper.
-// See linux_ptrace_dumper.h for detals.
-// This class was originally splitted from google_breakpad::LinuxDumper.
-
-// This code deals with the mechanics of getting information about a crashed
-// process. Since this code may run in a compromised address space, the same
-// rules apply as detailed at the top of minidump_writer.h: no libc calls and
-// use the alternative allocator.
-
-#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
-
-#include <asm/ptrace.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-
-#if defined(__i386)
-#include <cpuid.h>
-#endif
-
-#include "client/linux/minidump_writer/directory_reader.h"
-#include "client/linux/minidump_writer/line_reader.h"
-#include "common/linux/linux_libc_support.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-// Suspends a thread by attaching to it.
-static bool SuspendThread(pid_t pid) {
- // This may fail if the thread has just died or debugged.
- errno = 0;
- if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
- errno != 0) {
- return false;
- }
- while (sys_waitpid(pid, NULL, __WALL) < 0) {
- if (errno != EINTR) {
- sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
- return false;
- }
- }
-#if defined(__i386) || defined(__x86_64)
- // On x86, the stack pointer is NULL or -1, when executing trusted code in
- // the seccomp sandbox. Not only does this cause difficulties down the line
- // when trying to dump the thread's stack, it also results in the minidumps
- // containing information about the trusted threads. This information is
- // generally completely meaningless and just pollutes the minidumps.
- // We thus test the stack pointer and exclude any threads that are part of
- // the seccomp sandbox's trusted code.
- user_regs_struct regs;
- if (sys_ptrace(PTRACE_GETREGS, pid, NULL, &regs) == -1 ||
-#if defined(__i386)
- !regs.esp
-#elif defined(__x86_64)
- !regs.rsp
-#endif
- ) {
- sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
- return false;
- }
-#endif
- return true;
-}
-
-// Resumes a thread by detaching from it.
-static bool ResumeThread(pid_t pid) {
- return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
-}
-
-namespace google_breakpad {
-
-LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid)
- : LinuxDumper(pid),
- threads_suspended_(false) {
-}
-
-bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid,
- const char* node) const {
- if (!path || !node || pid <= 0)
- return false;
-
- size_t node_len = my_strlen(node);
- if (node_len == 0)
- return false;
-
- const unsigned pid_len = my_uint_len(pid);
- const size_t total_length = 6 + pid_len + 1 + node_len;
- if (total_length >= NAME_MAX)
- return false;
-
- my_memcpy(path, "/proc/", 6);
- my_uitos(path + 6, pid, pid_len);
- path[6 + pid_len] = '/';
- my_memcpy(path + 6 + pid_len + 1, node, node_len);
- path[total_length] = '\0';
- return true;
-}
-
-bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
- const void* src, size_t length) {
- unsigned long tmp = 55;
- size_t done = 0;
- static const size_t word_size = sizeof(tmp);
- uint8_t* const local = (uint8_t*) dest;
- uint8_t* const remote = (uint8_t*) src;
-
- while (done < length) {
- const size_t l = (length - done > word_size) ? word_size : (length - done);
- if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) {
- tmp = 0;
- }
- my_memcpy(local + done, &tmp, l);
- done += l;
- }
- return true;
-}
-
-// Read thread info from /proc/$pid/status.
-// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable,
-// these members are set to -1. Returns true iff all three members are
-// available.
-bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) {
- if (index >= threads_.size())
- return false;
-
- pid_t tid = threads_[index];
-
- assert(info != NULL);
- char status_path[NAME_MAX];
- if (!BuildProcPath(status_path, tid, "status"))
- return false;
-
- const int fd = sys_open(status_path, O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- LineReader* const line_reader = new(allocator_) LineReader(fd);
- const char* line;
- unsigned line_len;
-
- info->ppid = info->tgid = -1;
-
- while (line_reader->GetNextLine(&line, &line_len)) {
- if (my_strncmp("Tgid:\t", line, 6) == 0) {
- my_strtoui(&info->tgid, line + 6);
- } else if (my_strncmp("PPid:\t", line, 6) == 0) {
- my_strtoui(&info->ppid, line + 6);
- }
-
- line_reader->PopLine(line_len);
- }
- sys_close(fd);
-
- if (info->ppid == -1 || info->tgid == -1)
- return false;
-
-#ifdef PTRACE_GETREGSET
- struct iovec io;
- info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len);
- if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) {
- return false;
- }
-
- info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
- if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
- return false;
- }
-#else // PTRACE_GETREGSET
- void* gp_addr;
- info->GetGeneralPurposeRegisters(&gp_addr, NULL);
- if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) {
- return false;
- }
-
-#if !(defined(__ANDROID__) && defined(__ARM_EABI__))
- // When running an arm build on an arm64 device, attempting to get the
- // floating point registers fails. On Android, the floating point registers
- // aren't written to the cpu context anyway, so just don't get them here.
- // See http://crbug.com/508324
- void* fp_addr;
- info->GetFloatingPointRegisters(&fp_addr, NULL);
- if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
- return false;
- }
-#endif
-#endif // PTRACE_GETREGSET
-
-#if defined(__i386)
-#if !defined(bit_FXSAVE) // e.g. Clang
-#define bit_FXSAVE bit_FXSR
-#endif
- // Detect if the CPU supports the FXSAVE/FXRSTOR instructions
- int eax, ebx, ecx, edx;
- __cpuid(1, eax, ebx, ecx, edx);
- if (edx & bit_FXSAVE) {
- if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) {
- return false;
- }
- } else {
- memset(&info->fpxregs, 0, sizeof(info->fpxregs));
- }
-#endif // defined(__i386)
-
-#if defined(__i386) || defined(__x86_64)
- for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
- if (sys_ptrace(
- PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*> (offsetof(struct user,
- u_debugreg[0]) + i *
- sizeof(debugreg_t)),
- &info->dregs[i]) == -1) {
- return false;
- }
- }
-#endif
-
-#if defined(__mips__)
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE), &info->mcontext.hi1);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE + 1), &info->mcontext.lo1);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE + 2), &info->mcontext.hi2);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE + 3), &info->mcontext.lo2);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE + 4), &info->mcontext.hi3);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_BASE + 5), &info->mcontext.lo3);
- sys_ptrace(PTRACE_PEEKUSER, tid,
- reinterpret_cast<void*>(DSP_CONTROL), &info->mcontext.dsp);
-#endif
-
- const uint8_t* stack_pointer;
-#if defined(__i386)
- my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
-#elif defined(__x86_64)
- my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
-#elif defined(__ARM_EABI__)
- my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp));
-#elif defined(__aarch64__)
- my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp));
-#elif defined(__mips__)
- stack_pointer =
- reinterpret_cast<uint8_t*>(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]);
-#else
-#error "This code hasn't been ported to your platform yet."
-#endif
- info->stack_pointer = reinterpret_cast<uintptr_t>(stack_pointer);
-
- return true;
-}
-
-bool LinuxPtraceDumper::IsPostMortem() const {
- return false;
-}
-
-bool LinuxPtraceDumper::ThreadsSuspend() {
- if (threads_suspended_)
- return true;
- for (size_t i = 0; i < threads_.size(); ++i) {
- if (!SuspendThread(threads_[i])) {
- // If the thread either disappeared before we could attach to it, or if
- // it was part of the seccomp sandbox's trusted code, it is OK to
- // silently drop it from the minidump.
- if (i < threads_.size() - 1) {
- my_memmove(&threads_[i], &threads_[i + 1],
- (threads_.size() - i - 1) * sizeof(threads_[i]));
- }
- threads_.resize(threads_.size() - 1);
- --i;
- }
- }
- threads_suspended_ = true;
- return threads_.size() > 0;
-}
-
-bool LinuxPtraceDumper::ThreadsResume() {
- if (!threads_suspended_)
- return false;
- bool good = true;
- for (size_t i = 0; i < threads_.size(); ++i)
- good &= ResumeThread(threads_[i]);
- threads_suspended_ = false;
- return good;
-}
-
-// Parse /proc/$pid/task to list all the threads of the process identified by
-// pid.
-bool LinuxPtraceDumper::EnumerateThreads() {
- char task_path[NAME_MAX];
- if (!BuildProcPath(task_path, pid_, "task"))
- return false;
-
- const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
- if (fd < 0)
- return false;
- DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
-
- // The directory may contain duplicate entries which we filter by assuming
- // that they are consecutive.
- int last_tid = -1;
- const char* dent_name;
- while (dir_reader->GetNextEntry(&dent_name)) {
- if (my_strcmp(dent_name, ".") &&
- my_strcmp(dent_name, "..")) {
- int tid = 0;
- if (my_strtoui(&tid, dent_name) &&
- last_tid != tid) {
- last_tid = tid;
- threads_.push_back(tid);
- }
- }
- dir_reader->PopEntry();
- }
-
- sys_close(fd);
- return true;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h
deleted file mode 100644
index 2ce834b0f..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// linux_ptrace_dumper.h: Define the google_breakpad::LinuxPtraceDumper
-// class, which is derived from google_breakpad::LinuxDumper to extract
-// information from a crashed process via ptrace.
-// This class was originally splitted from google_breakpad::LinuxDumper.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-
-namespace google_breakpad {
-
-class LinuxPtraceDumper : public LinuxDumper {
- public:
- // Constructs a dumper for extracting information of a given process
- // with a process ID of |pid|.
- explicit LinuxPtraceDumper(pid_t pid);
-
- // Implements LinuxDumper::BuildProcPath().
- // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>).
- // |path| is a character array of at least NAME_MAX bytes to return the
- // result. |node| is the final node without any slashes. Returns true on
- // success.
- virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const;
-
- // Implements LinuxDumper::CopyFromProcess().
- // Copies content of |length| bytes from a given process |child|,
- // starting from |src|, into |dest|. This method uses ptrace to extract
- // the content from the target process. Always returns true.
- virtual bool CopyFromProcess(void* dest, pid_t child, const void* src,
- size_t length);
-
- // Implements LinuxDumper::GetThreadInfoByIndex().
- // Reads information about the |index|-th thread of |threads_|.
- // Returns true on success. One must have called |ThreadsSuspend| first.
- virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info);
-
- // Implements LinuxDumper::IsPostMortem().
- // Always returns false to indicate this dumper performs a dump of
- // a crashed process via ptrace.
- virtual bool IsPostMortem() const;
-
- // Implements LinuxDumper::ThreadsSuspend().
- // Suspends all threads in the given process. Returns true on success.
- virtual bool ThreadsSuspend();
-
- // Implements LinuxDumper::ThreadsResume().
- // Resumes all threads in the given process. Returns true on success.
- virtual bool ThreadsResume();
-
- protected:
- // Implements LinuxDumper::EnumerateThreads().
- // Enumerates all threads of the given process into |threads_|.
- virtual bool EnumerateThreads();
-
- private:
- // Set to true if all threads of the crashed process are suspended.
- bool threads_suspended_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_HANDLER_LINUX_PTRACE_DUMPER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
deleted file mode 100644
index be533e157..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-// 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.
-
-// linux_ptrace_dumper_unittest.cc:
-// Unit tests for google_breakpad::LinuxPtraceDumper.
-//
-// This file was renamed from linux_dumper_unittest.cc and modified due
-// to LinuxDumper being splitted into two classes.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "breakpad_googletest_includes.h"
-#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
-#include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
-#include "common/linux/eintr_wrapper.h"
-#include "common/linux/file_id.h"
-#include "common/linux/ignore_ret.h"
-#include "common/linux/safe_readlink.h"
-#include "common/memory.h"
-#include "common/using_std_string.h"
-
-#ifndef PR_SET_PTRACER
-#define PR_SET_PTRACER 0x59616d61
-#endif
-
-using namespace google_breakpad;
-
-namespace {
-
-typedef wasteful_vector<uint8_t> id_vector;
-typedef testing::Test LinuxPtraceDumperTest;
-
-/* Fixture for running tests in a child process. */
-class LinuxPtraceDumperChildTest : public testing::Test {
- protected:
- virtual void SetUp() {
- child_pid_ = fork();
-#ifndef __ANDROID__
- prctl(PR_SET_PTRACER, child_pid_);
-#endif
- }
-
- /* Gtest is calling TestBody from this class, which sets up a child
- * process in which the RealTestBody virtual member is called.
- * As such, TestBody is not supposed to be overridden in derived classes.
- */
- virtual void TestBody() /* final */ {
- if (child_pid_ == 0) {
- // child process
- RealTestBody();
- exit(HasFatalFailure() ? kFatalFailure :
- (HasNonfatalFailure() ? kNonFatalFailure : 0));
- }
-
- ASSERT_TRUE(child_pid_ > 0);
- int status;
- waitpid(child_pid_, &status, 0);
- if (WEXITSTATUS(status) == kFatalFailure) {
- GTEST_FATAL_FAILURE_("Test failed in child process");
- } else if (WEXITSTATUS(status) == kNonFatalFailure) {
- GTEST_NONFATAL_FAILURE_("Test failed in child process");
- }
- }
-
- /* Gtest defines TestBody functions through its macros, but classes
- * derived from this one need to define RealTestBody instead.
- * This is achieved by defining a TestBody macro further below.
- */
- virtual void RealTestBody() = 0;
-
- id_vector make_vector() {
- return id_vector(&allocator, kDefaultBuildIdSize);
- }
-
- private:
- static const int kFatalFailure = 1;
- static const int kNonFatalFailure = 2;
-
- pid_t child_pid_;
- PageAllocator allocator;
-};
-
-} // namespace
-
-/* Replace TestBody declarations within TEST*() with RealTestBody
- * declarations */
-#define TestBody RealTestBody
-
-TEST_F(LinuxPtraceDumperChildTest, Setup) {
- LinuxPtraceDumper dumper(getppid());
-}
-
-TEST_F(LinuxPtraceDumperChildTest, FindMappings) {
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
-
- ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid)));
- ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf)));
- ASSERT_FALSE(dumper.FindMapping(NULL));
-}
-
-TEST_F(LinuxPtraceDumperChildTest, ThreadList) {
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
-
- ASSERT_GE(dumper.threads().size(), (size_t)1);
- bool found = false;
- for (size_t i = 0; i < dumper.threads().size(); ++i) {
- if (dumper.threads()[i] == getppid()) {
- ASSERT_FALSE(found);
- found = true;
- }
- }
- ASSERT_TRUE(found);
-}
-
-// Helper stack class to close a file descriptor and unmap
-// a mmap'ed mapping.
-class StackHelper {
- public:
- StackHelper()
- : fd_(-1), mapping_(NULL), size_(0) {}
- ~StackHelper() {
- if (size_)
- munmap(mapping_, size_);
- if (fd_ >= 0)
- close(fd_);
- }
- void Init(int fd, char* mapping, size_t size) {
- fd_ = fd;
- mapping_ = mapping;
- size_ = size;
- }
-
- char* mapping() const { return mapping_; }
- size_t size() const { return size_; }
-
- private:
- int fd_;
- char* mapping_;
- size_t size_;
-};
-
-class LinuxPtraceDumperMappingsTest : public LinuxPtraceDumperChildTest {
- protected:
- virtual void SetUp();
-
- string helper_path_;
- size_t page_size_;
- StackHelper helper_;
-};
-
-void LinuxPtraceDumperMappingsTest::SetUp() {
- helper_path_ = GetHelperBinary();
- if (helper_path_.empty()) {
- FAIL() << "Couldn't find helper binary";
- exit(1);
- }
-
- // mmap two segments out of the helper binary, one
- // enclosed in the other, but with different protections.
- page_size_ = sysconf(_SC_PAGESIZE);
- const size_t kMappingSize = 3 * page_size_;
- int fd = open(helper_path_.c_str(), O_RDONLY);
- ASSERT_NE(-1, fd) << "Failed to open file: " << helper_path_
- << ", Error: " << strerror(errno);
- char* mapping =
- reinterpret_cast<char*>(mmap(NULL,
- kMappingSize,
- PROT_READ,
- MAP_SHARED,
- fd,
- 0));
- ASSERT_TRUE(mapping);
-
- // Ensure that things get cleaned up.
- helper_.Init(fd, mapping, kMappingSize);
-
- // Carve a page out of the first mapping with different permissions.
- char* inside_mapping = reinterpret_cast<char*>(
- mmap(mapping + 2 * page_size_,
- page_size_,
- PROT_NONE,
- MAP_SHARED | MAP_FIXED,
- fd,
- // Map a different offset just to
- // better test real-world conditions.
- page_size_));
- ASSERT_TRUE(inside_mapping);
-
- LinuxPtraceDumperChildTest::SetUp();
-}
-
-TEST_F(LinuxPtraceDumperMappingsTest, MergedMappings) {
- // Now check that LinuxPtraceDumper interpreted the mappings properly.
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
- int mapping_count = 0;
- for (unsigned i = 0; i < dumper.mappings().size(); ++i) {
- const MappingInfo& mapping = *dumper.mappings()[i];
- if (strcmp(mapping.name, this->helper_path_.c_str()) == 0) {
- // This mapping should encompass the entire original mapped
- // range.
- EXPECT_EQ(reinterpret_cast<uintptr_t>(this->helper_.mapping()),
- mapping.start_addr);
- EXPECT_EQ(this->helper_.size(), mapping.size);
- EXPECT_EQ(0U, mapping.offset);
- mapping_count++;
- }
- }
- EXPECT_EQ(1, mapping_count);
-}
-
-TEST_F(LinuxPtraceDumperChildTest, BuildProcPath) {
- const pid_t pid = getppid();
- LinuxPtraceDumper dumper(pid);
-
- char maps_path[NAME_MAX] = "";
- char maps_path_expected[NAME_MAX];
- snprintf(maps_path_expected, sizeof(maps_path_expected),
- "/proc/%d/maps", pid);
- EXPECT_TRUE(dumper.BuildProcPath(maps_path, pid, "maps"));
- EXPECT_STREQ(maps_path_expected, maps_path);
-
- EXPECT_FALSE(dumper.BuildProcPath(NULL, pid, "maps"));
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, 0, "maps"));
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, ""));
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, pid, NULL));
-
- char long_node[NAME_MAX];
- size_t long_node_len = NAME_MAX - strlen("/proc/123") - 1;
- memset(long_node, 'a', long_node_len);
- long_node[long_node_len] = '\0';
- EXPECT_FALSE(dumper.BuildProcPath(maps_path, 123, long_node));
-}
-
-#if !defined(__ARM_EABI__) && !defined(__mips__)
-// Ensure that the linux-gate VDSO is included in the mapping list.
-TEST_F(LinuxPtraceDumperChildTest, MappingsIncludeLinuxGate) {
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
-
- void* linux_gate_loc =
- reinterpret_cast<void *>(dumper.auxv()[AT_SYSINFO_EHDR]);
- ASSERT_TRUE(linux_gate_loc);
- bool found_linux_gate = false;
-
- const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
- const MappingInfo* mapping;
- for (unsigned i = 0; i < mappings.size(); ++i) {
- mapping = mappings[i];
- if (!strcmp(mapping->name, kLinuxGateLibraryName)) {
- found_linux_gate = true;
- break;
- }
- }
- EXPECT_TRUE(found_linux_gate);
- EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr));
- EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG));
-}
-
-// Ensure that the linux-gate VDSO can generate a non-zeroed File ID.
-TEST_F(LinuxPtraceDumperChildTest, LinuxGateMappingID) {
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
-
- bool found_linux_gate = false;
- const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
- unsigned index = 0;
- for (unsigned i = 0; i < mappings.size(); ++i) {
- if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) {
- found_linux_gate = true;
- index = i;
- break;
- }
- }
- ASSERT_TRUE(found_linux_gate);
-
- // Need to suspend the child so ptrace actually works.
- ASSERT_TRUE(dumper.ThreadsSuspend());
- id_vector identifier(make_vector());
- ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index],
- true,
- index,
- identifier));
-
- id_vector empty_identifier(make_vector());
- empty_identifier.resize(kDefaultBuildIdSize, 0);
- EXPECT_NE(empty_identifier, identifier);
- EXPECT_TRUE(dumper.ThreadsResume());
-}
-#endif
-
-TEST_F(LinuxPtraceDumperChildTest, FileIDsMatch) {
- // Calculate the File ID of our binary using both
- // FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping
- // and ensure that we get the same result from both.
- char exe_name[PATH_MAX];
- ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name));
-
- LinuxPtraceDumper dumper(getppid());
- ASSERT_TRUE(dumper.Init());
- const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
- bool found_exe = false;
- unsigned i;
- for (i = 0; i < mappings.size(); ++i) {
- const MappingInfo* mapping = mappings[i];
- if (!strcmp(mapping->name, exe_name)) {
- found_exe = true;
- break;
- }
- }
- ASSERT_TRUE(found_exe);
-
- id_vector identifier1(make_vector());
- id_vector identifier2(make_vector());
- EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[i], true, i,
- identifier1));
- FileID fileid(exe_name);
- EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2));
-
- string identifier_string1 =
- FileID::ConvertIdentifierToUUIDString(identifier1);
- string identifier_string2 =
- FileID::ConvertIdentifierToUUIDString(identifier2);
- EXPECT_EQ(identifier_string1, identifier_string2);
-}
-
-/* Get back to normal behavior of TEST*() macros wrt TestBody. */
-#undef TestBody
-
-TEST(LinuxPtraceDumperTest, VerifyStackReadWithMultipleThreads) {
- static const int kNumberOfThreadsInHelperProgram = 5;
- char kNumberOfThreadsArgument[2];
- sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram);
-
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- pid_t child_pid = fork();
- if (child_pid == 0) {
- // In child process.
- close(fds[0]);
-
- string helper_path(GetHelperBinary());
- if (helper_path.empty()) {
- FAIL() << "Couldn't find helper binary";
- exit(1);
- }
-
- // Pass the pipe fd and the number of threads as arguments.
- char pipe_fd_string[8];
- sprintf(pipe_fd_string, "%d", fds[1]);
- execl(helper_path.c_str(),
- "linux_dumper_unittest_helper",
- pipe_fd_string,
- kNumberOfThreadsArgument,
- NULL);
- // Kill if we get here.
- printf("Errno from exec: %d", errno);
- FAIL() << "Exec of " << helper_path << " failed: " << strerror(errno);
- exit(0);
- }
- close(fds[1]);
-
- // Wait for all child threads to indicate that they have started
- for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
- struct pollfd pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = fds[0];
- pfd.events = POLLIN | POLLERR;
-
- const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
- ASSERT_EQ(1, r);
- ASSERT_TRUE(pfd.revents & POLLIN);
- uint8_t junk;
- ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
- static_cast<ssize_t>(sizeof(junk)));
- }
- close(fds[0]);
-
- // There is a race here because we may stop a child thread before
- // it is actually running the busy loop. Empirically this sleep
- // is sufficient to avoid the race.
- usleep(100000);
-
- // Children are ready now.
- LinuxPtraceDumper dumper(child_pid);
- ASSERT_TRUE(dumper.Init());
- EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size());
- EXPECT_TRUE(dumper.ThreadsSuspend());
-
- ThreadInfo one_thread;
- for (size_t i = 0; i < dumper.threads().size(); ++i) {
- EXPECT_TRUE(dumper.GetThreadInfoByIndex(i, &one_thread));
- const void* stack;
- size_t stack_len;
- EXPECT_TRUE(dumper.GetStackInfo(&stack, &stack_len,
- one_thread.stack_pointer));
- // In the helper program, we stored a pointer to the thread id in a
- // specific register. Check that we can recover its value.
-#if defined(__ARM_EABI__)
- pid_t* process_tid_location = (pid_t*)(one_thread.regs.uregs[3]);
-#elif defined(__aarch64__)
- pid_t* process_tid_location = (pid_t*)(one_thread.regs.regs[3]);
-#elif defined(__i386)
- pid_t* process_tid_location = (pid_t*)(one_thread.regs.ecx);
-#elif defined(__x86_64)
- pid_t* process_tid_location = (pid_t*)(one_thread.regs.rcx);
-#elif defined(__mips__)
- pid_t* process_tid_location =
- reinterpret_cast<pid_t*>(one_thread.mcontext.gregs[1]);
-#else
-#error This test has not been ported to this platform.
-#endif
- pid_t one_thread_id;
- dumper.CopyFromProcess(&one_thread_id,
- dumper.threads()[i],
- process_tid_location,
- 4);
- EXPECT_EQ(dumper.threads()[i], one_thread_id);
- }
- EXPECT_TRUE(dumper.ThreadsResume());
- kill(child_pid, SIGKILL);
-
- // Reap child
- int status;
- ASSERT_NE(-1, HANDLE_EINTR(waitpid(child_pid, &status, 0)));
- ASSERT_TRUE(WIFSIGNALED(status));
- ASSERT_EQ(SIGKILL, WTERMSIG(status));
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc
deleted file mode 100644
index 4b1ae5ad3..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc
+++ /dev/null
@@ -1,1376 +0,0 @@
-// 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.
-
-// This code writes out minidump files:
-// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
-//
-// Minidumps are a Microsoft format which Breakpad uses for recording crash
-// dumps. This code has to run in a compromised environment (the address space
-// may have received SIGSEGV), thus the following rules apply:
-// * You may not enter the dynamic linker. This means that we cannot call
-// any symbols in a shared library (inc libc). Because of this we replace
-// libc functions in linux_libc_support.h.
-// * You may not call syscalls via the libc wrappers. This rule is a subset
-// of the first rule but it bears repeating. We have direct wrappers
-// around the system calls in linux_syscall_support.h.
-// * You may not malloc. There's an alternative allocator in memory.h and
-// a canonical instance in the LinuxDumper object. We use the placement
-// new form to allocate objects and we don't delete them.
-
-#include "client/linux/handler/minidump_descriptor.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "client/minidump_file_writer-inl.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <link.h>
-#include <stdio.h>
-#if defined(__ANDROID__)
-#include <sys/system_properties.h>
-#endif
-#include <sys/types.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <sys/utsname.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include "client/linux/dump_writer_common/thread_info.h"
-#include "client/linux/dump_writer_common/ucontext_reader.h"
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/minidump_writer/cpu_set.h"
-#include "client/linux/minidump_writer/line_reader.h"
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
-#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
-#include "client/minidump_file_writer.h"
-#include "common/linux/file_id.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/minidump_type_helper.h"
-#include "google_breakpad/common/minidump_format.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-namespace {
-
-using google_breakpad::AppMemoryList;
-using google_breakpad::auto_wasteful_vector;
-using google_breakpad::ExceptionHandler;
-using google_breakpad::CpuSet;
-using google_breakpad::kDefaultBuildIdSize;
-using google_breakpad::LineReader;
-using google_breakpad::LinuxDumper;
-using google_breakpad::LinuxPtraceDumper;
-using google_breakpad::MDTypeHelper;
-using google_breakpad::MappingEntry;
-using google_breakpad::MappingInfo;
-using google_breakpad::MappingList;
-using google_breakpad::MinidumpFileWriter;
-using google_breakpad::PageAllocator;
-using google_breakpad::ProcCpuInfoReader;
-using google_breakpad::RawContextCPU;
-using google_breakpad::ThreadInfo;
-using google_breakpad::TypedMDRVA;
-using google_breakpad::UContextReader;
-using google_breakpad::UntypedMDRVA;
-using google_breakpad::wasteful_vector;
-
-typedef MDTypeHelper<sizeof(void*)>::MDRawDebug MDRawDebug;
-typedef MDTypeHelper<sizeof(void*)>::MDRawLinkMap MDRawLinkMap;
-
-class MinidumpWriter {
- public:
- // The following kLimit* constants are for when minidump_size_limit_ is set
- // and the minidump size might exceed it.
- //
- // Estimate for how big each thread's stack will be (in bytes).
- static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
- // Number of threads whose stack size we don't want to limit. These base
- // threads will simply be the first N threads returned by the dumper (although
- // the crashing thread will never be limited). Threads beyond this count are
- // the extra threads.
- static const unsigned kLimitBaseThreadCount = 20;
- // Maximum stack size to dump for any extra thread (in bytes).
- static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024;
- // Make sure this number of additional bytes can fit in the minidump
- // (exclude the stack data).
- static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024;
-
- MinidumpWriter(const char* minidump_path,
- int minidump_fd,
- const ExceptionHandler::CrashContext* context,
- const MappingList& mappings,
- const AppMemoryList& appmem,
- LinuxDumper* dumper)
- : fd_(minidump_fd),
- path_(minidump_path),
- ucontext_(context ? &context->context : NULL),
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- float_state_(context ? &context->float_state : NULL),
-#endif
- dumper_(dumper),
- minidump_size_limit_(-1),
- memory_blocks_(dumper_->allocator()),
- mapping_list_(mappings),
- app_memory_list_(appmem) {
- // Assert there should be either a valid fd or a valid path, not both.
- assert(fd_ != -1 || minidump_path);
- assert(fd_ == -1 || !minidump_path);
- }
-
- bool Init() {
- if (!dumper_->Init())
- return false;
-
- if (fd_ != -1)
- minidump_writer_.SetFile(fd_);
- else if (!minidump_writer_.Open(path_))
- return false;
-
- return dumper_->ThreadsSuspend() && dumper_->LateInit();
- }
-
- ~MinidumpWriter() {
- // Don't close the file descriptor when it's been provided explicitly.
- // Callers might still need to use it.
- if (fd_ == -1)
- minidump_writer_.Close();
- dumper_->ThreadsResume();
- }
-
- bool Dump() {
- // A minidump file contains a number of tagged streams. This is the number
- // of stream which we write.
- unsigned kNumWriters = 13;
-
- TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
- {
- // Ensure the header gets flushed, as that happens in the destructor.
- // If we crash somewhere below, we should have a mostly-intact dump
- TypedMDRVA<MDRawHeader> header(&minidump_writer_);
- if (!header.Allocate())
- return false;
-
- if (!dir.AllocateArray(kNumWriters))
- return false;
-
- my_memset(header.get(), 0, sizeof(MDRawHeader));
-
- header.get()->signature = MD_HEADER_SIGNATURE;
- header.get()->version = MD_HEADER_VERSION;
- header.get()->time_date_stamp = time(NULL);
- header.get()->stream_count = kNumWriters;
- header.get()->stream_directory_rva = dir.position();
- }
-
- unsigned dir_index = 0;
- MDRawDirectory dirent;
-
- if (!WriteThreadListStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteMappings(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteAppMemory())
- return false;
-
- if (!WriteMemoryListStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteExceptionStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- if (!WriteSystemInfoStream(&dirent))
- return false;
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_CPU_INFO;
- if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_PROC_STATUS;
- if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_LSB_RELEASE;
- if (!WriteFile(&dirent.location, "/etc/lsb-release"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_CMD_LINE;
- if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_ENVIRON;
- if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_AUXV;
- if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_MAPS;
- if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- dirent.stream_type = MD_LINUX_DSO_DEBUG;
- if (!WriteDSODebugStream(&dirent))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
-
- // If you add more directory entries, don't forget to update kNumWriters,
- // above.
-
- dumper_->ThreadsResume();
- return true;
- }
-
- bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer,
- int max_stack_len, uint8_t** stack_copy) {
- *stack_copy = NULL;
- const void* stack;
- size_t stack_len;
- if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) {
- UntypedMDRVA memory(&minidump_writer_);
- if (max_stack_len >= 0 &&
- stack_len > static_cast<unsigned int>(max_stack_len)) {
- stack_len = max_stack_len;
- // Skip empty chunks of length max_stack_len.
- uintptr_t int_stack = reinterpret_cast<uintptr_t>(stack);
- if (max_stack_len > 0) {
- while (int_stack + max_stack_len < stack_pointer) {
- int_stack += max_stack_len;
- }
- }
- stack = reinterpret_cast<const void*>(int_stack);
- }
- if (!memory.Allocate(stack_len))
- return false;
- *stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
- dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack,
- stack_len);
- memory.Copy(*stack_copy, stack_len);
- thread->stack.start_of_memory_range =
- reinterpret_cast<uintptr_t>(stack);
- thread->stack.memory = memory.location();
- memory_blocks_.push_back(thread->stack);
- } else {
- thread->stack.start_of_memory_range = stack_pointer;
- thread->stack.memory.data_size = 0;
- thread->stack.memory.rva = minidump_writer_.position();
- }
- return true;
- }
-
- // Write information about the threads.
- bool WriteThreadListStream(MDRawDirectory* dirent) {
- const unsigned num_threads = dumper_->threads().size();
-
- TypedMDRVA<uint32_t> list(&minidump_writer_);
- if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
- return false;
-
- dirent->stream_type = MD_THREAD_LIST_STREAM;
- dirent->location = list.location();
-
- *list.get() = num_threads;
-
- // If there's a minidump size limit, check if it might be exceeded. Since
- // most of the space is filled with stack data, just check against that.
- // If this expects to exceed the limit, set extra_thread_stack_len such
- // that any thread beyond the first kLimitBaseThreadCount threads will
- // have only kLimitMaxExtraThreadStackLen bytes dumped.
- int extra_thread_stack_len = -1; // default to no maximum
- if (minidump_size_limit_ >= 0) {
- const unsigned estimated_total_stack_size = num_threads *
- kLimitAverageThreadStackLength;
- const off_t estimated_minidump_size = minidump_writer_.position() +
- estimated_total_stack_size + kLimitMinidumpFudgeFactor;
- if (estimated_minidump_size > minidump_size_limit_)
- extra_thread_stack_len = kLimitMaxExtraThreadStackLen;
- }
-
- for (unsigned i = 0; i < num_threads; ++i) {
- MDRawThread thread;
- my_memset(&thread, 0, sizeof(thread));
- thread.thread_id = dumper_->threads()[i];
-
- // We have a different source of information for the crashing thread. If
- // we used the actual state of the thread we would find it running in the
- // signal handler with the alternative stack, which would be deeply
- // unhelpful.
- if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
- ucontext_ &&
- !dumper_->IsPostMortem()) {
- uint8_t* stack_copy;
- const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_);
- if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy))
- return false;
-
- // Copy 256 bytes around crashing instruction pointer to minidump.
- const size_t kIPMemorySize = 256;
- uint64_t ip = UContextReader::GetInstructionPointer(ucontext_);
- // Bound it to the upper and lower bounds of the memory map
- // it's contained within. If it's not in mapped memory,
- // don't bother trying to write it.
- bool ip_is_mapped = false;
- MDMemoryDescriptor ip_memory_d;
- for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
- const MappingInfo& mapping = *dumper_->mappings()[j];
- if (ip >= mapping.start_addr &&
- ip < mapping.start_addr + mapping.size) {
- ip_is_mapped = true;
- // Try to get 128 bytes before and after the IP, but
- // settle for whatever's available.
- ip_memory_d.start_of_memory_range =
- std::max(mapping.start_addr,
- uintptr_t(ip - (kIPMemorySize / 2)));
- uintptr_t end_of_range =
- std::min(uintptr_t(ip + (kIPMemorySize / 2)),
- uintptr_t(mapping.start_addr + mapping.size));
- ip_memory_d.memory.data_size =
- end_of_range - ip_memory_d.start_of_memory_range;
- break;
- }
- }
-
- if (ip_is_mapped) {
- UntypedMDRVA ip_memory(&minidump_writer_);
- if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
- return false;
- uint8_t* memory_copy =
- reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
- dumper_->CopyFromProcess(
- memory_copy,
- thread.thread_id,
- reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
- ip_memory_d.memory.data_size);
- ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
- ip_memory_d.memory = ip_memory.location();
- memory_blocks_.push_back(ip_memory_d);
- }
-
- TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
- if (!cpu.Allocate())
- return false;
- my_memset(cpu.get(), 0, sizeof(RawContextCPU));
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_);
-#else
- UContextReader::FillCPUContext(cpu.get(), ucontext_);
-#endif
- thread.thread_context = cpu.location();
- crashing_thread_context_ = cpu.location();
- } else {
- ThreadInfo info;
- if (!dumper_->GetThreadInfoByIndex(i, &info))
- return false;
-
- uint8_t* stack_copy;
- int max_stack_len = -1; // default to no maximum for this thread
- if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount)
- max_stack_len = extra_thread_stack_len;
- if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len,
- &stack_copy))
- return false;
-
- TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
- if (!cpu.Allocate())
- return false;
- my_memset(cpu.get(), 0, sizeof(RawContextCPU));
- info.FillCPUContext(cpu.get());
- thread.thread_context = cpu.location();
- if (dumper_->threads()[i] == GetCrashThread()) {
- crashing_thread_context_ = cpu.location();
- if (!dumper_->IsPostMortem()) {
- // This is the crashing thread of a live process, but
- // no context was provided, so set the crash address
- // while the instruction pointer is already here.
- dumper_->set_crash_address(info.GetInstructionPointer());
- }
- }
- }
-
- list.CopyIndexAfterObject(i, &thread, sizeof(thread));
- }
-
- return true;
- }
-
- // Write application-provided memory regions.
- bool WriteAppMemory() {
- for (AppMemoryList::const_iterator iter = app_memory_list_.begin();
- iter != app_memory_list_.end();
- ++iter) {
- uint8_t* data_copy =
- reinterpret_cast<uint8_t*>(dumper_->allocator()->Alloc(iter->length));
- dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr,
- iter->length);
-
- UntypedMDRVA memory(&minidump_writer_);
- if (!memory.Allocate(iter->length)) {
- return false;
- }
- memory.Copy(data_copy, iter->length);
- MDMemoryDescriptor desc;
- desc.start_of_memory_range = reinterpret_cast<uintptr_t>(iter->ptr);
- desc.memory = memory.location();
- memory_blocks_.push_back(desc);
- }
-
- return true;
- }
-
- static bool ShouldIncludeMapping(const MappingInfo& mapping) {
- if (mapping.name[0] == 0 || // only want modules with filenames.
- // Only want to include one mapping per shared lib.
- // Avoid filtering executable mappings.
- (mapping.offset != 0 && !mapping.exec) ||
- mapping.size < 4096) { // too small to get a signature for.
- return false;
- }
-
- return true;
- }
-
- // If there is caller-provided information about this mapping
- // in the mapping_list_ list, return true. Otherwise, return false.
- bool HaveMappingInfo(const MappingInfo& mapping) {
- for (MappingList::const_iterator iter = mapping_list_.begin();
- iter != mapping_list_.end();
- ++iter) {
- // Ignore any mappings that are wholly contained within
- // mappings in the mapping_info_ list.
- if (mapping.start_addr >= iter->first.start_addr &&
- (mapping.start_addr + mapping.size) <=
- (iter->first.start_addr + iter->first.size)) {
- return true;
- }
- }
- return false;
- }
-
- // Write information about the mappings in effect. Because we are using the
- // minidump format, the information about the mappings is pretty limited.
- // Because of this, we also include the full, unparsed, /proc/$x/maps file in
- // another stream in the file.
- bool WriteMappings(MDRawDirectory* dirent) {
- const unsigned num_mappings = dumper_->mappings().size();
- unsigned num_output_mappings = mapping_list_.size();
-
- for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
- const MappingInfo& mapping = *dumper_->mappings()[i];
- if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
- num_output_mappings++;
- }
-
- TypedMDRVA<uint32_t> list(&minidump_writer_);
- if (num_output_mappings) {
- if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
- return false;
- } else {
- // Still create the module list stream, although it will have zero
- // modules.
- if (!list.Allocate())
- return false;
- }
-
- dirent->stream_type = MD_MODULE_LIST_STREAM;
- dirent->location = list.location();
- *list.get() = num_output_mappings;
-
- // First write all the mappings from the dumper
- unsigned int j = 0;
- for (unsigned i = 0; i < num_mappings; ++i) {
- const MappingInfo& mapping = *dumper_->mappings()[i];
- if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
- continue;
-
- MDRawModule mod;
- if (!FillRawModule(mapping, true, i, &mod, NULL))
- return false;
- list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
- }
- // Next write all the mappings provided by the caller
- for (MappingList::const_iterator iter = mapping_list_.begin();
- iter != mapping_list_.end();
- ++iter) {
- MDRawModule mod;
- if (!FillRawModule(iter->first, false, 0, &mod, iter->second))
- return false;
- list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
- }
-
- return true;
- }
-
- // Fill the MDRawModule |mod| with information about the provided
- // |mapping|. If |identifier| is non-NULL, use it instead of calculating
- // a file ID from the mapping.
- bool FillRawModule(const MappingInfo& mapping,
- bool member,
- unsigned int mapping_id,
- MDRawModule* mod,
- const uint8_t* identifier) {
- my_memset(mod, 0, MD_MODULE_SIZE);
-
- mod->base_of_image = mapping.start_addr;
- mod->size_of_image = mapping.size;
-
- auto_wasteful_vector<uint8_t, kDefaultBuildIdSize> identifier_bytes(
- dumper_->allocator());
-
- if (identifier) {
- // GUID was provided by caller.
- identifier_bytes.insert(identifier_bytes.end(),
- identifier,
- identifier + sizeof(MDGUID));
- } else {
- // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
- dumper_->ElfFileIdentifierForMapping(mapping,
- member,
- mapping_id,
- identifier_bytes);
- }
-
- if (!identifier_bytes.empty()) {
- UntypedMDRVA cv(&minidump_writer_);
- if (!cv.Allocate(MDCVInfoELF_minsize + identifier_bytes.size()))
- return false;
-
- const uint32_t cv_signature = MD_CVINFOELF_SIGNATURE;
- cv.Copy(&cv_signature, sizeof(cv_signature));
- cv.Copy(cv.position() + sizeof(cv_signature), &identifier_bytes[0],
- identifier_bytes.size());
-
- mod->cv_record = cv.location();
- }
-
- char file_name[NAME_MAX];
- char file_path[NAME_MAX];
- dumper_->GetMappingEffectiveNameAndPath(
- mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
-
- MDLocationDescriptor ld;
- if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
- return false;
- mod->module_name_rva = ld.rva;
- return true;
- }
-
- bool WriteMemoryListStream(MDRawDirectory* dirent) {
- TypedMDRVA<uint32_t> list(&minidump_writer_);
- if (memory_blocks_.size()) {
- if (!list.AllocateObjectAndArray(memory_blocks_.size(),
- sizeof(MDMemoryDescriptor)))
- return false;
- } else {
- // Still create the memory list stream, although it will have zero
- // memory blocks.
- if (!list.Allocate())
- return false;
- }
-
- dirent->stream_type = MD_MEMORY_LIST_STREAM;
- dirent->location = list.location();
-
- *list.get() = memory_blocks_.size();
-
- for (size_t i = 0; i < memory_blocks_.size(); ++i) {
- list.CopyIndexAfterObject(i, &memory_blocks_[i],
- sizeof(MDMemoryDescriptor));
- }
- return true;
- }
-
- bool WriteExceptionStream(MDRawDirectory* dirent) {
- TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
- if (!exc.Allocate())
- return false;
- my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
-
- dirent->stream_type = MD_EXCEPTION_STREAM;
- dirent->location = exc.location();
-
- exc.get()->thread_id = GetCrashThread();
- exc.get()->exception_record.exception_code = dumper_->crash_signal();
- exc.get()->exception_record.exception_address = dumper_->crash_address();
- exc.get()->thread_context = crashing_thread_context_;
-
- return true;
- }
-
- bool WriteSystemInfoStream(MDRawDirectory* dirent) {
- TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
- if (!si.Allocate())
- return false;
- my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
-
- dirent->stream_type = MD_SYSTEM_INFO_STREAM;
- dirent->location = si.location();
-
- WriteCPUInformation(si.get());
- WriteOSInformation(si.get());
-
- return true;
- }
-
- bool WriteDSODebugStream(MDRawDirectory* dirent) {
- ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]);
- char* base;
- int phnum = dumper_->auxv()[AT_PHNUM];
- if (!phnum || !phdr)
- return false;
-
- // Assume the program base is at the beginning of the same page as the PHDR
- base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
-
- // Search for the program PT_DYNAMIC segment
- ElfW(Addr) dyn_addr = 0;
- for (; phnum >= 0; phnum--, phdr++) {
- ElfW(Phdr) ph;
- if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph)))
- return false;
-
- // Adjust base address with the virtual address of the PT_LOAD segment
- // corresponding to offset 0
- if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
- base -= ph.p_vaddr;
- }
- if (ph.p_type == PT_DYNAMIC) {
- dyn_addr = ph.p_vaddr;
- }
- }
- if (!dyn_addr)
- return false;
-
- ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
-
- // The dynamic linker makes information available that helps gdb find all
- // DSOs loaded into the program. If this information is indeed available,
- // dump it to a MD_LINUX_DSO_DEBUG stream.
- struct r_debug* r_debug = NULL;
- uint32_t dynamic_length = 0;
-
- for (int i = 0; ; ++i) {
- ElfW(Dyn) dyn;
- dynamic_length += sizeof(dyn);
- if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i,
- sizeof(dyn))) {
- return false;
- }
-
-#ifdef __mips__
- const int32_t debug_tag = DT_MIPS_RLD_MAP;
-#else
- const int32_t debug_tag = DT_DEBUG;
-#endif
- if (dyn.d_tag == debug_tag) {
- r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
- continue;
- } else if (dyn.d_tag == DT_NULL) {
- break;
- }
- }
-
- // The "r_map" field of that r_debug struct contains a linked list of all
- // loaded DSOs.
- // Our list of DSOs potentially is different from the ones in the crashing
- // process. So, we have to be careful to never dereference pointers
- // directly. Instead, we use CopyFromProcess() everywhere.
- // See <link.h> for a more detailed discussion of the how the dynamic
- // loader communicates with debuggers.
-
- // Count the number of loaded DSOs
- int dso_count = 0;
- struct r_debug debug_entry;
- if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
- sizeof(debug_entry))) {
- return false;
- }
- for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
- struct link_map map;
- if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
- return false;
-
- ptr = map.l_next;
- dso_count++;
- }
-
- MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
- if (dso_count > 0) {
- // If we have at least one DSO, create an array of MDRawLinkMap
- // entries in the minidump file.
- TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
- if (!linkmap.AllocateArray(dso_count))
- return false;
- linkmap_rva = linkmap.location().rva;
- int idx = 0;
-
- // Iterate over DSOs and write their information to mini dump
- for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
- struct link_map map;
- if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map)))
- return false;
-
- ptr = map.l_next;
- char filename[257] = { 0 };
- if (map.l_name) {
- dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
- sizeof(filename) - 1);
- }
- MDLocationDescriptor location;
- if (!minidump_writer_.WriteString(filename, 0, &location))
- return false;
- MDRawLinkMap entry;
- entry.name = location.rva;
- entry.addr = map.l_addr;
- entry.ld = reinterpret_cast<uintptr_t>(map.l_ld);
- linkmap.CopyIndex(idx++, &entry);
- }
- }
-
- // Write MD_LINUX_DSO_DEBUG record
- TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
- if (!debug.AllocateObjectAndArray(1, dynamic_length))
- return false;
- my_memset(debug.get(), 0, sizeof(MDRawDebug));
- dirent->stream_type = MD_LINUX_DSO_DEBUG;
- dirent->location = debug.location();
-
- debug.get()->version = debug_entry.r_version;
- debug.get()->map = linkmap_rva;
- debug.get()->dso_count = dso_count;
- debug.get()->brk = debug_entry.r_brk;
- debug.get()->ldbase = debug_entry.r_ldbase;
- debug.get()->dynamic = reinterpret_cast<uintptr_t>(dynamic);
-
- wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
- // The passed-in size to the constructor (above) is only a hint.
- // Must call .resize() to do actual initialization of the elements.
- dso_debug_data.resize(dynamic_length);
- dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic,
- dynamic_length);
- debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length);
-
- return true;
- }
-
- void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; }
-
- private:
- void* Alloc(unsigned bytes) {
- return dumper_->allocator()->Alloc(bytes);
- }
-
- pid_t GetCrashThread() const {
- return dumper_->crash_thread();
- }
-
- void NullifyDirectoryEntry(MDRawDirectory* dirent) {
- dirent->stream_type = 0;
- dirent->location.data_size = 0;
- dirent->location.rva = 0;
- }
-
-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
- bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
- char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
- static const char vendor_id_name[] = "vendor_id";
-
- struct CpuInfoEntry {
- const char* info_name;
- int value;
- bool found;
- } cpu_info_table[] = {
- { "processor", -1, false },
-#if defined(__i386__) || defined(__x86_64__)
- { "model", 0, false },
- { "stepping", 0, false },
- { "cpu family", 0, false },
-#endif
- };
-
- // processor_architecture should always be set, do this first
- sys_info->processor_architecture =
-#if defined(__mips__)
-# if _MIPS_SIM == _ABIO32
- MD_CPU_ARCHITECTURE_MIPS;
-# elif _MIPS_SIM == _ABI64
- MD_CPU_ARCHITECTURE_MIPS64;
-# else
-# error "This mips ABI is currently not supported (n32)"
-#endif
-#elif defined(__i386__)
- MD_CPU_ARCHITECTURE_X86;
-#else
- MD_CPU_ARCHITECTURE_AMD64;
-#endif
-
- const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- {
- PageAllocator allocator;
- ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd);
- const char* field;
- while (reader->GetNextField(&field)) {
- bool is_first_entry = true;
- for (CpuInfoEntry& entry : cpu_info_table) {
- if (!is_first_entry && entry.found) {
- // except for the 'processor' field, ignore repeated values.
- continue;
- }
- is_first_entry = false;
- if (!my_strcmp(field, entry.info_name)) {
- size_t value_len;
- const char* value = reader->GetValueAndLen(&value_len);
- if (value_len == 0)
- continue;
-
- uintptr_t val;
- if (my_read_decimal_ptr(&val, value) == value)
- continue;
-
- entry.value = static_cast<int>(val);
- entry.found = true;
- }
- }
-
- // special case for vendor_id
- if (!my_strcmp(field, vendor_id_name)) {
- size_t value_len;
- const char* value = reader->GetValueAndLen(&value_len);
- if (value_len > 0)
- my_strlcpy(vendor_id, value, sizeof(vendor_id));
- }
- }
- sys_close(fd);
- }
-
- // make sure we got everything we wanted
- for (const CpuInfoEntry& entry : cpu_info_table) {
- if (!entry.found) {
- return false;
- }
- }
- // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo,
- // assuming this is the highest id, change it to the number of CPUs
- // by adding one.
- cpu_info_table[0].value++;
-
- sys_info->number_of_processors = cpu_info_table[0].value;
-#if defined(__i386__) || defined(__x86_64__)
- sys_info->processor_level = cpu_info_table[3].value;
- sys_info->processor_revision = cpu_info_table[1].value << 8 |
- cpu_info_table[2].value;
-#endif
-
- if (vendor_id[0] != '\0') {
- my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
- sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
- }
- return true;
- }
-#elif defined(__arm__) || defined(__aarch64__)
- bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
- // The CPUID value is broken up in several entries in /proc/cpuinfo.
- // This table is used to rebuild it from the entries.
- const struct CpuIdEntry {
- const char* field;
- char format;
- char bit_lshift;
- char bit_length;
- } cpu_id_entries[] = {
- { "CPU implementer", 'x', 24, 8 },
- { "CPU variant", 'x', 20, 4 },
- { "CPU part", 'x', 4, 12 },
- { "CPU revision", 'd', 0, 4 },
- };
-
- // The ELF hwcaps are listed in the "Features" entry as textual tags.
- // This table is used to rebuild them.
- const struct CpuFeaturesEntry {
- const char* tag;
- uint32_t hwcaps;
- } cpu_features_entries[] = {
-#if defined(__arm__)
- { "swp", MD_CPU_ARM_ELF_HWCAP_SWP },
- { "half", MD_CPU_ARM_ELF_HWCAP_HALF },
- { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB },
- { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT },
- { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT },
- { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA },
- { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP },
- { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP },
- { "java", MD_CPU_ARM_ELF_HWCAP_JAVA },
- { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT },
- { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH },
- { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE },
- { "neon", MD_CPU_ARM_ELF_HWCAP_NEON },
- { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 },
- { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 },
- { "tls", MD_CPU_ARM_ELF_HWCAP_TLS },
- { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 },
- { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA },
- { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT },
- { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT },
-#elif defined(__aarch64__)
- // No hwcaps on aarch64.
-#endif
- };
-
- // processor_architecture should always be set, do this first
- sys_info->processor_architecture =
-#if defined(__aarch64__)
- MD_CPU_ARCHITECTURE_ARM64;
-#else
- MD_CPU_ARCHITECTURE_ARM;
-#endif
-
- // /proc/cpuinfo is not readable under various sandboxed environments
- // (e.g. Android services with the android:isolatedProcess attribute)
- // prepare for this by setting default values now, which will be
- // returned when this happens.
- //
- // Note: Bogus values are used to distinguish between failures (to
- // read /sys and /proc files) and really badly configured kernels.
- sys_info->number_of_processors = 0;
- sys_info->processor_level = 1U; // There is no ARMv1
- sys_info->processor_revision = 42;
- sys_info->cpu.arm_cpu_info.cpuid = 0;
- sys_info->cpu.arm_cpu_info.elf_hwcaps = 0;
-
- // Counting the number of CPUs involves parsing two sysfs files,
- // because the content of /proc/cpuinfo will only mirror the number
- // of 'online' cores, and thus will vary with time.
- // See http://www.kernel.org/doc/Documentation/cputopology.txt
- {
- CpuSet cpus_present;
- CpuSet cpus_possible;
-
- int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0);
- if (fd >= 0) {
- cpus_present.ParseSysFile(fd);
- sys_close(fd);
-
- fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0);
- if (fd >= 0) {
- cpus_possible.ParseSysFile(fd);
- sys_close(fd);
-
- cpus_present.IntersectWith(cpus_possible);
- int cpu_count = cpus_present.GetCount();
- if (cpu_count > 255)
- cpu_count = 255;
- sys_info->number_of_processors = static_cast<uint8_t>(cpu_count);
- }
- }
- }
-
- // Parse /proc/cpuinfo to reconstruct the CPUID value, as well
- // as the ELF hwcaps field. For the latter, it would be easier to
- // read /proc/self/auxv but unfortunately, this file is not always
- // readable from regular Android applications on later versions
- // (>= 4.1) of the Android platform.
- const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
- if (fd < 0) {
- // Do not return false here to allow the minidump generation
- // to happen properly.
- return true;
- }
-
- {
- PageAllocator allocator;
- ProcCpuInfoReader* const reader =
- new(allocator) ProcCpuInfoReader(fd);
- const char* field;
- while (reader->GetNextField(&field)) {
- for (const CpuIdEntry& entry : cpu_id_entries) {
- if (my_strcmp(entry.field, field) != 0)
- continue;
- uintptr_t result = 0;
- const char* value = reader->GetValue();
- const char* p = value;
- if (value[0] == '0' && value[1] == 'x') {
- p = my_read_hex_ptr(&result, value+2);
- } else if (entry.format == 'x') {
- p = my_read_hex_ptr(&result, value);
- } else {
- p = my_read_decimal_ptr(&result, value);
- }
- if (p == value)
- continue;
-
- result &= (1U << entry.bit_length)-1;
- result <<= entry.bit_lshift;
- sys_info->cpu.arm_cpu_info.cpuid |=
- static_cast<uint32_t>(result);
- }
-#if defined(__arm__)
- // Get the architecture version from the "Processor" field.
- // Note that it is also available in the "CPU architecture" field,
- // however, some existing kernels are misconfigured and will report
- // invalid values here (e.g. 6, while the CPU is ARMv7-A based).
- // The "Processor" field doesn't have this issue.
- if (!my_strcmp(field, "Processor")) {
- size_t value_len;
- const char* value = reader->GetValueAndLen(&value_len);
- // Expected format: <text> (v<level><endian>)
- // Where <text> is some text like "ARMv7 Processor rev 2"
- // and <level> is a decimal corresponding to the ARM
- // architecture number. <endian> is either 'l' or 'b'
- // and corresponds to the endianess, it is ignored here.
- while (value_len > 0 && my_isspace(value[value_len-1]))
- value_len--;
-
- size_t nn = value_len;
- while (nn > 0 && value[nn-1] != '(')
- nn--;
- if (nn > 0 && value[nn] == 'v') {
- uintptr_t arch_level = 5;
- my_read_decimal_ptr(&arch_level, value + nn + 1);
- sys_info->processor_level = static_cast<uint16_t>(arch_level);
- }
- }
-#elif defined(__aarch64__)
- // The aarch64 architecture does not provide the architecture level
- // in the Processor field, so we instead check the "CPU architecture"
- // field.
- if (!my_strcmp(field, "CPU architecture")) {
- uintptr_t arch_level = 0;
- const char* value = reader->GetValue();
- const char* p = value;
- p = my_read_decimal_ptr(&arch_level, value);
- if (p == value)
- continue;
- sys_info->processor_level = static_cast<uint16_t>(arch_level);
- }
-#endif
- // Rebuild the ELF hwcaps from the 'Features' field.
- if (!my_strcmp(field, "Features")) {
- size_t value_len;
- const char* value = reader->GetValueAndLen(&value_len);
-
- // Parse each space-separated tag.
- while (value_len > 0) {
- const char* tag = value;
- size_t tag_len = value_len;
- const char* p = my_strchr(tag, ' ');
- if (p) {
- tag_len = static_cast<size_t>(p - tag);
- value += tag_len + 1;
- value_len -= tag_len + 1;
- } else {
- tag_len = strlen(tag);
- value_len = 0;
- }
- for (const CpuFeaturesEntry& entry : cpu_features_entries) {
- if (tag_len == strlen(entry.tag) &&
- !memcmp(tag, entry.tag, tag_len)) {
- sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry.hwcaps;
- break;
- }
- }
- }
- }
- }
- sys_close(fd);
- }
-
- return true;
- }
-#else
-# error "Unsupported CPU"
-#endif
-
- bool WriteFile(MDLocationDescriptor* result, const char* filename) {
- const int fd = sys_open(filename, O_RDONLY, 0);
- if (fd < 0)
- return false;
-
- // We can't stat the files because several of the files that we want to
- // read are kernel seqfiles, which always have a length of zero. So we have
- // to read as much as we can into a buffer.
- static const unsigned kBufSize = 1024 - 2*sizeof(void*);
- struct Buffers {
- Buffers* next;
- size_t len;
- uint8_t data[kBufSize];
- } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
- buffers->next = NULL;
- buffers->len = 0;
-
- size_t total = 0;
- for (Buffers* bufptr = buffers;;) {
- ssize_t r;
- do {
- r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
- } while (r == -1 && errno == EINTR);
-
- if (r < 1)
- break;
-
- total += r;
- bufptr->len += r;
- if (bufptr->len == kBufSize) {
- bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
- bufptr = bufptr->next;
- bufptr->next = NULL;
- bufptr->len = 0;
- }
- }
- sys_close(fd);
-
- if (!total)
- return false;
-
- UntypedMDRVA memory(&minidump_writer_);
- if (!memory.Allocate(total))
- return false;
- for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
- // Check for special case of a zero-length buffer. This should only
- // occur if a file's size happens to be a multiple of the buffer's
- // size, in which case the final sys_read() will have resulted in
- // zero bytes being read after the final buffer was just allocated.
- if (buffers->len == 0) {
- // This can only occur with final buffer.
- assert(buffers->next == NULL);
- continue;
- }
- memory.Copy(pos, &buffers->data, buffers->len);
- pos += buffers->len;
- }
- *result = memory.location();
- return true;
- }
-
- bool WriteOSInformation(MDRawSystemInfo* sys_info) {
-#if defined(__ANDROID__)
- sys_info->platform_id = MD_OS_ANDROID;
-#else
- sys_info->platform_id = MD_OS_LINUX;
-#endif
-
- struct utsname uts;
- if (uname(&uts))
- return false;
-
- static const size_t buf_len = 512;
- char buf[buf_len] = {0};
- size_t space_left = buf_len - 1;
- const char* info_table[] = {
- uts.sysname,
- uts.release,
- uts.version,
- uts.machine,
- NULL
- };
- bool first_item = true;
- for (const char** cur_info = info_table; *cur_info; cur_info++) {
- static const char separator[] = " ";
- size_t separator_len = sizeof(separator) - 1;
- size_t info_len = my_strlen(*cur_info);
- if (info_len == 0)
- continue;
-
- if (space_left < info_len + (first_item ? 0 : separator_len))
- break;
-
- if (!first_item) {
- my_strlcat(buf, separator, sizeof(buf));
- space_left -= separator_len;
- }
-
- first_item = false;
- my_strlcat(buf, *cur_info, sizeof(buf));
- space_left -= info_len;
- }
-
- MDLocationDescriptor location;
- if (!minidump_writer_.WriteString(buf, 0, &location))
- return false;
- sys_info->csd_version_rva = location.rva;
-
- return true;
- }
-
- bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
- const char* filename) {
- char buf[NAME_MAX];
- if (!dumper_->BuildProcPath(buf, pid, filename))
- return false;
- return WriteFile(result, buf);
- }
-
- // Only one of the 2 member variables below should be set to a valid value.
- const int fd_; // File descriptor where the minidum should be written.
- const char* path_; // Path to the file where the minidum should be written.
-
- const ucontext_t* const ucontext_; // also from the signal handler
-#if !defined(__ARM_EABI__) && !defined(__mips__)
- const google_breakpad::fpstate_t* const float_state_; // ditto
-#endif
- LinuxDumper* dumper_;
- MinidumpFileWriter minidump_writer_;
- off_t minidump_size_limit_;
- MDLocationDescriptor crashing_thread_context_;
- // Blocks of memory written to the dump. These are all currently
- // written while writing the thread list stream, but saved here
- // so a memory list stream can be written afterwards.
- wasteful_vector<MDMemoryDescriptor> memory_blocks_;
- // Additional information about some mappings provided by the caller.
- const MappingList& mapping_list_;
- // Additional memory regions to be included in the dump,
- // provided by the caller.
- const AppMemoryList& app_memory_list_;
-};
-
-
-bool WriteMinidumpImpl(const char* minidump_path,
- int minidump_fd,
- off_t minidump_size_limit,
- pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appmem) {
- LinuxPtraceDumper dumper(crashing_process);
- const ExceptionHandler::CrashContext* context = NULL;
- if (blob) {
- if (blob_size != sizeof(ExceptionHandler::CrashContext))
- return false;
- context = reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
- dumper.set_crash_address(
- reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
- dumper.set_crash_signal(context->siginfo.si_signo);
- dumper.set_crash_thread(context->tid);
- }
- MinidumpWriter writer(minidump_path, minidump_fd, context, mappings,
- appmem, &dumper);
- // Set desired limit for file size of minidump (-1 means no limit).
- writer.set_minidump_size_limit(minidump_size_limit);
- if (!writer.Init())
- return false;
- return writer.Dump();
-}
-
-} // namespace
-
-namespace google_breakpad {
-
-bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
- const void* blob, size_t blob_size) {
- return WriteMinidumpImpl(minidump_path, -1, -1,
- crashing_process, blob, blob_size,
- MappingList(), AppMemoryList());
-}
-
-bool WriteMinidump(int minidump_fd, pid_t crashing_process,
- const void* blob, size_t blob_size) {
- return WriteMinidumpImpl(NULL, minidump_fd, -1,
- crashing_process, blob, blob_size,
- MappingList(), AppMemoryList());
-}
-
-bool WriteMinidump(const char* minidump_path, pid_t process,
- pid_t process_blamed_thread) {
- LinuxPtraceDumper dumper(process);
- // MinidumpWriter will set crash address
- dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED);
- dumper.set_crash_thread(process_blamed_thread);
- MinidumpWriter writer(minidump_path, -1, NULL, MappingList(),
- AppMemoryList(), &dumper);
- if (!writer.Init())
- return false;
- return writer.Dump();
-}
-
-bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appmem) {
- return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process,
- blob, blob_size,
- mappings, appmem);
-}
-
-bool WriteMinidump(int minidump_fd, pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appmem) {
- return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process,
- blob, blob_size,
- mappings, appmem);
-}
-
-bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
- pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appmem) {
- return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit,
- crashing_process, blob, blob_size,
- mappings, appmem);
-}
-
-bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
- pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appmem) {
- return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit,
- crashing_process, blob, blob_size,
- mappings, appmem);
-}
-
-bool WriteMinidump(const char* filename,
- const MappingList& mappings,
- const AppMemoryList& appmem,
- LinuxDumper* dumper) {
- MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper);
- if (!writer.Init())
- return false;
- return writer.Dump();
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h
deleted file mode 100644
index d13fb120b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h
+++ /dev/null
@@ -1,124 +0,0 @@
-// 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_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/ucontext.h>
-#include <unistd.h>
-
-#include <list>
-#include <utility>
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "google_breakpad/common/minidump_format.h"
-
-namespace google_breakpad {
-
-class ExceptionHandler;
-
-#if defined(__aarch64__)
-typedef struct fpsimd_context fpstate_t;
-#elif !defined(__ARM_EABI__) && !defined(__mips__)
-typedef struct _libc_fpstate fpstate_t;
-#endif
-
-// These entries store a list of memory regions that the client wants included
-// in the minidump.
-struct AppMemory {
- void* ptr;
- size_t length;
-
- bool operator==(const struct AppMemory& other) const {
- return ptr == other.ptr;
- }
-
- bool operator==(const void* other) const {
- return ptr == other;
- }
-};
-typedef std::list<AppMemory> AppMemoryList;
-
-// Writes a minidump to the filesystem. These functions do not malloc nor use
-// libc functions which may. Thus, it can be used in contexts where the state
-// of the heap may be corrupt.
-// minidump_path: the path to the file to write to. This is opened O_EXCL and
-// fails open fails.
-// crashing_process: the pid of the crashing process. This must be trusted.
-// blob: a blob of data from the crashing process. See exception_handler.h
-// blob_size: the length of |blob|, in bytes
-//
-// Returns true iff successful.
-bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
- const void* blob, size_t blob_size);
-// Same as above but takes an open file descriptor instead of a path.
-bool WriteMinidump(int minidump_fd, pid_t crashing_process,
- const void* blob, size_t blob_size);
-
-// Alternate form of WriteMinidump() that works with processes that
-// are not expected to have crashed. If |process_blamed_thread| is
-// meaningful, it will be the one from which a crash signature is
-// extracted. It is not expected that this function will be called
-// from a compromised context, but it is safe to do so.
-bool WriteMinidump(const char* minidump_path, pid_t process,
- pid_t process_blamed_thread);
-
-// These overloads also allow passing a list of known mappings and
-// a list of additional memory regions to be included in the minidump.
-bool WriteMinidump(const char* minidump_path, pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appdata);
-bool WriteMinidump(int minidump_fd, pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appdata);
-
-// These overloads also allow passing a file size limit for the minidump.
-bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit,
- pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appdata);
-bool WriteMinidump(int minidump_fd, off_t minidump_size_limit,
- pid_t crashing_process,
- const void* blob, size_t blob_size,
- const MappingList& mappings,
- const AppMemoryList& appdata);
-
-bool WriteMinidump(const char* filename,
- const MappingList& mappings,
- const AppMemoryList& appdata,
- LinuxDumper* dumper);
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
diff --git 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
deleted file mode 100644
index 2e4749e7e..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc
+++ /dev/null
@@ -1,775 +0,0 @@
-// Copyright (c) 2011 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 <fcntl.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <string>
-
-#include "breakpad_googletest_includes.h"
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
-#include "common/linux/eintr_wrapper.h"
-#include "common/linux/file_id.h"
-#include "common/linux/ignore_ret.h"
-#include "common/linux/safe_readlink.h"
-#include "common/scoped_ptr.h"
-#include "common/tests/auto_tempdir.h"
-#include "common/tests/file_utils.h"
-#include "common/using_std_string.h"
-#include "google_breakpad/processor/minidump.h"
-
-using namespace google_breakpad;
-
-namespace {
-
-typedef testing::Test MinidumpWriterTest;
-
-const char kMDWriterUnitTestFileName[] = "/minidump-writer-unittest";
-
-TEST(MinidumpWriterTest, SetupWithPath) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
- // Set a non-zero tid to avoid tripping asserts.
- context.tid = child;
- ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
- struct stat st;
- ASSERT_EQ(0, stat(templ.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- close(fds[1]);
-}
-
-TEST(MinidumpWriterTest, SetupWithFD) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
- int fd = open(templ.c_str(), O_CREAT | O_WRONLY, S_IRWXU);
- // Set a non-zero tid to avoid tripping asserts.
- context.tid = child;
- ASSERT_TRUE(WriteMinidump(fd, child, &context, sizeof(context)));
- struct stat st;
- ASSERT_EQ(0, stat(templ.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- close(fds[1]);
-}
-
-// Test that mapping info can be specified when writing a minidump,
-// and that it ends up in the module list of the minidump.
-TEST(MinidumpWriterTest, MappingInfo) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const uint32_t memory_size = sysconf(_SC_PAGESIZE);
- const char* kMemoryName = "a fake module";
- const uint8_t kModuleGUID[sizeof(MDGUID)] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
- };
- const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
-
- // Get some memory.
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- memory_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON,
- -1,
- 0));
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
- ASSERT_EQ(0, getcontext(&context.context));
- context.tid = child;
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
-
- // Add information about the mapped memory.
- MappingInfo info;
- info.start_addr = kMemoryAddress;
- info.size = memory_size;
- info.offset = 0;
- info.exec = false;
- strcpy(info.name, kMemoryName);
-
- MappingList mappings;
- AppMemoryList memory_list;
- MappingEntry mapping;
- mapping.first = info;
- memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
- mappings.push_back(mapping);
- ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
- mappings, memory_list));
-
- // Read the minidump. Load the module list, and ensure that
- // the mmap'ed |memory| is listed with the given module name
- // and debug ID.
- Minidump minidump(templ);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpModuleList* module_list = minidump.GetModuleList();
- ASSERT_TRUE(module_list);
- const MinidumpModule* module =
- module_list->GetModuleForAddress(kMemoryAddress);
- ASSERT_TRUE(module);
-
- EXPECT_EQ(kMemoryAddress, module->base_address());
- EXPECT_EQ(memory_size, module->size());
- EXPECT_EQ(kMemoryName, module->code_file());
- EXPECT_EQ(module_identifier, module->debug_identifier());
-
- uint32_t len;
- // These streams are expected to be there
- EXPECT_TRUE(minidump.SeekToStreamType(MD_THREAD_LIST_STREAM, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_MEMORY_LIST_STREAM, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_EXCEPTION_STREAM, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_SYSTEM_INFO_STREAM, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CPU_INFO, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_PROC_STATUS, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_CMD_LINE, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_ENVIRON, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_AUXV, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_MAPS, &len));
- EXPECT_TRUE(minidump.SeekToStreamType(MD_LINUX_DSO_DEBUG, &len));
-
- close(fds[1]);
-}
-
-// Test that a binary with a longer-than-usual build id note
-// makes its way all the way through to the minidump unscathed.
-// The linux_client_unittest is linked with an explicit --build-id
-// in Makefile.am.
-TEST(MinidumpWriterTest, BuildIDLong) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
- ASSERT_EQ(0, getcontext(&context.context));
- context.tid = child;
-
- AutoTempDir temp_dir;
- const string dump_path = temp_dir.path() + kMDWriterUnitTestFileName;
-
- EXPECT_TRUE(WriteMinidump(dump_path.c_str(),
- child, &context, sizeof(context)));
- close(fds[1]);
-
- // Read the minidump. Load the module list, and ensure that
- // the main module has the correct debug id and code id.
- Minidump minidump(dump_path);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpModuleList* module_list = minidump.GetModuleList();
- ASSERT_TRUE(module_list);
- const MinidumpModule* module = module_list->GetMainModule();
- ASSERT_TRUE(module);
- const string module_identifier = "030201000504070608090A0B0C0D0E0F0";
- // This is passed explicitly to the linker in Makefile.am
- const string build_id =
- "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
- EXPECT_EQ(module_identifier, module->debug_identifier());
- EXPECT_EQ(build_id, module->code_identifier());
-}
-
-// Test that mapping info can be specified, and that it overrides
-// existing mappings that are wholly contained within the specified
-// range.
-TEST(MinidumpWriterTest, MappingInfoContained) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const int32_t memory_size = sysconf(_SC_PAGESIZE);
- const char* kMemoryName = "a fake module";
- const uint8_t kModuleGUID[sizeof(MDGUID)] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
- };
- const string module_identifier = "33221100554477668899AABBCCDDEEFF0";
-
- // mmap a file
- AutoTempDir temp_dir;
- string tempfile = temp_dir.path() + "/minidump-writer-unittest-temp";
- int fd = open(tempfile.c_str(), O_RDWR | O_CREAT, 0);
- ASSERT_NE(-1, fd);
- unlink(tempfile.c_str());
- // fill with zeros
- google_breakpad::scoped_array<char> buffer(new char[memory_size]);
- memset(buffer.get(), 0, memory_size);
- ASSERT_EQ(memory_size, write(fd, buffer.get(), memory_size));
- lseek(fd, 0, SEEK_SET);
-
- char* memory =
- reinterpret_cast<char*>(mmap(NULL,
- memory_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE,
- fd,
- 0));
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
- close(fd);
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b))));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
- context.tid = 1;
-
- string dumpfile = temp_dir.path() + kMDWriterUnitTestFileName;
-
- // Add information about the mapped memory. Report it as being larger than
- // it actually is.
- MappingInfo info;
- info.start_addr = kMemoryAddress - memory_size;
- info.size = memory_size * 3;
- info.offset = 0;
- info.exec = false;
- strcpy(info.name, kMemoryName);
-
- MappingList mappings;
- AppMemoryList memory_list;
- MappingEntry mapping;
- mapping.first = info;
- memcpy(mapping.second, kModuleGUID, sizeof(MDGUID));
- mappings.push_back(mapping);
- ASSERT_TRUE(WriteMinidump(dumpfile.c_str(), child, &context, sizeof(context),
- mappings, memory_list));
-
- // Read the minidump. Load the module list, and ensure that
- // the mmap'ed |memory| is listed with the given module name
- // and debug ID.
- Minidump minidump(dumpfile);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpModuleList* module_list = minidump.GetModuleList();
- ASSERT_TRUE(module_list);
- const MinidumpModule* module =
- module_list->GetModuleForAddress(kMemoryAddress);
- ASSERT_TRUE(module);
-
- EXPECT_EQ(info.start_addr, module->base_address());
- EXPECT_EQ(info.size, module->size());
- EXPECT_EQ(kMemoryName, module->code_file());
- EXPECT_EQ(module_identifier, module->debug_identifier());
-
- close(fds[1]);
-}
-
-TEST(MinidumpWriterTest, DeletedBinary) {
- const string kNumberOfThreadsArgument = "1";
- const string helper_path(GetHelperBinary());
- if (helper_path.empty()) {
- FAIL() << "Couldn't find helper binary";
- exit(1);
- }
-
- // Copy binary to a temp file.
- AutoTempDir temp_dir;
- string binpath = temp_dir.path() + "/linux-dumper-unittest-helper";
- ASSERT_TRUE(CopyFile(helper_path.c_str(), binpath.c_str()))
- << "Failed to copy " << helper_path << " to " << binpath;
- ASSERT_EQ(0, chmod(binpath.c_str(), 0755));
-
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- pid_t child_pid = fork();
- if (child_pid == 0) {
- // In child process.
- close(fds[0]);
-
- // Pass the pipe fd and the number of threads as arguments.
- char pipe_fd_string[8];
- sprintf(pipe_fd_string, "%d", fds[1]);
- execl(binpath.c_str(),
- binpath.c_str(),
- pipe_fd_string,
- kNumberOfThreadsArgument.c_str(),
- NULL);
- }
- close(fds[1]);
- // Wait for the child process to signal that it's ready.
- struct pollfd pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = fds[0];
- pfd.events = POLLIN | POLLERR;
-
- const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
- ASSERT_EQ(1, r);
- ASSERT_TRUE(pfd.revents & POLLIN);
- uint8_t junk;
- const int nr = HANDLE_EINTR(read(fds[0], &junk, sizeof(junk)));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(junk)), nr);
- close(fds[0]);
-
- // Child is ready now.
- // Unlink the test binary.
- unlink(binpath.c_str());
-
- ExceptionHandler::CrashContext context;
- memset(&context, 0, sizeof(context));
-
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
- // Set a non-zero tid to avoid tripping asserts.
- context.tid = child_pid;
- ASSERT_TRUE(WriteMinidump(templ.c_str(), child_pid, &context,
- sizeof(context)));
- kill(child_pid, SIGKILL);
-
- struct stat st;
- ASSERT_EQ(0, stat(templ.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
-
- Minidump minidump(templ);
- ASSERT_TRUE(minidump.Read());
-
- // Check that the main module filename is correct.
- MinidumpModuleList* module_list = minidump.GetModuleList();
- ASSERT_TRUE(module_list);
- const MinidumpModule* module = module_list->GetMainModule();
- EXPECT_STREQ(binpath.c_str(), module->code_file().c_str());
- // Check that the file ID is correct.
- FileID fileid(helper_path.c_str());
- PageAllocator allocator;
- wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
- EXPECT_TRUE(fileid.ElfFileIdentifier(identifier));
- string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
- string module_identifier(identifier_string);
- // Strip out dashes
- size_t pos;
- while ((pos = module_identifier.find('-')) != string::npos) {
- module_identifier.erase(pos, 1);
- }
- // And append a zero, because module IDs include an "age" field
- // which is always zero on Linux.
- module_identifier += "0";
- EXPECT_EQ(module_identifier, module->debug_identifier());
-}
-
-// Test that an additional memory region can be added to the minidump.
-TEST(MinidumpWriterTest, AdditionalMemory) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- // These are defined here so the parent can use them to check the
- // data from the minidump afterwards.
- const uint32_t kMemorySize = sysconf(_SC_PAGESIZE);
-
- // Get some heap memory.
- uint8_t* memory = new uint8_t[kMemorySize];
- const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
- ASSERT_TRUE(memory);
-
- // Stick some data into the memory so the contents can be verified.
- for (uint32_t i = 0; i < kMemorySize; ++i) {
- memory[i] = i % 255;
- }
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
-
- // This needs a valid context for minidump writing to work, but getting
- // a useful one from the child is too much work, so just use one from
- // the parent since the child is just a forked copy anyway.
- ASSERT_EQ(0, getcontext(&context.context));
- context.tid = child;
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
- unlink(templ.c_str());
-
- MappingList mappings;
- AppMemoryList memory_list;
-
- // Add the memory region to the list of memory to be included.
- AppMemory app_memory;
- app_memory.ptr = memory;
- app_memory.length = kMemorySize;
- memory_list.push_back(app_memory);
- ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context),
- mappings, memory_list));
-
- // Read the minidump. Ensure that the memory region is present
- Minidump minidump(templ);
- ASSERT_TRUE(minidump.Read());
-
- MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
- ASSERT_TRUE(dump_memory_list);
- const MinidumpMemoryRegion* region =
- dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
- ASSERT_TRUE(region);
-
- EXPECT_EQ(kMemoryAddress, region->GetBase());
- EXPECT_EQ(kMemorySize, region->GetSize());
-
- // Verify memory contents.
- EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
-
- delete[] memory;
- close(fds[1]);
-}
-
-// Test that an invalid thread stack pointer still results in a minidump.
-TEST(MinidumpWriterTest, InvalidStackPointer) {
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- const pid_t child = fork();
- if (child == 0) {
- close(fds[1]);
- char b;
- HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
- close(fds[0]);
- syscall(__NR_exit);
- }
- close(fds[0]);
-
- ExceptionHandler::CrashContext context;
-
- // This needs a valid context for minidump writing to work, but getting
- // a useful one from the child is too much work, so just use one from
- // the parent since the child is just a forked copy anyway.
- ASSERT_EQ(0, getcontext(&context.context));
- context.tid = child;
-
- // Fake the child's stack pointer for its crashing thread. NOTE: This must
- // be an invalid memory address for the child process (stack or otherwise).
- // Try 1MB below the current stack.
- uintptr_t invalid_stack_pointer =
- reinterpret_cast<uintptr_t>(&context) - 1024*1024;
-#if defined(__i386)
- context.context.uc_mcontext.gregs[REG_ESP] = invalid_stack_pointer;
-#elif defined(__x86_64)
- context.context.uc_mcontext.gregs[REG_RSP] = invalid_stack_pointer;
-#elif defined(__ARM_EABI__)
- context.context.uc_mcontext.arm_sp = invalid_stack_pointer;
-#elif defined(__aarch64__)
- context.context.uc_mcontext.sp = invalid_stack_pointer;
-#elif defined(__mips__)
- context.context.uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP] =
- invalid_stack_pointer;
-#else
-# error "This code has not been ported to your platform yet."
-#endif
-
- AutoTempDir temp_dir;
- string templ = temp_dir.path() + kMDWriterUnitTestFileName;
- // NOTE: In previous versions of Breakpad, WriteMinidump() would fail if
- // presented with an invalid stack pointer.
- ASSERT_TRUE(WriteMinidump(templ.c_str(), child, &context, sizeof(context)));
-
- // Read the minidump. Ensure that the memory region is present
- Minidump minidump(templ);
- ASSERT_TRUE(minidump.Read());
-
- // TODO(ted.mielczarek,mkrebs): Enable this part of the test once
- // https://breakpad.appspot.com/413002/ is committed.
-#if 0
- // Make sure there's a thread without a stack. NOTE: It's okay if
- // GetThreadList() shows the error: "ERROR: MinidumpThread has a memory
- // region problem".
- MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
- ASSERT_TRUE(dump_thread_list);
- bool found_empty_stack = false;
- for (int i = 0; i < dump_thread_list->thread_count(); i++) {
- MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
- ASSERT_TRUE(thread->thread() != NULL);
- // When the stack size is zero bytes, GetMemory() returns NULL.
- if (thread->GetMemory() == NULL) {
- found_empty_stack = true;
- break;
- }
- }
- // NOTE: If you fail this, first make sure that "invalid_stack_pointer"
- // above is indeed set to an invalid address.
- ASSERT_TRUE(found_empty_stack);
-#endif
-
- close(fds[1]);
-}
-
-// Test that limiting the size of the minidump works.
-TEST(MinidumpWriterTest, MinidumpSizeLimit) {
- static const int kNumberOfThreadsInHelperProgram = 40;
-
- char number_of_threads_arg[3];
- sprintf(number_of_threads_arg, "%d", kNumberOfThreadsInHelperProgram);
-
- string helper_path(GetHelperBinary());
- if (helper_path.empty()) {
- FAIL() << "Couldn't find helper binary";
- exit(1);
- }
-
- int fds[2];
- ASSERT_NE(-1, pipe(fds));
-
- pid_t child_pid = fork();
- if (child_pid == 0) {
- // In child process.
- close(fds[0]);
-
- // Pass the pipe fd and the number of threads as arguments.
- char pipe_fd_string[8];
- sprintf(pipe_fd_string, "%d", fds[1]);
- execl(helper_path.c_str(),
- helper_path.c_str(),
- pipe_fd_string,
- number_of_threads_arg,
- NULL);
- }
- close(fds[1]);
-
- // Wait for all child threads to indicate that they have started
- for (int threads = 0; threads < kNumberOfThreadsInHelperProgram; threads++) {
- struct pollfd pfd;
- memset(&pfd, 0, sizeof(pfd));
- pfd.fd = fds[0];
- pfd.events = POLLIN | POLLERR;
-
- const int r = HANDLE_EINTR(poll(&pfd, 1, 1000));
- ASSERT_EQ(1, r);
- ASSERT_TRUE(pfd.revents & POLLIN);
- uint8_t junk;
- ASSERT_EQ(read(fds[0], &junk, sizeof(junk)),
- static_cast<ssize_t>(sizeof(junk)));
- }
- close(fds[0]);
-
- // There is a race here because we may stop a child thread before
- // it is actually running the busy loop. Empirically this sleep
- // is sufficient to avoid the race.
- usleep(100000);
-
- // Child and its threads are ready now.
-
-
- off_t normal_file_size;
- int total_normal_stack_size = 0;
- AutoTempDir temp_dir;
-
- // First, write a minidump with no size limit.
- {
- string normal_dump = temp_dir.path() +
- "/minidump-writer-unittest.dmp";
- ASSERT_TRUE(WriteMinidump(normal_dump.c_str(), -1,
- child_pid, NULL, 0,
- MappingList(), AppMemoryList()));
- struct stat st;
- ASSERT_EQ(0, stat(normal_dump.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
- normal_file_size = st.st_size;
-
- Minidump minidump(normal_dump);
- ASSERT_TRUE(minidump.Read());
- MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
- ASSERT_TRUE(dump_thread_list);
- for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
- MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
- ASSERT_TRUE(thread->thread() != NULL);
- // When the stack size is zero bytes, GetMemory() returns NULL.
- MinidumpMemoryRegion* memory = thread->GetMemory();
- ASSERT_TRUE(memory != NULL);
- total_normal_stack_size += memory->GetSize();
- }
- }
-
- // Second, write a minidump with a size limit big enough to not trigger
- // anything.
- {
- // Set size limit arbitrarily 1MB larger than the normal file size -- such
- // that the limiting code will not kick in.
- const off_t minidump_size_limit = normal_file_size + 1024*1024;
-
- string same_dump = temp_dir.path() +
- "/minidump-writer-unittest-same.dmp";
- ASSERT_TRUE(WriteMinidump(same_dump.c_str(), minidump_size_limit,
- child_pid, NULL, 0,
- MappingList(), AppMemoryList()));
- struct stat st;
- ASSERT_EQ(0, stat(same_dump.c_str(), &st));
- // Make sure limiting wasn't actually triggered. NOTE: If you fail this,
- // first make sure that "minidump_size_limit" above is indeed set to a
- // large enough value -- the limit-checking code in minidump_writer.cc
- // does just a rough estimate.
- ASSERT_EQ(normal_file_size, st.st_size);
- }
-
- // Third, write a minidump with a size limit small enough to be triggered.
- {
- // Set size limit to some arbitrary amount, such that the limiting code
- // will kick in. The equation used to set this value was determined by
- // simply reversing the size-limit logic a little bit in order to pick a
- // size we know will trigger it. The definition of
- // kLimitAverageThreadStackLength here was copied from class
- // MinidumpWriter in minidump_writer.cc.
- static const unsigned kLimitAverageThreadStackLength = 8 * 1024;
- off_t minidump_size_limit = kNumberOfThreadsInHelperProgram *
- kLimitAverageThreadStackLength;
- // If, in reality, each of the threads' stack is *smaller* than
- // kLimitAverageThreadStackLength, the normal file size could very well be
- // smaller than the arbitrary limit that was just set. In that case,
- // either of these numbers should trigger the size-limiting code, but we
- // might as well pick the smallest.
- if (normal_file_size < minidump_size_limit)
- minidump_size_limit = normal_file_size;
-
- string limit_dump = temp_dir.path() +
- "/minidump-writer-unittest-limit.dmp";
- ASSERT_TRUE(WriteMinidump(limit_dump.c_str(), minidump_size_limit,
- child_pid, NULL, 0,
- MappingList(), AppMemoryList()));
- struct stat st;
- ASSERT_EQ(0, stat(limit_dump.c_str(), &st));
- ASSERT_GT(st.st_size, 0);
- // Make sure the file size is at least smaller than the original. If this
- // fails because it's the same size, then the size-limit logic didn't kick
- // in like it was supposed to.
- EXPECT_LT(st.st_size, normal_file_size);
-
- Minidump minidump(limit_dump);
- ASSERT_TRUE(minidump.Read());
- MinidumpThreadList* dump_thread_list = minidump.GetThreadList();
- ASSERT_TRUE(dump_thread_list);
- int total_limit_stack_size = 0;
- for (unsigned int i = 0; i < dump_thread_list->thread_count(); i++) {
- MinidumpThread* thread = dump_thread_list->GetThreadAtIndex(i);
- ASSERT_TRUE(thread->thread() != NULL);
- // When the stack size is zero bytes, GetMemory() returns NULL.
- MinidumpMemoryRegion* memory = thread->GetMemory();
- ASSERT_TRUE(memory != NULL);
- total_limit_stack_size += memory->GetSize();
- }
-
- // Make sure stack size shrunk by at least 1KB per extra thread. The
- // definition of kLimitBaseThreadCount here was copied from class
- // MinidumpWriter in minidump_writer.cc.
- // Note: The 1KB is arbitrary, and assumes that the thread stacks are big
- // enough to shrink by that much. For example, if each thread stack was
- // originally only 2KB, the current size-limit logic wouldn't actually
- // shrink them because that's the size to which it tries to shrink. If
- // you fail this part of the test due to something like that, the test
- // logic should probably be improved to account for your situation.
- const unsigned kLimitBaseThreadCount = 20;
- const unsigned kMinPerExtraThreadStackReduction = 1024;
- const int min_expected_reduction = (kNumberOfThreadsInHelperProgram -
- kLimitBaseThreadCount) * kMinPerExtraThreadStackReduction;
- EXPECT_LT(total_limit_stack_size,
- total_normal_stack_size - min_expected_reduction);
- }
-
- // Kill the helper program.
- kill(child_pid, SIGKILL);
-}
-
-} // namespace
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc
deleted file mode 100644
index 9f46fa65c..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2011 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.
-
-// minidump_writer_unittest_utils.cc:
-// Shared routines used by unittests under client/linux/minidump_writer.
-
-#include <limits.h>
-#include <stdlib.h>
-
-#include "client/linux/minidump_writer/minidump_writer_unittest_utils.h"
-#include "common/linux/safe_readlink.h"
-#include "common/using_std_string.h"
-
-namespace google_breakpad {
-
-string GetHelperBinary() {
- string helper_path;
- char *bindir = getenv("bindir");
- if (bindir) {
- helper_path = string(bindir) + "/";
- } else {
- // Locate helper binary next to the current binary.
- char self_path[PATH_MAX];
- if (!SafeReadLink("/proc/self/exe", self_path)) {
- return "";
- }
- helper_path = string(self_path);
- size_t pos = helper_path.rfind('/');
- if (pos == string::npos) {
- return "";
- }
- helper_path.erase(pos + 1);
- }
-
- helper_path += "linux_dumper_unittest_helper";
-
- return helper_path;
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h
deleted file mode 100644
index f16cc086b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest_utils.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// minidump_writer_unittest_utils.h:
-// Shared routines used by unittests under client/linux/minidump_writer.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_
-
-#include <string>
-
-#include "common/using_std_string.h"
-
-namespace google_breakpad {
-
-// Returns the full path to linux_dumper_unittest_helper. The full path is
-// discovered either by using the environment variable "bindir" or by using
-// the location of the main module of the currently running process.
-string GetHelperBinary();
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_UNITTEST_UTILS_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
deleted file mode 100644
index d9461bf30..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2013, 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_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_
-
-#include <stdint.h>
-#include <assert.h>
-#include <string.h>
-
-#include "client/linux/minidump_writer/line_reader.h"
-#include "common/linux/linux_libc_support.h"
-#include "third_party/lss/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for reading /proc/cpuinfo without using fopen/fgets or other
-// functions which may allocate memory.
-class ProcCpuInfoReader {
-public:
- ProcCpuInfoReader(int fd)
- : line_reader_(fd), pop_count_(-1) {
- }
-
- // Return the next field name, or NULL in case of EOF.
- // field: (output) Pointer to zero-terminated field name.
- // Returns true on success, or false on EOF or error (line too long).
- bool GetNextField(const char** field) {
- for (;;) {
- const char* line;
- unsigned line_len;
-
- // Try to read next line.
- if (pop_count_ >= 0) {
- line_reader_.PopLine(pop_count_);
- pop_count_ = -1;
- }
-
- if (!line_reader_.GetNextLine(&line, &line_len))
- return false;
-
- pop_count_ = static_cast<int>(line_len);
-
- const char* line_end = line + line_len;
-
- // Expected format: <field-name> <space>+ ':' <space> <value>
- // Note that:
- // - empty lines happen.
- // - <field-name> can contain spaces.
- // - some fields have an empty <value>
- char* sep = static_cast<char*>(my_memchr(line, ':', line_len));
- if (sep == NULL)
- continue;
-
- // Record the value. Skip leading space after the column to get
- // its start.
- const char* val = sep+1;
- while (val < line_end && my_isspace(*val))
- val++;
-
- value_ = val;
- value_len_ = static_cast<size_t>(line_end - val);
-
- // Remove trailing spaces before the column to properly 0-terminate
- // the field name.
- while (sep > line && my_isspace(sep[-1]))
- sep--;
-
- if (sep == line)
- continue;
-
- // zero-terminate field name.
- *sep = '\0';
-
- *field = line;
- return true;
- }
- }
-
- // Return the field value. This must be called after a succesful
- // call to GetNextField().
- const char* GetValue() {
- assert(value_);
- return value_;
- }
-
- // Same as GetValue(), but also returns the length in characters of
- // the value.
- const char* GetValueAndLen(size_t* length) {
- assert(value_);
- *length = value_len_;
- return value_;
- }
-
-private:
- LineReader line_reader_;
- int pop_count_;
- const char* value_;
- size_t value_len_;
-};
-
-} // namespace google_breakpad
-
-#endif // CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc
deleted file mode 100644
index 6037c7e66..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (c) 2013, 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 <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-
-#include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
-#include "breakpad_googletest_includes.h"
-#include "common/linux/tests/auto_testfile.h"
-
-using namespace google_breakpad;
-
-#if !defined(__ANDROID__)
-#define TEMPDIR "/tmp"
-#else
-#define TEMPDIR "/data/local/tmp"
-#endif
-
-
-namespace {
-
-typedef testing::Test ProcCpuInfoReaderTest;
-
-class ScopedTestFile : public AutoTestFile {
-public:
- explicit ScopedTestFile(const char* text)
- : AutoTestFile("proc_cpuinfo_reader", text) {
- }
-};
-
-}
-
-TEST(ProcCpuInfoReaderTest, EmptyFile) {
- ScopedTestFile file("");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char *field;
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, OneLineTerminated) {
- ScopedTestFile file("foo : bar\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char *field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, OneLine) {
- ScopedTestFile file("foo : bar");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char *field;
- size_t value_len;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValueAndLen(&value_len));
- ASSERT_EQ(3U, value_len);
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) {
- ScopedTestFile file("foo : bar\nzoo : tut\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("zoo", field);
- ASSERT_STREQ("tut", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, SkipMalformedLine) {
- ScopedTestFile file("this line should have a column\nfoo : bar\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) {
- ScopedTestFile file("\n\nfoo : bar\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, SkipEmptyField) {
- ScopedTestFile file(" : bar\nzoo : tut\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("zoo", field);
- ASSERT_STREQ("tut", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) {
- ScopedTestFile file("foo : bar\n\n\nfoo : bar\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- ASSERT_STREQ("bar", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, FieldWithSpaces) {
- ScopedTestFile file("foo bar : zoo\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo bar", field);
- ASSERT_STREQ("zoo", reader.GetValue());
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
-
-TEST(ProcCpuInfoReaderTest, EmptyValue) {
- ScopedTestFile file("foo :\n");
- ASSERT_TRUE(file.IsOk());
- ProcCpuInfoReader reader(file.GetFd());
-
- const char* field;
- ASSERT_TRUE(reader.GetNextField(&field));
- ASSERT_STREQ("foo", field);
- size_t value_len;
- ASSERT_STREQ("", reader.GetValueAndLen(&value_len));
- ASSERT_EQ(0U, value_len);
-
- ASSERT_FALSE(reader.GetNextField(&field));
-}
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/moz.build b/toolkit/crashreporter/google-breakpad/src/client/linux/moz.build
deleted file mode 100644
index 9bb8bace3..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/moz.build
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-UNIFIED_SOURCES += [
- 'crash_generation/crash_generation_client.cc',
- 'crash_generation/crash_generation_server.cc',
- 'dump_writer_common/thread_info.cc',
- 'dump_writer_common/ucontext_reader.cc',
- 'handler/exception_handler.cc',
- 'handler/minidump_descriptor.cc',
- 'log/log.cc',
- 'microdump_writer/microdump_writer.cc',
- 'minidump_writer/linux_dumper.cc',
- 'minidump_writer/linux_ptrace_dumper.cc',
- 'minidump_writer/minidump_writer.cc',
-]
-
-if CONFIG['OS_TARGET'] == 'Android':
- LOCAL_INCLUDES += [
- '/toolkit/crashreporter/google-breakpad/src/common/android/include',
- ]
-
-# We allow warnings for third-party code that can be updated from upstream.
-ALLOW_COMPILER_WARNINGS = True
-
-FINAL_LIBRARY = 'xul'
-
-if CONFIG['OS_TARGET'] == 'Android' and CONFIG['CPU_ARCH'] == 'x86':
- # The NDK's user.h defines this struct with a different name.
- DEFINES['user_fpxregs_struct'] = 'user_fxsr_struct'
-
-include('/toolkit/crashreporter/crashreporter.mozbuild')
diff --git a/toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc b/toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc
deleted file mode 100644
index ec6c06e87..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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 "common/linux/google_crashdump_uploader.h"
-#include "third_party/linux/include/gflags/gflags.h"
-#include <string>
-#include <iostream>
-
-#include "common/using_std_string.h"
-
-DEFINE_string(crash_server, "https://clients2.google.com/cr",
- "The crash server to upload minidumps to.");
-DEFINE_string(product_name, "",
- "The product name that the minidump corresponds to.");
-DEFINE_string(product_version, "",
- "The version of the product that produced the minidump.");
-DEFINE_string(client_id, "",
- "The client GUID");
-DEFINE_string(minidump_path, "",
- "The path of the minidump file.");
-DEFINE_string(ptime, "",
- "The process uptime in milliseconds.");
-DEFINE_string(ctime, "",
- "The cumulative process uptime in milliseconds.");
-DEFINE_string(email, "",
- "The user's email address.");
-DEFINE_string(comments, "",
- "Extra user comments");
-DEFINE_string(proxy_host, "",
- "Proxy host");
-DEFINE_string(proxy_userpasswd, "",
- "Proxy username/password in user:pass format.");
-
-
-bool CheckForRequiredFlagsOrDie() {
- string error_text = "";
- if (FLAGS_product_name.empty()) {
- error_text.append("\nProduct name must be specified.");
- }
-
- if (FLAGS_product_version.empty()) {
- error_text.append("\nProduct version must be specified.");
- }
-
- if (FLAGS_client_id.empty()) {
- error_text.append("\nClient ID must be specified.");
- }
-
- if (FLAGS_minidump_path.empty()) {
- error_text.append("\nMinidump pathname must be specified.");
- }
-
- if (!error_text.empty()) {
- std::cout << error_text;
- return false;
- }
- return true;
-}
-
-int main(int argc, char *argv[]) {
- google::InitGoogleLogging(argv[0]);
- google::ParseCommandLineFlags(&argc, &argv, true);
- if (!CheckForRequiredFlagsOrDie()) {
- return 1;
- }
- google_breakpad::GoogleCrashdumpUploader g(FLAGS_product_name,
- FLAGS_product_version,
- FLAGS_client_id,
- FLAGS_ptime,
- FLAGS_ctime,
- FLAGS_email,
- FLAGS_comments,
- FLAGS_minidump_path,
- FLAGS_crash_server,
- FLAGS_proxy_host,
- FLAGS_proxy_userpasswd);
- g.Upload(NULL, NULL, NULL);
-}