Add breakpad support to mojo shell apk.
This enables breakpad and save minidump locally when the application crashes,
but at this point it doesn't upload those yet.
R=viettrungluu@chromium.org, tonyg@chromium.org
Review URL: https://codereview.chromium.org/1227333002 .
diff --git a/.gitignore b/.gitignore
index 230d359..c038307 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@
/third_party/android_tools/
/third_party/angle/
/third_party/appurify-python/
+/third_party/breakpad/src/
/third_party/boringssl/src/
/third_party/brotli/src/
/third_party/colorama/src/
@@ -61,6 +62,7 @@
/third_party/libjpeg_turbo/
/third_party/llvm/
/third_party/llvm-build/
+/third_party/lss/
/third_party/junit/src/
/third_party/mesa/src/
/third_party/mockito/src/
diff --git a/DEPS b/DEPS
index 66fcaf8..95b0b00 100644
--- a/DEPS
+++ b/DEPS
@@ -27,7 +27,7 @@
'dart_observatory_packages_revision': 'cdc4b3d4c15b9c0c8e7702dff127b440afbb7485',
'pdfium_revision': 'b0115665b0f33971f1b7077740d51e155583cec0',
'boringssl_revision': '642f1498d056dbba3e50ed5a232ab2f482626dec',
- 'lss_revision': 'e079768b7e3a94dcbe7d338496c0c3bde7151b6e',
+ 'lss_revision': '6f97298fe3794e92c8c896a6bc06e0b36e4c3de3',
'nss_revision': 'bb4e75a43d007518ae7d618665ea2f25b0c60b63',
'nacl_revision': '87d5dd90911a0657c27574f78e86b7dfc4ad8b29',
'archive_dart_revision': '07ffd98c5403b7f9ae067b57dc9487611be420f5',
@@ -154,6 +154,12 @@
'src/third_party/pyelftools':
Var('chromium_git') + '/chromiumos/third_party/pyelftools.git' + '@' + '19b3e610c86fcadb837d252c794cb5e8008826ae',
+
+ 'src/third_party/breakpad/src':
+ Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + '242fb9a38db6ba534b1f7daa341dd4d79171658b', # from svn revision 1471
+
+ 'src/third_party/lss':
+ Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'),
}
deps_os = {
diff --git a/shell/BUILD.gn b/shell/BUILD.gn
index 143ef6d..9cf9537 100644
--- a/shell/BUILD.gn
+++ b/shell/BUILD.gn
@@ -47,6 +47,7 @@
if (!mojo_use_prebuilt_mojo_shell) {
shell_common_deps = [
":parent_lib",
+ "crash",
"//base",
"//base/allocator",
"//build/config/sanitizers:deps",
diff --git a/shell/android/main.cc b/shell/android/main.cc
index 6b713c0..173eb08 100644
--- a/shell/android/main.cc
+++ b/shell/android/main.cc
@@ -31,6 +31,7 @@
#include "shell/background_application_loader.h"
#include "shell/command_line_util.h"
#include "shell/context.h"
+#include "shell/crash/breakpad.h"
#include "shell/init.h"
#include "shell/switches.h"
#include "shell/tracer.h"
@@ -237,6 +238,10 @@
base::CommandLine::Init(0, nullptr);
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->InitFromArgv(parameters);
+
+ base::FilePath dumps_path = base::FilePath(tmp_dir).Append("breakpad_dumps");
+ breakpad::InitCrashReporter(dumps_path);
+
Tracer* tracer = new Tracer;
g_internal_data.Get().tracer.reset(tracer);
bool trace_startup = command_line->HasSwitch(switches::kTraceStartup);
diff --git a/shell/crash/BUILD.gn b/shell/crash/BUILD.gn
new file mode 100644
index 0000000..d2f0d8b
--- /dev/null
+++ b/shell/crash/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+}
+
+source_set("crash") {
+ sources = [
+ "breakpad.cc",
+ "breakpad.h",
+ ]
+
+ if (is_android) {
+ libs = [ "log" ]
+ }
+
+ deps = [
+ "//base",
+ "//third_party/breakpad:client",
+ ]
+}
diff --git a/shell/crash/breakpad.cc b/shell/crash/breakpad.cc
new file mode 100644
index 0000000..28b74e3
--- /dev/null
+++ b/shell/crash/breakpad.cc
@@ -0,0 +1,781 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was forked from components/crash/app/breakpad_linux.cc and
+// components/crash/app/breakpad_linux_impl.h in chromium.
+
+// For linux_syscall_support.h. This makes it safe to call embedded system
+// calls when in seccomp mode.
+
+#include "shell/crash/breakpad.h"
+
+#include <fcntl.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/linux_util.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/memory.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "third_party/breakpad/src/client/linux/crash_generation/crash_generation_client.h"
+#include "third_party/breakpad/src/client/linux/handler/exception_handler.h"
+#include "third_party/breakpad/src/client/linux/minidump_writer/directory_reader.h"
+#include "third_party/breakpad/src/common/linux/linux_libc_support.h"
+#include "third_party/breakpad/src/common/memory.h"
+#include "third_party/breakpad/src/common/simple_string_dictionary.h"
+
+#if defined(OS_ANDROID)
+#include <android/log.h>
+#include <sys/stat.h>
+
+#include "base/android/build_info.h"
+#include "base/android/path_utils.h"
+#endif
+#include "third_party/lss/linux_syscall_support.h"
+
+#if defined(OS_ANDROID)
+#define STAT_STRUCT struct stat
+#define FSTAT_FUNC fstat
+#else
+#define STAT_STRUCT struct kernel_stat
+#define FSTAT_FUNC sys_fstat
+#endif
+
+// Some versions of gcc are prone to warn about unused return values. In cases
+// where we either a) know the call cannot fail, or b) there is nothing we
+// can do when a call fails, we mark the return code as ignored. This avoids
+// spurious compiler warnings.
+#define IGNORE_RET(x) \
+ do { \
+ if (x) \
+ ; \
+ } while (0)
+
+using google_breakpad::ExceptionHandler;
+using google_breakpad::MinidumpDescriptor;
+
+namespace breakpad {
+
+namespace {
+
+using CrashKeyStorage = google_breakpad::NonAllocatingMap<256, 256, 64>;
+
+// BreakpadInfo describes a crash report.
+// The minidump information can either be contained in a file descriptor (fd) or
+// in a file (whose path is in filename).
+struct BreakpadInfo {
+ int fd; // File descriptor to the Breakpad dump data.
+ const char* filename; // Path to the Breakpad dump data.
+ const char* process_type; // Process type, e.g. "renderer".
+ unsigned process_type_length; // Length of |process_type|.
+ const char* distro; // Linux distro string.
+ unsigned distro_length; // Length of |distro|.
+ uint64_t process_start_time; // Uptime of the crashing process.
+ size_t oom_size; // Amount of memory requested if OOM.
+ uint64_t pid; // PID where applicable.
+ CrashKeyStorage* crash_keys;
+};
+
+// Define a preferred limit on minidump sizes, because Crash Server currently
+// throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
+// no limit.
+static const off_t kMaxMinidumpFileSize = 1258291;
+bool g_is_crash_reporter_enabled = false;
+uint64_t g_process_start_time = 0;
+pid_t g_pid = 0;
+ExceptionHandler* g_breakpad = nullptr;
+
+CrashKeyStorage* g_crash_keys = nullptr;
+
+#if defined(OS_ANDROID)
+const char kProductName[] = "Mojo_Android";
+#else
+const char kProductName[] = "Mojo";
+#endif
+const char kVersion[] = "1.0.0";
+
+// Writes the value |v| as 16 hex characters to the memory pointed at by
+// |output|.
+void write_uint64_hex(char* output, uint64_t v) {
+ static const char hextable[] = "0123456789abcdef";
+
+ for (int i = 15; i >= 0; --i) {
+ output[i] = hextable[v & 15];
+ v >>= 4;
+ }
+}
+
+// The following helper functions are for calculating uptime.
+
+// Converts a struct timeval to milliseconds.
+uint64_t timeval_to_ms(struct timeval* tv) {
+ uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
+ ret *= 1000;
+ ret += tv->tv_usec / 1000;
+ return ret;
+}
+
+// Converts a struct timeval to milliseconds.
+uint64_t kernel_timeval_to_ms(struct kernel_timeval* tv) {
+ uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
+ ret *= 1000;
+ ret += tv->tv_usec / 1000;
+ return ret;
+}
+
+// String buffer size to use to convert a uint64_t to string.
+const size_t kUint64StringSize = 21;
+
+void SetProcessStartTime() {
+ // Set the base process start time value.
+ struct timeval tv;
+ if (!gettimeofday(&tv, nullptr))
+ g_process_start_time = timeval_to_ms(&tv);
+ else
+ g_process_start_time = 0;
+}
+
+// uint64_t version of my_int_len() from
+// breakpad/src/common/linux/linux_libc_support.h. Return the length of the
+// given, non-negative integer when expressed in base 10.
+unsigned my_uint64_len(uint64_t i) {
+ if (!i)
+ return 1;
+
+ unsigned len = 0;
+ while (i) {
+ len++;
+ i /= 10;
+ }
+
+ return len;
+}
+
+// uint64_t version of my_uitos() from
+// breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
+// integer to a string (not null-terminated).
+void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
+ for (unsigned index = i_len; index; --index, i /= 10)
+ output[index - 1] = '0' + (i % 10);
+}
+
+size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
+ while (len > 0 && str[len - 1] == ' ') {
+ len--;
+ }
+ return len;
+}
+
+// MIME substrings.
+const char g_rn[] = "\r\n";
+const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
+const char g_quote_msg[] = "\"";
+const char g_dashdash_msg[] = "--";
+const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
+const char g_content_type_msg[] = "Content-Type: application/octet-stream";
+
+// MimeWriter manages an iovec for writing MIMEs to a file.
+class MimeWriter {
+ public:
+ static const int kIovCapacity = 30;
+ static const size_t kMaxCrashChunkSize = 64;
+
+ MimeWriter(int fd, const char* const mime_boundary);
+ ~MimeWriter();
+
+ // Append boundary.
+ virtual void AddBoundary();
+
+ // Append end of file boundary.
+ virtual void AddEnd();
+
+ // Append key/value pair with specified sizes.
+ virtual void AddPairData(const char* msg_type,
+ size_t msg_type_size,
+ const char* msg_data,
+ size_t msg_data_size);
+
+ // Append key/value pair.
+ void AddPairString(const char* msg_type, const char* msg_data) {
+ AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
+ }
+
+ // Append key/value pair, splitting value into chunks no larger than
+ // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
+ // The msg_type string will have a counter suffix to distinguish each chunk.
+ virtual void AddPairDataInChunks(const char* msg_type,
+ size_t msg_type_size,
+ const char* msg_data,
+ size_t msg_data_size,
+ size_t chunk_size,
+ bool strip_trailing_spaces);
+
+ // Add binary file contents to be uploaded with the specified filename.
+ virtual void AddFileContents(const char* filename_msg,
+ uint8_t* file_data,
+ size_t file_size);
+
+ // Flush any pending iovecs to the output file.
+ void Flush() {
+ IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
+ iov_index_ = 0;
+ }
+
+ protected:
+ void AddItem(const void* base, size_t size);
+ // Minor performance trade-off for easier-to-maintain code.
+ void AddString(const char* str) { AddItem(str, my_strlen(str)); }
+ void AddItemWithoutTrailingSpaces(const void* base, size_t size);
+
+ struct kernel_iovec iov_[kIovCapacity];
+ int iov_index_;
+
+ // Output file descriptor.
+ int fd_;
+
+ const char* const mime_boundary_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MimeWriter);
+};
+
+MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
+ : iov_index_(0), fd_(fd), mime_boundary_(mime_boundary) {
+}
+
+MimeWriter::~MimeWriter() {
+}
+
+void MimeWriter::AddBoundary() {
+ AddString(mime_boundary_);
+ AddString(g_rn);
+}
+
+void MimeWriter::AddEnd() {
+ AddString(mime_boundary_);
+ AddString(g_dashdash_msg);
+ AddString(g_rn);
+}
+
+void MimeWriter::AddPairData(const char* msg_type,
+ size_t msg_type_size,
+ const char* msg_data,
+ size_t msg_data_size) {
+ AddString(g_form_data_msg);
+ AddItem(msg_type, msg_type_size);
+ AddString(g_quote_msg);
+ AddString(g_rn);
+ AddString(g_rn);
+ AddItem(msg_data, msg_data_size);
+ AddString(g_rn);
+}
+
+void MimeWriter::AddPairDataInChunks(const char* msg_type,
+ size_t msg_type_size,
+ const char* msg_data,
+ size_t msg_data_size,
+ size_t chunk_size,
+ bool strip_trailing_spaces) {
+ if (chunk_size > kMaxCrashChunkSize)
+ return;
+
+ unsigned i = 0;
+ size_t done = 0, msg_length = msg_data_size;
+
+ while (msg_length) {
+ char num[kUint64StringSize];
+ const unsigned num_len = my_uint_len(++i);
+ my_uitos(num, i, num_len);
+
+ size_t chunk_len = std::min(chunk_size, msg_length);
+
+ AddString(g_form_data_msg);
+ AddItem(msg_type, msg_type_size);
+ AddItem(num, num_len);
+ AddString(g_quote_msg);
+ AddString(g_rn);
+ AddString(g_rn);
+ if (strip_trailing_spaces) {
+ AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
+ } else {
+ AddItem(msg_data + done, chunk_len);
+ }
+ AddString(g_rn);
+ AddBoundary();
+ Flush();
+
+ done += chunk_len;
+ msg_length -= chunk_len;
+ }
+}
+
+void MimeWriter::AddFileContents(const char* filename_msg,
+ uint8_t* file_data,
+ size_t file_size) {
+ AddString(g_form_data_msg);
+ AddString(filename_msg);
+ AddString(g_rn);
+ AddString(g_content_type_msg);
+ AddString(g_rn);
+ AddString(g_rn);
+ AddItem(file_data, file_size);
+ AddString(g_rn);
+}
+
+void MimeWriter::AddItem(const void* base, size_t size) {
+ // Check if the iovec is full and needs to be flushed to output file.
+ if (iov_index_ == kIovCapacity) {
+ Flush();
+ }
+ iov_[iov_index_].iov_base = const_cast<void*>(base);
+ iov_[iov_index_].iov_len = size;
+ ++iov_index_;
+}
+
+void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
+ AddItem(base,
+ LengthWithoutTrailingSpaces(static_cast<const char*>(base), size));
+}
+
+void DumpProcess() {
+ if (g_breakpad)
+ g_breakpad->WriteMinidump();
+}
+
+#if defined(OS_ANDROID)
+const char kGoogleBreakpad[] = "google-breakpad";
+#endif
+
+size_t WriteLog(const char* buf, size_t nbytes) {
+#if defined(OS_ANDROID)
+ return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
+#else
+ return sys_write(2, buf, nbytes);
+#endif
+}
+
+#if defined(OS_ANDROID)
+void AndroidLogWriteHorizontalRule() {
+ __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
+ "### ### ### ### ### ### ### ### ### ### ### ### ###");
+}
+
+// Android's native crash handler outputs a diagnostic tombstone to the device
+// log. By returning false from the HandlerCallbacks, breakpad will reinstall
+// the previous (i.e. native) signal handlers before returning from its own
+// handler. A Mojo shell build fingerprint is written to the log, so that the
+// specific build of the shell and the location of the archived shell symbols
+// can be determined directly from it.
+bool FinalizeCrashDoneAndroid() {
+ base::android::BuildInfo* android_build_info =
+ base::android::BuildInfo::GetInstance();
+
+ AndroidLogWriteHorizontalRule();
+ __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
+ "Mojo shell build fingerprint:");
+ __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
+ android_build_info->package_version_name());
+ __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
+ android_build_info->package_version_code());
+ AndroidLogWriteHorizontalRule();
+
+ return false;
+}
+#endif
+
+void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
+ int fd,
+ bool close_fd,
+ uint8_t** file_data,
+ size_t* size) {
+ STAT_STRUCT st;
+ if (FSTAT_FUNC(fd, &st) != 0) {
+ static const char msg[] = "Cannot upload crash dump: stat failed\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ if (close_fd)
+ IGNORE_RET(sys_close(fd));
+ return;
+ }
+
+ *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
+ if (!(*file_data)) {
+ static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ if (close_fd)
+ IGNORE_RET(sys_close(fd));
+ return;
+ }
+ my_memset(*file_data, 0xf, st.st_size);
+
+ *size = st.st_size;
+ int byte_read = sys_read(fd, *file_data, *size);
+ if (byte_read == -1) {
+ static const char msg[] = "Cannot upload crash dump: read failed\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ if (close_fd)
+ IGNORE_RET(sys_close(fd));
+ return;
+ }
+
+ if (close_fd)
+ IGNORE_RET(sys_close(fd));
+}
+
+void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
+ const char* filename,
+ int* fd,
+ uint8_t** file_data,
+ size_t* size) {
+ // WARNING: this code runs in a compromised context. It may not call into
+ // libc nor allocate memory normally.
+ *fd = sys_open(filename, O_RDONLY, 0);
+ *size = 0;
+
+ if (*fd < 0) {
+ static const char msg[] = "Cannot upload crash dump: failed to open\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ return;
+ }
+
+ LoadDataFromFD(allocator, *fd, true, file_data, size);
+}
+
+void HandleCrashDump(const BreakpadInfo& info) {
+ int dumpfd;
+ bool keep_fd = false;
+ size_t dump_size;
+ uint8_t* dump_data;
+ google_breakpad::PageAllocator allocator;
+
+ if (info.fd != -1) {
+ // Dump is provided with an open FD.
+ keep_fd = true;
+ dumpfd = info.fd;
+
+ // The FD is pointing to the end of the file.
+ // Rewind, we'll read the data next.
+ if (lseek(dumpfd, 0, SEEK_SET) == -1) {
+ static const char msg[] =
+ "Cannot upload crash dump: failed to "
+ "reposition minidump FD\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ IGNORE_RET(sys_close(dumpfd));
+ return;
+ }
+ LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
+ } else {
+ // Dump is provided with a path.
+ keep_fd = false;
+ LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
+ }
+
+ // We need to build a MIME block for uploading to the server. Since we are
+ // going to fork and run wget, it needs to be written to a temp file.
+ const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
+ if (ufd < 0) {
+ static const char msg[] =
+ "Cannot upload crash dump because /dev/urandom"
+ " is missing\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ return;
+ }
+
+ int temp_file_fd = -1;
+ if (keep_fd) {
+ LOG(WARNING) << "Keeping fd...";
+ temp_file_fd = dumpfd;
+ // Rewind the destination, we are going to overwrite it.
+ if (lseek(dumpfd, 0, SEEK_SET) == -1) {
+ static const char msg[] =
+ "Cannot upload crash dump: failed to "
+ "reposition minidump FD (2)\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ IGNORE_RET(sys_close(dumpfd));
+ return;
+ }
+ } else {
+ LOG(WARNING) << "Opening file: " << info.filename;
+ temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
+ if (temp_file_fd < 0) {
+ static const char msg[] = "Failed to save crash dump: failed to open\n";
+ WriteLog(msg, sizeof(msg) - 1);
+ IGNORE_RET(sys_close(ufd));
+ return;
+ }
+ }
+
+ // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
+ char mime_boundary[28 + 16 + 1];
+ my_memset(mime_boundary, '-', 28);
+ uint64_t boundary_rand;
+ sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
+ write_uint64_hex(mime_boundary + 28, boundary_rand);
+ mime_boundary[28 + 16] = 0;
+ IGNORE_RET(sys_close(ufd));
+
+ // The MIME block looks like this:
+ // BOUNDARY \r\n
+ // Content-Disposition: form-data; name="prod" \r\n \r\n
+ // MojoShell \r\n
+ // BOUNDARY \r\n
+ // Content-Disposition: form-data; name="ver" \r\n \r\n
+ // 1.2.3.4 \r\n
+ // BOUNDARY \r\n
+ //
+ // zero or one:
+ // Content-Disposition: form-data; name="ptime" \r\n \r\n
+ // abcdef \r\n
+ // BOUNDARY \r\n
+ //
+ // zero or one:
+ // Content-Disposition: form-data; name="ptype" \r\n \r\n
+ // abcdef \r\n
+ // BOUNDARY \r\n
+ //
+ // zero or one:
+ // Content-Disposition: form-data; name="lsb-release" \r\n \r\n
+ // abcdef \r\n
+ // BOUNDARY \r\n
+ //
+ // zero or one:
+ // Content-Disposition: form-data; name="oom-size" \r\n \r\n
+ // 1234567890 \r\n
+ // BOUNDARY \r\n
+ //
+ // zero or more (up to CrashKeyStorage::num_entries = 64):
+ // Content-Disposition: form-data; name=crash-key-name \r\n
+ // crash-key-value \r\n
+ // BOUNDARY \r\n
+ //
+ // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
+ // Content-Type: application/octet-stream \r\n \r\n
+ // <dump contents>
+ // \r\n BOUNDARY -- \r\n
+
+ MimeWriter writer(temp_file_fd, mime_boundary);
+ {
+ writer.AddBoundary();
+ writer.AddPairString("prod", kProductName);
+ writer.AddBoundary();
+ writer.AddPairString("ver", kVersion);
+ writer.AddBoundary();
+ if (info.pid > 0) {
+ char pid_value_buf[kUint64StringSize];
+ uint64_t pid_value_len = my_uint64_len(info.pid);
+ my_uint64tos(pid_value_buf, info.pid, pid_value_len);
+ static const char pid_key_name[] = "pid";
+ writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, pid_value_buf,
+ pid_value_len);
+ writer.AddBoundary();
+ }
+#if defined(OS_ANDROID)
+ // Addtional MIME blocks are added for logging on Android devices.
+ static const char android_build_id[] = "android_build_id";
+ static const char android_build_fp[] = "android_build_fp";
+ static const char device[] = "device";
+ static const char model[] = "model";
+ static const char brand[] = "brand";
+ static const char exception_info[] = "exception_info";
+
+ base::android::BuildInfo* android_build_info =
+ base::android::BuildInfo::GetInstance();
+ writer.AddPairString(android_build_id,
+ android_build_info->android_build_id());
+ writer.AddBoundary();
+ writer.AddPairString(android_build_fp,
+ android_build_info->android_build_fp());
+ writer.AddBoundary();
+ writer.AddPairString(device, android_build_info->device());
+ writer.AddBoundary();
+ writer.AddPairString(model, android_build_info->model());
+ writer.AddBoundary();
+ writer.AddPairString(brand, android_build_info->brand());
+ writer.AddBoundary();
+ if (android_build_info->java_exception_info() != nullptr) {
+ writer.AddPairString(exception_info,
+ android_build_info->java_exception_info());
+ writer.AddBoundary();
+ }
+#endif
+ writer.Flush();
+ }
+
+ if (info.process_start_time > 0) {
+ struct kernel_timeval tv;
+ if (!sys_gettimeofday(&tv, nullptr)) {
+ uint64_t time = kernel_timeval_to_ms(&tv);
+ if (time > info.process_start_time) {
+ time -= info.process_start_time;
+ char time_str[kUint64StringSize];
+ const unsigned time_len = my_uint64_len(time);
+ my_uint64tos(time_str, time, time_len);
+
+ static const char process_time_msg[] = "ptime";
+ writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
+ time_str, time_len);
+ writer.AddBoundary();
+ writer.Flush();
+ }
+ }
+ }
+
+ if (info.process_type_length) {
+ writer.AddPairString("ptype", info.process_type);
+ writer.AddBoundary();
+ writer.Flush();
+ }
+
+ if (info.distro_length) {
+ static const char distro_msg[] = "lsb-release";
+ writer.AddPairString(distro_msg, info.distro);
+ writer.AddBoundary();
+ writer.Flush();
+ }
+
+ if (info.oom_size) {
+ char oom_size_str[kUint64StringSize];
+ const unsigned oom_size_len = my_uint64_len(info.oom_size);
+ my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
+ static const char oom_size_msg[] = "oom-size";
+ writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, oom_size_str,
+ oom_size_len);
+ writer.AddBoundary();
+ writer.Flush();
+ }
+
+ if (info.crash_keys) {
+ CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
+ const CrashKeyStorage::Entry* entry;
+ while ((entry = crash_key_iterator.Next())) {
+ writer.AddPairString(entry->key, entry->value);
+ writer.AddBoundary();
+ writer.Flush();
+ }
+ }
+
+ writer.AddFileContents(g_dump_msg, dump_data, dump_size);
+ writer.AddEnd();
+ writer.Flush();
+
+ IGNORE_RET(sys_close(temp_file_fd));
+}
+
+bool CrashDone(const MinidumpDescriptor& minidump, const bool succeeded) {
+ // WARNING: this code runs in a compromised context. It may not call into
+ // libc nor allocate memory normally.
+ if (!succeeded) {
+ const char msg[] = "Failed to generate minidump.";
+ WriteLog(msg, sizeof(msg) - 1);
+ return false;
+ }
+
+ DCHECK(!minidump.IsFD());
+
+ BreakpadInfo info = {0};
+ info.filename = minidump.path();
+ info.fd = minidump.fd();
+ info.process_type = "shell";
+ info.process_type_length = 7;
+ info.distro = base::g_linux_distro;
+ info.distro_length = my_strlen(base::g_linux_distro);
+ info.process_start_time = g_process_start_time;
+ info.oom_size = base::g_oom_size;
+ info.pid = g_pid;
+ info.crash_keys = g_crash_keys;
+ HandleCrashDump(info);
+#if defined(OS_ANDROID)
+ return FinalizeCrashDoneAndroid();
+#else
+ return true;
+#endif
+}
+
+// Wrapper function, do not add more code here.
+bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
+ void* context,
+ bool succeeded) {
+ LOG(WARNING) << "CrashDoneNoUpload";
+ return CrashDone(minidump, succeeded);
+}
+
+void EnableCrashDumping(const base::FilePath& dumps_path) {
+ g_is_crash_reporter_enabled = true;
+
+ DCHECK(!g_breakpad);
+ DCHECK(base::CreateDirectoryAndGetError(dumps_path, nullptr));
+ MinidumpDescriptor minidump_descriptor(dumps_path.value());
+ minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
+ g_breakpad = new ExceptionHandler(
+ minidump_descriptor, nullptr, CrashDoneNoUpload, nullptr,
+ true, // Install handlers.
+ -1); // Server file descriptor. -1 for in-process.
+}
+
+void SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ g_crash_keys->SetKeyValue(key.data(), value.data());
+}
+
+void ClearCrashKey(const base::StringPiece& key) {
+ g_crash_keys->RemoveKey(key.data());
+}
+
+void RegisterCrashKeys() {
+ // TODO(qsr): Is there any key to register here?
+}
+
+void InitCrashKeys() {
+ g_crash_keys = new CrashKeyStorage;
+ RegisterCrashKeys();
+ base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey);
+}
+
+// Miscellaneous initialization functions to call after Breakpad has been
+// enabled.
+void PostEnableBreakpadInitialization() {
+ SetProcessStartTime();
+ g_pid = getpid();
+
+ base::debug::SetDumpWithoutCrashingFunction(&DumpProcess);
+}
+
+} // namespace
+
+void InitCrashReporter(const base::FilePath& dumps_path) {
+#if defined(OS_ANDROID)
+ // This will guarantee that the BuildInfo has been initialized and subsequent
+ // calls will not require memory allocation.
+ base::android::BuildInfo::GetInstance();
+#endif
+
+ InitCrashKeys();
+ EnableCrashDumping(dumps_path);
+
+ PostEnableBreakpadInitialization();
+}
+
+bool IsCrashReporterEnabled() {
+ return g_is_crash_reporter_enabled;
+}
+
+} // namespace breakpad
diff --git a/shell/crash/breakpad.h b/shell/crash/breakpad.h
new file mode 100644
index 0000000..e180ca2
--- /dev/null
+++ b/shell/crash/breakpad.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was forked from components/crash/app/breakpad_linux.h in chromium.
+
+// Public interface for enabling Breakpad on Linux systems.
+
+#ifndef SHELL_CRASH_BREAKPAD_H_
+#define SHELL_CRASH_BREAKPAD_H_
+
+#include "base/files/file_path.h"
+
+namespace breakpad {
+
+// Turns on the crash reporter.
+void InitCrashReporter(const base::FilePath& dumps_path);
+
+// Checks if crash reporting is enabled.
+bool IsCrashReporterEnabled();
+
+} // namespace breakpad
+
+#endif // SHELL_CRASH_BREAKPAD_H_
diff --git a/third_party/breakpad/BUILD.gn b/third_party/breakpad/BUILD.gn
new file mode 100644
index 0000000..ad1011e
--- /dev/null
+++ b/third_party/breakpad/BUILD.gn
@@ -0,0 +1,796 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file was forked from breakpad/BUILD.gn in chromium.
+
+import("//testing/test.gni")
+
+config("tools_config") {
+ include_dirs = [
+ "src",
+ "src/third_party",
+ ]
+ if (is_android) {
+ defines = [ "__ANDROID__" ]
+ }
+ if (is_clang) {
+ cflags = [ "-Wno-tautological-constant-out-of-range-compare" ]
+ }
+}
+
+config("internal_config") {
+ include_dirs = [ "src" ]
+ defines = []
+ if (is_debug) {
+ # This is needed for GTMLogger to work correctly.
+ defines += [ "DEBUG" ]
+ }
+ if (is_android) {
+ defines += [ "__ANDROID__" ]
+ }
+}
+
+config("client_config") {
+ include_dirs = [ "src" ]
+ if (is_android) {
+ include_dirs += [ "src/common/android/include" ]
+ }
+}
+
+config("handler_config") {
+ include_dirs = [ "src" ]
+}
+
+config("sender_config") {
+ include_dirs = [ "src" ]
+}
+
+# {micro,mini}dump_stackwalk and minidump_dump are tool-type executables that do
+# not build on iOS.
+if (current_toolchain == host_toolchain && !is_win) {
+ # Contains the code shared by both {micro,mini}dump_stackwalk.
+ static_library("stackwalk_common") {
+ sources = [
+ "src/processor/basic_code_module.h",
+ "src/processor/basic_code_modules.cc",
+ "src/processor/basic_code_modules.h",
+ "src/processor/basic_source_line_resolver.cc",
+ "src/processor/binarystream.cc",
+ "src/processor/binarystream.h",
+ "src/processor/call_stack.cc",
+ "src/processor/cfi_frame_info.cc",
+ "src/processor/cfi_frame_info.h",
+ "src/processor/disassembler_x86.cc",
+ "src/processor/disassembler_x86.h",
+ "src/processor/dump_context.cc",
+ "src/processor/dump_object.cc",
+ "src/processor/logging.cc",
+ "src/processor/logging.h",
+ "src/processor/pathname_stripper.cc",
+ "src/processor/pathname_stripper.h",
+ "src/processor/process_state.cc",
+ "src/processor/simple_symbol_supplier.cc",
+ "src/processor/simple_symbol_supplier.h",
+ "src/processor/source_line_resolver_base.cc",
+ "src/processor/stack_frame_cpu.cc",
+ "src/processor/stack_frame_symbolizer.cc",
+ "src/processor/stackwalk_common.cc",
+ "src/processor/stackwalker.cc",
+ "src/processor/stackwalker_amd64.cc",
+ "src/processor/stackwalker_amd64.h",
+ "src/processor/stackwalker_arm.cc",
+ "src/processor/stackwalker_arm.h",
+ "src/processor/stackwalker_arm64.cc",
+ "src/processor/stackwalker_arm64.h",
+ "src/processor/stackwalker_mips.cc",
+ "src/processor/stackwalker_mips.h",
+ "src/processor/stackwalker_ppc.cc",
+ "src/processor/stackwalker_ppc.h",
+ "src/processor/stackwalker_ppc64.cc",
+ "src/processor/stackwalker_ppc64.h",
+ "src/processor/stackwalker_sparc.cc",
+ "src/processor/stackwalker_sparc.h",
+ "src/processor/stackwalker_x86.cc",
+ "src/processor/stackwalker_x86.h",
+ "src/processor/tokenize.cc",
+ "src/processor/tokenize.h",
+
+ # libdisasm
+ "src/third_party/libdisasm/ia32_implicit.c",
+ "src/third_party/libdisasm/ia32_implicit.h",
+ "src/third_party/libdisasm/ia32_insn.c",
+ "src/third_party/libdisasm/ia32_insn.h",
+ "src/third_party/libdisasm/ia32_invariant.c",
+ "src/third_party/libdisasm/ia32_invariant.h",
+ "src/third_party/libdisasm/ia32_modrm.c",
+ "src/third_party/libdisasm/ia32_modrm.h",
+ "src/third_party/libdisasm/ia32_opcode_tables.c",
+ "src/third_party/libdisasm/ia32_opcode_tables.h",
+ "src/third_party/libdisasm/ia32_operand.c",
+ "src/third_party/libdisasm/ia32_operand.h",
+ "src/third_party/libdisasm/ia32_reg.c",
+ "src/third_party/libdisasm/ia32_reg.h",
+ "src/third_party/libdisasm/ia32_settings.c",
+ "src/third_party/libdisasm/ia32_settings.h",
+ "src/third_party/libdisasm/libdis.h",
+ "src/third_party/libdisasm/qword.h",
+ "src/third_party/libdisasm/x86_disasm.c",
+ "src/third_party/libdisasm/x86_format.c",
+ "src/third_party/libdisasm/x86_imm.c",
+ "src/third_party/libdisasm/x86_imm.h",
+ "src/third_party/libdisasm/x86_insn.c",
+ "src/third_party/libdisasm/x86_misc.c",
+ "src/third_party/libdisasm/x86_operand_list.c",
+ "src/third_party/libdisasm/x86_operand_list.h",
+ ]
+
+ defines = [ "BPLOG_MINIMUM_SEVERITY=SEVERITY_ERROR" ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [ ":tools_config" ]
+ }
+
+ executable("microdump_stackwalk") {
+ sources = [
+ "src/processor/microdump.cc",
+ "src/processor/microdump_processor.cc",
+ "src/processor/microdump_stackwalk.cc",
+ ]
+
+ deps = [
+ ":stackwalk_common",
+ ]
+
+ defines = [ "BPLOG_MINIMUM_SEVERITY=SEVERITY_ERROR" ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [ ":tools_config" ]
+ }
+
+ executable("minidump_stackwalk") {
+ sources = [
+ "src/processor/exploitability.cc",
+ "src/processor/minidump.cc",
+ "src/processor/minidump_processor.cc",
+ "src/processor/minidump_stackwalk.cc",
+ ]
+
+ deps = [
+ ":stackwalk_common",
+ ]
+
+ defines = [ "BPLOG_MINIMUM_SEVERITY=SEVERITY_ERROR" ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [ ":tools_config" ]
+
+ # Always want these files included regardless of platform.
+ set_sources_assignment_filter([])
+ sources += [
+ "src/processor/exploitability_linux.cc",
+ "src/processor/exploitability_linux.h",
+ "src/processor/exploitability_win.cc",
+ "src/processor/exploitability_win.h",
+ "src/processor/symbolic_constants_win.cc",
+ "src/processor/symbolic_constants_win.h",
+ ]
+ }
+
+ executable("minidump_dump") {
+ sources = [
+ "src/processor/basic_code_module.h",
+ "src/processor/basic_code_modules.cc",
+ "src/processor/basic_code_modules.h",
+ "src/processor/dump_context.cc",
+ "src/processor/dump_object.cc",
+ "src/processor/logging.cc",
+ "src/processor/logging.h",
+ "src/processor/minidump.cc",
+ "src/processor/minidump_dump.cc",
+ "src/processor/pathname_stripper.cc",
+ "src/processor/pathname_stripper.h",
+ ]
+
+ configs += [ ":tools_config" ]
+
+ # There are some warnings in this code.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+}
+
+# Mac --------------------------------------------------------------------------
+
+if (current_toolchain == host_toolchain && is_mac) {
+ # TODO(GYP) This should be only 64-bit on Mac. From .gypi:
+ # Like ld, dump_syms needs to operate on enough data that it may
+ # actually need to be able to address more than 4GB. Use x86_64.
+ # Don't worry! An x86_64 dump_syms is perfectly able to dump
+ # 32-bit files.
+ executable("dump_syms") {
+ sources = [
+ "src/common/dwarf/bytereader.cc",
+ "src/common/dwarf/dwarf2diehandler.cc",
+ "src/common/dwarf/dwarf2reader.cc",
+ "src/common/dwarf_cfi_to_module.cc",
+ "src/common/dwarf_cu_to_module.cc",
+ "src/common/dwarf_line_to_module.cc",
+ "src/common/language.cc",
+ "src/common/mac/arch_utilities.cc",
+ "src/common/mac/arch_utilities.h",
+ "src/common/mac/dump_syms.mm",
+ "src/common/mac/file_id.cc",
+ "src/common/mac/macho_id.cc",
+ "src/common/mac/macho_reader.cc",
+ "src/common/mac/macho_utilities.cc",
+ "src/common/mac/macho_walker.cc",
+ "src/common/md5.cc",
+ "src/common/module.cc",
+ "src/common/stabs_reader.cc",
+ "src/common/stabs_to_module.cc",
+ "src/tools/mac/dump_syms/dump_syms_tool.mm",
+ ]
+
+ # For src/common/stabs_reader.h.
+ defines = [ "HAVE_MACH_O_NLIST_H" ]
+ include_dirs = [ "src/common/mac" ]
+
+ # The DWARF utilities require -funsigned-char.
+ cflags = [ "-funsigned-char" ]
+
+ configs += [ ":internal_config" ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ # dwarf2reader.cc uses dynamic_cast.
+ configs -= [ "//build/config/compiler:no_rtti" ]
+ configs += [ "//build/config/compiler:rtti" ]
+
+ libs = [ "Foundation.framework" ]
+
+ if (!is_debug) {
+ # dump_syms crashes when built at -O1, -O2, and -O3. It does
+ # not crash at -Os. To play it safe, dump_syms is always built
+ # at -O0 until this can be sorted out.
+ # http://code.google.com/p/google-breakpad/issues/detail?id=329
+ configs -= [ "//build/config/compiler:optimize" ]
+ cflags += [ "-O0" ]
+ }
+ }
+
+ executable("symupload") {
+ sources = [
+ "src/common/mac/HTTPMultipartUpload.m",
+ "src/tools/mac/symupload/symupload.m",
+ ]
+
+ include_dirs = [ "src/common/mac" ]
+
+ libs = [ "Foundation.framework" ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+}
+
+if (is_mac) {
+ static_library("utilities") {
+ sources = [
+ "src/client/mac/crash_generation/ConfigFile.mm",
+ "src/client/mac/handler/breakpad_nlist_64.cc",
+ "src/client/mac/handler/dynamic_images.cc",
+ "src/client/mac/handler/minidump_generator.cc",
+ "src/client/minidump_file_writer.cc",
+ "src/common/convert_UTF.c",
+ "src/common/mac/MachIPC.mm",
+ "src/common/mac/arch_utilities.cc",
+ "src/common/mac/bootstrap_compat.cc",
+ "src/common/mac/file_id.cc",
+ "src/common/mac/launch_reporter.cc",
+ "src/common/mac/macho_id.cc",
+ "src/common/mac/macho_utilities.cc",
+ "src/common/mac/macho_walker.cc",
+ "src/common/mac/string_utilities.cc",
+ "src/common/md5.cc",
+ "src/common/simple_string_dictionary.cc",
+ "src/common/string_conversion.cc",
+ ]
+
+ configs += [ ":internal_config" ]
+
+ # There are some warnings in this code.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+
+ executable("crash_inspector") {
+ sources = [
+ "src/client/mac/crash_generation/Inspector.mm",
+ "src/client/mac/crash_generation/InspectorMain.mm",
+ ]
+
+ # TODO(GYP): 'mac_real_dsym': 1,
+
+ include_dirs = [
+ "src/client/apple/Framework",
+ "src/common/mac",
+ "src",
+ ]
+ libs = [
+ "CoreServices.framework",
+ "Foundation.framework",
+ ]
+
+ deps = [
+ ":utilities",
+ ]
+ }
+
+ # TODO(GYP) this target has some mac_bundle_resources stuff.
+ # executable("crash_report_sender") {
+ # }
+ group("crash_report_sender") {
+ }
+
+ config("breakpad_config") {
+ include_dirs = [ "src/client/apple/Framework" ]
+ }
+
+ static_library("breakpad") {
+ sources = [
+ "src/client/mac/Framework/Breakpad.mm",
+ "src/client/mac/Framework/OnDemandServer.mm",
+ "src/client/mac/crash_generation/crash_generation_client.cc",
+ "src/client/mac/crash_generation/crash_generation_client.h",
+ "src/client/mac/handler/exception_handler.cc",
+ "src/client/mac/handler/protected_memory_allocator.cc",
+ ]
+
+ configs += [ ":internal_config" ]
+ public_configs = [ ":breakpad_config" ]
+
+ defines = [ "USE_PROTECTED_ALLOCATIONS=1" ]
+ include_dirs = [ "src/client/apple/Framework" ]
+
+ deps = [
+ ":utilities",
+ ":crash_inspector",
+ ":crash_report_sender",
+ ]
+ }
+
+ group("client") {
+ public_configs = [ ":client_config" ]
+ }
+}
+
+if (is_linux) {
+ executable("symupload") {
+ sources = [
+ "src/common/linux/http_upload.cc",
+ "src/common/linux/http_upload.h",
+ "src/tools/linux/symupload/sym_upload.cc",
+ ]
+
+ include_dirs = [
+ "src",
+ "src/third_party",
+ ]
+
+ configs += [ ":tools_config" ]
+
+ libs = [ "dl" ]
+ }
+}
+
+if (is_linux || is_android) {
+ if (current_toolchain == host_toolchain) {
+ # dump_syms is a host tool, so only compile it for the host system.
+ executable("dump_syms") {
+ sources = [
+ "src/common/dwarf/bytereader.cc",
+ "src/common/dwarf/dwarf2diehandler.cc",
+ "src/common/dwarf/dwarf2reader.cc",
+ "src/common/dwarf_cfi_to_module.cc",
+ "src/common/dwarf_cfi_to_module.h",
+ "src/common/dwarf_cu_to_module.cc",
+ "src/common/dwarf_cu_to_module.h",
+ "src/common/dwarf_line_to_module.cc",
+ "src/common/dwarf_line_to_module.h",
+ "src/common/language.cc",
+ "src/common/language.h",
+ "src/common/linux/crc32.cc",
+ "src/common/linux/crc32.h",
+ "src/common/linux/dump_symbols.cc",
+ "src/common/linux/dump_symbols.h",
+ "src/common/linux/elf_symbols_to_module.cc",
+ "src/common/linux/elf_symbols_to_module.h",
+ "src/common/linux/elfutils.cc",
+ "src/common/linux/elfutils.h",
+ "src/common/linux/file_id.cc",
+ "src/common/linux/file_id.h",
+ "src/common/linux/guid_creator.h",
+ "src/common/linux/linux_libc_support.cc",
+ "src/common/linux/linux_libc_support.h",
+ "src/common/linux/memory_mapped_file.cc",
+ "src/common/linux/memory_mapped_file.h",
+ "src/common/module.cc",
+ "src/common/module.h",
+ "src/common/stabs_reader.cc",
+ "src/common/stabs_reader.h",
+ "src/common/stabs_to_module.cc",
+ "src/common/stabs_to_module.h",
+ "src/tools/linux/dump_syms/dump_syms.cc",
+ ]
+
+ # There are some warnings in this code.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ # dwarf2reader.cc uses dynamic_cast. Because we don't typically
+ # don't support RTTI, we enable it for this single target. Since
+ # dump_syms doesn't share any object files with anything else,
+ # this doesn't end up polluting Chrome itself.
+ configs -= [ "//build/config/compiler:no_rtti" ]
+ configs += [ "//build/config/compiler:rtti" ]
+
+ # Breakpad rev 583 introduced this flag.
+ # Using this define, stabs_reader.h will include a.out.h to
+ # build on Linux.
+ defines = [ "HAVE_A_OUT_H" ]
+
+ include_dirs = [ "src" ]
+ }
+ }
+
+ static_library("client") {
+ # Want all these sources for both Linux and Android.
+ set_sources_assignment_filter([])
+ sources = [
+ "src/client/linux/crash_generation/crash_generation_client.cc",
+ "src/client/linux/crash_generation/crash_generation_client.h",
+ "src/client/linux/dump_writer_common/mapping_info.h",
+ "src/client/linux/dump_writer_common/seccomp_unwinder.cc",
+ "src/client/linux/dump_writer_common/seccomp_unwinder.h",
+ "src/client/linux/dump_writer_common/thread_info.cc",
+ "src/client/linux/dump_writer_common/thread_info.h",
+ "src/client/linux/dump_writer_common/ucontext_reader.cc",
+ "src/client/linux/dump_writer_common/ucontext_reader.h",
+ "src/client/linux/handler/exception_handler.cc",
+ "src/client/linux/handler/exception_handler.h",
+ "src/client/linux/handler/minidump_descriptor.cc",
+ "src/client/linux/handler/minidump_descriptor.h",
+ "src/client/linux/log/log.cc",
+ "src/client/linux/log/log.h",
+ "src/client/linux/microdump_writer/microdump_writer.cc",
+ "src/client/linux/microdump_writer/microdump_writer.h",
+ "src/client/linux/minidump_writer/cpu_set.h",
+ "src/client/linux/minidump_writer/directory_reader.h",
+ "src/client/linux/minidump_writer/line_reader.h",
+ "src/client/linux/minidump_writer/linux_core_dumper.cc",
+ "src/client/linux/minidump_writer/linux_core_dumper.h",
+ "src/client/linux/minidump_writer/linux_dumper.cc",
+ "src/client/linux/minidump_writer/linux_dumper.h",
+ "src/client/linux/minidump_writer/linux_ptrace_dumper.cc",
+ "src/client/linux/minidump_writer/linux_ptrace_dumper.h",
+ "src/client/linux/minidump_writer/minidump_writer.cc",
+ "src/client/linux/minidump_writer/minidump_writer.h",
+ "src/client/linux/minidump_writer/proc_cpuinfo_reader.h",
+ "src/client/minidump_file_writer-inl.h",
+ "src/client/minidump_file_writer.cc",
+ "src/client/minidump_file_writer.h",
+ "src/common/convert_UTF.c",
+ "src/common/convert_UTF.h",
+ "src/common/linux/elf_core_dump.cc",
+ "src/common/linux/elf_core_dump.h",
+ "src/common/linux/elfutils.cc",
+ "src/common/linux/elfutils.h",
+ "src/common/linux/file_id.cc",
+ "src/common/linux/file_id.h",
+ "src/common/linux/google_crashdump_uploader.cc",
+ "src/common/linux/google_crashdump_uploader.h",
+ "src/common/linux/guid_creator.cc",
+ "src/common/linux/guid_creator.h",
+ "src/common/linux/libcurl_wrapper.cc",
+ "src/common/linux/libcurl_wrapper.h",
+ "src/common/linux/linux_libc_support.cc",
+ "src/common/linux/linux_libc_support.h",
+ "src/common/linux/memory_mapped_file.cc",
+ "src/common/linux/memory_mapped_file.h",
+ "src/common/linux/safe_readlink.cc",
+ "src/common/linux/safe_readlink.h",
+ "src/common/memory.h",
+ "src/common/simple_string_dictionary.cc",
+ "src/common/simple_string_dictionary.h",
+ "src/common/string_conversion.cc",
+ "src/common/string_conversion.h",
+ ]
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ public_configs = [ ":client_config" ]
+
+ if (current_cpu == "arm" && is_chromeos) {
+ # Avoid running out of registers in
+ # linux_syscall_support.h:sys_clone()'s inline assembly.
+ cflags = [ "-marm" ]
+ }
+
+ if (is_android) {
+ sources += [ "src/common/android/breakpad_getcontext.S" ]
+ }
+
+ libs = [ "dl" ]
+
+ include_dirs = [
+ ".",
+ "src",
+ "src/client",
+ "src/third_party/linux/include",
+ ]
+ }
+
+ static_library("processor_support") {
+ sources = [
+ "src/common/scoped_ptr.h",
+ "src/processor/basic_code_modules.cc",
+ "src/processor/basic_code_modules.h",
+ "src/processor/dump_context.cc",
+ "src/processor/dump_object.cc",
+ "src/processor/logging.cc",
+ "src/processor/logging.h",
+ "src/processor/minidump.cc",
+ "src/processor/pathname_stripper.cc",
+ "src/processor/pathname_stripper.h",
+ ]
+
+ include_dirs = [
+ "src",
+ "src/client",
+ "src/third_party/linux/include",
+ ".",
+ ]
+
+ # There are some warnings in this code.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+ }
+}
+
+if (is_linux) {
+ test("breakpad_unittests") {
+ sources = [
+ "linux/breakpad_googletest_includes.h",
+ "src/client/linux/handler/exception_handler_unittest.cc",
+ "src/client/linux/minidump_writer/cpu_set_unittest.cc",
+ "src/client/linux/minidump_writer/directory_reader_unittest.cc",
+ "src/client/linux/minidump_writer/line_reader_unittest.cc",
+ "src/client/linux/minidump_writer/linux_core_dumper_unittest.cc",
+ "src/client/linux/minidump_writer/linux_ptrace_dumper_unittest.cc",
+ "src/client/linux/minidump_writer/minidump_writer_unittest.cc",
+ "src/client/linux/minidump_writer/minidump_writer_unittest_utils.cc",
+ "src/client/linux/minidump_writer/proc_cpuinfo_reader_unittest.cc",
+ "src/common/linux/elf_core_dump_unittest.cc",
+ "src/common/linux/file_id_unittest.cc",
+ "src/common/linux/linux_libc_support_unittest.cc",
+ "src/common/linux/synth_elf.cc",
+ "src/common/linux/tests/auto_testfile.h",
+ "src/common/linux/tests/crash_generator.cc",
+ "src/common/linux/tests/crash_generator.h",
+ "src/common/memory_range.h",
+ "src/common/memory_unittest.cc",
+ "src/common/simple_string_dictionary_unittest.cc",
+ "src/common/test_assembler.cc",
+ "src/common/tests/file_utils.cc",
+ "src/common/tests/file_utils.h",
+ "src/tools/linux/md2core/minidump_memory_range.h",
+ "src/tools/linux/md2core/minidump_memory_range_unittest.cc",
+ ]
+
+ deps = [
+ ":client",
+ ":processor_support",
+ ":linux_dumper_unittest_helper",
+ "//testing/gtest",
+ "//testing/gtest:gtest_main",
+ "//testing/gmock",
+ ]
+
+ include_dirs = [
+ "linux", # Use our copy of breakpad_googletest_includes.h
+ "src",
+ ".",
+ ]
+
+ # There are some warnings in this code.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ if (is_clang) {
+ # See http://crbug.com/138571#c18
+ cflags = [ "-Wno-unused-value" ]
+ }
+
+ if (is_android) {
+ sources += [ "src/common/android/breakpad_getcontext_unittest.cc" ]
+ libs = [ "log" ]
+ include_dirs += [ "src/common/android/include" ]
+ isolate_file = "breakpad_unittests.isolate"
+ }
+ }
+
+ executable("linux_dumper_unittest_helper") {
+ testonly = true
+ sources = [
+ "src/client/linux/minidump_writer/linux_dumper_unittest_helper.cc",
+ ]
+ deps = [
+ ":processor_support",
+ ]
+
+ include_dirs = [ "src" ]
+
+ if (current_cpu == "mipsel" && is_android) {
+ include_dirs += [ "src/common/android/include" ]
+ }
+ }
+
+ executable("generate_test_dump") {
+ testonly = true
+ sources = [
+ "linux/generate-test-dump.cc",
+ ]
+
+ # This file has an unused variable warning.
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+
+ deps = [
+ ":client",
+ ]
+
+ include_dirs = [ "src" ]
+
+ if (is_android) {
+ libs = [ "log" ]
+ include_dirs += [ "src/common/android/include" ]
+ }
+ }
+
+ executable("minidump-2-core") {
+ sources = [
+ "src/tools/linux/md2core/minidump-2-core.cc",
+ ]
+
+ include_dirs = [ "src" ]
+
+ deps = [
+ ":client",
+ ]
+ }
+
+ executable("core-2-minidump") {
+ sources = [
+ "src/tools/linux/core2md/core2md.cc",
+ ]
+
+ deps = [
+ ":client",
+ ]
+
+ include_dirs = [ "src" ]
+ }
+}
+
+if (is_ios) {
+ static_library("client") {
+ sources = [
+ "src/client/ios/Breakpad.h",
+ "src/client/ios/Breakpad.mm",
+ "src/client/ios/BreakpadController.h",
+ "src/client/ios/BreakpadController.mm",
+ "src/client/ios/handler/ios_exception_minidump_generator.h",
+ "src/client/ios/handler/ios_exception_minidump_generator.mm",
+ "src/client/mac/crash_generation/ConfigFile.h",
+ "src/client/mac/crash_generation/ConfigFile.mm",
+ "src/client/mac/handler/breakpad_nlist_64.cc",
+ "src/client/mac/handler/breakpad_nlist_64.h",
+ "src/client/mac/handler/dynamic_images.cc",
+ "src/client/mac/handler/dynamic_images.h",
+ "src/client/mac/handler/exception_handler.cc",
+ "src/client/mac/handler/exception_handler.h",
+ "src/client/mac/handler/minidump_generator.cc",
+ "src/client/mac/handler/minidump_generator.h",
+ "src/client/mac/handler/protected_memory_allocator.cc",
+ "src/client/mac/handler/protected_memory_allocator.h",
+ "src/client/mac/sender/uploader.h",
+ "src/client/mac/sender/uploader.mm",
+ "src/client/minidump_file_writer-inl.h",
+ "src/client/minidump_file_writer.cc",
+ "src/client/minidump_file_writer.h",
+ "src/common/convert_UTF.c",
+ "src/common/convert_UTF.h",
+ "src/common/mac/HTTPMultipartUpload.m",
+ "src/common/mac/file_id.cc",
+ "src/common/mac/file_id.h",
+ "src/common/mac/macho_id.cc",
+ "src/common/mac/macho_id.h",
+ "src/common/mac/macho_utilities.cc",
+ "src/common/mac/macho_utilities.h",
+ "src/common/mac/macho_walker.cc",
+ "src/common/mac/macho_walker.h",
+ "src/common/mac/string_utilities.cc",
+ "src/common/mac/string_utilities.h",
+ "src/common/md5.cc",
+ "src/common/md5.h",
+ "src/common/simple_string_dictionary.cc",
+ "src/common/simple_string_dictionary.h",
+ "src/common/string_conversion.cc",
+ "src/common/string_conversion.h",
+ "src/google_breakpad/common/minidump_format.h",
+ ]
+
+ include_dirs = [
+ "src",
+ "src/client/mac/Framework",
+ "src/common/mac",
+ ]
+ }
+ # TODO(GYP) There is some XCode-only targets like ninja-breakpad.
+}
+
+if (is_win) {
+ group("client") {
+ public_configs = [ ":client_config" ]
+ }
+
+ source_set("breakpad_handler") {
+ configs += [ ":handler_config" ]
+ if (is_win) {
+ public_configs = [ ":handler_config" ]
+ }
+
+ defines = [ "BREAKPAD_NO_TERMINATE_THREAD" ]
+
+ sources = [
+ "src/client/windows/crash_generation/client_info.cc",
+ "src/client/windows/crash_generation/client_info.h",
+ "src/client/windows/crash_generation/crash_generation_client.cc",
+ "src/client/windows/crash_generation/crash_generation_client.h",
+ "src/client/windows/crash_generation/crash_generation_server.cc",
+ "src/client/windows/crash_generation/crash_generation_server.h",
+ "src/client/windows/crash_generation/minidump_generator.cc",
+ "src/client/windows/crash_generation/minidump_generator.h",
+ "src/client/windows/handler/exception_handler.cc",
+ "src/client/windows/handler/exception_handler.h",
+ "src/common/windows/guid_string.cc",
+ "src/common/windows/guid_string.h",
+ "src/common/windows/string_utils-inl.h",
+ "src/google_breakpad/common/minidump_format.h",
+ ]
+ config("breakpad_handler_warnings") {
+ if (is_clang) {
+ # See https://code.google.com/p/google-breakpad/issues/detail?id=658.
+ cflags = [ "-Wno-reorder" ]
+ }
+ }
+
+ configs += [ ":breakpad_handler_warnings" ]
+ }
+
+ source_set("breakpad_sender") {
+ sources = [
+ "src/client/windows/sender/crash_report_sender.cc",
+ "src/client/windows/sender/crash_report_sender.h",
+ "src/common/windows/http_upload.cc",
+ "src/common/windows/http_upload.h",
+ ]
+ configs += [ ":sender_config" ]
+ public_configs = [ ":sender_config" ]
+ }
+}