diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/tools')
64 files changed, 14198 insertions, 0 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc new file mode 100644 index 0000000000..c3a9da3988 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/core2md/core2md.cc @@ -0,0 +1,72 @@ +// 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. + +// core2md.cc: A utility to convert an ELF core file to a minidump file. + +#include <stdio.h> + +#include "client/linux/minidump_writer/minidump_writer.h" +#include "client/linux/minidump_writer/linux_core_dumper.h" + +using google_breakpad::AppMemoryList; +using google_breakpad::MappingList; +using google_breakpad::LinuxCoreDumper; + +static int ShowUsage(const char* argv0) { + fprintf(stderr, "Usage: %s <core file> <procfs dir> <output>\n", argv0); + return 1; +} + +bool WriteMinidumpFromCore(const char* filename, + const char* core_path, + const char* procfs_override) { + MappingList mappings; + AppMemoryList memory_list; + LinuxCoreDumper dumper(0, core_path, procfs_override); + return google_breakpad::WriteMinidump(filename, mappings, memory_list, + &dumper); +} + +int main(int argc, char *argv[]) { + if (argc != 4) { + return ShowUsage(argv[0]); + } + + const char* core_file = argv[1]; + const char* procfs_dir = argv[2]; + const char* minidump_file = argv[3]; + if (!WriteMinidumpFromCore(minidump_file, + core_file, + procfs_dir)) { + perror("core2md: Unable to generate minidump"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..ebdf23146c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc @@ -0,0 +1,137 @@ +// 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 <paths.h> +#include <stdio.h> +#include <unistd.h> + +#include <cstring> +#include <iostream> +#include <string> +#include <vector> + +#include "common/linux/dump_symbols.h" + +using google_breakpad::WriteSymbolFile; +using google_breakpad::WriteSymbolFileHeader; + +int usage(const char* self) { + fprintf(stderr, "Usage: %s [OPTION] <binary-with-debugging-info> " + "[directories-for-debug-file]\n\n", self); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -i: Output module header information only.\n"); + fprintf(stderr, " -c Do not generate CFI section\n"); + fprintf(stderr, " -r Do not handle inter-compilation " + "unit references\n"); + fprintf(stderr, " -v Print all warnings to stderr\n"); + fprintf(stderr, " -n <name> Use specified name for name of the object\n"); + fprintf(stderr, " -o <os> Use specified name for the " + "operating system\n"); + return 1; +} + +int main(int argc, char **argv) { + if (argc < 2) + return usage(argv[0]); + bool header_only = false; + bool cfi = true; + bool handle_inter_cu_refs = true; + bool log_to_stderr = false; + std::string obj_name; + const char* obj_os = "Linux"; + int arg_index = 1; + while (arg_index < argc && strlen(argv[arg_index]) > 0 && + argv[arg_index][0] == '-') { + if (strcmp("-i", argv[arg_index]) == 0) { + header_only = true; + } else if (strcmp("-c", argv[arg_index]) == 0) { + cfi = false; + } else if (strcmp("-r", argv[arg_index]) == 0) { + handle_inter_cu_refs = false; + } else if (strcmp("-v", argv[arg_index]) == 0) { + log_to_stderr = true; + } else if (strcmp("-n", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -n\n"); + return usage(argv[0]); + } + obj_name = argv[arg_index + 1]; + ++arg_index; + } else if (strcmp("-o", argv[arg_index]) == 0) { + if (arg_index + 1 >= argc) { + fprintf(stderr, "Missing argument to -o\n"); + return usage(argv[0]); + } + obj_os = argv[arg_index + 1]; + ++arg_index; + } else { + printf("2.4 %s\n", argv[arg_index]); + return usage(argv[0]); + } + ++arg_index; + } + if (arg_index == argc) + return usage(argv[0]); + // Save stderr so it can be used below. + FILE* saved_stderr = fdopen(dup(fileno(stderr)), "w"); + if (!log_to_stderr) { + if (freopen(_PATH_DEVNULL, "w", stderr)) { + // If it fails, not a lot we can (or should) do. + // Add this brace section to silence gcc warnings. + } + } + const char* binary; + std::vector<string> debug_dirs; + binary = argv[arg_index]; + for (int debug_dir_index = arg_index + 1; + debug_dir_index < argc; + ++debug_dir_index) { + debug_dirs.push_back(argv[debug_dir_index]); + } + + if (obj_name.empty()) + obj_name = binary; + + if (header_only) { + if (!WriteSymbolFileHeader(binary, obj_name, obj_os, std::cout)) { + fprintf(saved_stderr, "Failed to process file.\n"); + return 1; + } + } else { + SymbolData symbol_data = cfi ? ALL_SYMBOL_DATA : NO_CFI; + google_breakpad::DumpOptions options(symbol_data, handle_inter_cu_refs); + if (!WriteSymbolFile(binary, obj_name, obj_os, debug_dirs, options, + std::cout)) { + fprintf(saved_stderr, "Failed to write symbol file.\n"); + return 1; + } + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc new file mode 100644 index 0000000000..a60be32354 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc @@ -0,0 +1,1428 @@ +// 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. + +// Converts a minidump file to a core file which gdb can read. +// Large parts lifted from the userspace core dumper: +// http://code.google.com/p/google-coredumper/ + +#include <elf.h> +#include <errno.h> +#include <limits.h> +#include <link.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/user.h> +#include <unistd.h> + +#include <map> +#include <string> +#include <vector> + +#include "common/linux/memory_mapped_file.h" +#include "common/minidump_type_helper.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/common/minidump_format.h" +#include "third_party/lss/linux_syscall_support.h" +#include "tools/linux/md2core/minidump_memory_range.h" + +#if ULONG_MAX == 0xffffffffffffffff + #define ELF_CLASS ELFCLASS64 +#else + #define ELF_CLASS ELFCLASS32 +#endif +#define Ehdr ElfW(Ehdr) +#define Phdr ElfW(Phdr) +#define Shdr ElfW(Shdr) +#define Nhdr ElfW(Nhdr) +#define auxv_t ElfW(auxv_t) + + +#if defined(__x86_64__) + #define ELF_ARCH EM_X86_64 +#elif defined(__i386__) + #define ELF_ARCH EM_386 +#elif defined(__arm__) + #define ELF_ARCH EM_ARM +#elif defined(__mips__) + #define ELF_ARCH EM_MIPS +#elif defined(__aarch64__) + #define ELF_ARCH EM_AARCH64 +#endif + +#if defined(__arm__) +// GLibc/ARM and Android/ARM both use 'user_regs' for the structure type +// containing core registers, while they use 'user_regs_struct' on other +// architectures. This file-local typedef simplifies the source code. +typedef user_regs user_regs_struct; +#elif defined (__mips__) +// This file-local typedef simplifies the source code. +typedef gregset_t user_regs_struct; +#endif + +using google_breakpad::MDTypeHelper; +using google_breakpad::MemoryMappedFile; +using google_breakpad::MinidumpMemoryRange; + +typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawDebug MDRawDebug; +typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap; + +static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1); + +struct Options { + string minidump_path; + bool verbose; + int out_fd; + bool use_filename; + bool inc_guid; + string so_basedir; +}; + +static void +Usage(int argc, const char* argv[]) { + fprintf(stderr, + "Usage: %s [options] <minidump file>\n" + "\n" + "Convert a minidump file into a core file (often for use by gdb).\n" + "\n" + "The shared library list will by default have filenames as the runtime expects.\n" + "There are many flags to control the output names though to make it easier to\n" + "integrate with your debug environment (e.g. gdb).\n" + " Default: /lib64/libpthread.so.0\n" + " -f: /lib64/libpthread-2.19.so\n" + " -i: /lib64/<module id>-libpthread.so.0\n" + " -f -i: /lib64/<module id>-libpthread-2.19.so\n" + " -S /foo/: /foo/libpthread.so.0\n" + "\n" + "Options:\n" + " -v Enable verbose output\n" + " -o <file> Write coredump to specified file (otherwise use stdout).\n" + " -f Use the filename rather than the soname in the sharedlib list.\n" + " The soname is what the runtime system uses, but the filename is\n" + " how it's stored on disk.\n" + " -i Prefix sharedlib names with ID (when available). This makes it\n" + " easier to have a single directory full of symbols.\n" + " -S <dir> Set soname base directory. This will force all debug/symbol\n" + " lookups to be done in this directory rather than the filesystem\n" + " layout as it exists in the crashing image. This path should end\n" + " with a slash if it's a directory. e.g. /var/lib/breakpad/\n" + "", google_breakpad::BaseName(argv[0]).c_str()); +} + +static void +SetupOptions(int argc, const char* argv[], Options* options) { + extern int optind; + int ch; + const char* output_file = NULL; + + // Initialize the options struct as needed. + options->verbose = false; + options->use_filename = false; + options->inc_guid = false; + + while ((ch = getopt(argc, (char * const *)argv, "fhio:S:v")) != -1) { + switch (ch) { + case 'h': + Usage(argc, argv); + exit(0); + break; + case '?': + Usage(argc, argv); + exit(1); + break; + + case 'f': + options->use_filename = true; + break; + case 'i': + options->inc_guid = true; + break; + case 'o': + output_file = optarg; + break; + case 'S': + options->so_basedir = optarg; + break; + case 'v': + options->verbose = true; + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + if (output_file == NULL || !strcmp(output_file, "-")) { + options->out_fd = STDOUT_FILENO; + } else { + options->out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (options->out_fd == -1) { + fprintf(stderr, "%s: could not open output %s: %s\n", argv[0], + output_file, strerror(errno)); + exit(1); + } + } + + options->minidump_path = argv[optind]; +} + +// Write all of the given buffer, handling short writes and EINTR. Return true +// iff successful. +static bool +writea(int fd, const void* idata, size_t length) { + const uint8_t* data = (const uint8_t*) idata; + + size_t done = 0; + while (done < length) { + ssize_t r; + do { + r = write(fd, data + done, length - done); + } while (r == -1 && errno == EINTR); + + if (r < 1) + return false; + done += r; + } + + return true; +} + +/* Dynamically determines the byte sex of the system. Returns non-zero + * for big-endian machines. + */ +static inline int sex() { + int probe = 1; + return !*(char *)&probe; +} + +typedef struct elf_timeval { /* Time value with microsecond resolution */ + long tv_sec; /* Seconds */ + long tv_usec; /* Microseconds */ +} elf_timeval; + +typedef struct _elf_siginfo { /* Information about signal (unused) */ + int32_t si_signo; /* Signal number */ + int32_t si_code; /* Extra code */ + int32_t si_errno; /* Errno */ +} _elf_siginfo; + +typedef struct prstatus { /* Information about thread; includes CPU reg*/ + _elf_siginfo pr_info; /* Info associated with signal */ + uint16_t pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + pid_t pr_pid; /* Process ID */ + pid_t pr_ppid; /* Parent's process ID */ + pid_t pr_pgrp; /* Group ID */ + pid_t pr_sid; /* Session ID */ + elf_timeval pr_utime; /* User time */ + elf_timeval pr_stime; /* System time */ + elf_timeval pr_cutime; /* Cumulative user time */ + elf_timeval pr_cstime; /* Cumulative system time */ + user_regs_struct pr_reg; /* CPU registers */ + uint32_t pr_fpvalid; /* True if math co-processor being used */ +} prstatus; + +typedef struct prpsinfo { /* Information about process */ + unsigned char pr_state; /* Numeric process state */ + char pr_sname; /* Char for pr_state */ + unsigned char pr_zomb; /* Zombie */ + signed char pr_nice; /* Nice val */ + unsigned long pr_flag; /* Flags */ +#if defined(__x86_64__) || defined(__mips__) + uint32_t pr_uid; /* User ID */ + uint32_t pr_gid; /* Group ID */ +#else + uint16_t pr_uid; /* User ID */ + uint16_t pr_gid; /* Group ID */ +#endif + pid_t pr_pid; /* Process ID */ + pid_t pr_ppid; /* Parent's process ID */ + pid_t pr_pgrp; /* Group ID */ + pid_t pr_sid; /* Session ID */ + char pr_fname[16]; /* Filename of executable */ + char pr_psargs[80]; /* Initial part of arg list */ +} prpsinfo; + +// We parse the minidump file and keep the parsed information in this structure +struct CrashedProcess { + CrashedProcess() + : crashing_tid(-1), + auxv(NULL), + auxv_length(0) { + memset(&prps, 0, sizeof(prps)); + prps.pr_sname = 'R'; + memset(&debug, 0, sizeof(debug)); + } + + struct Mapping { + Mapping() + : permissions(0xFFFFFFFF), + start_address(0), + end_address(0), + offset(0) { + } + + uint32_t permissions; + uint64_t start_address, end_address, offset; + // The name we write out to the core. + string filename; + string data; + }; + std::map<uint64_t, Mapping> mappings; + + pid_t crashing_tid; + int fatal_signal; + + struct Thread { + pid_t tid; +#if defined(__mips__) + mcontext_t mcontext; +#else + user_regs_struct regs; +#endif +#if defined(__i386__) || defined(__x86_64__) + user_fpregs_struct fpregs; +#endif +#if defined(__i386__) + user_fpxregs_struct fpxregs; +#endif +#if defined(__aarch64__) + user_fpsimd_struct fpregs; +#endif + uintptr_t stack_addr; + const uint8_t* stack; + size_t stack_length; + }; + std::vector<Thread> threads; + + const uint8_t* auxv; + size_t auxv_length; + + prpsinfo prps; + + // The GUID/filename from MD_MODULE_LIST_STREAM entries. + // We gather them for merging later on into the list of maps. + struct Signature { + char guid[40]; + string filename; + }; + std::map<uintptr_t, Signature> signatures; + + string dynamic_data; + MDRawDebug debug; + std::vector<MDRawLinkMap> link_map; +}; + +#if defined(__i386__) +static uint32_t +U32(const uint8_t* data) { + uint32_t v; + memcpy(&v, data, sizeof(v)); + return v; +} + +static uint16_t +U16(const uint8_t* data) { + uint16_t v; + memcpy(&v, data, sizeof(v)); + return v; +} + +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextX86* rawregs = range.GetData<MDRawContextX86>(0); + + thread->regs.ebx = rawregs->ebx; + thread->regs.ecx = rawregs->ecx; + thread->regs.edx = rawregs->edx; + thread->regs.esi = rawregs->esi; + thread->regs.edi = rawregs->edi; + thread->regs.ebp = rawregs->ebp; + thread->regs.eax = rawregs->eax; + thread->regs.xds = rawregs->ds; + thread->regs.xes = rawregs->es; + thread->regs.xfs = rawregs->fs; + thread->regs.xgs = rawregs->gs; + thread->regs.orig_eax = rawregs->eax; + thread->regs.eip = rawregs->eip; + thread->regs.xcs = rawregs->cs; + thread->regs.eflags = rawregs->eflags; + thread->regs.esp = rawregs->esp; + thread->regs.xss = rawregs->ss; + + thread->fpregs.cwd = rawregs->float_save.control_word; + thread->fpregs.swd = rawregs->float_save.status_word; + thread->fpregs.twd = rawregs->float_save.tag_word; + thread->fpregs.fip = rawregs->float_save.error_offset; + thread->fpregs.fcs = rawregs->float_save.error_selector; + thread->fpregs.foo = rawregs->float_save.data_offset; + thread->fpregs.fos = rawregs->float_save.data_selector; + memcpy(thread->fpregs.st_space, rawregs->float_save.register_area, + 10 * 8); + + thread->fpxregs.cwd = rawregs->float_save.control_word; + thread->fpxregs.swd = rawregs->float_save.status_word; + thread->fpxregs.twd = rawregs->float_save.tag_word; + thread->fpxregs.fop = U16(rawregs->extended_registers + 6); + thread->fpxregs.fip = U16(rawregs->extended_registers + 8); + thread->fpxregs.fcs = U16(rawregs->extended_registers + 12); + thread->fpxregs.foo = U16(rawregs->extended_registers + 16); + thread->fpxregs.fos = U16(rawregs->extended_registers + 20); + thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24); + memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128); + memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128); +} +#elif defined(__x86_64__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextAMD64* rawregs = range.GetData<MDRawContextAMD64>(0); + + thread->regs.r15 = rawregs->r15; + thread->regs.r14 = rawregs->r14; + thread->regs.r13 = rawregs->r13; + thread->regs.r12 = rawregs->r12; + thread->regs.rbp = rawregs->rbp; + thread->regs.rbx = rawregs->rbx; + thread->regs.r11 = rawregs->r11; + thread->regs.r10 = rawregs->r10; + thread->regs.r9 = rawregs->r9; + thread->regs.r8 = rawregs->r8; + thread->regs.rax = rawregs->rax; + thread->regs.rcx = rawregs->rcx; + thread->regs.rdx = rawregs->rdx; + thread->regs.rsi = rawregs->rsi; + thread->regs.rdi = rawregs->rdi; + thread->regs.orig_rax = rawregs->rax; + thread->regs.rip = rawregs->rip; + thread->regs.cs = rawregs->cs; + thread->regs.eflags = rawregs->eflags; + thread->regs.rsp = rawregs->rsp; + thread->regs.ss = rawregs->ss; + thread->regs.fs_base = 0; + thread->regs.gs_base = 0; + thread->regs.ds = rawregs->ds; + thread->regs.es = rawregs->es; + thread->regs.fs = rawregs->fs; + thread->regs.gs = rawregs->gs; + + thread->fpregs.cwd = rawregs->flt_save.control_word; + thread->fpregs.swd = rawregs->flt_save.status_word; + thread->fpregs.ftw = rawregs->flt_save.tag_word; + thread->fpregs.fop = rawregs->flt_save.error_opcode; + thread->fpregs.rip = rawregs->flt_save.error_offset; + thread->fpregs.rdp = rawregs->flt_save.data_offset; + thread->fpregs.mxcsr = rawregs->flt_save.mx_csr; + thread->fpregs.mxcr_mask = rawregs->flt_save.mx_csr_mask; + memcpy(thread->fpregs.st_space, rawregs->flt_save.float_registers, 8 * 16); + memcpy(thread->fpregs.xmm_space, rawregs->flt_save.xmm_registers, 16 * 16); +} +#elif defined(__arm__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextARM* rawregs = range.GetData<MDRawContextARM>(0); + + thread->regs.uregs[0] = rawregs->iregs[0]; + thread->regs.uregs[1] = rawregs->iregs[1]; + thread->regs.uregs[2] = rawregs->iregs[2]; + thread->regs.uregs[3] = rawregs->iregs[3]; + thread->regs.uregs[4] = rawregs->iregs[4]; + thread->regs.uregs[5] = rawregs->iregs[5]; + thread->regs.uregs[6] = rawregs->iregs[6]; + thread->regs.uregs[7] = rawregs->iregs[7]; + thread->regs.uregs[8] = rawregs->iregs[8]; + thread->regs.uregs[9] = rawregs->iregs[9]; + thread->regs.uregs[10] = rawregs->iregs[10]; + thread->regs.uregs[11] = rawregs->iregs[11]; + thread->regs.uregs[12] = rawregs->iregs[12]; + thread->regs.uregs[13] = rawregs->iregs[13]; + thread->regs.uregs[14] = rawregs->iregs[14]; + thread->regs.uregs[15] = rawregs->iregs[15]; + + thread->regs.uregs[16] = rawregs->cpsr; + thread->regs.uregs[17] = 0; // what is ORIG_r0 exactly? +} +#elif defined(__aarch64__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { +#define COPY_REGS(rawregs) \ + do { \ + for (int i = 0; i < 31; ++i) \ + thread->regs.regs[i] = rawregs->iregs[i]; \ + thread->regs.sp = rawregs->iregs[MD_CONTEXT_ARM64_REG_SP]; \ + thread->regs.pc = rawregs->iregs[MD_CONTEXT_ARM64_REG_PC]; \ + thread->regs.pstate = rawregs->cpsr; \ + \ + memcpy(thread->fpregs.vregs, rawregs->float_save.regs, 8 * 32); \ + thread->fpregs.fpsr = rawregs->float_save.fpsr; \ + thread->fpregs.fpcr = rawregs->float_save.fpcr; \ + } while (false) + + if (range.length() == sizeof(MDRawContextARM64_Old)) { + const MDRawContextARM64_Old* rawregs = + range.GetData<MDRawContextARM64_Old>(0); + COPY_REGS(rawregs); + } else { + const MDRawContextARM64* rawregs = range.GetData<MDRawContextARM64>(0); + COPY_REGS(rawregs); + } +#undef COPY_REGS +} +#elif defined(__mips__) +static void +ParseThreadRegisters(CrashedProcess::Thread* thread, + const MinidumpMemoryRange& range) { + const MDRawContextMIPS* rawregs = range.GetData<MDRawContextMIPS>(0); + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + thread->mcontext.gregs[i] = rawregs->iregs[i]; + + thread->mcontext.pc = rawregs->epc; + + thread->mcontext.mdlo = rawregs->mdlo; + thread->mcontext.mdhi = rawregs->mdhi; + + thread->mcontext.hi1 = rawregs->hi[0]; + thread->mcontext.lo1 = rawregs->lo[0]; + thread->mcontext.hi2 = rawregs->hi[1]; + thread->mcontext.lo2 = rawregs->lo[1]; + thread->mcontext.hi3 = rawregs->hi[2]; + thread->mcontext.lo3 = rawregs->lo[2]; + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) { + thread->mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs = + rawregs->float_save.regs[i]; + } + + thread->mcontext.fpc_csr = rawregs->float_save.fpcsr; +#if _MIPS_SIM == _ABIO32 + thread->mcontext.fpc_eir = rawregs->float_save.fir; +#endif +} +#else +#error "This code has not been ported to your platform yet" +#endif + +static void +ParseThreadList(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const uint32_t num_threads = *range.GetData<uint32_t>(0); + if (options.verbose) { + fprintf(stderr, + "MD_THREAD_LIST_STREAM:\n" + "Found %d threads\n" + "\n\n", + num_threads); + } + for (unsigned i = 0; i < num_threads; ++i) { + CrashedProcess::Thread thread; + memset(&thread, 0, sizeof(thread)); + const MDRawThread* rawthread = + range.GetArrayElement<MDRawThread>(sizeof(uint32_t), i); + thread.tid = rawthread->thread_id; + thread.stack_addr = rawthread->stack.start_of_memory_range; + MinidumpMemoryRange stack_range = + full_file.Subrange(rawthread->stack.memory); + thread.stack = stack_range.data(); + thread.stack_length = rawthread->stack.memory.data_size; + + ParseThreadRegisters(&thread, + full_file.Subrange(rawthread->thread_context)); + + crashinfo->threads.push_back(thread); + } +} + +static void +ParseSystemInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const MDRawSystemInfo* sysinfo = range.GetData<MDRawSystemInfo>(0); + if (!sysinfo) { + fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n"); + exit(1); + } +#if defined(__i386__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) { + fprintf(stderr, + "This version of minidump-2-core only supports x86 (32bit)%s.\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ? + ",\nbut the minidump file is from a 64bit machine" : ""); + exit(1); + } +#elif defined(__x86_64__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) { + fprintf(stderr, + "This version of minidump-2-core only supports x86 (64bit)%s.\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ? + ",\nbut the minidump file is from a 32bit machine" : ""); + exit(1); + } +#elif defined(__arm__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) { + fprintf(stderr, + "This version of minidump-2-core only supports ARM (32bit).\n"); + exit(1); + } +#elif defined(__aarch64__) + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD) { + fprintf(stderr, + "This version of minidump-2-core only supports ARM (64bit).\n"); + exit(1); + } +#elif defined(__mips__) +# if _MIPS_SIM == _ABIO32 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) { + fprintf(stderr, + "This version of minidump-2-core only supports mips o32 (32bit).\n"); + exit(1); + } +# elif _MIPS_SIM == _ABI64 + if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS64) { + fprintf(stderr, + "This version of minidump-2-core only supports mips n64 (64bit).\n"); + exit(1); + } +# else +# error "This mips ABI is currently not supported (n32)" +# endif +#else +#error "This code has not been ported to your platform yet" +#endif + if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(), + "Linux") && + sysinfo->platform_id != MD_OS_NACL) { + fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n"); + exit(1); + } + + if (options.verbose) { + fprintf(stderr, + "MD_SYSTEM_INFO_STREAM:\n" + "Architecture: %s\n" + "Number of processors: %d\n" + "Processor level: %d\n" + "Processor model: %d\n" + "Processor stepping: %d\n", + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 + ? "i386" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 + ? "x86-64" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_ARM + ? "ARM" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS + ? "MIPS" + : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64 + ? "MIPS64" + : "???", + sysinfo->number_of_processors, + sysinfo->processor_level, + sysinfo->processor_revision >> 8, + sysinfo->processor_revision & 0xFF); + if (sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 || + sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) { + fputs("Vendor id: ", stderr); + const char *nul = + (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0, + sizeof(sysinfo->cpu.x86_cpu_info.vendor_id)); + fwrite(sysinfo->cpu.x86_cpu_info.vendor_id, + nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0] + : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr); + fputs("\n", stderr); + } + fprintf(stderr, "OS: %s\n", + full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str()); + fputs("\n\n", stderr); + } +} + +static void +ParseCPUInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_CPU_INFO:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n\n", stderr); + } +} + +static void +ParseProcessStatus(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_PROC_STATUS:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseLSBRelease(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_LSB_RELEASE:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseMaps(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_MAPS:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + } + for (const uint8_t* ptr = range.data(); + ptr < range.data() + range.length();) { + const uint8_t* eol = (uint8_t*)memchr(ptr, '\n', + range.data() + range.length() - ptr); + string line((const char*)ptr, + eol ? eol - ptr : range.data() + range.length() - ptr); + ptr = eol ? eol + 1 : range.data() + range.length(); + unsigned long long start, stop, offset; + char* permissions = NULL; + char* filename = NULL; + sscanf(line.c_str(), "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms", + &start, &stop, &permissions, &offset, &filename); + if (filename && *filename == '/') { + CrashedProcess::Mapping mapping; + mapping.permissions = 0; + if (strchr(permissions, 'r')) { + mapping.permissions |= PF_R; + } + if (strchr(permissions, 'w')) { + mapping.permissions |= PF_W; + } + if (strchr(permissions, 'x')) { + mapping.permissions |= PF_X; + } + mapping.start_address = start; + mapping.end_address = stop; + mapping.offset = offset; + if (filename) { + mapping.filename = filename; + } + crashinfo->mappings[mapping.start_address] = mapping; + } + free(permissions); + free(filename); + } + if (options.verbose) { + fputs("\n\n\n", stderr); + } +} + +static void +ParseEnvironment(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (options.verbose) { + fputs("MD_LINUX_ENVIRON:\n", stderr); + char* env = new char[range.length()]; + memcpy(env, range.data(), range.length()); + int nul_count = 0; + for (char *ptr = env;;) { + ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env)); + if (!ptr) { + break; + } + if (ptr > env && ptr[-1] == '\n') { + if (++nul_count > 5) { + // Some versions of Chrome try to rewrite the process' command line + // in a way that causes the environment to be corrupted. Afterwards, + // part of the environment will contain the trailing bit of the + // command line. The rest of the environment will be filled with + // NUL bytes. + // We detect this corruption by counting the number of consecutive + // NUL bytes. Normally, we would not expect any consecutive NUL + // bytes. But we are conservative and only suppress printing of + // the environment if we see at least five consecutive NULs. + fputs("Environment has been corrupted; no data available", stderr); + goto env_corrupted; + } + } else { + nul_count = 0; + } + *ptr = '\n'; + } + fwrite(env, range.length(), 1, stderr); + env_corrupted: + delete[] env; + fputs("\n\n\n", stderr); + } +} + +static void +ParseAuxVector(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + // Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value + // when dumping /proc/$x/maps + if (range.length() > 17) { + // The AUXV vector contains binary data, whereas the maps always begin + // with an 8+ digit hex address followed by a hyphen and another 8+ digit + // address. + char addresses[18]; + memcpy(addresses, range.data(), 17); + addresses[17] = '\000'; + if (strspn(addresses, "0123456789abcdef-") == 17) { + ParseMaps(options, crashinfo, range); + return; + } + } + + crashinfo->auxv = range.data(); + crashinfo->auxv_length = range.length(); +} + +static void +ParseCmdLine(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + // The command line is supposed to use NUL bytes to separate arguments. + // As Chrome rewrites its own command line and (incorrectly) substitutes + // spaces, this is often not the case in our minidump files. + const char* cmdline = (const char*) range.data(); + if (options.verbose) { + fputs("MD_LINUX_CMD_LINE:\n", stderr); + unsigned i = 0; + for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { } + fputs("argv[0] = \"", stderr); + fwrite(cmdline, i, 1, stderr); + fputs("\"\n", stderr); + for (unsigned j = ++i, argc = 1; j < range.length(); ++j) { + if (!cmdline[j] || cmdline[j] == ' ') { + fprintf(stderr, "argv[%d] = \"", argc++); + fwrite(cmdline + i, j - i, 1, stderr); + fputs("\"\n", stderr); + i = j + 1; + } + } + fputs("\n\n", stderr); + } + + const char *binary_name = cmdline; + for (size_t i = 0; i < range.length(); ++i) { + if (cmdline[i] == '/') { + binary_name = cmdline + i + 1; + } else if (cmdline[i] == 0 || cmdline[i] == ' ') { + static const size_t fname_len = sizeof(crashinfo->prps.pr_fname) - 1; + static const size_t args_len = sizeof(crashinfo->prps.pr_psargs) - 1; + memset(crashinfo->prps.pr_fname, 0, fname_len + 1); + memset(crashinfo->prps.pr_psargs, 0, args_len + 1); + unsigned len = cmdline + i - binary_name; + memcpy(crashinfo->prps.pr_fname, binary_name, + len > fname_len ? fname_len : len); + + len = range.length() > args_len ? args_len : range.length(); + memcpy(crashinfo->prps.pr_psargs, cmdline, len); + for (unsigned j = 0; j < len; ++j) { + if (crashinfo->prps.pr_psargs[j] == 0) + crashinfo->prps.pr_psargs[j] = ' '; + } + break; + } + } +} + +static void +ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const MDRawDebug* debug = range.GetData<MDRawDebug>(0); + if (!debug) { + return; + } + if (options.verbose) { + fprintf(stderr, + "MD_LINUX_DSO_DEBUG:\n" + "Version: %d\n" + "Number of DSOs: %d\n" + "Brk handler: 0x%" PRIx64 "\n" + "Dynamic loader at: 0x%" PRIx64 "\n" + "_DYNAMIC: 0x%" PRIx64 "\n", + debug->version, + debug->dso_count, + static_cast<uint64_t>(debug->brk), + static_cast<uint64_t>(debug->ldbase), + static_cast<uint64_t>(debug->dynamic)); + } + crashinfo->debug = *debug; + if (range.length() > sizeof(MDRawDebug)) { + char* dynamic_data = (char*)range.data() + sizeof(MDRawDebug); + crashinfo->dynamic_data.assign(dynamic_data, + range.length() - sizeof(MDRawDebug)); + } + if (debug->map != kInvalidMDRVA) { + for (unsigned int i = 0; i < debug->dso_count; ++i) { + const MDRawLinkMap* link_map = + full_file.GetArrayElement<MDRawLinkMap>(debug->map, i); + if (link_map) { + if (options.verbose) { + fprintf(stderr, + "#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n", + i, static_cast<uint64_t>(link_map->addr), + static_cast<uint64_t>(link_map->ld), + full_file.GetAsciiMDString(link_map->name).c_str()); + } + crashinfo->link_map.push_back(*link_map); + } + } + } + if (options.verbose) { + fputs("\n\n", stderr); + } +} + +static void +ParseExceptionStream(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0); + crashinfo->crashing_tid = exp->thread_id; + crashinfo->fatal_signal = (int) exp->exception_record.exception_code; +} + +static bool +WriteThread(const Options& options, const CrashedProcess::Thread& thread, + int fatal_signal) { + struct prstatus pr; + memset(&pr, 0, sizeof(pr)); + + pr.pr_info.si_signo = fatal_signal; + pr.pr_cursig = fatal_signal; + pr.pr_pid = thread.tid; +#if defined(__mips__) + memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct)); +#else + memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct)); +#endif + + Nhdr nhdr; + memset(&nhdr, 0, sizeof(nhdr)); + nhdr.n_namesz = 5; + nhdr.n_descsz = sizeof(struct prstatus); + nhdr.n_type = NT_PRSTATUS; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &pr, sizeof(struct prstatus))) { + return false; + } + +#if defined(__i386__) || defined(__x86_64__) + nhdr.n_descsz = sizeof(user_fpregs_struct); + nhdr.n_type = NT_FPREGSET; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &thread.fpregs, sizeof(user_fpregs_struct))) { + return false; + } +#endif + +#if defined(__i386__) + nhdr.n_descsz = sizeof(user_fpxregs_struct); + nhdr.n_type = NT_PRXFPREG; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "LINUX\0\0\0", 8) || + !writea(options.out_fd, &thread.fpxregs, sizeof(user_fpxregs_struct))) { + return false; + } +#endif + + return true; +} + +static void +ParseModuleStream(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + if (options.verbose) { + fputs("MD_MODULE_LIST_STREAM:\n", stderr); + } + const uint32_t num_mappings = *range.GetData<uint32_t>(0); + for (unsigned i = 0; i < num_mappings; ++i) { + CrashedProcess::Mapping mapping; + const MDRawModule* rawmodule = reinterpret_cast<const MDRawModule*>( + range.GetArrayElement(sizeof(uint32_t), MD_MODULE_SIZE, i)); + mapping.start_address = rawmodule->base_of_image; + mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image; + + if (crashinfo->mappings.find(mapping.start_address) == + crashinfo->mappings.end()) { + // We prefer data from MD_LINUX_MAPS over MD_MODULE_LIST_STREAM, as + // the former is a strict superset of the latter. + crashinfo->mappings[mapping.start_address] = mapping; + } + + const MDCVInfoPDB70* record = reinterpret_cast<const MDCVInfoPDB70*>( + full_file.GetData(rawmodule->cv_record.rva, MDCVInfoPDB70_minsize)); + char guid[40]; + sprintf(guid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + record->signature.data1, record->signature.data2, + record->signature.data3, + record->signature.data4[0], record->signature.data4[1], + record->signature.data4[2], record->signature.data4[3], + record->signature.data4[4], record->signature.data4[5], + record->signature.data4[6], record->signature.data4[7]); + + string filename = full_file.GetAsciiMDString(rawmodule->module_name_rva); + + CrashedProcess::Signature signature; + strcpy(signature.guid, guid); + signature.filename = filename; + crashinfo->signatures[rawmodule->base_of_image] = signature; + + if (options.verbose) { + fprintf(stderr, "0x%" PRIx64 "-0x%" PRIx64 ", ChkSum: 0x%08X, GUID: %s, " + " \"%s\"\n", + rawmodule->base_of_image, + rawmodule->base_of_image + rawmodule->size_of_image, + rawmodule->checksum, guid, filename.c_str()); + } + } + if (options.verbose) { + fputs("\n\n", stderr); + } +} + +static void +AddDataToMapping(CrashedProcess* crashinfo, const string& data, + uintptr_t addr) { + for (std::map<uint64_t, CrashedProcess::Mapping>::iterator + iter = crashinfo->mappings.begin(); + iter != crashinfo->mappings.end(); + ++iter) { + if (addr >= iter->second.start_address && + addr < iter->second.end_address) { + CrashedProcess::Mapping mapping = iter->second; + if ((addr & ~4095) != iter->second.start_address) { + // If there are memory pages in the mapping prior to where the + // data starts, truncate the existing mapping so that it ends with + // the page immediately preceding the data region. + iter->second.end_address = addr & ~4095; + if (!mapping.filename.empty()) { + // "mapping" is a copy of "iter->second". We are splitting the + // existing mapping into two separate ones when we write the data + // to the core file. The first one does not have any associated + // data in the core file, the second one is backed by data that is + // included with the core file. + // If this mapping wasn't supposed to be anonymous, then we also + // have to update the file offset upon splitting the mapping. + mapping.offset += iter->second.end_address - + iter->second.start_address; + } + } + // Create a new mapping that contains the data contents. We often + // limit the amount of data that is actually written to the core + // file. But it is OK if the mapping itself extends past the end of + // the data. + mapping.start_address = addr & ~4095; + mapping.data.assign(addr & 4095, 0).append(data); + mapping.data.append(-mapping.data.size() & 4095, 0); + crashinfo->mappings[mapping.start_address] = mapping; + return; + } + } + // Didn't find a suitable existing mapping for the data. Create a new one. + CrashedProcess::Mapping mapping; + mapping.permissions = PF_R | PF_W; + mapping.start_address = addr & ~4095; + mapping.end_address = + (addr + data.size() + 4095) & ~4095; + mapping.data.assign(addr & 4095, 0).append(data); + mapping.data.append(-mapping.data.size() & 4095, 0); + crashinfo->mappings[mapping.start_address] = mapping; +} + +static void +AugmentMappings(const Options& options, CrashedProcess* crashinfo, + const MinidumpMemoryRange& full_file) { + // For each thread, find the memory mapping that matches the thread's stack. + // Then adjust the mapping to include the stack dump. + for (unsigned i = 0; i < crashinfo->threads.size(); ++i) { + const CrashedProcess::Thread& thread = crashinfo->threads[i]; + AddDataToMapping(crashinfo, + string((char *)thread.stack, thread.stack_length), + thread.stack_addr); + } + + // Create a new link map with information about DSOs. We move this map to + // the beginning of the address space, as this area should always be + // available. + static const uintptr_t start_addr = 4096; + string data; + struct r_debug debug = { 0 }; + debug.r_version = crashinfo->debug.version; + debug.r_brk = (ElfW(Addr))crashinfo->debug.brk; + debug.r_state = r_debug::RT_CONSISTENT; + debug.r_ldbase = (ElfW(Addr))crashinfo->debug.ldbase; + debug.r_map = crashinfo->debug.dso_count > 0 ? + (struct link_map*)(start_addr + sizeof(debug)) : 0; + data.append((char*)&debug, sizeof(debug)); + + struct link_map* prev = 0; + for (std::vector<MDRawLinkMap>::iterator iter = crashinfo->link_map.begin(); + iter != crashinfo->link_map.end(); + ++iter) { + struct link_map link_map = { 0 }; + link_map.l_addr = (ElfW(Addr))iter->addr; + link_map.l_name = (char*)(start_addr + data.size() + sizeof(link_map)); + link_map.l_ld = (ElfW(Dyn)*)iter->ld; + link_map.l_prev = prev; + prev = (struct link_map*)(start_addr + data.size()); + string filename = full_file.GetAsciiMDString(iter->name); + + // Look up signature for this filename. If available, change filename + // to point to GUID, instead. + std::map<uintptr_t, CrashedProcess::Signature>::const_iterator sig = + crashinfo->signatures.find((uintptr_t)iter->addr); + if (sig != crashinfo->signatures.end()) { + // At this point, we have: + // old_filename: The path as found via SONAME (e.g. /lib/libpthread.so.0). + // sig_filename: The path on disk (e.g. /lib/libpthread-2.19.so). + const char* guid = sig->second.guid; + string sig_filename = sig->second.filename; + string old_filename = filename.empty() ? sig_filename : filename; + string new_filename; + + // First set up the leading path. We assume dirname always ends with a + // trailing slash (as needed), so we won't be appending one manually. + if (options.so_basedir.empty()) { + string dirname; + if (options.use_filename) { + dirname = sig_filename; + } else { + dirname = old_filename; + } + size_t slash = dirname.find_last_of('/'); + if (slash != string::npos) { + new_filename = dirname.substr(0, slash + 1); + } + } else { + new_filename = options.so_basedir; + } + + // Insert the module ID if requested. + if (options.inc_guid && + strcmp(guid, "00000000-0000-0000-0000-000000000000") != 0) { + new_filename += guid; + new_filename += "-"; + } + + // Decide whether we use the filename or the SONAME (where the SONAME tends + // to be a symlink to the actual file). + new_filename += google_breakpad::BaseName( + options.use_filename ? sig_filename : old_filename); + + if (filename != new_filename) { + if (options.verbose) { + fprintf(stderr, "0x%" PRIx64": rewriting mapping \"%s\" to \"%s\"\n", + static_cast<uint64_t>(link_map.l_addr), + filename.c_str(), new_filename.c_str()); + } + filename = new_filename; + } + } + + if (std::distance(iter, crashinfo->link_map.end()) == 1) { + link_map.l_next = 0; + } else { + link_map.l_next = (struct link_map*)(start_addr + data.size() + + sizeof(link_map) + + ((filename.size() + 8) & ~7)); + } + data.append((char*)&link_map, sizeof(link_map)); + data.append(filename); + data.append(8 - (filename.size() & 7), 0); + } + AddDataToMapping(crashinfo, data, start_addr); + + // Map the page containing the _DYNAMIC array + if (!crashinfo->dynamic_data.empty()) { + // Make _DYNAMIC DT_DEBUG entry point to our link map + for (int i = 0;; ++i) { + ElfW(Dyn) dyn; + if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) { + no_dt_debug: + if (options.verbose) { + fprintf(stderr, "No DT_DEBUG entry found\n"); + } + return; + } + memcpy(&dyn, crashinfo->dynamic_data.c_str() + i*sizeof(dyn), + sizeof(dyn)); + if (dyn.d_tag == DT_DEBUG) { + crashinfo->dynamic_data.replace(i*sizeof(dyn) + + offsetof(ElfW(Dyn), d_un.d_ptr), + sizeof(start_addr), + (char*)&start_addr, sizeof(start_addr)); + break; + } else if (dyn.d_tag == DT_NULL) { + goto no_dt_debug; + } + } + AddDataToMapping(crashinfo, crashinfo->dynamic_data, + (uintptr_t)crashinfo->debug.dynamic); + } +} + +int +main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + + MemoryMappedFile mapped_file(options.minidump_path.c_str(), 0); + if (!mapped_file.data()) { + fprintf(stderr, "Failed to mmap dump file: %s: %s\n", + options.minidump_path.c_str(), strerror(errno)); + return 1; + } + + MinidumpMemoryRange dump(mapped_file.data(), mapped_file.size()); + + const MDRawHeader* header = dump.GetData<MDRawHeader>(0); + + CrashedProcess crashinfo; + + // Always check the system info first, as that allows us to tell whether + // this is a minidump file that is compatible with our converter. + bool ok = false; + for (unsigned i = 0; i < header->stream_count; ++i) { + const MDRawDirectory* dirent = + dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i); + switch (dirent->stream_type) { + case MD_SYSTEM_INFO_STREAM: + ParseSystemInfo(options, &crashinfo, dump.Subrange(dirent->location), + dump); + ok = true; + break; + default: + break; + } + } + if (!ok) { + fprintf(stderr, "Cannot determine input file format.\n"); + exit(1); + } + + for (unsigned i = 0; i < header->stream_count; ++i) { + const MDRawDirectory* dirent = + dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i); + switch (dirent->stream_type) { + case MD_THREAD_LIST_STREAM: + ParseThreadList(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + case MD_LINUX_CPU_INFO: + ParseCPUInfo(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_PROC_STATUS: + ParseProcessStatus(options, &crashinfo, + dump.Subrange(dirent->location)); + break; + case MD_LINUX_LSB_RELEASE: + ParseLSBRelease(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_ENVIRON: + ParseEnvironment(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_MAPS: + ParseMaps(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_AUXV: + ParseAuxVector(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_CMD_LINE: + ParseCmdLine(options, &crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_DSO_DEBUG: + ParseDSODebugInfo(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + case MD_EXCEPTION_STREAM: + ParseExceptionStream(options, &crashinfo, + dump.Subrange(dirent->location)); + break; + case MD_MODULE_LIST_STREAM: + ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location), + dump); + break; + default: + if (options.verbose) + fprintf(stderr, "Skipping %x\n", dirent->stream_type); + } + } + + AugmentMappings(options, &crashinfo, dump); + + // Write the ELF header. The file will look like: + // ELF header + // Phdr for the PT_NOTE + // Phdr for each of the thread stacks + // PT_NOTE + // each of the thread stacks + Ehdr ehdr; + memset(&ehdr, 0, sizeof(Ehdr)); + ehdr.e_ident[0] = ELFMAG0; + ehdr.e_ident[1] = ELFMAG1; + ehdr.e_ident[2] = ELFMAG2; + ehdr.e_ident[3] = ELFMAG3; + ehdr.e_ident[4] = ELF_CLASS; + ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB; + ehdr.e_ident[6] = EV_CURRENT; + ehdr.e_type = ET_CORE; + ehdr.e_machine = ELF_ARCH; + ehdr.e_version = EV_CURRENT; + ehdr.e_phoff = sizeof(Ehdr); + ehdr.e_ehsize = sizeof(Ehdr); + ehdr.e_phentsize= sizeof(Phdr); + ehdr.e_phnum = 1 + // PT_NOTE + crashinfo.mappings.size(); // memory mappings + ehdr.e_shentsize= sizeof(Shdr); + if (!writea(options.out_fd, &ehdr, sizeof(Ehdr))) + return 1; + + size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr); + size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) + + // sizeof(Nhdr) + 8 + sizeof(user) + + sizeof(Nhdr) + 8 + crashinfo.auxv_length + + crashinfo.threads.size() * ( + (sizeof(Nhdr) + 8 + sizeof(prstatus)) +#if defined(__i386__) || defined(__x86_64__) + + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) +#endif +#if defined(__i386__) + + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct) +#endif + ); + + Phdr phdr; + memset(&phdr, 0, sizeof(Phdr)); + phdr.p_type = PT_NOTE; + phdr.p_offset = offset; + phdr.p_filesz = filesz; + if (!writea(options.out_fd, &phdr, sizeof(phdr))) + return 1; + + phdr.p_type = PT_LOAD; + phdr.p_align = 4096; + size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align); + if (note_align == phdr.p_align) + note_align = 0; + offset += note_align; + + for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter = + crashinfo.mappings.begin(); + iter != crashinfo.mappings.end(); ++iter) { + const CrashedProcess::Mapping& mapping = iter->second; + if (mapping.permissions == 0xFFFFFFFF) { + // This is a map that we found in MD_MODULE_LIST_STREAM (as opposed to + // MD_LINUX_MAPS). It lacks some of the information that we would like + // to include. + phdr.p_flags = PF_R; + } else { + phdr.p_flags = mapping.permissions; + } + phdr.p_vaddr = mapping.start_address; + phdr.p_memsz = mapping.end_address - mapping.start_address; + if (mapping.data.size()) { + offset += filesz; + filesz = mapping.data.size(); + phdr.p_filesz = mapping.data.size(); + phdr.p_offset = offset; + } else { + phdr.p_filesz = 0; + phdr.p_offset = 0; + } + if (!writea(options.out_fd, &phdr, sizeof(phdr))) + return 1; + } + + Nhdr nhdr; + memset(&nhdr, 0, sizeof(nhdr)); + nhdr.n_namesz = 5; + nhdr.n_descsz = sizeof(prpsinfo); + nhdr.n_type = NT_PRPSINFO; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, &crashinfo.prps, sizeof(prpsinfo))) { + return 1; + } + + nhdr.n_descsz = crashinfo.auxv_length; + nhdr.n_type = NT_AUXV; + if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) || + !writea(options.out_fd, "CORE\0\0\0\0", 8) || + !writea(options.out_fd, crashinfo.auxv, crashinfo.auxv_length)) { + return 1; + } + + for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { + if (crashinfo.threads[i].tid == crashinfo.crashing_tid) { + WriteThread(options, crashinfo.threads[i], crashinfo.fatal_signal); + break; + } + } + + for (unsigned i = 0; i < crashinfo.threads.size(); ++i) { + if (crashinfo.threads[i].tid != crashinfo.crashing_tid) + WriteThread(options, crashinfo.threads[i], 0); + } + + if (note_align) { + google_breakpad::scoped_array<char> scratch(new char[note_align]); + memset(scratch.get(), 0, note_align); + if (!writea(options.out_fd, scratch.get(), note_align)) + return 1; + } + + for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter = + crashinfo.mappings.begin(); + iter != crashinfo.mappings.end(); ++iter) { + const CrashedProcess::Mapping& mapping = iter->second; + if (mapping.data.size()) { + if (!writea(options.out_fd, mapping.data.c_str(), mapping.data.size())) + return 1; + } + } + + if (options.out_fd != STDOUT_FILENO) { + close(options.out_fd); + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h new file mode 100644 index 0000000000..a793e2cfb9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range.h @@ -0,0 +1,89 @@ +// 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_memory_range.h: Define the google_breakpad::MinidumpMemoryRange +// class, which adds methods for handling minidump specific data structures +// on top of google_breakpad::MemoryRange. See common/memory_range.h for +// more details on MemoryRange. + +#ifndef TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ +#define TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ + +#include <string> + +#include "common/memory_range.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// A derived class of MemoryRange with added methods for handling minidump +// specific data structures. To avoid virtual functions, it is not designed +// to be used polymorphically. +class MinidumpMemoryRange : public MemoryRange { + public: + MinidumpMemoryRange() {} + + MinidumpMemoryRange(const void* data, size_t length) + : MemoryRange(data, length) {} + + // Returns a subrange of |length| bytes at |offset| bytes of this memory + // range, or an empty range if the subrange is out of bounds. + // This methods overrides the base implemementation in order to return + // an instance of MinidumpMemoryRange instead of MemoryRange. + MinidumpMemoryRange Subrange(size_t sub_offset, size_t sub_length) const { + if (Covers(sub_offset, sub_length)) + return MinidumpMemoryRange(data() + sub_offset, sub_length); + return MinidumpMemoryRange(); + } + + // Returns a subrange that covers the offset and length specified by + // |location|, or an empty range if the subrange is out of bounds. + MinidumpMemoryRange Subrange(const MDLocationDescriptor& location) const { + return MinidumpMemoryRange::Subrange(location.rva, location.data_size); + } + + // Gets a STL string from a MDString at |sub_offset| bytes of this memory + // range. This method only works correctly for ASCII characters and does + // not convert between UTF-16 and UTF-8. + const std::string GetAsciiMDString(size_t sub_offset) const { + std::string str; + const MDString* md_str = GetData<MDString>(sub_offset); + if (md_str) { + const uint16_t* buffer = &md_str->buffer[0]; + for (uint32_t i = 0; i < md_str->length && buffer[i]; ++i) { + str.push_back(buffer[i]); + } + } + return str; + } +}; + +} // namespace google_breakpad + +#endif // TOOLS_LINUX_MD2CORE_MINIDUMP_MEMORY_RANGE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc new file mode 100644 index 0000000000..fe4ded83dc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump_memory_range_unittest.cc @@ -0,0 +1,258 @@ +// 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_memory_range_unittest.cc: +// Unit tests for google_breakpad::MinidumpMemoryRange. + +#include "breakpad_googletest_includes.h" +#include "tools/linux/md2core/minidump_memory_range.h" + +using google_breakpad::MinidumpMemoryRange; +using testing::Message; + +namespace { + +const uint32_t kBuffer[10] = { 0 }; +const size_t kBufferSize = sizeof(kBuffer); +const uint8_t* kBufferPointer = reinterpret_cast<const uint8_t*>(kBuffer); + +// Test vectors for verifying Covers, GetData, and Subrange. +const struct { + bool valid; + size_t offset; + size_t length; +} kSubranges[] = { + { true, 0, 0 }, + { true, 0, 2 }, + { true, 0, kBufferSize }, + { true, 2, 0 }, + { true, 2, 4 }, + { true, 2, kBufferSize - 2 }, + { true, kBufferSize - 1, 1 }, + { false, kBufferSize, 0 }, + { false, kBufferSize, static_cast<size_t>(-1) }, + { false, kBufferSize + 1, 0 }, + { false, static_cast<size_t>(-1), 2 }, + { false, 1, kBufferSize }, + { false, kBufferSize - 1, 2 }, + { false, 0, static_cast<size_t>(-1) }, + { false, 1, static_cast<size_t>(-1) }, +}; +const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]); + +// Test vectors for verifying GetArrayElement. +const struct { + size_t offset; + size_t size; + size_t index; + const void* const pointer; +} kElements[] = { + // Valid array elemenets + { 0, 1, 0, kBufferPointer }, + { 0, 1, 1, kBufferPointer + 1 }, + { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 }, + { 0, 2, 1, kBufferPointer + 2 }, + { 0, 4, 2, kBufferPointer + 8 }, + { 0, 4, 9, kBufferPointer + 36 }, + { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, + // Invalid array elemenets + { 0, 1, kBufferSize, NULL }, + { 0, 4, 10, NULL }, + { kBufferSize - 1, 1, 1, NULL }, + { kBufferSize - 1, 2, 0, NULL }, + { kBufferSize, 1, 0, NULL }, +}; +const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); + +} // namespace + +TEST(MinidumpMemoryRangeTest, DefaultConstructor) { + MinidumpMemoryRange range; + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, ConstructorWithDataAndLength) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); +} + +TEST(MinidumpMemoryRangeTest, Reset) { + MinidumpMemoryRange range; + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); + + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Reset(); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, Set) { + MinidumpMemoryRange range; + range.Set(kBuffer, kBufferSize); + EXPECT_EQ(kBufferPointer, range.data()); + EXPECT_EQ(kBufferSize, range.length()); + + range.Set(NULL, 0); + EXPECT_EQ(NULL, range.data()); + EXPECT_EQ(0U, range.length()); +} + +TEST(MinidumpMemoryRangeTest, SubrangeOfEmptyMemoryRange) { + MinidumpMemoryRange range; + MinidumpMemoryRange subrange = range.Subrange(0, 10); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); +} + +TEST(MinidumpMemoryRangeTest, SubrangeAndGetData) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MinidumpMemoryRange subrange = range.Subrange(sub_offset, sub_length); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MinidumpMemoryRangeTest, SubrangeWithMDLocationDescriptor) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumSubranges; ++i) { + bool valid = kSubranges[i].valid; + size_t sub_offset = kSubranges[i].offset; + size_t sub_length = kSubranges[i].length; + SCOPED_TRACE(Message() << "offset=" << sub_offset + << ", length=" << sub_length); + + MDLocationDescriptor location; + location.rva = sub_offset; + location.data_size = sub_length; + MinidumpMemoryRange subrange = range.Subrange(location); + if (valid) { + EXPECT_TRUE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, + range.GetData(sub_offset, sub_length)); + EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); + EXPECT_EQ(sub_length, subrange.length()); + } else { + EXPECT_FALSE(range.Covers(sub_offset, sub_length)); + EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); + EXPECT_EQ(NULL, subrange.data()); + EXPECT_EQ(0U, subrange.length()); + } + } +} + +TEST(MinidumpMemoryRangeTest, GetDataWithTemplateType) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetData<char>(0); + EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer); + const int* int_pointer = range.GetData<int>(0); + EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer); +} + +TEST(MinidumpMemoryRangeTest, GetArrayElement) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + for (size_t i = 0; i < kNumElements; ++i) { + size_t element_offset = kElements[i].offset; + size_t element_size = kElements[i].size; + unsigned element_index = kElements[i].index; + const void* const element_pointer = kElements[i].pointer; + SCOPED_TRACE(Message() << "offset=" << element_offset + << ", size=" << element_size + << ", index=" << element_index); + EXPECT_EQ(element_pointer, range.GetArrayElement( + element_offset, element_size, element_index)); + } +} + +TEST(MinidumpMemoryRangeTest, GetArrayElmentWithTemplateType) { + MinidumpMemoryRange range(kBuffer, kBufferSize); + const char* char_pointer = range.GetArrayElement<char>(0, 0); + EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer); + const int* int_pointer = range.GetArrayElement<int>(0, 0); + EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer); +} + +TEST(MinidumpMemoryRangeTest, GetAsciiMDString) { + uint8_t buffer[100] = { 0 }; + + MDString* md_str = reinterpret_cast<MDString*>(buffer); + md_str->length = 4; + md_str->buffer[0] = 'T'; + md_str->buffer[1] = 'e'; + md_str->buffer[2] = 's'; + md_str->buffer[3] = 't'; + md_str->buffer[4] = '\0'; + + size_t str2_offset = + sizeof(MDString) + (md_str->length + 1) * sizeof(uint16_t); + + md_str = reinterpret_cast<MDString*>(buffer + str2_offset); + md_str->length = 9; // Test length larger than actual string + md_str->buffer[0] = 'S'; + md_str->buffer[1] = 't'; + md_str->buffer[2] = 'r'; + md_str->buffer[3] = 'i'; + md_str->buffer[4] = 'n'; + md_str->buffer[5] = 'g'; + md_str->buffer[6] = '\0'; + md_str->buffer[7] = '1'; + md_str->buffer[8] = '2'; + + MinidumpMemoryRange range(buffer, sizeof(buffer)); + EXPECT_EQ("Test", range.GetAsciiMDString(0)); + EXPECT_EQ("String", range.GetAsciiMDString(str2_offset)); + + // Test out-of-bounds cases. + EXPECT_EQ("", range.GetAsciiMDString( + sizeof(buffer) - sizeof(MDString) + 1)); + EXPECT_EQ("", range.GetAsciiMDString(sizeof(buffer))); +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc new file mode 100644 index 0000000000..19f17450a1 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/minidump_upload.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2006, 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_upload.cc: Upload a minidump to a HTTP server. +// The upload is sent as a multipart/form-data POST request with +// the following parameters: +// prod: the product name +// ver: the product version +// symbol_file: the breakpad format symbol file + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <string> + +#include "common/linux/http_upload.h" +#include "common/using_std_string.h" + +using google_breakpad::HTTPUpload; + +struct Options { + string minidumpPath; + string uploadURLStr; + string product; + string version; + string proxy; + string proxy_user_pwd; + bool success; +}; + +//============================================================================= +static void Start(Options *options) { + std::map<string, string> parameters; + // Add parameters + parameters["prod"] = options->product; + parameters["ver"] = options->version; + + std::map<string, string> files; + files["upload_file_minidump"] = options->minidumpPath; + + // Send it + string response, error; + bool success = HTTPUpload::SendRequest(options->uploadURLStr, + parameters, + files, + options->proxy, + options->proxy_user_pwd, + "", + &response, + NULL, + &error); + + if (success) { + printf("Successfully sent the minidump file.\n"); + } else { + printf("Failed to send minidump: %s\n", error.c_str()); + } + printf("Response:\n"); + printf("%s\n", response.c_str()); + options->success = success; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit minidump information.\n"); + fprintf(stderr, "Usage: %s [options...] -p <product> -v <version> <minidump> " + "<upload-URL>\n", argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "<minidump> should be a minidump.\n"); + fprintf(stderr, "<upload-URL> is the destination for the upload\n"); + + fprintf(stderr, "-p:\t <product> Product name\n"); + fprintf(stderr, "-v:\t <version> Product version\n"); + fprintf(stderr, "-x:\t <host[:port]> Use HTTP proxy on given port\n"); + fprintf(stderr, "-u:\t <user[:password]> Set proxy user and password\n"); + fprintf(stderr, "-h:\t Usage\n"); + fprintf(stderr, "-?:\t Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + int ch; + + while ((ch = getopt(argc, (char * const *)argv, "p:u:v:x:h?")) != -1) { + switch (ch) { + case 'p': + options->product = optarg; + break; + case 'u': + options->proxy_user_pwd = optarg; + break; + case 'v': + options->version = optarg; + break; + case 'x': + options->proxy = optarg; + break; + + default: + fprintf(stderr, "Invalid option '%c'\n", ch); + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = argv[optind]; + options->uploadURLStr = argv[optind + 1]; +} + +//============================================================================= +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + Start(&options); + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc new file mode 100644 index 0000000000..f155eb9552 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc @@ -0,0 +1,210 @@ +// Copyright (c) 2006, 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. + +// symupload.cc: Upload a symbol file to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// code_file: the basename of the module, e.g. "app" +// debug_file: the basename of the debugging file, e.g. "app" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// version: the file version of the module, e.g. "1.2.3.4" +// os: the operating system that the module was built for +// cpu: the CPU that the module was built for +// symbol_file: the contents of the breakpad-format symbol file + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <locale> + +#include "common/linux/symbol_upload.h" + +using google_breakpad::sym_upload::UploadProtocol; +using google_breakpad::sym_upload::Options; + +static void StrToUpper(std::string* str) { + if (str == nullptr) { + fprintf(stderr, "nullptr passed to StrToUpper.\n"); + exit(1); + } + for (size_t i = 0; i < str->length(); i++) { + (*str)[i] = std::toupper((*str)[i], std::locale::classic()); + } +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s [options...] <symbol-file> <upload-URL>\n", + argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "<symbol-file> should be created by using the dump_syms" + "tool.\n"); + fprintf(stderr, "<upload-URL> is the destination for the upload\n"); + fprintf(stderr, "-p:\t <protocol> One of ['sym-upload-v1'," + " 'sym-upload-v2'], defaults to 'sym-upload-v1'.\n"); + fprintf(stderr, "-v:\t Version information (e.g., 1.2.3.4)\n"); + fprintf(stderr, "-x:\t <host[:port]> Use HTTP proxy on given port\n"); + fprintf(stderr, "-u:\t <user[:password]> Set proxy user and password\n"); + fprintf(stderr, "-h:\t Usage\n"); + fprintf(stderr, "-?:\t Usage\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "These options only work with 'sym-upload-v2' protocol:\n"); + fprintf(stderr, "-k:\t <API-key> A secret used to authenticate with the" + " API.\n"); + fprintf(stderr, "-f:\t Force symbol upload if already exists.\n"); + fprintf(stderr, "-t:\t <symbol-type> Explicitly set symbol upload type (" + "default is 'breakpad').\n" + "\t One of ['breakpad', 'elf', 'pe', 'macho', 'debug_only', 'dwp', " + "'dsym', 'pdb'].\n" + "\t Note: When this flag is set to anything other than 'breakpad', then " + "the '-c' and '-i' flags must also be set.\n"); + fprintf(stderr, "-c:\t <code-file> Explicitly set 'code_file' for symbol " + "upload (basename of executable).\n"); + fprintf(stderr, "-i:\t <debug-id> Explicitly set 'debug_id' for symbol " + "upload (typically build ID of executable).\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Examples:\n"); + fprintf(stderr, " With 'sym-upload-v1':\n"); + fprintf(stderr, " %s path/to/symbol_file http://myuploadserver\n", + argv[0]); + fprintf(stderr, " With 'sym-upload-v2':\n"); + fprintf(stderr, " [Defaulting to symbol type 'BREAKPAD']\n"); + fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! " + "path/to/symbol_file http://myuploadserver\n", argv[0]); + fprintf(stderr, " [Explicitly set symbol type to 'elf']\n"); + fprintf(stderr, " %s -p sym-upload-v2 -k mysecret123! -t elf " + "-c app -i 11111111BBBB3333DDDD555555555555F " + "path/to/symbol_file http://myuploadserver\n", argv[0]); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + int ch; + constexpr char flag_pattern[] = "u:v:x:p:k:t:c:i:hf?"; + + while ((ch = getopt(argc, (char * const *)argv, flag_pattern)) != -1) { + switch (ch) { + case 'h': + case '?': + Usage(argc, argv); + exit(0); + break; + case 'u': + options->proxy_user_pwd = optarg; + break; + case 'v': + options->version = optarg; + break; + case 'x': + options->proxy = optarg; + break; + case 'p': + if (strcmp(optarg, "sym-upload-v2") == 0) { + options->upload_protocol = UploadProtocol::SYM_UPLOAD_V2; + } else if (strcmp(optarg, "sym-upload-v1") == 0) { + options->upload_protocol = UploadProtocol::SYM_UPLOAD_V1; + } else { + fprintf(stderr, "Invalid protocol '%s'\n", optarg); + Usage(argc, argv); + exit(1); + } + break; + case 'k': + options->api_key = optarg; + break; + case 't': { + // This is really an enum, so treat as upper-case for consistency with + // enum naming convention on server-side. + options->type = optarg; + StrToUpper(&(options->type)); + break; + } + case 'c': + options->code_file = optarg; + break; + case 'i': + options->debug_id = optarg; + break; + case 'f': + options->force = true; + break; + + default: + fprintf(stderr, "Invalid option '%c'\n", ch); + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + bool is_breakpad_upload = options->type.empty() || + options->type == google_breakpad::sym_upload::kBreakpadSymbolType; + bool has_code_file = !options->code_file.empty(); + bool has_debug_id = !options->debug_id.empty(); + if (is_breakpad_upload && (has_code_file || has_debug_id)) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: -c and -i should only be specified for non-breakpad " + "symbol upload types.\n", argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + if (!is_breakpad_upload && (!has_code_file || !has_debug_id)) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: -c and -i must be specified for non-breakpad " + "symbol upload types.\n", argv[0]); + fprintf(stderr, "\n"); + Usage(argc, argv); + exit(1); + } + + options->symbolsPath = argv[optind]; + options->uploadURLStr = argv[optind + 1]; +} + +//============================================================================= +int main(int argc, const char* argv[]) { + Options options; + SetupOptions(argc, argv, &options); + google_breakpad::sym_upload::Start(&options); + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi b/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi new file mode 100644 index 0000000000..020e4c1c71 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/tools_linux.gypi @@ -0,0 +1,83 @@ +# Copyright 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. + +{ + 'target_defaults': { + 'include_dirs': [ + '../..', + ], + }, + 'targets': [ + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms/dump_syms.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'md2core', + 'type': 'executable', + 'sources': [ + 'md2core/minidump-2-core.cc', + 'md2core/minidump_memory_range.h', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'minidump_upload', + 'type': 'executable', + 'sources': [ + 'symupload/minidump_upload.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload/sym_upload.cc', + ], + 'link_settings': { + 'libraries': [ + '-ldl', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm new file mode 100644 index 0000000000..f68200c7c9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.mm @@ -0,0 +1,408 @@ +// 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. + +// crash_report.mm: Convert the contents of a minidump into a format that +// looks more like Apple's CrashReporter format + +#include <unistd.h> + +#include <mach/machine.h> +#include <mach-o/arch.h> + +#include <string> + +#include <Foundation/Foundation.h> + +#include "common/scoped_ptr.h" +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/call_stack.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/minidump_processor.h" +#include "google_breakpad/processor/process_state.h" +#include "google_breakpad/processor/stack_frame_cpu.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/pathname_stripper.h" +#include "processor/simple_symbol_supplier.h" + +#include "on_demand_symbol_supplier.h" + +using std::string; + +using google_breakpad::BasicSourceLineResolver; +using google_breakpad::CallStack; +using google_breakpad::CodeModule; +using google_breakpad::CodeModules; +using google_breakpad::Minidump; +using google_breakpad::MinidumpProcessor; +using google_breakpad::OnDemandSymbolSupplier; +using google_breakpad::PathnameStripper; +using google_breakpad::ProcessState; +using google_breakpad::scoped_ptr; +using google_breakpad::StackFrame; +using google_breakpad::StackFramePPC; +using google_breakpad::StackFrameX86; +using google_breakpad::SystemInfo; + +typedef struct { + NSString *minidumpPath; + NSString *searchDir; + NSString *symbolSearchDir; + BOOL printThreadMemory; +} Options; + +//============================================================================= +static int PrintRegister(const char *name, u_int32_t value, int sequence) { + if (sequence % 4 == 0) { + printf("\n"); + } + printf("%6s = 0x%08x ", name, value); + return ++sequence; +} + +//============================================================================= +static void PrintStack(const CallStack *stack, const string &cpu) { + size_t frame_count = stack->frames()->size(); + char buffer[1024]; + for (size_t frame_index = 0; frame_index < frame_count; ++frame_index) { + const StackFrame *frame = stack->frames()->at(frame_index); + const CodeModule *module = frame->module; + printf("%2zu ", frame_index); + + if (module) { + // Module name (20 chars max) + strcpy(buffer, PathnameStripper::File(module->code_file()).c_str()); + int maxStr = 20; + buffer[maxStr] = 0; + printf("%-*s", maxStr, buffer); + + strcpy(buffer, module->version().c_str()); + buffer[maxStr] = 0; + + printf("%-*s",maxStr, buffer); + + u_int64_t instruction = frame->instruction; + + // PPC only: Adjust the instruction to match that of Crash reporter. The + // instruction listed is actually the return address. See the detailed + // comments in stackwalker_ppc.cc for more information. + if (cpu == "ppc" && frame_index) + instruction += 4; + + printf(" 0x%08llx ", instruction); + + // Function name + if (!frame->function_name.empty()) { + printf("%s", frame->function_name.c_str()); + if (!frame->source_file_name.empty()) { + string source_file = PathnameStripper::File(frame->source_file_name); + printf(" + 0x%llx (%s:%d)", + instruction - frame->source_line_base, + source_file.c_str(), frame->source_line); + } else { + printf(" + 0x%llx", instruction - frame->function_base); + } + } + } + printf("\n"); + } +} + +//============================================================================= +static void PrintRegisters(const CallStack *stack, const string &cpu) { + int sequence = 0; + const StackFrame *frame = stack->frames()->at(0); + if (cpu == "x86") { + const StackFrameX86 *frame_x86 = + reinterpret_cast<const StackFrameX86*>(frame); + + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP) + sequence = PrintRegister("eip", frame_x86->context.eip, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP) + sequence = PrintRegister("esp", frame_x86->context.esp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP) + sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX) + sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI) + sequence = PrintRegister("esi", frame_x86->context.esi, sequence); + if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI) + sequence = PrintRegister("edi", frame_x86->context.edi, sequence); + if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) { + sequence = PrintRegister("eax", frame_x86->context.eax, sequence); + sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence); + sequence = PrintRegister("edx", frame_x86->context.edx, sequence); + sequence = PrintRegister("efl", frame_x86->context.eflags, sequence); + } + } else if (cpu == "ppc") { + const StackFramePPC *frame_ppc = + reinterpret_cast<const StackFramePPC*>(frame); + + if ((frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL) == + StackFramePPC::CONTEXT_VALID_ALL) { + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence); + sequence = PrintRegister("cr", frame_ppc->context.cr, sequence); + sequence = PrintRegister("xer", frame_ppc->context.xer, sequence); + sequence = PrintRegister("lr", frame_ppc->context.lr, sequence); + sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence); + sequence = PrintRegister("mq", frame_ppc->context.mq, sequence); + sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence); + + sequence = 0; + char buffer[5]; + for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) { + sprintf(buffer, "r%d", i); + sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence); + } + } else { + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0) + sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence); + if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1) + sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence); + } + } + + printf("\n"); +} + +static void PrintModules(const CodeModules *modules) { + if (!modules) + return; + + printf("\n"); + printf("Loaded modules:\n"); + + u_int64_t main_address = 0; + const CodeModule *main_module = modules->GetMainModule(); + if (main_module) { + main_address = main_module->base_address(); + } + + unsigned int module_count = modules->module_count(); + for (unsigned int module_sequence = 0; + module_sequence < module_count; + ++module_sequence) { + const CodeModule *module = modules->GetModuleAtSequence(module_sequence); + assert(module); + u_int64_t base_address = module->base_address(); + printf("0x%08llx - 0x%08llx %s %s%s %s\n", + base_address, base_address + module->size() - 1, + PathnameStripper::File(module->code_file()).c_str(), + module->version().empty() ? "???" : module->version().c_str(), + main_module != NULL && base_address == main_address ? + " (main)" : "", + module->code_file().c_str()); + } +} + +static void ProcessSingleReport(Options *options, NSString *file_path) { + string minidump_file([file_path fileSystemRepresentation]); + BasicSourceLineResolver resolver; + string search_dir = options->searchDir ? + [options->searchDir fileSystemRepresentation] : ""; + string symbol_search_dir = options->symbolSearchDir ? + [options->symbolSearchDir fileSystemRepresentation] : ""; + scoped_ptr<OnDemandSymbolSupplier> symbol_supplier( + new OnDemandSymbolSupplier(search_dir, symbol_search_dir)); + scoped_ptr<MinidumpProcessor> + minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver)); + ProcessState process_state; + scoped_ptr<Minidump> dump(new google_breakpad::Minidump(minidump_file)); + + if (!dump->Read()) { + fprintf(stderr, "Minidump %s could not be read\n", dump->path().c_str()); + return; + } + if (minidump_processor->Process(dump.get(), &process_state) != + google_breakpad::PROCESS_OK) { + fprintf(stderr, "MinidumpProcessor::Process failed\n"); + return; + } + + const SystemInfo *system_info = process_state.system_info(); + string cpu = system_info->cpu; + + // Convert the time to a string + u_int32_t time_date_stamp = process_state.time_date_stamp(); + struct tm timestruct; + gmtime_r(reinterpret_cast<time_t*>(&time_date_stamp), ×truct); + char timestr[20]; + strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); + printf("Date: %s GMT\n", timestr); + + printf("Operating system: %s (%s)\n", system_info->os.c_str(), + system_info->os_version.c_str()); + printf("Architecture: %s\n", cpu.c_str()); + + if (process_state.crashed()) { + printf("Crash reason: %s\n", process_state.crash_reason().c_str()); + printf("Crash address: 0x%llx\n", process_state.crash_address()); + } else { + printf("No crash\n"); + } + + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread != -1) { + printf("\n"); + printf("Thread %d (%s)\n", + requesting_thread, + process_state.crashed() ? "crashed" : + "requested dump, did not crash"); + PrintStack(process_state.threads()->at(requesting_thread), cpu); + } + + // Print all of the threads in the dump. + int thread_count = static_cast<int>(process_state.threads()->size()); + const std::vector<google_breakpad::MemoryRegion*> + *thread_memory_regions = process_state.thread_memory_regions(); + + for (int thread_index = 0; thread_index < thread_count; ++thread_index) { + if (thread_index != requesting_thread) { + // Don't print the crash thread again, it was already printed. + printf("\n"); + printf("Thread %d\n", thread_index); + PrintStack(process_state.threads()->at(thread_index), cpu); + google_breakpad::MemoryRegion *thread_stack_bytes = + thread_memory_regions->at(thread_index); + if (options->printThreadMemory) { + thread_stack_bytes->Print(); + } + } + } + + // Print the crashed registers + if (requesting_thread != -1) { + printf("\nThread %d:", requesting_thread); + PrintRegisters(process_state.threads()->at(requesting_thread), cpu); + } + + // Print information about modules + PrintModules(process_state.modules()); +} + +//============================================================================= +static void Start(Options *options) { + NSFileManager *manager = [NSFileManager defaultManager]; + NSString *minidump_path = options->minidumpPath; + BOOL is_dir = NO; + BOOL file_exists = [manager fileExistsAtPath:minidump_path + isDirectory:&is_dir]; + if (file_exists && is_dir) { + NSDirectoryEnumerator *enumerator = + [manager enumeratorAtPath:minidump_path]; + NSString *current_file = nil; + while ((current_file = [enumerator nextObject])) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if ([[current_file pathExtension] isEqualTo:@"dmp"]) { + printf("Attempting to process report: %s\n", + [current_file cStringUsingEncoding:NSASCIIStringEncoding]); + NSString *full_path = + [minidump_path stringByAppendingPathComponent:current_file]; + ProcessSingleReport(options, full_path); + } + [pool release]; + } + } else if (file_exists) { + ProcessSingleReport(options, minidump_path); + } +} + +//============================================================================= +static void Usage(int argc, const char *argv[]) { + fprintf(stderr, "Convert a minidump to a crash report. Breakpad symbol " + "files will be used (or created if missing) in /tmp.\n" + "If a symbol-file-search-dir is specified, any symbol " + "files in it will be used instead of being loaded from " + "modules on disk.\n" + "If modules cannot be found at the paths stored in the " + "minidump file, they will be searched for at " + "<module-search-dir>/<path-in-minidump-file>.\n"); + fprintf(stderr, "Usage: %s [-s module-search-dir] [-S symbol-file-search-dir] " + "minidump-file\n", argv[0]); + fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n" + "\t-S: Specify a search directory to use for symbol files\n" + "\t-t: Print thread stack memory in hex\n" + "\t-h: Usage\n" + "\t-?: Usage\n"); +} + +//============================================================================= +static void SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "S:s:ht?")) != -1) { + switch (ch) { + case 's': + options->searchDir = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:optarg + length:strlen(optarg)]; + break; + + case 'S': + options->symbolSearchDir = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:optarg + length:strlen(optarg)]; + break; + + case 't': + options->printThreadMemory = YES; + break; + case 'h': + case '?': + Usage(argc, argv); + exit(1); + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "%s: Missing minidump file\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:argv[optind] + length:strlen(argv[optind])]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + [pool release]; + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..33204f7e2e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj @@ -0,0 +1,618 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; }; + 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */; }; + 4247E6402110D5A500482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4247E63F2110D5A500482558 /* path_helper.cc */; }; + 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; }; + 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; }; + 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; }; + 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */; }; + 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */; }; + 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722C126F9B6E00B43EAF /* x86_misc.c */; }; + 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */; }; + 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7234126F9BC200B43EAF /* ia32_settings.c */; }; + 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */; }; + 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */; settings = {COMPILER_FLAGS = "-Wno-error"; }; }; + 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725A126F9C8000B43EAF /* ia32_operand.c */; }; + 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C725C126F9C9200B43EAF /* x86_insn.c */; }; + 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */; }; + 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7263126F9CBB00B43EAF /* x86_imm.c */; }; + 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CA5613DFBA84006CABE3 /* md5.cc */; }; + 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; }; + 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */; }; + 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */; }; + 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */; }; + 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */; }; + 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */; }; + 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */; }; + 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8411F0C6FB00FCF3E4 /* language.cc */; }; + 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FF8611F0C6FB00FCF3E4 /* module.cc */; }; + 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */; }; + 8B40BDC00C0638E4009535AF /* logging.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B40BDBF0C0638E4009535AF /* logging.cc */; }; + 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; }; + 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; }; + 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; }; + 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; }; + 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; }; + 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; }; + 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; }; + 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; }; + 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; }; + 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; }; + 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; }; + 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */; }; + 9BE650B20B52FE3000611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AC0B52FE3000611104 /* file_id.cc */; }; + 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650AE0B52FE3000611104 /* macho_id.cc */; }; + 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650B00B52FE3000611104 /* macho_walker.cc */; }; + D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */; }; + D2A5DD631188658B00081F03 /* tokenize.cc in Sources */ = {isa = PBXBuildFile; fileRef = D2A5DD621188658B00081F03 /* tokenize.cc */; }; + F407DC48185773C10064622B /* exploitability_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC40185773C10064622B /* exploitability_linux.cc */; }; + F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC41185773C10064622B /* stack_frame_symbolizer.cc */; }; + F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC42185773C10064622B /* stackwalker_arm64.cc */; }; + F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC44185773C10064622B /* stackwalker_mips.cc */; }; + F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */ = {isa = PBXBuildFile; fileRef = F407DC46185773C10064622B /* stackwalker_ppc64.cc */; }; + F44DDD8719C85CD50047280E /* dump_context.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8419C85CD50047280E /* dump_context.cc */; }; + F44DDD8819C85CD50047280E /* dump_object.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8519C85CD50047280E /* dump_object.cc */; }; + F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = F44DDD8619C85CD50047280E /* microdump_processor.cc */; }; + F47180561D745DEF0032F208 /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180541D745DEF0032F208 /* elf_reader.cc */; }; + F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180571D7467630032F208 /* proc_maps_linux.cc */; }; + F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = F47180591D7468A40032F208 /* symbolic_constants_win.cc */; }; + F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */ = {isa = PBXBuildFile; fileRef = F4D43B2E1A38490700C290B2 /* microdump.cc */; }; + F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE20E8ABCA600E953AD /* bytereader.cc */; }; + F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */; }; + F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */; }; + F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */; }; + FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */; }; + FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */ = {isa = PBXBuildFile; fileRef = FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = "<group>"; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; }; + 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; }; + 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_old_arm64_context.cc; path = ../../../processor/convert_old_arm64_context.cc; sourceTree = "<group>"; }; + 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert_old_arm64_context.h; path = ../../../processor/convert_old_arm64_context.h; sourceTree = "<group>"; }; + 4247E63E2110D5A500482558 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; }; + 4247E63F2110D5A500482558 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; }; + 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; }; + 4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; }; + 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; }; + 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = disassembler_x86.cc; path = ../../../processor/disassembler_x86.cc; sourceTree = SOURCE_ROOT; }; + 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_disasm.c; path = ../../../third_party/libdisasm/x86_disasm.c; sourceTree = SOURCE_ROOT; }; + 4D2C722C126F9B6E00B43EAF /* x86_misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_misc.c; path = ../../../third_party/libdisasm/x86_misc.c; sourceTree = SOURCE_ROOT; }; + 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_operand_list.c; path = ../../../third_party/libdisasm/x86_operand_list.c; sourceTree = SOURCE_ROOT; }; + 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_invariant.c; path = ../../../third_party/libdisasm/ia32_invariant.c; sourceTree = SOURCE_ROOT; }; + 4D2C7234126F9BC200B43EAF /* ia32_settings.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_settings.c; path = ../../../third_party/libdisasm/ia32_settings.c; sourceTree = SOURCE_ROOT; }; + 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_insn.c; path = ../../../third_party/libdisasm/ia32_insn.c; sourceTree = SOURCE_ROOT; }; + 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_opcode_tables.c; path = ../../../third_party/libdisasm/ia32_opcode_tables.c; sourceTree = SOURCE_ROOT; }; + 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_implicit.c; path = ../../../third_party/libdisasm/ia32_implicit.c; sourceTree = SOURCE_ROOT; }; + 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_reg.c; path = ../../../third_party/libdisasm/ia32_reg.c; sourceTree = SOURCE_ROOT; }; + 4D2C725A126F9C8000B43EAF /* ia32_operand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_operand.c; path = ../../../third_party/libdisasm/ia32_operand.c; sourceTree = SOURCE_ROOT; }; + 4D2C725C126F9C9200B43EAF /* x86_insn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_insn.c; path = ../../../third_party/libdisasm/x86_insn.c; sourceTree = SOURCE_ROOT; }; + 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ia32_modrm.c; path = ../../../third_party/libdisasm/ia32_modrm.c; sourceTree = SOURCE_ROOT; }; + 4D2C7263126F9CBB00B43EAF /* x86_imm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = x86_imm.c; path = ../../../third_party/libdisasm/x86_imm.c; sourceTree = SOURCE_ROOT; }; + 4D72CA5613DFBA84006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; + 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; + 5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; + 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; + 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; + 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; + 8B31FF8411F0C6FB00FCF3E4 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF8511F0C6FB00FCF3E4 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; + 8B31FF8611F0C6FB00FCF3E4 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; + 8B31FF8711F0C6FB00FCF3E4 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; + 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; + 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; + 8B40BDBF0C0638E4009535AF /* logging.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = logging.cc; path = ../../../processor/logging.cc; sourceTree = SOURCE_ROOT; }; + 8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; }; + 9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; }; + 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; }; + 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; }; + 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = "<group>"; }; + 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = "<group>"; }; + 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; }; + 9B44619D0B66C66B00BBB817 /* system_info.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = system_info.h; sourceTree = "<group>"; }; + 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = breakpad_types.h; sourceTree = "<group>"; }; + 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = "<group>"; }; + 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = "<group>"; }; + 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = "<group>"; }; + 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = "<group>"; }; + 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = "<group>"; }; + 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = "<group>"; }; + 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = "<group>"; }; + 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = "<group>"; }; + 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = "<group>"; }; + 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = "<group>"; }; + 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; }; + 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; }; + 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; }; + 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; }; + 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; }; + 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = "<group>"; }; + 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = "<group>"; }; + 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; }; + 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = SOURCE_ROOT; }; + 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; }; + 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; }; + 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; }; + 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; }; + 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; }; + 9BE650AC0B52FE3000611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650AD0B52FE3000611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650AE0B52FE3000611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650AF0B52FE3000611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650B00B52FE3000611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; + 9BE650B10B52FE3000611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; + D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_frame_info.cc; path = ../../../processor/cfi_frame_info.cc; sourceTree = SOURCE_ROOT; }; + D2A5DD621188658B00081F03 /* tokenize.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = tokenize.cc; path = ../../../processor/tokenize.cc; sourceTree = SOURCE_ROOT; }; + F407DC40185773C10064622B /* exploitability_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_linux.cc; path = ../../../processor/exploitability_linux.cc; sourceTree = "<group>"; }; + F407DC41185773C10064622B /* stack_frame_symbolizer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stack_frame_symbolizer.cc; path = ../../../processor/stack_frame_symbolizer.cc; sourceTree = "<group>"; }; + F407DC42185773C10064622B /* stackwalker_arm64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm64.cc; path = ../../../processor/stackwalker_arm64.cc; sourceTree = "<group>"; }; + F407DC43185773C10064622B /* stackwalker_arm64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm64.h; path = ../../../processor/stackwalker_arm64.h; sourceTree = "<group>"; }; + F407DC44185773C10064622B /* stackwalker_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_mips.cc; path = ../../../processor/stackwalker_mips.cc; sourceTree = "<group>"; }; + F407DC45185773C10064622B /* stackwalker_mips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_mips.h; path = ../../../processor/stackwalker_mips.h; sourceTree = "<group>"; }; + F407DC46185773C10064622B /* stackwalker_ppc64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc64.cc; path = ../../../processor/stackwalker_ppc64.cc; sourceTree = "<group>"; }; + F407DC47185773C10064622B /* stackwalker_ppc64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_ppc64.h; path = ../../../processor/stackwalker_ppc64.h; sourceTree = "<group>"; }; + F44DDD8419C85CD50047280E /* dump_context.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_context.cc; path = ../../../processor/dump_context.cc; sourceTree = "<group>"; }; + F44DDD8519C85CD50047280E /* dump_object.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dump_object.cc; path = ../../../processor/dump_object.cc; sourceTree = "<group>"; }; + F44DDD8619C85CD50047280E /* microdump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump_processor.cc; path = ../../../processor/microdump_processor.cc; sourceTree = "<group>"; }; + F44DDD8A19C85CFB0047280E /* dump_context.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_context.h; path = ../../../google_breakpad/processor/dump_context.h; sourceTree = "<group>"; }; + F44DDD8B19C85CFB0047280E /* dump_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dump_object.h; path = ../../../google_breakpad/processor/dump_object.h; sourceTree = "<group>"; }; + F44DDD8C19C85CFC0047280E /* microdump_processor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump_processor.h; path = ../../../google_breakpad/processor/microdump_processor.h; sourceTree = "<group>"; }; + F44DDD8D19C85CFC0047280E /* process_result.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = process_result.h; path = ../../../google_breakpad/processor/process_result.h; sourceTree = "<group>"; }; + F47180541D745DEF0032F208 /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; }; + F47180551D745DEF0032F208 /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; }; + F47180571D7467630032F208 /* proc_maps_linux.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proc_maps_linux.cc; path = ../../../processor/proc_maps_linux.cc; sourceTree = "<group>"; }; + F47180591D7468A40032F208 /* symbolic_constants_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = symbolic_constants_win.cc; path = ../../../processor/symbolic_constants_win.cc; sourceTree = "<group>"; }; + F4D43B2E1A38490700C290B2 /* microdump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = microdump.cc; path = ../../../processor/microdump.cc; sourceTree = "<group>"; }; + F4D43B301A38492000C290B2 /* microdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = microdump.h; path = ../../../google_breakpad/processor/microdump.h; sourceTree = "<group>"; }; + F9C7ECE20E8ABCA600E953AD /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; + F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; + F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; }; + F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_arm.cc; path = ../../../processor/stackwalker_arm.cc; sourceTree = SOURCE_ROOT; }; + F9F0706610FBC02D0037B88B /* stackwalker_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_arm.h; path = ../../../processor/stackwalker_arm.h; sourceTree = SOURCE_ROOT; }; + FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_amd64.cc; path = ../../../processor/stackwalker_amd64.cc; sourceTree = SOURCE_ROOT; }; + FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stackwalker_amd64.h; path = ../../../processor/stackwalker_amd64.h; sourceTree = SOURCE_ROOT; }; + FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_sparc.cc; path = ../../../processor/stackwalker_sparc.cc; sourceTree = SOURCE_ROOT; }; + FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = stackwalker_sparc.h; path = ../../../processor/stackwalker_sparc.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* crash_report */ = { + isa = PBXGroup; + children = ( + 4214B7FE211109A600B769FA /* convert_old_arm64_context.cc */, + 4214B7FF211109A600B769FA /* convert_old_arm64_context.h */, + 4247E63F2110D5A500482558 /* path_helper.cc */, + 4247E63E2110D5A500482558 /* path_helper.h */, + 8B31025311F0D2D400FCF3E4 /* Breakpad.xcconfig */, + 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */, + F9C7ECE10E8ABC7F00E953AD /* DWARF */, + 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */, + 162F64FD161C5ECB00CD68D5 /* arch_utilities.h */, + 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */, + 5578003F0BE1F28500EC23E0 /* macho_utilities.h */, + 8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */, + 8B31FF7311F0C6E000FCF3E4 /* macho_reader.h */, + 9BDF192D0B1BC15D00F8391B /* dump_syms.h */, + 9BDF192E0B1BC15D00F8391B /* dump_syms.cc */, + 08FB7796FE84155DC02AAC07 /* crash_report.mm */, + F44DDD8D19C85CFC0047280E /* process_result.h */, + 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */, + F44DDD8419C85CD50047280E /* dump_context.cc */, + F44DDD8A19C85CFB0047280E /* dump_context.h */, + F44DDD8519C85CD50047280E /* dump_object.cc */, + F44DDD8B19C85CFB0047280E /* dump_object.h */, + F4D43B2E1A38490700C290B2 /* microdump.cc */, + F4D43B301A38492000C290B2 /* microdump.h */, + F44DDD8619C85CD50047280E /* microdump_processor.cc */, + F44DDD8C19C85CFC0047280E /* microdump_processor.h */, + 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */, + 8B31FF2411F0C62700FCF3E4 /* dwarf_cfi_to_module.cc */, + 8B31FF2511F0C62700FCF3E4 /* dwarf_cfi_to_module.h */, + 8B31FF2611F0C62700FCF3E4 /* dwarf_cu_to_module.cc */, + 8B31FF2711F0C62700FCF3E4 /* dwarf_cu_to_module.h */, + 8B31FF2811F0C62700FCF3E4 /* dwarf_line_to_module.cc */, + 8B31FF2911F0C62700FCF3E4 /* dwarf_line_to_module.h */, + 8B31FF3D11F0C64400FCF3E4 /* stabs_reader.cc */, + 8B31FF3E11F0C64400FCF3E4 /* stabs_reader.h */, + 8B31FF3F11F0C64400FCF3E4 /* stabs_to_module.cc */, + 8B31FF4011F0C64400FCF3E4 /* stabs_to_module.h */, + 8B31FF8411F0C6FB00FCF3E4 /* language.cc */, + 8B31FF8511F0C6FB00FCF3E4 /* language.h */, + 4D72CA5613DFBA84006CABE3 /* md5.cc */, + 8B31FF8611F0C6FB00FCF3E4 /* module.cc */, + 8B31FF8711F0C6FB00FCF3E4 /* module.h */, + 08FB7795FE84155DC02AAC07 /* breakpad */, + 4D2C726E126F9CE200B43EAF /* libdisasm */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = crash_report; + sourceTree = "<group>"; + }; + 08FB7795FE84155DC02AAC07 /* breakpad */ = { + isa = PBXGroup; + children = ( + 9BE650AB0B52FE1A00611104 /* common */, + 9BDF17280B1B8B0200F8391B /* processor */, + 9BDF16F70B1B8ACD00F8391B /* google_breakpad */, + ); + name = breakpad; + sourceTree = "<group>"; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = "<group>"; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* crash_report */, + ); + name = Products; + sourceTree = "<group>"; + }; + 4D2C726E126F9CE200B43EAF /* libdisasm */ = { + isa = PBXGroup; + children = ( + 4D2C7226126F9B0F00B43EAF /* disassembler_x86.cc */, + 4D2C724B126F9C3800B43EAF /* ia32_implicit.c */, + 4D2C7245126F9C0B00B43EAF /* ia32_insn.c */, + 4D2C7232126F9BB000B43EAF /* ia32_invariant.c */, + 4D2C7261126F9CBB00B43EAF /* ia32_modrm.c */, + 4D2C7249126F9C2300B43EAF /* ia32_opcode_tables.c */, + 4D2C725A126F9C8000B43EAF /* ia32_operand.c */, + 4D2C724D126F9C4D00B43EAF /* ia32_reg.c */, + 4D2C7234126F9BC200B43EAF /* ia32_settings.c */, + 4D2C722A126F9B5A00B43EAF /* x86_disasm.c */, + 4D2C7263126F9CBB00B43EAF /* x86_imm.c */, + 4D2C725C126F9C9200B43EAF /* x86_insn.c */, + 4D2C722C126F9B6E00B43EAF /* x86_misc.c */, + 4D2C722E126F9B8300B43EAF /* x86_operand_list.c */, + ); + name = libdisasm; + sourceTree = "<group>"; + }; + 9BDF16F70B1B8ACD00F8391B /* google_breakpad */ = { + isa = PBXGroup; + children = ( + 9BDF16F80B1B8ACD00F8391B /* common */, + 9BDF16FB0B1B8ACD00F8391B /* processor */, + ); + name = google_breakpad; + path = ../../../google_breakpad; + sourceTree = SOURCE_ROOT; + }; + 9BDF16F80B1B8ACD00F8391B /* common */ = { + isa = PBXGroup; + children = ( + 9BDF16F90B1B8ACD00F8391B /* breakpad_types.h */, + 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */, + ); + path = common; + sourceTree = "<group>"; + }; + 9BDF16FB0B1B8ACD00F8391B /* processor */ = { + isa = PBXGroup; + children = ( + 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */, + 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */, + 9B35FEE20B2675F9008DE8C7 /* code_module.h */, + 9B35FEE30B2675F9008DE8C7 /* code_modules.h */, + 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */, + 9BDF16FE0B1B8ACD00F8391B /* minidump.h */, + 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */, + 9BDF17000B1B8ACD00F8391B /* process_state.h */, + 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */, + 9BDF17010B1B8ACD00F8391B /* stack_frame.h */, + 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */, + 9BDF17030B1B8ACD00F8391B /* stackwalker.h */, + 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */, + 9B44619D0B66C66B00BBB817 /* system_info.h */, + ); + path = processor; + sourceTree = "<group>"; + }; + 9BDF17280B1B8B0200F8391B /* processor */ = { + isa = PBXGroup; + children = ( + 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */, + F407DC40185773C10064622B /* exploitability_linux.cc */, + F407DC41185773C10064622B /* stack_frame_symbolizer.cc */, + F407DC42185773C10064622B /* stackwalker_arm64.cc */, + F407DC43185773C10064622B /* stackwalker_arm64.h */, + F407DC44185773C10064622B /* stackwalker_mips.cc */, + F407DC45185773C10064622B /* stackwalker_mips.h */, + F407DC46185773C10064622B /* stackwalker_ppc64.cc */, + F407DC47185773C10064622B /* stackwalker_ppc64.h */, + 4D2C721E126F9ADE00B43EAF /* exploitability.cc */, + 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */, + D2A5DD621188658B00081F03 /* tokenize.cc */, + D2A5DD4C1188651100081F03 /* cfi_frame_info.cc */, + F9F0706510FBC02D0037B88B /* stackwalker_arm.cc */, + F9F0706610FBC02D0037B88B /* stackwalker_arm.h */, + 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */, + 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */, + 9BDF1AFB0B1BEB6300F8391B /* address_map.h */, + 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */, + 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */, + 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */, + 9BDF172A0B1B8B2400F8391B /* call_stack.cc */, + 8B40BDBF0C0638E4009535AF /* logging.cc */, + 9BDF173F0B1B8B9A00F8391B /* minidump.cc */, + 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */, + 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */, + F47180571D7467630032F208 /* proc_maps_linux.cc */, + 9BDF175B0B1B8C1B00F8391B /* process_state.cc */, + 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */, + 9BDF1A7B0B1BE30100F8391B /* range_map.h */, + 9BDF17530B1B8BF900F8391B /* stackwalker.cc */, + 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */, + 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */, + FD8EDEAC0CADDAD400A5EDF1 /* stackwalker_sparc.cc */, + FD8EDEAD0CADDAD400A5EDF1 /* stackwalker_sparc.h */, + FD6625C40CF4D438004AC844 /* stackwalker_amd64.cc */, + FD6625C50CF4D438004AC844 /* stackwalker_amd64.h */, + F47180591D7468A40032F208 /* symbolic_constants_win.cc */, + ); + name = processor; + sourceTree = "<group>"; + }; + 9BE650AB0B52FE1A00611104 /* common */ = { + isa = PBXGroup; + children = ( + 9BE650AC0B52FE3000611104 /* file_id.cc */, + 9BE650AD0B52FE3000611104 /* file_id.h */, + 9BE650AE0B52FE3000611104 /* macho_id.cc */, + 9BE650AF0B52FE3000611104 /* macho_id.h */, + 9BE650B00B52FE3000611104 /* macho_walker.cc */, + 9BE650B10B52FE3000611104 /* macho_walker.h */, + ); + name = common; + sourceTree = "<group>"; + }; + F9C7ECE10E8ABC7F00E953AD /* DWARF */ = { + isa = PBXGroup; + children = ( + F9C7ECE20E8ABCA600E953AD /* bytereader.cc */, + F9C7ECE30E8ABCA600E953AD /* dwarf2reader.cc */, + 8B31FFC311F0C8AB00FCF3E4 /* dwarf2diehandler.cc */, + 8B31FFC411F0C8AB00FCF3E4 /* dwarf2diehandler.h */, + F47180541D745DEF0032F208 /* elf_reader.cc */, + F47180551D745DEF0032F208 /* elf_reader.h */, + F9C7ECE40E8ABCA600E953AD /* functioninfo.cc */, + ); + name = DWARF; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* crash_report */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = crash_report; + productInstallPath = "$(HOME)/bin"; + productName = crash_report; + productReference = 8DD76FA10486AA7600D96B5E /* crash_report */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + }; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* crash_report */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */, + 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */, + F47180581D7467630032F208 /* proc_maps_linux.cc in Sources */, + 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */, + 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */, + 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */, + F44DDD8719C85CD50047280E /* dump_context.cc in Sources */, + 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */, + 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */, + 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */, + 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */, + F47180561D745DEF0032F208 /* elf_reader.cc in Sources */, + 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */, + 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */, + 9BDF21A70B1E825400F8391B /* dump_syms.cc in Sources */, + 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */, + 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */, + 9BE650B20B52FE3000611104 /* file_id.cc in Sources */, + 9BE650B40B52FE3000611104 /* macho_id.cc in Sources */, + 9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */, + 557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */, + 8B40BDC00C0638E4009535AF /* logging.cc in Sources */, + FD8EDEAE0CADDAD400A5EDF1 /* stackwalker_sparc.cc in Sources */, + FD6625CD0CF4D45C004AC844 /* stackwalker_amd64.cc in Sources */, + F9C7ECE50E8ABCA600E953AD /* bytereader.cc in Sources */, + F9C7ECE60E8ABCA600E953AD /* dwarf2reader.cc in Sources */, + F9C7ECE70E8ABCA600E953AD /* functioninfo.cc in Sources */, + F9F0706710FBC02D0037B88B /* stackwalker_arm.cc in Sources */, + D2A5DD4D1188651100081F03 /* cfi_frame_info.cc in Sources */, + D2A5DD631188658B00081F03 /* tokenize.cc in Sources */, + 8B31FF2A11F0C62700FCF3E4 /* dwarf_cfi_to_module.cc in Sources */, + F4D43B2F1A38490700C290B2 /* microdump.cc in Sources */, + 8B31FF2B11F0C62700FCF3E4 /* dwarf_cu_to_module.cc in Sources */, + F44DDD8819C85CD50047280E /* dump_object.cc in Sources */, + 8B31FF2C11F0C62700FCF3E4 /* dwarf_line_to_module.cc in Sources */, + 8B31FF4111F0C64400FCF3E4 /* stabs_reader.cc in Sources */, + 8B31FF4211F0C64400FCF3E4 /* stabs_to_module.cc in Sources */, + 8B31FF7411F0C6E000FCF3E4 /* macho_reader.cc in Sources */, + 8B31FF8811F0C6FB00FCF3E4 /* language.cc in Sources */, + 8B31FF8911F0C6FB00FCF3E4 /* module.cc in Sources */, + 8B31FFC511F0C8AB00FCF3E4 /* dwarf2diehandler.cc in Sources */, + F407DC49185773C10064622B /* stack_frame_symbolizer.cc in Sources */, + F471805A1D7468A40032F208 /* symbolic_constants_win.cc in Sources */, + 4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */, + 4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */, + 4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */, + 4D2C7227126F9B0F00B43EAF /* disassembler_x86.cc in Sources */, + F407DC48185773C10064622B /* exploitability_linux.cc in Sources */, + 4214B800211109A600B769FA /* convert_old_arm64_context.cc in Sources */, + 4D2C722B126F9B5A00B43EAF /* x86_disasm.c in Sources */, + 4D2C722D126F9B6E00B43EAF /* x86_misc.c in Sources */, + 4D2C722F126F9B8300B43EAF /* x86_operand_list.c in Sources */, + F407DC4A185773C10064622B /* stackwalker_arm64.cc in Sources */, + 4D2C7233126F9BB000B43EAF /* ia32_invariant.c in Sources */, + 4D2C7235126F9BC200B43EAF /* ia32_settings.c in Sources */, + 4D2C7246126F9C0B00B43EAF /* ia32_insn.c in Sources */, + 4D2C724A126F9C2300B43EAF /* ia32_opcode_tables.c in Sources */, + 4D2C724C126F9C3800B43EAF /* ia32_implicit.c in Sources */, + 4247E6402110D5A500482558 /* path_helper.cc in Sources */, + F44DDD8919C85CD50047280E /* microdump_processor.cc in Sources */, + 4D2C724E126F9C4D00B43EAF /* ia32_reg.c in Sources */, + 4D2C725B126F9C8000B43EAF /* ia32_operand.c in Sources */, + F407DC4C185773C10064622B /* stackwalker_ppc64.cc in Sources */, + 4D2C725D126F9C9200B43EAF /* x86_insn.c in Sources */, + 4D2C7264126F9CBB00B43EAF /* ia32_modrm.c in Sources */, + F407DC4B185773C10064622B /* stackwalker_mips.cc in Sources */, + 4D2C726D126F9CDC00B43EAF /* x86_imm.c in Sources */, + 4D72CA5713DFBA84006CABE3 /* md5.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ../../../../src; + PRODUCT_NAME = crash_report; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ../../../../src; + PRODUCT_NAME = crash_report; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h new file mode 100644 index 0000000000..3fbe108ebd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.h @@ -0,0 +1,111 @@ +// Copyright (c) 2006, 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. + +// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create +// a breakpad symbol file on demand. + +#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ +#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ + +#include <map> +#include <string> +#include "google_breakpad/processor/symbol_supplier.h" + +namespace google_breakpad { + +using std::map; +using std::string; +class MinidumpModule; + +class OnDemandSymbolSupplier : public SymbolSupplier { + public: + // |search_dir| is the directory to search for alternative symbols with + // the same name as the module in the minidump + OnDemandSymbolSupplier(const string &search_dir, + const string &symbol_search_dir); + virtual ~OnDemandSymbolSupplier() {} + + // Returns the path to the symbol file for the given module. + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file); + + // Returns the path to the symbol file for the given module. + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data); + // Allocates data buffer on heap, and takes the ownership of + // the data buffer. + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size); + + // Delete the data buffer allocated for module in GetCStringSymbolData(). + virtual void FreeSymbolData(const CodeModule *module); + + protected: + // Search directory + string search_dir_; + string symbol_search_dir_; + + // When we create a symbol file for a module, save the name of the module + // and the path to that module's symbol file. + map<string, string> module_file_map_; + + // Map of allocated data buffers, keyed by module->code_file(). + map<string, char *> memory_buffers_; + + // Return the name for |module| This will be the value used as the key + // to the |module_file_map_|. + string GetNameForModule(const CodeModule *module); + + // Find the module on local system. If the module resides in a different + // location than the full path in the minidump, this will be the location + // used. + string GetLocalModulePath(const CodeModule *module); + + // Return the full path for |module|. + string GetModulePath(const CodeModule *module); + + // Return the path to the symbol file for |module|. If an empty string is + // returned, then |module| doesn't have a symbol file. + string GetModuleSymbolFile(const CodeModule *module); + + // Generate the breakpad symbol file for |module|. Return true if successful. + // File is generated in /tmp. + bool GenerateSymbolFile(const CodeModule *module, + const SystemInfo *system_info); +}; + +} // namespace google_breakpad + +#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm new file mode 100644 index 0000000000..1955d2667b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm @@ -0,0 +1,314 @@ +// Copyright (c) 2006, 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. + +#import <Foundation/Foundation.h> +#include <sys/stat.h> +#include <map> +#include <string> +#include <iostream> +#include <fstream> +#include <utility> + +#include "google_breakpad/processor/basic_source_line_resolver.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/pathname_stripper.h" + +#include "on_demand_symbol_supplier.h" +#include "common/mac/dump_syms.h" + +using std::map; +using std::string; + +using google_breakpad::OnDemandSymbolSupplier; +using google_breakpad::PathnameStripper; +using google_breakpad::SymbolSupplier; +using google_breakpad::SystemInfo; + +OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &search_dir, + const string &symbol_search_dir) + : search_dir_(search_dir) { + NSFileManager *mgr = [NSFileManager defaultManager]; + size_t length = symbol_search_dir.length(); + if (length) { + // Load all sym files in symbol_search_dir into our module_file_map + // A symbol file always starts with a line like this: + // MODULE mac x86 BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + // or + // MODULE mac ppc BBF0A8F9BEADDD2048E6464001CA193F0 GoogleDesktopDaemon + const char *symbolSearchStr = symbol_search_dir.c_str(); + NSString *symbolSearchPath = + [mgr stringWithFileSystemRepresentation:symbolSearchStr + length:strlen(symbolSearchStr)]; + NSDirectoryEnumerator *dirEnum = [mgr enumeratorAtPath:symbolSearchPath]; + NSString *fileName; + NSCharacterSet *hexSet = + [NSCharacterSet characterSetWithCharactersInString:@"0123456789ABCDEF"]; + NSCharacterSet *newlineSet = + [NSCharacterSet characterSetWithCharactersInString:@"\r\n"]; + while ((fileName = [dirEnum nextObject])) { + // Check to see what type of file we have + NSDictionary *attrib = [dirEnum fileAttributes]; + NSString *fileType = [attrib objectForKey:NSFileType]; + if ([fileType isEqualToString:NSFileTypeDirectory]) { + // Skip subdirectories + [dirEnum skipDescendents]; + } else { + NSString *filePath = [symbolSearchPath stringByAppendingPathComponent:fileName]; + NSString *dataStr = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; + if (dataStr) { + // Check file to see if it is of appropriate type, and grab module + // name. + NSScanner *scanner = [NSScanner scannerWithString:dataStr]; + BOOL goodScan = [scanner scanString:@"MODULE mac " intoString:nil]; + if (goodScan) { + goodScan = ([scanner scanString:@"x86 " intoString:nil] || + [scanner scanString:@"x86_64 " intoString:nil] || + [scanner scanString:@"ppc " intoString:nil]); + if (goodScan) { + NSString *moduleID; + goodScan = [scanner scanCharactersFromSet:hexSet + intoString:&moduleID]; + if (goodScan) { + // Module IDs are always 33 chars long + goodScan = [moduleID length] == 33; + if (goodScan) { + NSString *moduleName; + goodScan = [scanner scanUpToCharactersFromSet:newlineSet + intoString:&moduleName]; + if (goodScan) { + goodScan = [moduleName length] > 0; + if (goodScan) { + const char *moduleNameStr = [moduleName UTF8String]; + const char *filePathStr = [filePath fileSystemRepresentation]; + // Map our file + module_file_map_[moduleNameStr] = filePathStr; + } + } + } + } + } + } + } + } + } + } +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) { + string path(GetModuleSymbolFile(module)); + + if (path.empty()) { + if (!GenerateSymbolFile(module, system_info)) + return NOT_FOUND; + + path = GetModuleSymbolFile(module); + } + + if (path.empty()) + return NOT_FOUND; + + *symbol_file = path; + return FOUND; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) { + SymbolSupplier::SymbolResult s = GetSymbolFile(module, + system_info, + symbol_file); + + + if (s == FOUND) { + std::ifstream in(symbol_file->c_str()); + getline(in, *symbol_data, std::string::traits_type::to_char_type( + std::string::traits_type::eof())); + in.close(); + } + + return s; +} + +SymbolSupplier::SymbolResult +OnDemandSymbolSupplier::GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) { + std::string symbol_data_string; + SymbolSupplier::SymbolResult result = GetSymbolFile(module, + system_info, + symbol_file, + &symbol_data_string); + if (result == FOUND) { + *symbol_data_size = symbol_data_string.size() + 1; + *symbol_data = new char[*symbol_data_size]; + if (*symbol_data == NULL) { + // Should return INTERRUPT on memory allocation failure. + return INTERRUPT; + } + memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size()); + (*symbol_data)[symbol_data_string.size()] = '\0'; + memory_buffers_.insert(make_pair(module->code_file(), *symbol_data)); + } + return result; +} + +void OnDemandSymbolSupplier::FreeSymbolData(const CodeModule *module) { + map<string, char *>::iterator it = memory_buffers_.find(module->code_file()); + if (it != memory_buffers_.end()) { + delete [] it->second; + memory_buffers_.erase(it); + } +} + +string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) { + NSFileManager *mgr = [NSFileManager defaultManager]; + const char *moduleStr = module->code_file().c_str(); + NSString *modulePath = + [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)]; + const char *searchStr = search_dir_.c_str(); + NSString *searchDir = + [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)]; + + if ([mgr fileExistsAtPath:modulePath]) + return module->code_file(); + + // If the module is not found, try to start appending the components to the + // search string and stop if a file (not dir) is found or all components + // have been appended + NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"]; + size_t count = [pathComponents count]; + NSMutableString *path = [NSMutableString string]; + + for (size_t i = 0; i < count; ++i) { + [path setString:searchDir]; + + for (size_t j = 0; j < i + 1; ++j) { + size_t idx = count - 1 - i + j; + [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]]; + } + + BOOL isDir; + if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) { + return [path fileSystemRepresentation]; + } + } + + return ""; +} + +string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) { + return module->code_file(); +} + +string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) { + return PathnameStripper::File(module->code_file()); +} + +string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) { + string name(GetNameForModule(module)); + map<string, string>::iterator result = module_file_map_.find(name); + + return (result == module_file_map_.end()) ? "" : (*result).second; +} + +static float GetFileModificationTime(const char *path) { + float result = 0; + struct stat file_stat; + if (stat(path, &file_stat) == 0) + result = (float)file_stat.st_mtimespec.tv_sec + + (float)file_stat.st_mtimespec.tv_nsec / 1.0e9f; + + return result; +} + +bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module, + const SystemInfo *system_info) { + bool result = true; + string name = GetNameForModule(module); + string module_path = GetLocalModulePath(module); + NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym", + name.c_str(), system_info->cpu.c_str()]; + + if (module_path.empty()) + return false; + + // Check if there's already a symbol file cached. Ensure that the file is + // newer than the module. Otherwise, generate a new one. + BOOL generate_file = YES; + if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) { + // Check if the module file is newer than the saved symbols + float cache_time = + GetFileModificationTime([symbol_path fileSystemRepresentation]); + float module_time = + GetFileModificationTime(module_path.c_str()); + + if (cache_time > module_time) + generate_file = NO; + } + + if (generate_file) { + DumpSymbols dump(ALL_SYMBOL_DATA, false); + if (dump.Read(module_path)) { + // What Breakpad calls "x86" should be given to the system as "i386". + std::string architecture; + if (system_info->cpu.compare("x86") == 0) { + architecture = "i386"; + } else { + architecture = system_info->cpu; + } + + if (dump.SetArchitecture(architecture)) { + std::fstream file([symbol_path fileSystemRepresentation], + std::ios_base::out | std::ios_base::trunc); + dump.WriteSymbolFile(file); + } else { + printf("Architecture %s not available for %s\n", + system_info->cpu.c_str(), name.c_str()); + result = false; + } + } else { + printf("Unable to open %s\n", module_path.c_str()); + result = false; + } + } + + // Add the mapping + if (result) + module_file_map_[name] = [symbol_path fileSystemRepresentation]; + + return result; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..5b644e24c8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj @@ -0,0 +1,1857 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXAggregateTarget section */ + B88FAFC9116BDCAD00407530 /* all_unittests */ = { + isa = PBXAggregateTarget; + buildConfigurationList = B88FAFCC116BDCCC00407530 /* Build configuration list for PBXAggregateTarget "all_unittests" */; + buildPhases = ( + B88FB094116CE73E00407530 /* ShellScript */, + ); + dependencies = ( + B88FB15B116CF53E00407530 /* PBXTargetDependency */, + B88FAFCF116BDD7000407530 /* PBXTargetDependency */, + B88FB01D116BDF9800407530 /* PBXTargetDependency */, + B88FB167116CF54B00407530 /* PBXTargetDependency */, + B88FAFD1116BDD7000407530 /* PBXTargetDependency */, + B88FB165116CF54B00407530 /* PBXTargetDependency */, + B88FB161116CF54B00407530 /* PBXTargetDependency */, + B88FB15F116CF54B00407530 /* PBXTargetDependency */, + B88FB15D116CF54B00407530 /* PBXTargetDependency */, + B84A9201116CF7D2006C210E /* PBXTargetDependency */, + B88FB0C8116CEB4A00407530 /* PBXTargetDependency */, + 8B31051511F100CF00FCF3E4 /* PBXTargetDependency */, + ); + name = all_unittests; + productName = all_unittests; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; }; + 162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; }; + 4247E63D2110D4B200482558 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; }; + 4262382721AC496F00E5A3A6 /* dwarf_range_list_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */; }; + 4262382821AC49A000E5A3A6 /* dwarf_range_list_handler.h in Sources */ = {isa = PBXBuildFile; fileRef = 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */; }; + 4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CAF413DFBAC2006CABE3 /* md5.cc */; }; + 8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; }; + 8BCAAA4D1CE3B1260046090B /* elf_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */; }; + B84A91F8116CF78F006C210E /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B84A91FB116CF7AF006C210E /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3C11666C8900407530 /* stabs_to_module.cc */; }; + B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */; }; + B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1711665FE400407530 /* dwarf2diehandler.cc */; }; + B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */; }; + B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE201166603300407530 /* dwarf_line_to_module.cc */; }; + B88FAE281166603300407530 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE221166603300407530 /* language.cc */; }; + B88FAE291166603300407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FAE2C1166606200407530 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */; }; + B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3911666C6F00407530 /* stabs_reader.cc */; }; + B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3C11666C8900407530 /* stabs_to_module.cc */; }; + B88FAF37116A595400407530 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF34116A595400407530 /* cfi_assembler.cc */; }; + B88FAF38116A595400407530 /* dwarf2reader_cfi_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */; }; + B88FAF3F116A5A2E00407530 /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */; }; + B88FAF40116A5A2E00407530 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B88FB00F116BDEA700407530 /* stabs_reader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */; }; + B88FB010116BDEA700407530 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3911666C6F00407530 /* stabs_reader.cc */; }; + B88FB028116BE03100407530 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; }; + B88FB029116BE03100407530 /* gmock-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA311665AEA00DD08C9 /* gmock-all.cc */; }; + B88FB02A116BE03100407530 /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E9F11665AC300DD08C9 /* gtest_main.cc */; }; + B88FB02B116BE03100407530 /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA011665AC300DD08C9 /* gtest-all.cc */; }; + B88FB03F116BE24200407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB042116BE3C400407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB057116C0CDE00407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0B5116CEA8A00407530 /* module_unittest.cc */; }; + B88FB0C1116CEB0600407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0C4116CEB4100407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB0E3116CEEB000407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1711665FE400407530 /* dwarf2diehandler.cc */; }; + B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */; }; + B88FB0F6116CEF2000407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE201166603300407530 /* dwarf_line_to_module.cc */; }; + B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */; }; + B88FB0FE116CF02400407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB10E116CF08100407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */; }; + B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */; }; + B88FB114116CF1F000407530 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE221166603300407530 /* language.cc */; }; + B88FB115116CF1F000407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB123116CF28500407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB129116CF2DD00407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; }; + B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */; }; + B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */; }; + B88FB139116CF31600407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAF34116A595400407530 /* cfi_assembler.cc */; }; + B88FB13E116CF38300407530 /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B88FB13F116CF38300407530 /* bytereader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */; }; + B88FB14F116CF4AE00407530 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + B88FB152116CF4D300407530 /* byte_cursor_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */; }; + B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E701166573700DD08C9 /* macho_dump.cc */; }; + B89E0E9911665A7200DD08C9 /* macho_reader_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */; }; + B89E0E9A11665A7200DD08C9 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; }; + B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */; }; + B8C5B5181166534700D34F4E /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; }; + B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */; }; + B8C5B51A1166534700D34F4E /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650410B52F6D800611104 /* file_id.cc */; }; + B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650430B52F6D800611104 /* macho_id.cc */; }; + B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650450B52F6D800611104 /* macho_walker.cc */; }; + B8C5B51D1166534700D34F4E /* dump_syms.cc in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dump_syms.cc */; }; + B8C5B51E1166534700D34F4E /* dump_syms_tool.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */; }; + B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */; }; + D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; }; + D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; }; + EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */ = {isa = PBXBuildFile; fileRef = EB06C7511FEBC515000214D9 /* path_helper.cc */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D21F97D111CBA0F200239E38; + remoteInfo = test_assembler_unittest; + }; + B84A91F9116CF796006C210E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B84A9200116CF7D2006C210E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B84A91F3116CF784006C210E; + remoteInfo = stabs_to_module_unittest; + }; + B88FAFCE116BDD7000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B89E0E9411665A6400DD08C9; + remoteInfo = macho_reader_unittest; + }; + B88FAFD0116BDD7000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FAF2E116A591D00407530; + remoteInfo = dwarf2reader_cfi_unittest; + }; + B88FB01C116BDF9800407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB006116BDE8300407530; + remoteInfo = stabs_reader_unittest; + }; + B88FB039116BE17E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB087116CE6D800407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB08F116CE71000407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0BF116CEAFE00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0C7116CEB4A00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0B8116CEABF00407530; + remoteInfo = module_unittest; + }; + B88FB0E7116CEEDA00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB0F7116CEF2E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB10F116CF08A00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB124116CF29E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB13B116CF35C00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB150116CF4C100407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB023116BDFFF00407530; + remoteInfo = gtestmockall; + }; + B88FB15A116CF53E00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB14A116CF4A700407530; + remoteInfo = byte_cursor_unittest; + }; + B88FB15C116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB11E116CF27F00407530; + remoteInfo = dwarf_cfi_to_module_unittest; + }; + B88FB15E116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0F1116CEF1900407530; + remoteInfo = dwarf_line_to_module_unittest; + }; + B88FB160116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB109116CF07900407530; + remoteInfo = dwarf_cu_to_module_unittest; + }; + B88FB164116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB0DE116CEEA800407530; + remoteInfo = dwarf2diehandler_unittest; + }; + B88FB166116CF54B00407530 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B88FB134116CF30F00407530; + remoteInfo = bytereader_unittest; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* dump_syms.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.cc; path = ../../../common/mac/dump_syms.cc; sourceTree = "<group>"; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 162F64F8161C591500CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; }; + 162F64F9161C591500CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; }; + 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_range_list_handler.cc; path = ../../../common/dwarf_range_list_handler.cc; sourceTree = "<group>"; }; + 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_range_list_handler.h; path = ../../../common/dwarf_range_list_handler.h; sourceTree = "<group>"; }; + 4D72CAF413DFBAC2006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; }; + 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; }; + 5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; }; + 8B31023E11F0CF1C00FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elf_reader.cc; path = ../../../common/dwarf/elf_reader.cc; sourceTree = "<group>"; }; + 8BCAAA4B1CE3A7980046090B /* elf_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elf_reader.h; path = ../../../common/dwarf/elf_reader.h; sourceTree = "<group>"; }; + 9BDF186D0B1BB43700F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; }; + 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = dump_syms_tool.cc; sourceTree = "<group>"; }; + 9BE650410B52F6D800611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650420B52F6D800611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650430B52F6D800611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; }; + 9BE650440B52F6D800611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; }; + 9BE650450B52F6D800611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; }; + 9BE650460B52F6D800611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; }; + B84A91F4116CF784006C210E /* stabs_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stabs_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FAE0911665B5700407530 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = SOURCE_ROOT; }; + B88FAE0A11665B5700407530 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = SOURCE_ROOT; }; + B88FAE1711665FE400407530 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; }; + B88FAE1811665FE400407530 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; }; + B88FAE1D1166603300407530 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = SOURCE_ROOT; }; + B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE201166603300407530 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE211166603300407530 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE221166603300407530 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; }; + B88FAE231166603300407530 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; }; + B88FAE241166603300407530 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE251166603300407530 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; }; + B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAE3911666C6F00407530 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; }; + B88FAE3A11666C6F00407530 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; }; + B88FAE3C11666C8900407530 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; }; + B88FAE3D11666C8900407530 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; }; + B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf2reader_cfi_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FAF34116A595400407530 /* cfi_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cfi_assembler.cc; path = ../../../common/dwarf/cfi_assembler.cc; sourceTree = SOURCE_ROOT; }; + B88FAF35116A595400407530 /* cfi_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cfi_assembler.h; path = ../../../common/dwarf/cfi_assembler.h; sourceTree = SOURCE_ROOT; }; + B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader_cfi_unittest.cc; path = ../../../common/dwarf/dwarf2reader_cfi_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader_unittest.cc; path = ../../../common/stabs_reader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB007116BDE8300407530 /* stabs_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stabs_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB024116BDFFF00407530 /* libgtestmockall.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtestmockall.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0B5116CEA8A00407530 /* module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module_unittest.cc; path = ../../../common/module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0B9116CEABF00407530 /* module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = byte_cursor_unittest.cc; path = ../../../common/byte_cursor_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module_unittest.cc; path = ../../../common/dwarf_cfi_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module_unittest.cc; path = ../../../common/dwarf_cu_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module_unittest.cc; path = ../../../common/dwarf_line_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module_unittest.cc; path = ../../../common/stabs_to_module_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler_unittest.cc; path = ../../../common/test_assembler_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader_unittest.cc; path = ../../../common/dwarf/bytereader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler_unittest.cc; path = ../../../common/dwarf/dwarf2diehandler_unittest.cc; sourceTree = SOURCE_ROOT; }; + B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf2diehandler_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_line_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_cu_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dwarf_cfi_to_module_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB135116CF30F00407530 /* bytereader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bytereader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B88FB14B116CF4A700407530 /* byte_cursor_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = byte_cursor_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader_unittest.cc; path = ../../../common/mac/macho_reader_unittest.cc; sourceTree = SOURCE_ROOT; }; + B89E0E6E1166571D00DD08C9 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; }; + B89E0E6F1166571D00DD08C9 /* macho_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macho_reader.h; path = ../../../common/mac/macho_reader.h; sourceTree = SOURCE_ROOT; }; + B89E0E701166573700DD08C9 /* macho_dump.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_dump.cc; sourceTree = "<group>"; }; + B89E0E741166575200DD08C9 /* macho_dump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_dump; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E9511665A6400DD08C9 /* macho_reader_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = macho_reader_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + B89E0E9F11665AC300DD08C9 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gtest_main.cc; path = ../../../testing/googletest/src/gtest_main.cc; sourceTree = SOURCE_ROOT; }; + B89E0EA011665AC300DD08C9 /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gtest-all.cc"; path = "../../../testing/googletest/src/gtest-all.cc"; sourceTree = SOURCE_ROOT; }; + B89E0EA311665AEA00DD08C9 /* gmock-all.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "gmock-all.cc"; path = "../../../testing/googlemock/src/gmock-all.cc"; sourceTree = SOURCE_ROOT; }; + B8C5B5111166531A00D34F4E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; }; + B8E8CA0C1156C854009E61B2 /* byteswap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byteswap.h; path = ../../../common/mac/byteswap.h; sourceTree = SOURCE_ROOT; }; + D21F97D211CBA0F200239E38 /* test_assembler_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_assembler_unittest; sourceTree = BUILT_PRODUCTS_DIR; }; + EB06C7511FEBC515000214D9 /* path_helper.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = path_helper.cc; path = ../../../common/path_helper.cc; sourceTree = "<group>"; }; + EB06C7521FEBC516000214D9 /* path_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = path_helper.h; path = ../../../common/path_helper.h; sourceTree = "<group>"; }; + F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "bytereader-inl.h"; path = "../../../common/dwarf/bytereader-inl.h"; sourceTree = SOURCE_ROOT; }; + F95B422C0E0E22D100DBDE83 /* bytereader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bytereader.cc; path = ../../../common/dwarf/bytereader.cc; sourceTree = SOURCE_ROOT; }; + F95B422D0E0E22D100DBDE83 /* bytereader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bytereader.h; path = ../../../common/dwarf/bytereader.h; sourceTree = SOURCE_ROOT; }; + F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2enums.h; path = ../../../common/dwarf/dwarf2enums.h; sourceTree = SOURCE_ROOT; }; + F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; }; + F95B42300E0E22D100DBDE83 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = SOURCE_ROOT; }; + F95B42310E0E22D100DBDE83 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B84A91F2116CF784006C210E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B84A91F8116CF78F006C210E /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FAF2D116A591D00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB042116BE3C400407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB005116BDE8300407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB03F116BE24200407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB022116BDFFF00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0B7116CEABF00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0C1116CEB0600407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0DD116CEEA800407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0E3116CEEB000407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0F0116CEF1900407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0F6116CEF2000407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB108116CF07900407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB10E116CF08100407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB11D116CF27F00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB123116CF28500407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB133116CF30F00407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB139116CF31600407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB149116CF4A700407530 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB14F116CF4AE00407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E721166575200DD08C9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E9311665A6400DD08C9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB057116C0CDE00407530 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B8C5B50F1166531A00D34F4E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B8C5B523116653BA00D34F4E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D21F97D011CBA0F200239E38 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D21F97D811CBA13D00239E38 /* libgtestmockall.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* dump_syms */ = { + isa = PBXGroup; + children = ( + 8B31023E11F0CF1C00FCF3E4 /* Breakpad.xcconfig */, + 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */, + B89E0E9D11665A9500DD08C9 /* TESTING */, + F9F5344B0E7C8FFC0012363F /* DWARF */, + B89E0E6C1166569700DD08C9 /* MACHO */, + B88FAE3811666A1700407530 /* STABS */, + B88FAE1C11665FFD00407530 /* MODULE */, + 162F64F8161C591500CD68D5 /* arch_utilities.cc */, + 162F64F9161C591500CD68D5 /* arch_utilities.h */, + B88FAE1D1166603300407530 /* byte_cursor.h */, + B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */, + B8E8CA0C1156C854009E61B2 /* byteswap.h */, + 9BE650410B52F6D800611104 /* file_id.cc */, + 9BE650420B52F6D800611104 /* file_id.h */, + 9BDF186D0B1BB43700F8391B /* dump_syms.h */, + 08FB7796FE84155DC02AAC07 /* dump_syms.cc */, + 9BDF186E0B1BB43700F8391B /* dump_syms_tool.cc */, + B89E0E701166573700DD08C9 /* macho_dump.cc */, + 4D72CAF413DFBAC2006CABE3 /* md5.cc */, + EB06C7511FEBC515000214D9 /* path_helper.cc */, + EB06C7521FEBC516000214D9 /* path_helper.h */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = dump_syms; + sourceTree = "<group>"; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = "<group>"; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + B8C5B5111166531A00D34F4E /* dump_syms */, + B89E0E741166575200DD08C9 /* macho_dump */, + B89E0E9511665A6400DD08C9 /* macho_reader_unittest */, + B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */, + B88FB007116BDE8300407530 /* stabs_reader_unittest */, + B88FB024116BDFFF00407530 /* libgtestmockall.a */, + B88FB0B9116CEABF00407530 /* module_unittest */, + B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */, + B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */, + B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */, + B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */, + B88FB135116CF30F00407530 /* bytereader_unittest */, + B88FB14B116CF4A700407530 /* byte_cursor_unittest */, + B84A91F4116CF784006C210E /* stabs_to_module_unittest */, + D21F97D211CBA0F200239E38 /* test_assembler_unittest */, + ); + name = Products; + sourceTree = "<group>"; + }; + B88FAE1C11665FFD00407530 /* MODULE */ = { + isa = PBXGroup; + children = ( + B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */, + B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */, + B88FB0D6116CEC0600407530 /* dwarf_cu_to_module_unittest.cc */, + B88FAE201166603300407530 /* dwarf_line_to_module.cc */, + B88FAE211166603300407530 /* dwarf_line_to_module.h */, + B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */, + B88FAE221166603300407530 /* language.cc */, + B88FAE231166603300407530 /* language.h */, + B88FAE241166603300407530 /* module.cc */, + B88FAE251166603300407530 /* module.h */, + B88FB0B5116CEA8A00407530 /* module_unittest.cc */, + B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */, + B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */, + B88FB0D5116CEC0600407530 /* dwarf_cfi_to_module_unittest.cc */, + B88FAE3C11666C8900407530 /* stabs_to_module.cc */, + B88FAE3D11666C8900407530 /* stabs_to_module.h */, + B88FB0D8116CEC0600407530 /* stabs_to_module_unittest.cc */, + ); + name = MODULE; + sourceTree = "<group>"; + }; + B88FAE3811666A1700407530 /* STABS */ = { + isa = PBXGroup; + children = ( + B88FB003116BDE7200407530 /* stabs_reader_unittest.cc */, + B88FAE3911666C6F00407530 /* stabs_reader.cc */, + B88FAE3A11666C6F00407530 /* stabs_reader.h */, + ); + name = STABS; + sourceTree = "<group>"; + }; + B89E0E6C1166569700DD08C9 /* MACHO */ = { + isa = PBXGroup; + children = ( + B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */, + B89E0E6E1166571D00DD08C9 /* macho_reader.cc */, + B89E0E6F1166571D00DD08C9 /* macho_reader.h */, + 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */, + 5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */, + 9BE650430B52F6D800611104 /* macho_id.cc */, + 9BE650440B52F6D800611104 /* macho_id.h */, + 9BE650450B52F6D800611104 /* macho_walker.cc */, + 9BE650460B52F6D800611104 /* macho_walker.h */, + ); + name = MACHO; + sourceTree = "<group>"; + }; + B89E0E9D11665A9500DD08C9 /* TESTING */ = { + isa = PBXGroup; + children = ( + B88FAE0911665B5700407530 /* test_assembler.cc */, + B88FAE0A11665B5700407530 /* test_assembler.h */, + B88FB0D9116CEC0600407530 /* test_assembler_unittest.cc */, + B89E0EA311665AEA00DD08C9 /* gmock-all.cc */, + B89E0E9F11665AC300DD08C9 /* gtest_main.cc */, + B89E0EA011665AC300DD08C9 /* gtest-all.cc */, + ); + name = TESTING; + sourceTree = "<group>"; + }; + F9F5344B0E7C8FFC0012363F /* DWARF */ = { + isa = PBXGroup; + children = ( + B88FAF34116A595400407530 /* cfi_assembler.cc */, + B88FAF35116A595400407530 /* cfi_assembler.h */, + F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */, + F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */, + 4262382521AC496F00E5A3A6 /* dwarf_range_list_handler.cc */, + 4262382621AC496F00E5A3A6 /* dwarf_range_list_handler.h */, + F95B42300E0E22D100DBDE83 /* dwarf2reader.h */, + B88FAF36116A595400407530 /* dwarf2reader_cfi_unittest.cc */, + F95B422D0E0E22D100DBDE83 /* bytereader.h */, + F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */, + F95B422C0E0E22D100DBDE83 /* bytereader.cc */, + B88FB0DA116CEC5800407530 /* bytereader_unittest.cc */, + F95B42310E0E22D100DBDE83 /* line_state_machine.h */, + B88FAE1711665FE400407530 /* dwarf2diehandler.cc */, + B88FAE1811665FE400407530 /* dwarf2diehandler.h */, + B88FB0DB116CEC5800407530 /* dwarf2diehandler_unittest.cc */, + 8BCAAA4A1CE3A7980046090B /* elf_reader.cc */, + 8BCAAA4B1CE3A7980046090B /* elf_reader.h */, + ); + name = DWARF; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B88FB020116BDFFF00407530 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B84A91F3116CF784006C210E /* stabs_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B84A9202116CF7F0006C210E /* Build configuration list for PBXNativeTarget "stabs_to_module_unittest" */; + buildPhases = ( + B84A91F1116CF784006C210E /* Sources */, + B84A91F2116CF784006C210E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B84A91FA116CF796006C210E /* PBXTargetDependency */, + ); + name = stabs_to_module_unittest; + productName = stabs_to_module_unittest; + productReference = B84A91F4116CF784006C210E /* stabs_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FAF33116A594800407530 /* Build configuration list for PBXNativeTarget "dwarf2reader_cfi_unittest" */; + buildPhases = ( + B88FAF2C116A591D00407530 /* Sources */, + B88FAF2D116A591D00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB03A116BE17E00407530 /* PBXTargetDependency */, + ); + name = dwarf2reader_cfi_unittest; + productName = dwarf2reader_cfi_unittest; + productReference = B88FAF2F116A591E00407530 /* dwarf2reader_cfi_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB006116BDE8300407530 /* stabs_reader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB013116BDEC800407530 /* Build configuration list for PBXNativeTarget "stabs_reader_unittest" */; + buildPhases = ( + B88FB004116BDE8300407530 /* Sources */, + B88FB005116BDE8300407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB088116CE6D800407530 /* PBXTargetDependency */, + ); + name = stabs_reader_unittest; + productName = stabs_reader_unittest; + productReference = B88FB007116BDE8300407530 /* stabs_reader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB023116BDFFF00407530 /* gtestmockall */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB027116BE02900407530 /* Build configuration list for PBXNativeTarget "gtestmockall" */; + buildPhases = ( + B88FB020116BDFFF00407530 /* Headers */, + B88FB021116BDFFF00407530 /* Sources */, + B88FB022116BDFFF00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = gtestmockall; + productName = gtestmockall; + productReference = B88FB024116BDFFF00407530 /* libgtestmockall.a */; + productType = "com.apple.product-type.library.static"; + }; + B88FB0B8116CEABF00407530 /* module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0BE116CEAFE00407530 /* Build configuration list for PBXNativeTarget "module_unittest" */; + buildPhases = ( + B88FB0B6116CEABF00407530 /* Sources */, + B88FB0B7116CEABF00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0C0116CEAFE00407530 /* PBXTargetDependency */, + ); + name = module_unittest; + productName = module_unittest; + productReference = B88FB0B9116CEABF00407530 /* module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0E4116CEECE00407530 /* Build configuration list for PBXNativeTarget "dwarf2diehandler_unittest" */; + buildPhases = ( + B88FB0DC116CEEA800407530 /* Sources */, + B88FB0DD116CEEA800407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0E8116CEEDA00407530 /* PBXTargetDependency */, + ); + name = dwarf2diehandler_unittest; + productName = dwarf2diehandler_unittest; + productReference = B88FB0DF116CEEA800407530 /* dwarf2diehandler_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB0F9116CEF9800407530 /* Build configuration list for PBXNativeTarget "dwarf_line_to_module_unittest" */; + buildPhases = ( + B88FB0EF116CEF1900407530 /* Sources */, + B88FB0F0116CEF1900407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB0F8116CEF2E00407530 /* PBXTargetDependency */, + ); + name = dwarf_line_to_module_unittest; + productName = dwarf_line_to_module_unittest; + productReference = B88FB0F2116CEF1900407530 /* dwarf_line_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB111116CF0A800407530 /* Build configuration list for PBXNativeTarget "dwarf_cu_to_module_unittest" */; + buildPhases = ( + B88FB107116CF07900407530 /* Sources */, + B88FB108116CF07900407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB110116CF08A00407530 /* PBXTargetDependency */, + ); + name = dwarf_cu_to_module_unittest; + productName = dwarf_cu_to_module_unittest; + productReference = B88FB10A116CF07900407530 /* dwarf_cu_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB128116CF2C800407530 /* Build configuration list for PBXNativeTarget "dwarf_cfi_to_module_unittest" */; + buildPhases = ( + B88FB11C116CF27F00407530 /* Sources */, + B88FB11D116CF27F00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB125116CF29E00407530 /* PBXTargetDependency */, + ); + name = dwarf_cfi_to_module_unittest; + productName = dwarf_cfi_to_module_unittest; + productReference = B88FB11F116CF27F00407530 /* dwarf_cfi_to_module_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB134116CF30F00407530 /* bytereader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB13A116CF33400407530 /* Build configuration list for PBXNativeTarget "bytereader_unittest" */; + buildPhases = ( + B88FB132116CF30F00407530 /* Sources */, + B88FB133116CF30F00407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB13C116CF35C00407530 /* PBXTargetDependency */, + ); + name = bytereader_unittest; + productName = bytereader_unittest; + productReference = B88FB135116CF30F00407530 /* bytereader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B88FB14A116CF4A700407530 /* byte_cursor_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B88FB159116CF4F900407530 /* Build configuration list for PBXNativeTarget "byte_cursor_unittest" */; + buildPhases = ( + B88FB148116CF4A700407530 /* Sources */, + B88FB149116CF4A700407530 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB151116CF4C100407530 /* PBXTargetDependency */, + ); + name = byte_cursor_unittest; + productName = byte_cursor_unittest; + productReference = B88FB14B116CF4A700407530 /* byte_cursor_unittest */; + productType = "com.apple.product-type.tool"; + }; + B89E0E731166575200DD08C9 /* macho_dump */ = { + isa = PBXNativeTarget; + buildConfigurationList = B89E0E7F116657A100DD08C9 /* Build configuration list for PBXNativeTarget "macho_dump" */; + buildPhases = ( + B89E0E711166575200DD08C9 /* Sources */, + B89E0E721166575200DD08C9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = macho_dump; + productName = macho_dump; + productReference = B89E0E741166575200DD08C9 /* macho_dump */; + productType = "com.apple.product-type.tool"; + }; + B89E0E9411665A6400DD08C9 /* macho_reader_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = B89E0E9E11665A9600DD08C9 /* Build configuration list for PBXNativeTarget "macho_reader_unittest" */; + buildPhases = ( + B89E0E9211665A6400DD08C9 /* Sources */, + B89E0E9311665A6400DD08C9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + B88FB090116CE71000407530 /* PBXTargetDependency */, + ); + name = macho_reader_unittest; + productName = macho_reader_unittest; + productReference = B89E0E9511665A6400DD08C9 /* macho_reader_unittest */; + productType = "com.apple.product-type.tool"; + }; + B8C5B5101166531A00D34F4E /* dump_syms */ = { + isa = PBXNativeTarget; + buildConfigurationList = B8C5B5151166533900D34F4E /* Build configuration list for PBXNativeTarget "dump_syms" */; + buildPhases = ( + B8C5B50E1166531A00D34F4E /* Sources */, + B8C5B50F1166531A00D34F4E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dump_syms; + productName = dump_syms; + productReference = B8C5B5111166531A00D34F4E /* dump_syms */; + productType = "com.apple.product-type.tool"; + }; + D21F97D111CBA0F200239E38 /* test_assembler_unittest */ = { + isa = PBXNativeTarget; + buildConfigurationList = D21F97D611CBA11000239E38 /* Build configuration list for PBXNativeTarget "test_assembler_unittest" */; + buildPhases = ( + D21F97CF11CBA0F200239E38 /* Sources */, + D21F97D011CBA0F200239E38 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = test_assembler_unittest; + productName = test_assembler_unittest; + productReference = D21F97D211CBA0F200239E38 /* test_assembler_unittest */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + }; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "dump_syms" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* dump_syms */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B8C5B5101166531A00D34F4E /* dump_syms */, + B89E0E731166575200DD08C9 /* macho_dump */, + B88FB023116BDFFF00407530 /* gtestmockall */, + B88FB14A116CF4A700407530 /* byte_cursor_unittest */, + B89E0E9411665A6400DD08C9 /* macho_reader_unittest */, + B88FB006116BDE8300407530 /* stabs_reader_unittest */, + B88FB134116CF30F00407530 /* bytereader_unittest */, + B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */, + B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */, + B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */, + B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */, + B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */, + B84A91F3116CF784006C210E /* stabs_to_module_unittest */, + B88FB0B8116CEABF00407530 /* module_unittest */, + B88FAFC9116BDCAD00407530 /* all_unittests */, + D21F97D111CBA0F200239E38 /* test_assembler_unittest */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + B88FB094116CE73E00407530 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -eu\n\ncd $BUILT_PRODUCTS_DIR\npwd\n\n./byte_cursor_unittest\n./macho_reader_unittest\n./stabs_reader_unittest\n./bytereader_unittest\n./dwarf2reader_cfi_unittest\n./dwarf2diehandler_unittest\n./dwarf_cu_to_module_unittest\n./dwarf_line_to_module_unittest\n./dwarf_cfi_to_module_unittest\n./stabs_to_module_unittest\n./module_unittest\n./test_assembler_unittest\n\necho \"Expect two warnings from the following tests:\"\necho \" Errors.BadFileNumber\"\necho \" Errors.BadDirectoryNumber\"\necho \"The proper behavior of these tests is to print text that XCode confuses with compiler warnings.\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + B84A91F1116CF784006C210E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B84A91FB116CF7AF006C210E /* module.cc in Sources */, + B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */, + B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FAF2C116A591D00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FAF38116A595400407530 /* dwarf2reader_cfi_unittest.cc in Sources */, + B88FAF3F116A5A2E00407530 /* dwarf2reader.cc in Sources */, + 8BCAAA4D1CE3B1260046090B /* elf_reader.cc in Sources */, + B88FAF40116A5A2E00407530 /* bytereader.cc in Sources */, + B88FAF37116A595400407530 /* cfi_assembler.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB004116BDE8300407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB00F116BDEA700407530 /* stabs_reader_unittest.cc in Sources */, + B88FB010116BDEA700407530 /* stabs_reader.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB021116BDFFF00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB028116BE03100407530 /* test_assembler.cc in Sources */, + B88FB029116BE03100407530 /* gmock-all.cc in Sources */, + B88FB02A116BE03100407530 /* gtest_main.cc in Sources */, + B88FB02B116BE03100407530 /* gtest-all.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0B6116CEABF00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0BD116CEAE000407530 /* module_unittest.cc in Sources */, + B88FB0C4116CEB4100407530 /* module.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0DC116CEEA800407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0E5116CEED300407530 /* dwarf2diehandler.cc in Sources */, + B88FB0E6116CEED300407530 /* dwarf2diehandler_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB0EF116CEF1900407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */, + B88FB0FE116CF02400407530 /* module.cc in Sources */, + B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB107116CF07900407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */, + B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */, + B88FB114116CF1F000407530 /* language.cc in Sources */, + B88FB115116CF1F000407530 /* module.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB11C116CF27F00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB129116CF2DD00407530 /* module.cc in Sources */, + B88FB12A116CF2DD00407530 /* dwarf_cfi_to_module.cc in Sources */, + B88FB12B116CF2DD00407530 /* dwarf_cfi_to_module_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB132116CF30F00407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */, + B88FB13E116CF38300407530 /* bytereader.cc in Sources */, + B88FB13F116CF38300407530 /* bytereader_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B88FB148116CF4A700407530 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B88FB152116CF4D300407530 /* byte_cursor_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E711166575200DD08C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4247E63D2110D4B200482558 /* path_helper.cc in Sources */, + 162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */, + B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */, + B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B89E0E9211665A6400DD08C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B89E0E9911665A7200DD08C9 /* macho_reader_unittest.cc in Sources */, + B89E0E9A11665A7200DD08C9 /* macho_reader.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B8C5B50E1166531A00D34F4E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4262382821AC49A000E5A3A6 /* dwarf_range_list_handler.h in Sources */, + 162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */, + B88FAE2C1166606200407530 /* macho_reader.cc in Sources */, + 8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */, + B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */, + EB06C7531FEBC516000214D9 /* path_helper.cc in Sources */, + B8C5B5181166534700D34F4E /* bytereader.cc in Sources */, + B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */, + B8C5B51A1166534700D34F4E /* file_id.cc in Sources */, + B8C5B51B1166534700D34F4E /* macho_id.cc in Sources */, + B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */, + B8C5B51D1166534700D34F4E /* dump_syms.cc in Sources */, + B8C5B51E1166534700D34F4E /* dump_syms_tool.cc in Sources */, + B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */, + B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */, + B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */, + 4262382721AC496F00E5A3A6 /* dwarf_range_list_handler.cc in Sources */, + B88FAE281166603300407530 /* language.cc in Sources */, + B88FAE291166603300407530 /* module.cc in Sources */, + B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */, + B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */, + B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */, + 4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D21F97CF11CBA0F200239E38 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D21F97E911CBA1FF00239E38 /* test_assembler.cc in Sources */, + D21F97D711CBA12300239E38 /* test_assembler_unittest.cc in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 8B31051511F100CF00FCF3E4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D21F97D111CBA0F200239E38 /* test_assembler_unittest */; + targetProxy = 8B31051411F100CF00FCF3E4 /* PBXContainerItemProxy */; + }; + B84A91FA116CF796006C210E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B84A91F9116CF796006C210E /* PBXContainerItemProxy */; + }; + B84A9201116CF7D2006C210E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B84A91F3116CF784006C210E /* stabs_to_module_unittest */; + targetProxy = B84A9200116CF7D2006C210E /* PBXContainerItemProxy */; + }; + B88FAFCF116BDD7000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B89E0E9411665A6400DD08C9 /* macho_reader_unittest */; + targetProxy = B88FAFCE116BDD7000407530 /* PBXContainerItemProxy */; + }; + B88FAFD1116BDD7000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FAF2E116A591D00407530 /* dwarf2reader_cfi_unittest */; + targetProxy = B88FAFD0116BDD7000407530 /* PBXContainerItemProxy */; + }; + B88FB01D116BDF9800407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB006116BDE8300407530 /* stabs_reader_unittest */; + targetProxy = B88FB01C116BDF9800407530 /* PBXContainerItemProxy */; + }; + B88FB03A116BE17E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB039116BE17E00407530 /* PBXContainerItemProxy */; + }; + B88FB088116CE6D800407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB087116CE6D800407530 /* PBXContainerItemProxy */; + }; + B88FB090116CE71000407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB08F116CE71000407530 /* PBXContainerItemProxy */; + }; + B88FB0C0116CEAFE00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0BF116CEAFE00407530 /* PBXContainerItemProxy */; + }; + B88FB0C8116CEB4A00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0B8116CEABF00407530 /* module_unittest */; + targetProxy = B88FB0C7116CEB4A00407530 /* PBXContainerItemProxy */; + }; + B88FB0E8116CEEDA00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0E7116CEEDA00407530 /* PBXContainerItemProxy */; + }; + B88FB0F8116CEF2E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB0F7116CEF2E00407530 /* PBXContainerItemProxy */; + }; + B88FB110116CF08A00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB10F116CF08A00407530 /* PBXContainerItemProxy */; + }; + B88FB125116CF29E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB124116CF29E00407530 /* PBXContainerItemProxy */; + }; + B88FB13C116CF35C00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB13B116CF35C00407530 /* PBXContainerItemProxy */; + }; + B88FB151116CF4C100407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB023116BDFFF00407530 /* gtestmockall */; + targetProxy = B88FB150116CF4C100407530 /* PBXContainerItemProxy */; + }; + B88FB15B116CF53E00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB14A116CF4A700407530 /* byte_cursor_unittest */; + targetProxy = B88FB15A116CF53E00407530 /* PBXContainerItemProxy */; + }; + B88FB15D116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB11E116CF27F00407530 /* dwarf_cfi_to_module_unittest */; + targetProxy = B88FB15C116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB15F116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0F1116CEF1900407530 /* dwarf_line_to_module_unittest */; + targetProxy = B88FB15E116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB161116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB109116CF07900407530 /* dwarf_cu_to_module_unittest */; + targetProxy = B88FB160116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB165116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB0DE116CEEA800407530 /* dwarf2diehandler_unittest */; + targetProxy = B88FB164116CF54B00407530 /* PBXContainerItemProxy */; + }; + B88FB167116CF54B00407530 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B88FB134116CF30F00407530 /* bytereader_unittest */; + targetProxy = B88FB166116CF54B00407530 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102D411F0D60300FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Release; + }; + B84A91F6116CF784006C210E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Debug; + }; + B84A91F7116CF784006C210E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Release; + }; + B88FAF31116A591F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/build/Debug\""; + PRODUCT_NAME = dwarf2reader_cfi_unittest; + }; + name = Debug; + }; + B88FAF32116A591F00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)", + ); + LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/build/Debug\""; + PRODUCT_NAME = dwarf2reader_cfi_unittest; + }; + name = Release; + }; + B88FAFCA116BDCAD00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = all_unittests; + }; + name = Debug; + }; + B88FAFCB116BDCAD00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = all_unittests; + }; + name = Release; + }; + B88FB009116BDE8400407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_reader_unittest; + }; + name = Debug; + }; + B88FB00A116BDE8400407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = stabs_reader_unittest; + }; + name = Release; + }; + B88FB025116BE00100407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Debug; + }; + B88FB026116BE00100407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Release; + }; + B88FB0BB116CEAC000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Debug; + }; + B88FB0BC116CEAC000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Release; + }; + B88FB0E1116CEEA800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Debug; + }; + B88FB0E2116CEEA800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Release; + }; + B88FB0F4116CEF1900407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Debug; + }; + B88FB0F5116CEF1900407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Release; + }; + B88FB10C116CF07A00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Debug; + }; + B88FB10D116CF07A00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Release; + }; + B88FB121116CF28000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Debug; + }; + B88FB122116CF28000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Release; + }; + B88FB137116CF30F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Debug; + }; + B88FB138116CF30F00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ../../../testing/googletest, + ../../../testing/googletest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Release; + }; + B88FB14D116CF4A800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = byte_cursor_unittest; + }; + name = Debug; + }; + B88FB14E116CF4A800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = byte_cursor_unittest; + }; + name = Release; + }; + B89E0E761166575300DD08C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = macho_dump; + }; + name = Debug; + }; + B89E0E771166575300DD08C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = macho_dump; + }; + name = Release; + }; + B89E0E9711665A6400DD08C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = macho_reader_unittest; + }; + name = Debug; + }; + B89E0E9811665A6400DD08C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = macho_reader_unittest; + }; + name = Release; + }; + B8C5B5131166531B00D34F4E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_VERSION = ""; + PRODUCT_NAME = dump_syms; + }; + name = Debug; + }; + B8C5B5141166531B00D34F4E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = HAVE_MACH_O_NLIST_H; + GCC_VERSION = ""; + PRODUCT_NAME = dump_syms; + }; + name = Release; + }; + D21F97D411CBA0F200239E38 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = test_assembler_unittest; + }; + name = Debug; + }; + D21F97D511CBA0F200239E38 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing/googletest, + ../../../testing/googletest/include, + ../../../testing/googlemock, + ../../../testing/googlemock/include, + ); + PRODUCT_NAME = test_assembler_unittest; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "dump_syms" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B84A9202116CF7F0006C210E /* Build configuration list for PBXNativeTarget "stabs_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B84A91F6116CF784006C210E /* Debug */, + B84A91F7116CF784006C210E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FAF33116A594800407530 /* Build configuration list for PBXNativeTarget "dwarf2reader_cfi_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FAF31116A591F00407530 /* Debug */, + B88FAF32116A591F00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FAFCC116BDCCC00407530 /* Build configuration list for PBXAggregateTarget "all_unittests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FAFCA116BDCAD00407530 /* Debug */, + B88FAFCB116BDCAD00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB013116BDEC800407530 /* Build configuration list for PBXNativeTarget "stabs_reader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB009116BDE8400407530 /* Debug */, + B88FB00A116BDE8400407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB027116BE02900407530 /* Build configuration list for PBXNativeTarget "gtestmockall" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB025116BE00100407530 /* Debug */, + B88FB026116BE00100407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0BE116CEAFE00407530 /* Build configuration list for PBXNativeTarget "module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0BB116CEAC000407530 /* Debug */, + B88FB0BC116CEAC000407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0E4116CEECE00407530 /* Build configuration list for PBXNativeTarget "dwarf2diehandler_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0E1116CEEA800407530 /* Debug */, + B88FB0E2116CEEA800407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB0F9116CEF9800407530 /* Build configuration list for PBXNativeTarget "dwarf_line_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB0F4116CEF1900407530 /* Debug */, + B88FB0F5116CEF1900407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB111116CF0A800407530 /* Build configuration list for PBXNativeTarget "dwarf_cu_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB10C116CF07A00407530 /* Debug */, + B88FB10D116CF07A00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB128116CF2C800407530 /* Build configuration list for PBXNativeTarget "dwarf_cfi_to_module_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB121116CF28000407530 /* Debug */, + B88FB122116CF28000407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB13A116CF33400407530 /* Build configuration list for PBXNativeTarget "bytereader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB137116CF30F00407530 /* Debug */, + B88FB138116CF30F00407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B88FB159116CF4F900407530 /* Build configuration list for PBXNativeTarget "byte_cursor_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B88FB14D116CF4A800407530 /* Debug */, + B88FB14E116CF4A800407530 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B89E0E7F116657A100DD08C9 /* Build configuration list for PBXNativeTarget "macho_dump" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B89E0E761166575300DD08C9 /* Debug */, + B89E0E771166575300DD08C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B89E0E9E11665A9600DD08C9 /* Build configuration list for PBXNativeTarget "macho_reader_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B89E0E9711665A6400DD08C9 /* Debug */, + B89E0E9811665A6400DD08C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B8C5B5151166533900D34F4E /* Build configuration list for PBXNativeTarget "dump_syms" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B8C5B5131166531B00D34F4E /* Debug */, + B8C5B5141166531B00D34F4E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D21F97D611CBA11000239E38 /* Build configuration list for PBXNativeTarget "test_assembler_unittest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D21F97D411CBA0F200239E38 /* Debug */, + D21F97D511CBA0F200239E38 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc new file mode 100644 index 0000000000..6f68457b4c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms_tool.cc @@ -0,0 +1,264 @@ +// -*- mode: c++ -*- + +// 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. + +// dump_syms_tool.cc: Command line tool that uses the DumpSymbols class. +// TODO(waylonis): accept stdin + +#include <mach-o/arch.h> +#include <unistd.h> + +#include <algorithm> +#include <iostream> +#include <vector> + +#include "common/mac/dump_syms.h" +#include "common/mac/arch_utilities.h" +#include "common/mac/macho_utilities.h" +#include "common/scoped_ptr.h" + +using google_breakpad::DumpSymbols; +using google_breakpad::Module; +using google_breakpad::scoped_ptr; +using std::vector; + +struct Options { + Options() + : srcPath(), dsymPath(), arch(), header_only(false), + cfi(true), handle_inter_cu_refs(true) {} + + string srcPath; + string dsymPath; + const NXArchInfo *arch; + bool header_only; + bool cfi; + bool handle_inter_cu_refs; +}; + +static bool StackFrameEntryComparator(const Module::StackFrameEntry* a, + const Module::StackFrameEntry* b) { + return a->address < b->address; +} + +// Copy the CFI data from |from_module| into |to_module|, for any non- +// overlapping ranges. +static void CopyCFIDataBetweenModules(Module* to_module, + const Module* from_module) { + typedef vector<Module::StackFrameEntry*>::const_iterator Iterator; + + // Get the CFI data from both the source and destination modules and ensure + // it is sorted by start address. + vector<Module::StackFrameEntry*> from_data; + from_module->GetStackFrameEntries(&from_data); + std::sort(from_data.begin(), from_data.end(), &StackFrameEntryComparator); + + vector<Module::StackFrameEntry*> to_data; + to_module->GetStackFrameEntries(&to_data); + std::sort(to_data.begin(), to_data.end(), &StackFrameEntryComparator); + + Iterator to_it = to_data.begin(); + + for (Iterator it = from_data.begin(); it != from_data.end(); ++it) { + Module::StackFrameEntry* from_entry = *it; + Module::Address from_entry_end = from_entry->address + from_entry->size; + + // Find the first CFI record in the |to_module| that does not have an + // address less than the entry to be copied. + while (to_it != to_data.end()) { + if (from_entry->address > (*to_it)->address) + ++to_it; + else + break; + } + + // If the entry does not overlap, then it is safe to copy to |to_module|. + if (to_it == to_data.end() || (from_entry->address < (*to_it)->address && + from_entry_end < (*to_it)->address)) { + to_module->AddStackFrameEntry(new Module::StackFrameEntry(*from_entry)); + } + } +} + +static bool Start(const Options &options) { + SymbolData symbol_data = options.cfi ? ALL_SYMBOL_DATA : NO_CFI; + DumpSymbols dump_symbols(symbol_data, options.handle_inter_cu_refs); + + // For x86_64 binaries, the CFI data is in the __TEXT,__eh_frame of the + // Mach-O file, which is not copied into the dSYM. Whereas in i386, the CFI + // data is in the __DWARF,__debug_frame section, which is moved into the + // dSYM. Therefore, to get x86_64 CFI data, dump_syms needs to look at both + // the dSYM and the Mach-O file. If both paths are present and CFI was + // requested, then consider the Module as "split" and dump all the debug data + // from the primary debug info file, the dSYM, and then dump additional CFI + // data from the source Mach-O file. + bool split_module = + !options.dsymPath.empty() && !options.srcPath.empty() && options.cfi; + const string& primary_file = + split_module ? options.dsymPath : options.srcPath; + + if (!dump_symbols.Read(primary_file)) + return false; + + if (options.arch) { + if (!dump_symbols.SetArchitecture(options.arch->cputype, + options.arch->cpusubtype)) { + fprintf(stderr, "%s: no architecture '%s' is present in file.\n", + primary_file.c_str(), options.arch->name); + size_t available_size; + const SuperFatArch *available = + dump_symbols.AvailableArchitectures(&available_size); + if (available_size == 1) + fprintf(stderr, "the file's architecture is: "); + else + fprintf(stderr, "architectures present in the file are:\n"); + for (size_t i = 0; i < available_size; i++) { + const SuperFatArch *arch = &available[i]; + const NXArchInfo *arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType( + arch->cputype, arch->cpusubtype); + if (arch_info) + fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description); + else + fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n", + arch->cputype, arch->cpusubtype); + } + return false; + } + } + + if (options.header_only) + return dump_symbols.WriteSymbolFileHeader(std::cout); + + // Read the primary file into a Breakpad Module. + Module* module = NULL; + if (!dump_symbols.ReadSymbolData(&module)) + return false; + scoped_ptr<Module> scoped_module(module); + + // If this is a split module, read the secondary Mach-O file, from which the + // CFI data will be extracted. + if (split_module && primary_file == options.dsymPath) { + if (!dump_symbols.Read(options.srcPath)) + return false; + + Module* cfi_module = NULL; + if (!dump_symbols.ReadSymbolData(&cfi_module)) + return false; + scoped_ptr<Module> scoped_cfi_module(cfi_module); + + // Ensure that the modules are for the same debug code file. + if (cfi_module->name() != module->name() || + cfi_module->os() != module->os() || + cfi_module->architecture() != module->architecture() || + cfi_module->identifier() != module->identifier()) { + fprintf(stderr, "Cannot generate a symbol file from split sources that do" + " not match.\n"); + return false; + } + + CopyCFIDataBetweenModules(module, cfi_module); + } + + return module->Write(std::cout, symbol_data); +} + +//============================================================================= +static void Usage(int argc, const char *argv[]) { + fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n"); + fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] [-g dSYM path] " + "<Mach-o file>\n", argv[0]); + fprintf(stderr, "\t-i: Output module header information only.\n"); + fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n"); + fprintf(stderr, "\t in the file, if it contains only one architecture]\n"); + fprintf(stderr, "\t-g: Debug symbol file (dSYM) to dump in addition to the " + "Mach-o file\n"); + fprintf(stderr, "\t-c: Do not generate CFI section\n"); + fprintf(stderr, "\t-r: Do not handle inter-compilation unit references\n"); + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + signed char ch; + + while ((ch = getopt(argc, (char * const *)argv, "ia:g:chr?")) != -1) { + switch (ch) { + case 'i': + options->header_only = true; + break; + case 'a': { + const NXArchInfo *arch_info = + google_breakpad::BreakpadGetArchInfoFromName(optarg); + if (!arch_info) { + fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg); + Usage(argc, argv); + exit(1); + } + options->arch = arch_info; + break; + } + case 'g': + options->dsymPath = optarg; + break; + case 'c': + options->cfi = false; + break; + case 'r': + options->handle_inter_cu_refs = false; + break; + case '?': + case 'h': + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 1) { + fprintf(stderr, "Must specify Mach-o file\n"); + Usage(argc, argv); + exit(1); + } + + options->srcPath = argv[optind]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + Options options; + bool result; + + SetupOptions(argc, argv, &options); + result = Start(options); + + return !result; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc new file mode 100644 index 0000000000..6e784ca709 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/macho_dump.cc @@ -0,0 +1,203 @@ +// 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. + +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> + +// macho_dump.cc: Dump the contents of a Mach-O file. This is mostly +// a test program for the Mach_O::FatReader and Mach_O::Reader classes. + +#include <errno.h> +#include <fcntl.h> +#include <mach-o/arch.h> +#include <sys/mman.h> +#include <stdint.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <sstream> +#include <string> +#include <vector> + +#include "common/byte_cursor.h" +#include "common/mac/arch_utilities.h" +#include "common/mac/macho_reader.h" +#include "common/path_helper.h" + +using google_breakpad::ByteBuffer; +using std::ostringstream; +using std::string; +using std::vector; + +namespace { +namespace mach_o = google_breakpad::mach_o; + +string program_name; + +int check_syscall(int result, const char *operation, const char *filename) { + if (result < 0) { + fprintf(stderr, "%s: %s '%s': %s\n", + program_name.c_str(), operation, + filename, strerror(errno)); + exit(1); + } + return result; +} + +class DumpSection: public mach_o::Reader::SectionHandler { + public: + DumpSection() : index_(0) { } + bool HandleSection(const mach_o::Section §ion) { + printf(" section %d '%s' in segment '%s'\n" + " address: 0x%llx\n" + " alignment: 1 << %d B\n" + " flags: %d\n" + " size: %ld\n", + index_++, section.section_name.c_str(), section.segment_name.c_str(), + section.address, section.align, + mach_o::SectionFlags(section.flags), + section.contents.Size()); + return true; + } + + private: + int index_; +}; + +class DumpCommand: public mach_o::Reader::LoadCommandHandler { + public: + DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { } + bool UnknownCommand(mach_o::LoadCommandType type, + const ByteBuffer &contents) { + printf(" load command %d: %d", index_++, type); + return true; + } + bool SegmentCommand(const mach_o::Segment &segment) { + printf(" load command %d: %s-bit segment '%s'\n" + " address: 0x%llx\n" + " memory size: 0x%llx\n" + " maximum protection: 0x%x\n" + " initial protection: 0x%x\n" + " flags: %d\n" + " section_list size: %ld B\n", + index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(), + segment.vmaddr, segment.vmsize, segment.maxprot, + segment.initprot, mach_o::SegmentFlags(segment.flags), + segment.section_list.Size()); + + DumpSection dump_section; + return reader_->WalkSegmentSections(segment, &dump_section); + } + private: + mach_o::Reader *reader_; + int index_; +}; + +void DumpFile(const char *filename) { + int fd = check_syscall(open(filename, O_RDONLY), "opening", filename); + struct stat attributes; + check_syscall(fstat(fd, &attributes), + "getting file attributes for", filename); + void *mapping = mmap(NULL, attributes.st_size, PROT_READ, + MAP_PRIVATE, fd, 0); + close(fd); + check_syscall(mapping == (void *)-1 ? -1 : 0, + "mapping contents of", filename); + + mach_o::FatReader::Reporter fat_reporter(filename); + mach_o::FatReader fat_reader(&fat_reporter); + if (!fat_reader.Read(reinterpret_cast<uint8_t *>(mapping), + attributes.st_size)) { + exit(1); + } + printf("filename: %s\n", filename); + size_t object_files_size; + const SuperFatArch* super_fat_object_files = + fat_reader.object_files(&object_files_size); + struct fat_arch *object_files; + if (!super_fat_object_files->ConvertToFatArch(object_files)) { + exit(1); + } + printf(" object file count: %ld\n", object_files_size); + for (size_t i = 0; i < object_files_size; i++) { + const struct fat_arch &file = object_files[i]; + const NXArchInfo *fat_arch_info = + google_breakpad::BreakpadGetArchInfoFromCpuType( + file.cputype, file.cpusubtype); + printf("\n object file %ld:\n" + " fat header:\n:" + " CPU type: %s (%s)\n" + " size: %d B\n" + " alignment: 1<<%d B\n", + i, fat_arch_info->name, fat_arch_info->description, + file.size, file.align); + + ostringstream name; + name << filename; + if (object_files_size > 1) + name << ", object file #" << i; + ByteBuffer file_contents(reinterpret_cast<uint8_t *>(mapping) + + file.offset, file.size); + mach_o::Reader::Reporter reporter(name.str()); + mach_o::Reader reader(&reporter); + if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) { + exit(1); + } + + const NXArchInfo *macho_arch_info = + NXGetArchInfoFromCpuType(reader.cpu_type(), + reader.cpu_subtype()); + printf(" Mach-O header:\n" + " word size: %s\n" + " CPU type: %s (%s)\n" + " File type: %d\n" + " flags: %x\n", + (reader.bits_64() ? "64 bits" : "32 bits"), + macho_arch_info->name, macho_arch_info->description, + reader.file_type(), reader.flags()); + + DumpCommand dump_command(&reader); + reader.WalkLoadCommands(&dump_command); + } + munmap(mapping, attributes.st_size); +} + +} // namespace + +int main(int argc, char **argv) { + program_name = google_breakpad::BaseName(argv[0]); + if (argc == 1) { + fprintf(stderr, "Usage: %s FILE ...\n" + "Dump the contents of the Mach-O or fat binary files " + "'FILE ...'.\n", program_name.c_str()); + } + for (int i = 1; i < argc; i++) { + DumpFile(argv[i]); + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m new file mode 100644 index 0000000000..741ad765e5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/minidump_upload.m @@ -0,0 +1,135 @@ +// Copyright (c) 2006, 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_upload.m: Upload a minidump to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// prod: the product name +// ver: the product version +// symbol_file: the breakpad format symbol file + +#import <unistd.h> + +#import <Foundation/Foundation.h> + +#import "common/mac/HTTPMultipartUpload.h" + +typedef struct { + NSString *minidumpPath; + NSString *uploadURLStr; + NSString *product; + NSString *version; + BOOL success; +} Options; + +//============================================================================= +static void Start(Options *options) { + NSURL *url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + + // Add parameters + [parameters setObject:options->product forKey:@"prod"]; + [parameters setObject:options->version forKey:@"ver"]; + [ul setParameters:parameters]; + + // Add file + [ul addFileAtPath:options->minidumpPath name:@"upload_file_minidump"]; + + // Send it + NSError *error = nil; + NSData *data = [ul send:&error]; + NSString *result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + + NSLog(@"Send: %@", error ? [error description] : @"No Error"); + NSLog(@"Response: %ld", (long)[[ul response] statusCode]); + NSLog(@"Result: %lu bytes\n%@", (unsigned long)[data length], result); + + [result release]; + [ul release]; + options->success = !error; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit minidump information.\n"); + fprintf(stderr, "Usage: %s -p <product> -v <version> <minidump> " + "<upload-URL>\n", argv[0]); + fprintf(stderr, "<minidump> should be a minidump.\n"); + fprintf(stderr, "<upload-URL> is the destination for the upload\n"); + + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "p:v:h?")) != -1) { + switch (ch) { + case 'p': + options->product = [NSString stringWithUTF8String:optarg]; + break; + case 'v': + options->version = [NSString stringWithUTF8String:optarg]; + break; + + default: + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + options->minidumpPath = [NSString stringWithUTF8String:argv[optind]]; + options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + + [pool release]; + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m new file mode 100644 index 0000000000..a7cce7b00c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.m @@ -0,0 +1,204 @@ +// Copyright (c) 2006, 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. + +// symupload.m: Upload a symbol file to a HTTP server. The upload is sent as +// a multipart/form-data POST request with the following parameters: +// code_file: the basename of the module, e.g. "app" +// debug_file: the basename of the debugging file, e.g. "app" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// os: the operating system that the module was built for +// cpu: the CPU that the module was built for (x86 or ppc) +// symbol_file: the contents of the breakpad-format symbol file + +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <Foundation/Foundation.h> +#include "HTTPMultipartUpload.h" + +typedef struct { + NSString *symbolsPath; + NSString *uploadURLStr; + BOOL success; +} Options; + +//============================================================================= +static NSArray *ModuleDataForSymbolFile(NSString *file) { + NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:file]; + NSData *data = [fh readDataOfLength:1024]; + NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSScanner *scanner = [NSScanner scannerWithString:str]; + NSString *line; + NSMutableArray *parts = nil; + const int MODULE_ID_INDEX = 3; + + if ([scanner scanUpToString:@"\n" intoString:&line]) { + parts = [[NSMutableArray alloc] init]; + NSScanner *moduleInfoScanner = [NSScanner scannerWithString:line]; + NSString *moduleInfo; + // Get everything BEFORE the module name. None of these properties + // can have spaces. + for (int i = 0; i <= MODULE_ID_INDEX; i++) { + [moduleInfoScanner scanUpToString:@" " intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + // Now get the module name. This can have a space so we scan to + // the end of the line. + [moduleInfoScanner scanUpToString:@"\n" intoString:&moduleInfo]; + [parts addObject:moduleInfo]; + } + + [str release]; + + return parts; +} + +//============================================================================= +static void Start(Options *options) { + NSURL *url = [NSURL URLWithString:options->uploadURLStr]; + HTTPMultipartUpload *ul = [[HTTPMultipartUpload alloc] initWithURL:url]; + NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; + NSArray *moduleParts = ModuleDataForSymbolFile(options->symbolsPath); + NSMutableString *compactedID = + [NSMutableString stringWithString:[moduleParts objectAtIndex:3]]; + [compactedID replaceOccurrencesOfString:@"-" withString:@"" options:0 + range:NSMakeRange(0, [compactedID length])]; + + // Add parameters + [parameters setObject:compactedID forKey:@"debug_identifier"]; + + // MODULE <os> <cpu> <uuid> <module-name> + // 0 1 2 3 4 + [parameters setObject:[moduleParts objectAtIndex:1] forKey:@"os"]; + [parameters setObject:[moduleParts objectAtIndex:2] forKey:@"cpu"]; + [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"debug_file"]; + [parameters setObject:[moduleParts objectAtIndex:4] forKey:@"code_file"]; + [ul setParameters:parameters]; + + NSArray *keys = [parameters allKeys]; + int count = [keys count]; + for (int i = 0; i < count; ++i) { + NSString *key = [keys objectAtIndex:i]; + NSString *value = [parameters objectForKey:key]; + fprintf(stdout, "'%s' = '%s'\n", [key UTF8String], + [value UTF8String]); + } + + // Add file + [ul addFileAtPath:options->symbolsPath name:@"symbol_file"]; + + // Send it + NSError *error = nil; + NSData *data = [ul send:&error]; + NSString *result = [[NSString alloc] initWithData:data + encoding:NSUTF8StringEncoding]; + int status = [[ul response] statusCode]; + + fprintf(stdout, "Send: %s\n", error ? [[error description] UTF8String] : + "No Error"); + fprintf(stdout, "Response: %d\n", status); + fprintf(stdout, "Result: %lu bytes\n%s\n", + (unsigned long)[data length], [result UTF8String]); + + [result release]; + [ul release]; + options->success = !error && status==200; +} + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s <symbols> <upload-URL>\n", argv[0]); + fprintf(stderr, "<symbols> should be created by using the dump_syms tool.\n"); + fprintf(stderr, "<upload-URL> is the destination for the upload\n"); + fprintf(stderr, "\t-h: Usage\n"); + fprintf(stderr, "\t-?: Usage\n"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + char ch; + + while ((ch = getopt(argc, (char * const *)argv, "h?")) != -1) { + switch (ch) { + default: + Usage(argc, argv); + exit(0); + break; + } + } + + if ((argc - optind) != 2) { + fprintf(stderr, "%s: Missing symbols file and/or upload-URL\n", argv[0]); + Usage(argc, argv); + exit(1); + } + + int fd = open(argv[optind], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + exit(1); + } + + struct stat statbuf; + if (fstat(fd, &statbuf) < 0) { + fprintf(stderr, "%s: %s: %s\n", argv[0], argv[optind], strerror(errno)); + close(fd); + exit(1); + } + close(fd); + + if (!S_ISREG(statbuf.st_mode)) { + fprintf(stderr, "%s: %s: not a regular file\n", argv[0], argv[optind]); + exit(1); + } + + options->symbolsPath = [NSString stringWithUTF8String:argv[optind]]; + options->uploadURLStr = [NSString stringWithUTF8String:argv[optind + 1]]; +} + +//============================================================================= +int main (int argc, const char * argv[]) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Options options; + + bzero(&options, sizeof(Options)); + SetupOptions(argc, argv, &options); + Start(&options); + + [pool release]; + return options.success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..a6a78dc5f3 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj @@ -0,0 +1,254 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* symupload.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD836000B0544BA0055103E /* minidump_upload.m */; }; + 9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */; }; + 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; }; + 9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 9BD8336A0B03E4080055103E /* HTTPMultipartUpload.h in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Breakpad.xcconfig; path = ../../../common/mac/Breakpad.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadDebug.xcconfig; path = ../../../common/mac/BreakpadDebug.xcconfig; sourceTree = SOURCE_ROOT; }; + 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BreakpadRelease.xcconfig; path = ../../../common/mac/BreakpadRelease.xcconfig; sourceTree = SOURCE_ROOT; }; + 8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; }; + 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; }; + 9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; }; + 9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD835F90B0544950055103E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8B31022C11F0CEBD00FCF3E4 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* symupload */ = { + isa = PBXGroup; + children = ( + 8B31022B11F0CE6900FCF3E4 /* Breakpad.xcconfig */, + 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */, + 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */, + 08FB7796FE84155DC02AAC07 /* symupload.m */, + 9BD836000B0544BA0055103E /* minidump_upload.m */, + 9BD833680B03E4080055103E /* HTTPMultipartUpload.h */, + 9BD833690B03E4080055103E /* HTTPMultipartUpload.m */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = symupload; + sourceTree = "<group>"; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = "<group>"; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* symupload */, + 9BD835FB0B0544950055103E /* minidump_upload */, + ); + name = Products; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* symupload */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = symupload; + productInstallPath = "$(HOME)/bin"; + productName = symupload; + productReference = 8DD76FA10486AA7600D96B5E /* symupload */; + productType = "com.apple.product-type.tool"; + }; + 9BD835FA0B0544950055103E /* minidump_upload */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */; + buildPhases = ( + 9BD835F80B0544950055103E /* Sources */, + 9BD835F90B0544950055103E /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = minidump_upload; + productName = minidump_upload; + productReference = 9BD835FB0B0544950055103E /* minidump_upload */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* symupload */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* symupload */, + 9BD835FA0B0544950055103E /* minidump_upload */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E /* symupload.m in Sources */, + 9BD8336B0B03E4080055103E /* HTTPMultipartUpload.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9BD835F80B0544950055103E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9BD836180B0549F70055103E /* HTTPMultipartUpload.m in Sources */, + 9BC1D49E0B37427A00F2A2B4 /* minidump_upload.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = symupload; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = symupload; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102B611F0D5CE00FCF3E4 /* BreakpadDebug.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102B711F0D5CE00FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + }; + name = Release; + }; + 9BD836030B0544BB0055103E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = minidump_upload; + }; + name = Debug; + }; + 9BD836040B0544BB0055103E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ../../..; + PRODUCT_NAME = minidump_upload; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "symupload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "symupload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9BD836020B0544BB0055103E /* Build configuration list for PBXNativeTarget "minidump_upload" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9BD836030B0544BB0055103E /* Debug */, + 9BD836040B0544BB0055103E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi b/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi new file mode 100644 index 0000000000..7457573b4b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/tools_mac.gypi @@ -0,0 +1,116 @@ +# Copyright 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. + +{ + 'target_defaults': { + 'include_dirs': [ + '../..', + ], + }, + 'targets': [ + { + 'target_name': 'crash_report', + 'type': 'executable', + 'sources': [ + 'crash_report/crash_report.mm', + 'crash_report/on_demand_symbol_supplier.h', + 'crash_report/on_demand_symbol_supplier.mm', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + '../processor/processor.gyp:processor', + ], + }, + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms/dump_syms_tool.cc', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'macho_dump', + 'type': 'executable', + 'sources': [ + 'dump_syms/macho_dump.cc', + ], + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'minidump_upload', + 'type': 'executable', + 'sources': [ + 'symupload/minidump_upload.m', + ], + 'include_dirs': [ + '../../common/mac', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload/symupload.m', + ], + 'include_dirs': [ + '../../common/mac', + ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', + ], + }, + 'dependencies': [ + '../common/common.gyp:common', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h new file mode 100644 index 0000000000..e12e53e229 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h @@ -0,0 +1,67 @@ +/* Copyright 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 <mach-o/arch.h> +#include <mach-o/loader.h> +#include <mach/machine.h> + +// Go/Cgo does not support #define constants, so turn them into symbols +// that are reachable from Go. + +#ifndef CPU_TYPE_ARM64 +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) +#endif + +#ifndef CPU_SUBTYPE_ARM64_ALL +#define CPU_SUBTYPE_ARM64_ALL 0 +#endif + +#ifndef CPU_SUBTYPE_ARM64_E +#define CPU_SUBTYPE_ARM64_E 2 +#endif + +const cpu_type_t kCPU_TYPE_ARM = CPU_TYPE_ARM; +const cpu_type_t kCPU_TYPE_ARM64 = CPU_TYPE_ARM64; + +const cpu_subtype_t kCPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM64_ALL; +const cpu_subtype_t kCPU_SUBTYPE_ARM64_E = CPU_SUBTYPE_ARM64_E; +const cpu_subtype_t kCPU_SUBTYPE_ARM_V7S = CPU_SUBTYPE_ARM_V7S; + +const char* GetNXArchInfoName(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + const NXArchInfo* arch_info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); + if (!arch_info) + return 0; + return arch_info->name; +} + +const uint32_t kMachHeaderFtypeDylib = MH_DYLIB; +const uint32_t kMachHeaderFtypeBundle = MH_BUNDLE; +const uint32_t kMachHeaderFtypeExe = MH_EXECUTE; +const uint32_t kMachHeaderFtypeDylinker = MH_DYLINKER; diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go new file mode 100644 index 0000000000..ed98fa60f4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go @@ -0,0 +1,69 @@ +/* Copyright 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. +*/ + +package main + +import ( + "debug/macho" +) + +/* +#include "arch_constants.h" +*/ +import "C" + +// getArchStringFromHeader takes a MachO FileHeader and returns a string that +// represents the CPU type and subtype. +// This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType(). +func getArchStringFromHeader(header macho.FileHeader) string { + // TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h. + if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL { + return "arm64" + } + if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_E { + return "arm64e" + } + if header.Cpu == C.kCPU_TYPE_ARM && header.SubCpu == C.kCPU_SUBTYPE_ARM_V7S { + return "armv7s" + } + + cstr := C.GetNXArchInfoName(C.cpu_type_t(header.Cpu), C.cpu_subtype_t(header.SubCpu)) + if cstr == nil { + return "" + } + return C.GoString(cstr) +} + +const ( + MachODylib macho.Type = C.kMachHeaderFtypeDylib + MachOBundle = C.kMachHeaderFtypeBundle + MachOExe = C.kMachHeaderFtypeExe + MachODylinker = C.kMachHeaderFtypeDylinker +) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go new file mode 100644 index 0000000000..05a7764abf --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -0,0 +1,432 @@ +/* Copyright 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. +*/ + +/* +Tool upload_system_symbols generates and uploads Breakpad symbol files for OS X system libraries. + +This tool shells out to the dump_syms and symupload Breakpad tools. In its default mode, this +will find all dynamic libraries on the system, run dump_syms to create the Breakpad symbol files, +and then upload them to Google's crash infrastructure. + +The tool can also be used to only dump libraries or upload from a directory. See -help for more +information. + +Both i386 and x86_64 architectures will be dumped and uploaded. +*/ +package main + +import ( + "debug/macho" + "flag" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path" + "regexp" + "strings" + "sync" + "time" +) + +var ( + breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.") + uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.") + dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.") + systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.") + dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.") +) + +var ( + // pathsToScan are the subpaths in the systemRoot that should be scanned for shared libraries. + pathsToScan = []string{ + "/System/Library/Components", + "/System/Library/Frameworks", + "/System/Library/PrivateFrameworks", + "/usr/lib", + } + + // optionalPathsToScan is just like pathsToScan, but the paths are permitted to be absent. + optionalPathsToScan = []string{ + // Gone in 10.15. + "/Library/QuickTime", + } + + // uploadServers are the list of servers to which symbols should be uploaded. + uploadServers = []string{ + "https://clients2.google.com/cr/symbol", + "https://clients2.google.com/cr/staging_symbol", + } + + // blacklistRegexps match paths that should be excluded from dumping. + blacklistRegexps = []*regexp.Regexp{ + regexp.MustCompile(`/System/Library/Frameworks/Python\.framework/`), + regexp.MustCompile(`/System/Library/Frameworks/Ruby\.framework/`), + regexp.MustCompile(`_profile\.dylib$`), + regexp.MustCompile(`_debug\.dylib$`), + regexp.MustCompile(`\.a$`), + regexp.MustCompile(`\.dat$`), + } +) + +func main() { + flag.Parse() + log.SetFlags(0) + + var uq *UploadQueue + + if *uploadOnlyPath != "" { + // -upload-from specified, so handle that case early. + uq = StartUploadQueue() + uploadFromDirectory(*uploadOnlyPath, uq) + uq.Wait() + return + } + + if *systemRoot == "" { + log.Fatal("Need a -system-root to dump symbols for") + } + + if *dumpOnlyPath != "" { + // -dump-to specified, so make sure that the path is a directory. + if fi, err := os.Stat(*dumpOnlyPath); err != nil { + log.Fatalf("-dump-to location: %v", err) + } else if !fi.IsDir() { + log.Fatal("-dump-to location is not a directory") + } + } + + dumpPath := *dumpOnlyPath + if *dumpOnlyPath == "" { + // If -dump-to was not specified, then run the upload pipeline and create + // a temporary dump output directory. + uq = StartUploadQueue() + + if p, err := ioutil.TempDir("", "upload_system_symbols"); err != nil { + log.Fatalf("Failed to create temporary directory: %v", err) + } else { + dumpPath = p + defer os.RemoveAll(p) + } + } + + dq := StartDumpQueue(*systemRoot, dumpPath, uq) + dq.Wait() + if uq != nil { + uq.Wait() + } +} + +type WorkerPool struct { + wg sync.WaitGroup +} + +// StartWorkerPool will launch numWorkers goroutines all running workerFunc. +// When workerFunc exits, the goroutine will terminate. +func StartWorkerPool(numWorkers int, workerFunc func()) *WorkerPool { + p := new(WorkerPool) + for i := 0; i < numWorkers; i++ { + p.wg.Add(1) + go func() { + workerFunc() + p.wg.Done() + }() + } + return p +} + +// Wait for all the workers in the pool to complete the workerFunc. +func (p *WorkerPool) Wait() { + p.wg.Wait() +} + +type UploadQueue struct { + *WorkerPool + queue chan string +} + +// StartUploadQueue creates a new worker pool and queue, to which paths to +// Breakpad symbol files may be sent for uploading. +func StartUploadQueue() *UploadQueue { + uq := &UploadQueue{ + queue: make(chan string, 10), + } + uq.WorkerPool = StartWorkerPool(5, uq.worker) + return uq +} + +// Upload enqueues the contents of filepath to be uploaded. +func (uq *UploadQueue) Upload(filepath string) { + uq.queue <- filepath +} + +// Done tells the queue that no more files need to be uploaded. This must be +// called before WorkerPool.Wait. +func (uq *UploadQueue) Done() { + close(uq.queue) +} + +func (uq *UploadQueue) worker() { + symUpload := path.Join(*breakpadTools, "symupload") + + for symfile := range uq.queue { + for _, server := range uploadServers { + for i := 0; i < 3; i++ { // Give each upload 3 attempts to succeed. + cmd := exec.Command(symUpload, symfile, server) + if output, err := cmd.Output(); err == nil { + // Success. No retry needed. + fmt.Printf("Uploaded %s to %s\n", symfile, server) + break + } else { + log.Printf("Error running symupload(%s, %s), attempt %d: %v: %s\n", symfile, server, i, err, output) + time.Sleep(1 * time.Second) + } + } + } + } +} + +type DumpQueue struct { + *WorkerPool + dumpPath string + queue chan dumpRequest + uq *UploadQueue +} + +type dumpRequest struct { + path string + arch string +} + +// StartDumpQueue creates a new worker pool to find all the Mach-O libraries in +// root and dump their symbols to dumpPath. If an UploadQueue is passed, the +// path to the symbol file will be enqueued there, too. +func StartDumpQueue(root, dumpPath string, uq *UploadQueue) *DumpQueue { + dq := &DumpQueue{ + dumpPath: dumpPath, + queue: make(chan dumpRequest), + uq: uq, + } + dq.WorkerPool = StartWorkerPool(12, dq.worker) + + findLibsInRoot(root, dq) + + return dq +} + +// DumpSymbols enqueues the filepath to have its symbols dumped in the specified +// architecture. +func (dq *DumpQueue) DumpSymbols(filepath string, arch string) { + dq.queue <- dumpRequest{ + path: filepath, + arch: arch, + } +} + +func (dq *DumpQueue) Wait() { + dq.WorkerPool.Wait() + if dq.uq != nil { + dq.uq.Done() + } +} + +func (dq *DumpQueue) done() { + close(dq.queue) +} + +func (dq *DumpQueue) worker() { + dumpSyms := path.Join(*breakpadTools, "dump_syms") + + for req := range dq.queue { + filebase := path.Join(dq.dumpPath, strings.Replace(req.path, "/", "_", -1)) + symfile := fmt.Sprintf("%s_%s.sym", filebase, req.arch) + f, err := os.Create(symfile) + if err != nil { + log.Fatalf("Error creating symbol file: %v", err) + } + + cmd := exec.Command(dumpSyms, "-a", req.arch, req.path) + cmd.Stdout = f + err = cmd.Run() + f.Close() + + if err != nil { + os.Remove(symfile) + log.Printf("Error running dump_syms(%s, %s): %v\n", req.arch, req.path, err) + } else if dq.uq != nil { + dq.uq.Upload(symfile) + } + } +} + +// uploadFromDirectory handles the upload-only case and merely uploads all files in +// a directory. +func uploadFromDirectory(directory string, uq *UploadQueue) { + d, err := os.Open(directory) + if err != nil { + log.Fatalf("Could not open directory to upload: %v", err) + } + defer d.Close() + + entries, err := d.Readdirnames(0) + if err != nil { + log.Fatalf("Could not read directory: %v", err) + } + + for _, entry := range entries { + uq.Upload(path.Join(directory, entry)) + } + + uq.Done() +} + +// findQueue is an implementation detail of the DumpQueue that finds all the +// Mach-O files and their architectures. +type findQueue struct { + *WorkerPool + queue chan string + dq *DumpQueue +} + +// findLibsInRoot looks in all the pathsToScan in the root and manages the +// interaction between findQueue and DumpQueue. +func findLibsInRoot(root string, dq *DumpQueue) { + fq := &findQueue{ + queue: make(chan string, 10), + dq: dq, + } + fq.WorkerPool = StartWorkerPool(12, fq.worker) + + for _, p := range pathsToScan { + fq.findLibsInPath(path.Join(root, p), true) + } + + for _, p := range optionalPathsToScan { + fq.findLibsInPath(path.Join(root, p), false) + } + + close(fq.queue) + fq.Wait() + dq.done() +} + +// findLibsInPath recursively walks the directory tree, sending file paths to +// test for being Mach-O to the findQueue. +func (fq *findQueue) findLibsInPath(loc string, mustExist bool) { + d, err := os.Open(loc) + if err != nil { + if !mustExist && os.IsNotExist(err) { + return + } + log.Fatalf("Could not open %s: %v", loc, err) + } + defer d.Close() + + for { + fis, err := d.Readdir(100) + if err != nil && err != io.EOF { + log.Fatalf("Error reading directory %s: %v", loc, err) + } + + for _, fi := range fis { + fp := path.Join(loc, fi.Name()) + if fi.IsDir() { + fq.findLibsInPath(fp, true) + continue + } else if fi.Mode()&os.ModeSymlink != 0 { + continue + } + + // Test the blacklist in the worker to not slow down this main loop. + + fq.queue <- fp + } + + if err == io.EOF { + break + } + } +} + +func (fq *findQueue) worker() { + for fp := range fq.queue { + blacklisted := false + for _, re := range blacklistRegexps { + blacklisted = blacklisted || re.MatchString(fp) + } + if blacklisted { + continue + } + + f, err := os.Open(fp) + if err != nil { + log.Printf("%s: %v", fp, err) + continue + } + + fatFile, err := macho.NewFatFile(f) + if err == nil { + // The file is fat, so dump its architectures. + for _, fatArch := range fatFile.Arches { + fq.dumpMachOFile(fp, fatArch.File) + } + fatFile.Close() + } else if err == macho.ErrNotFat { + // The file isn't fat but may still be MachO. + thinFile, err := macho.NewFile(f) + if err != nil { + log.Printf("%s: %v", fp, err) + continue + } + fq.dumpMachOFile(fp, thinFile) + thinFile.Close() + } else { + f.Close() + } + } +} + +func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) { + if image.Type != MachODylib && image.Type != MachOBundle && image.Type != MachODylinker { + return + } + + arch := getArchStringFromHeader(image.FileHeader) + if arch == "" { + // Don't know about this architecture type. + return + } + + if (*dumpArchitecture != "" && *dumpArchitecture == arch) || *dumpArchitecture == "" { + fq.dq.DumpSymbols(fp, arch) + } +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py b/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py new file mode 100755 index 0000000000..b456285431 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/deps-to-manifest.py @@ -0,0 +1,167 @@ +#!/usr/bin/python +# Copyright 2016 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. + +"""Convert gclient's DEPS file to repo's manifest xml file.""" + +from __future__ import print_function + +import argparse +import os +import sys + + +REMOTES = { + 'chromium': 'https://chromium.googlesource.com/', + 'github': 'https://github.com/', +} +REVIEWS = { + 'chromium': 'https://chromium-review.googlesource.com', +} + +MANIFEST_HEAD = """<?xml version='1.0' encoding='UTF-8'?> +<!-- AUTOGENERATED BY %(prog)s; DO NOT EDIT --> +<manifest> + + <default revision='refs/heads/master' + remote='chromium' + sync-c='true' + sync-j='8' /> +""" + +MANIFEST_REMOTE = """ + <remote name='%(name)s' + fetch='%(fetch)s' + review='%(review)s' /> +""" + +MANIFEST_PROJECT = """ + <project path='%(path)s' + name='%(name)s' + revision='%(revision)s' + remote='%(remote)s' /> +""" + +MANIFEST_TAIL = """ +</manifest> +""" + + +def ConvertDepsToManifest(deps, manifest): + """Convert the |deps| file to the |manifest|.""" + # Load the DEPS file data. + ctx = {} + execfile(deps, ctx) + + new_contents = '' + + # Write out the common header. + data = { + 'prog': os.path.basename(__file__), + } + new_contents += MANIFEST_HEAD % data + + # Write out the <remote> sections. + for name, fetch in REMOTES.items(): + data = { + 'name': name, + 'fetch': fetch, + 'review': REVIEWS.get(name, ''), + } + new_contents += MANIFEST_REMOTE % data + + # Write out the main repo itself. + data = { + 'path': 'src', + 'name': 'breakpad/breakpad', + 'revision': 'refs/heads/master', + 'remote': 'chromium', + } + new_contents += MANIFEST_PROJECT % data + + # Write out the <project> sections. + for path, url in ctx['deps'].items(): + for name, fetch in REMOTES.items(): + if url.startswith(fetch): + remote = name + break + else: + raise ValueError('Unknown DEPS remote: %s: %s' % (path, url)) + + # The DEPS url will look like: + # https://chromium.googlesource.com/external/gyp/@e8ab0833a42691cd2 + remote_path, rev = url.split('@') + remote_path = remote_path[len(fetch):] + + # If it's not a revision, assume it's a tag. Repo wants full ref names. + if len(rev) != 40: + rev = 'refs/tags/%s' % rev + + data = { + 'path': path, + 'name': remote_path, + 'revision': rev, + 'remote': remote, + } + new_contents += MANIFEST_PROJECT % data + + # Write out the common footer. + new_contents += MANIFEST_TAIL + + # See if the manifest has actually changed contents to avoid thrashing. + try: + old_contents = open(manifest).read() + except IOError: + # In case the file doesn't exist yet. + old_contents = '' + if old_contents != new_contents: + print('Updating %s due to changed %s' % (manifest, deps)) + with open(manifest, 'w') as fp: + fp.write(new_contents) + + +def GetParser(): + """Return a CLI parser.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('deps', + help='The DEPS file to convert') + parser.add_argument('manifest', + help='The manifest xml to generate') + return parser + + +def main(argv): + """The main func!""" + parser = GetParser() + opts = parser.parse_args(argv) + ConvertDepsToManifest(opts.deps, opts.manifest) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py b/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py new file mode 100644 index 0000000000..abddf7893e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python +# 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. + +"""Normalizes and de-duplicates paths within Breakpad symbol files. + +When using DWARF for storing debug symbols, some file information will be +stored relative to the current working directory of the current compilation +unit, and may be further relativized based upon how the file was #included. + +This helper can be used to parse the Breakpad symbol file generated from such +DWARF files and normalize and de-duplicate the FILE records found within, +updating any references to the FILE records in the other record types. +""" + +import macpath +import ntpath +import optparse +import os +import posixpath +import sys + +class BreakpadParseError(Exception): + """Unsupported Breakpad symbol record exception class.""" + pass + +class SymbolFileParser(object): + """Parser for Breakpad symbol files. + + The format of these files is documented at + https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md + """ + + def __init__(self, input_stream, output_stream, ignored_prefixes=None, + path_handler=os.path): + """Inits a SymbolFileParser to read symbol records from |input_stream| and + write the processed output to |output_stream|. + + |ignored_prefixes| contains a list of optional path prefixes that + should be stripped from the final, normalized path outputs. + + For example, if the Breakpad symbol file had all paths starting with a + common prefix, such as: + FILE 1 /b/build/src/foo.cc + FILE 2 /b/build/src/bar.cc + Then adding "/b/build/src" as an ignored prefix would result in an output + file that contained: + FILE 1 foo.cc + FILE 2 bar.cc + + Note that |ignored_prefixes| does not necessarily contain file system + paths, as the contents of the DWARF DW_AT_comp_dir attribute is dependent + upon the host system and compiler, and may contain additional information + such as hostname or compiler version. + """ + + self.unique_files = {} + self.duplicate_files = {} + self.input_stream = input_stream + self.output_stream = output_stream + self.ignored_prefixes = ignored_prefixes or [] + self.path_handler = path_handler + + def Process(self): + """Processes the Breakpad symbol file.""" + for line in self.input_stream: + parsed = self._ParseRecord(line.rstrip()) + if parsed: + self.output_stream.write(parsed + '\n') + + def _ParseRecord(self, record): + """Parses a single Breakpad symbol record - a single line from the symbol + file. + + Returns: + The modified string to write to the output file, or None if no line + should be written. + """ + record_type = record.partition(' ')[0] + if record_type == 'FILE': + return self._ParseFileRecord(record) + elif self._IsLineRecord(record_type): + return self._ParseLineRecord(record) + else: + # Simply pass the record through unaltered. + return record + + def _NormalizePath(self, path): + """Normalizes a file path to its canonical form. + + As this may not execute on the machine or file system originally + responsible for compilation, it may be necessary to further correct paths + for symlinks, junctions, or other such file system indirections. + + Returns: + A unique, canonical representation for the the file path. + """ + return self.path_handler.normpath(path) + + def _AdjustPath(self, path): + """Adjusts the supplied path after performing path de-duplication. + + This may be used to perform secondary adjustments, such as removing a + common prefix, such as "/D/build", or replacing the file system path with + information from the version control system. + + Returns: + The actual path to use when writing the FILE record. + """ + return path[len(filter(path.startswith, + self.ignored_prefixes + [''])[0]):] + + def _ParseFileRecord(self, file_record): + """Parses and corrects a FILE record.""" + file_info = file_record[5:].split(' ', 3) + if len(file_info) > 2: + raise BreakpadParseError('Unsupported FILE record: ' + file_record) + file_index = int(file_info[0]) + file_name = self._NormalizePath(file_info[1]) + existing_file_index = self.unique_files.get(file_name) + if existing_file_index is None: + self.unique_files[file_name] = file_index + file_info[1] = self._AdjustPath(file_name) + return 'FILE ' + ' '.join(file_info) + else: + self.duplicate_files[file_index] = existing_file_index + return None + + def _IsLineRecord(self, record_type): + """Determines if the current record type is a Line record""" + try: + line = int(record_type, 16) + except (ValueError, TypeError): + return False + return True + + def _ParseLineRecord(self, line_record): + """Parses and corrects a Line record.""" + line_info = line_record.split(' ', 5) + if len(line_info) > 4: + raise BreakpadParseError('Unsupported Line record: ' + line_record) + file_index = int(line_info[3]) + line_info[3] = str(self.duplicate_files.get(file_index, file_index)) + return ' '.join(line_info) + +def main(): + option_parser = optparse.OptionParser() + option_parser.add_option("-p", "--prefix", + action="append", dest="prefixes", type="string", + default=[], + help="A path prefix that should be removed from " + "all FILE lines. May be repeated to specify " + "multiple prefixes.") + option_parser.add_option("-t", "--path_type", + action="store", type="choice", dest="path_handler", + choices=['win32', 'posix'], + help="Indicates how file paths should be " + "interpreted. The default is to treat paths " + "the same as the OS running Python (eg: " + "os.path)") + options, args = option_parser.parse_args() + if args: + option_parser.error('Unknown argument: %s' % args) + + path_handler = { 'win32': ntpath, + 'posix': posixpath }.get(options.path_handler, os.path) + try: + symbol_parser = SymbolFileParser(sys.stdin, sys.stdout, options.prefixes, + path_handler) + symbol_parser.Process() + except BreakpadParseError, e: + print >> sys.stderr, 'Got an error while processing symbol file' + print >> sys.stderr, str(e) + return 1 + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py b/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py new file mode 100644 index 0000000000..b111f34983 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/python/tests/filter_syms_unittest.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# 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. + +"""Unit tests for filter_syms.py""" + +import cStringIO +import ntpath +import os +import StringIO +import sys +import unittest + +ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(ROOT_DIR, '..')) + +# In root +import filter_syms + +class FilterSysmsTest(unittest.TestCase): + def assertParsed(self, input_data, ignored_prefixes, expected): + input_io = cStringIO.StringIO(input_data) + output_io = cStringIO.StringIO() + parser = filter_syms.SymbolFileParser(input_io, output_io, + ignored_prefixes, ntpath) + parser.Process() + self.assertEqual(output_io.getvalue(), expected) + + def testDuplicateFiles(self): + """Tests that duplicate files in FILE records are correctly removed and + that Line records are updated.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 foo/../file1_1.cc +FILE 2 bar/../file1_1.cc +FILE 3 baz/../file1_1.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 1 +1008 4 46 1 +100c 4 44 1 +""" + self.assertParsed(INPUT, [], EXPECTED_OUTPUT) + + def testIgnoredPrefix(self): + """Tests that prefixes in FILE records are correctly removed.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 /src/build/foo/../file1_1.cc +FILE 2 /src/build/bar/../file1_2.cc +FILE 3 /src/build/baz/../file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FILE 2 file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 2 +100c 4 44 1 +""" + IGNORED_PREFIXES = ['\\src\\build\\'] + self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) + + def testIgnoredPrefixesDuplicateFiles(self): + """Tests that de-duplication of FILE records happens BEFORE prefixes + are removed.""" + + INPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 /src/build/foo/../file1_1.cc +FILE 2 /src/build/bar/../file1_2.cc +FILE 3 D:/src/build2/baz/../file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + EXPECTED_OUTPUT = \ +"""MODULE windows x86 111111111111111111111111111111111 module1.pdb +INFO CODE_ID FFFFFFFF module1.exe +FILE 1 file1_1.cc +FILE 2 file1_2.cc +FILE 3 file1_2.cc +FUNC 1000 c 0 Function1_1 +1000 8 45 2 +1008 4 46 3 +100c 4 44 1 +""" + IGNORED_PREFIXES = ['\\src\\build\\', 'D:\\src\\build2\\'] + self.assertParsed(INPUT, IGNORED_PREFIXES, EXPECTED_OUTPUT) + +if __name__ == '__main__': + unittest.main()
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile new file mode 100644 index 0000000000..ff77105c61 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile @@ -0,0 +1,64 @@ +# Copyright (c) 2007, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Author: Alfred Peng + +CXX=CC +CC=cc + +CXXFLAGS=-g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -lelf -ldemangle -D_REENTRANT + +.PHONY:all clean + +BIN=dump_syms + +all:$(BIN) + +DUMP_OBJ=dump_symbols.o guid_creator.o dump_syms.o file_id.o md5.o + +dump_syms:$(DUMP_OBJ) + $(CXX) $(CXXFLAGS) -o $@ $^ + +dump_symbols.o:../../../common/solaris/dump_symbols.cc + $(CXX) $(CXXFLAGS) -c $^ + +guid_creator.o:../../../common/solaris/guid_creator.cc + $(CXX) $(CXXFLAGS) -c $^ + +file_id.o:../../../common/solaris/file_id.cc + $(CXX) $(CXXFLAGS) -c $^ + +md5.o:../../../common/md5.cc + $(CXX) $(CXXFLAGS) -c $^ + +test:all + ./run_regtest.sh + +clean: + rm -f $(BIN) $(DUMP_OBJ) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in new file mode 100644 index 0000000000..7bef51e078 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/Makefile.in @@ -0,0 +1,5 @@ +# 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/. + +HOST_LDFLAGS += -lelf -ldemangle diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..54cea57e75 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/dump_syms.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Alfred Peng + +#include <string> +#include <cstdio> + +#include "common/solaris/dump_symbols.h" + +using namespace google_breakpad; + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]); + return 1; + } + + const char *binary = argv[1]; + + DumpSymbols dumper; + if (!dumper.WriteSymbolFile(binary, fileno(stdout))) { + fprintf(stderr, "Failed to write symbol file.\n"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh new file mode 100644 index 0000000000..ffb3433067 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/run_regtest.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +# Copyright (c) 2007, 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. + +./dump_syms testdata/dump_syms_regtest.o > testdata/dump_syms_regtest.new +status=$? + +if [ $status -ne 0 ] ; then + echo "FAIL, dump_syms failed" + exit $status +fi + +diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \ + testdata/dump_syms_regtest.diff +status=$? + +if [ $status -eq 0 ] ; then + rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new + echo "PASS" +else + echo "FAIL, see testdata/dump_syms_regtest.[new|diff]" +fi + +exit $status diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc new file mode 100644 index 0000000000..e617a23b81 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.cc @@ -0,0 +1,64 @@ +// Copyright (c) 2007, 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. + +// ./dump_syms dump_syms_regtest.pdb > dump_syms_regtest.sym + +namespace google_breakpad { + +class C { + public: + C() : member_(1) {} + virtual ~C() {} + + void set_member(int value) { member_ = value; } + int member() const { return member_; } + + void f() { member_ = g(); } + virtual int g() { return 2; } + static char* h(const C &that) { return 0; } + + private: + int member_; +}; + +static int i() { + return 3; +} + +} // namespace google_breakpad + +int main(int argc, char **argv) { + google_breakpad::C object; + object.set_member(google_breakpad::i()); + object.f(); + int value = object.g(); + char *nothing = object.h(object); + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs new file mode 100644 index 0000000000..c5f93ef78c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.stabs @@ -0,0 +1,129 @@ + + +Debugging Stab table -- 104 entries + + 0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x67,0x71c + 1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0 + 2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0 + 3: .stabs "",N_OBJ,0x0,0x0,0x0 + 4: .stabs "",N_OBJ,0x0,0x0,0x0 + 5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<<Sun C++ 5.8 Patch 121018-07 2006/11/01 (ccfe)>>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e + 6: .stabs "dump_syms_regtest.cc",N_SOL,0x0,0x0,0x0 + 7: .stabs "char:t(0,1)=bsc1;0;8",N_ISYM,0x0,0x0,0x0 + 8: .stabs "short:t(0,2)=bs2;0;16",N_ISYM,0x0,0x0,0x0 + 9: .stabs "int:t(0,3)=bs4;0;32",N_ISYM,0x0,0x0,0x0 + 10: .stabs "long:t(0,4)=bs4;0;32",N_ISYM,0x0,0x0,0x0 + 11: .stabs "long long:t(0,5)=bs8;0;64",N_ISYM,0x0,0x0,0x0 + 12: .stabs "unsigned char:t(0,6)=buc1;0;8",N_ISYM,0x0,0x0,0x0 + 13: .stabs "unsigned short:t(0,7)=bu2;0;16",N_ISYM,0x0,0x0,0x0 + 14: .stabs "unsigned:t(0,8)=bu4;0;32",N_ISYM,0x0,0x0,0x0 + 15: .stabs "unsigned long:t(0,9)=bu4;0;32",N_ISYM,0x0,0x0,0x0 + 16: .stabs "unsigned long long:t(0,10)=bu8;0;64",N_ISYM,0x0,0x0,0x0 + 17: .stabs "signed char:t(0,11)=bsc1;0;8",N_ISYM,0x0,0x0,0x0 + 18: .stabs "wchar_t:t(0,12)=buc4;0;32",N_ISYM,0x0,0x0,0x0 + 19: .stabs "void:t(0,13)=bs0;0;0",N_ISYM,0x0,0x0,0x0 + 20: .stabs "float:t(0,14)=R1;4",N_ISYM,0x0,0x0,0x0 + 21: .stabs "double:t(0,15)=R2;8",N_ISYM,0x0,0x0,0x0 + 22: .stabs "long double:t(0,16)=R6;12",N_ISYM,0x0,0x0,0x0 + 23: .stabs "...:t(0,17)=buv4;0;32",N_ISYM,0x0,0x0,0x0 + 24: .stabs "bool:t(0,18)=bub1;0;8",N_ISYM,0x0,0x0,0x0 + 25: .stabs "__1nPgoogle_breakpad_:T(0,19)=Yn0google_breakpad;",N_ISYM,0x0,0x0,0x0 + 26: .stabs "nBC(0,19):U(0,20)",N_ESYM,0x0,0x0,0x0 + 27: .stabs "nBC(0,19):T(0,20)=Yc8C;;AcHmember_:(0,3),32,32;;Cc2t6M_v K2c2T6M_v CcKset_member6Mi_v CcGmember6kM_i CcBf6M_v K3cBg6M_i GcBh6Frk1_pc;;;2 0;;;;110;",N_ESYM,0x0,0x8,0x0 + 28: .stabs "main:F(0,3);(0,3);(0,21)=*(0,22)=*(0,1)",N_FUN,0x0,0x38,0x0 + 29: .stabs "main",N_MAIN,0x0,0x0,0x0 + 30: .stabs "argc:p(0,3)",N_PSYM,0x0,0x4,0x8 + 31: .stabs "argv:p(0,21)",N_PSYM,0x0,0x4,0xc + 32: .stabn N_LBRAC,0x0,0x1,0x12 + 33: .stabs "object:(0,20)",N_LSYM,0x0,0x8,0xfffffff4 + 34: .stabs "value:(0,3)",N_LSYM,0x0,0x4,0xfffffff0 + 35: .stabs "nothing:(0,22)",N_LSYM,0x0,0x4,0xffffffec + 36: .stabn N_SLINE,0x0,0x39,0x12 + 37: .stabs "object:2",N_CONSTRUCT,0x0,0xc,0x12 + 38: .stabn N_SLINE,0x2,0x3a,0x1e + 39: .stabn N_SLINE,0x0,0x3b,0x36 + 40: .stabn N_SLINE,0x0,0x3c,0x42 + 41: .stabn N_SLINE,0x0,0x3d,0x57 + 42: .stabn N_SLINE,0x0,0x3f,0x6c + 43: .stabs "2:0",N_DESTRUCT,0x0,0xc,0x73 + 44: .stabn N_SLINE,0xfffffffe,0x40,0x9c + 45: .stabn N_RBRAC,0x0,0x1,0x9c + 46: .stabs "__1cPgoogle_breakpadBi6F_i_:f(0,3)",N_FUN,0x0,0x32,0x0 + 47: .stabn N_LBRAC,0x0,0x1,0x6 + 48: .stabn N_SLINE,0x0,0x33,0x6 + 49: .stabn N_SLINE,0x0,0x34,0x10 + 50: .stabn N_RBRAC,0x0,0x1,0x10 + 51: .stabs "__1cPgoogle_breakpadBC2t6M_v_:F(0,13);(0,23)=*(0,20)",N_FUN,0x0,0x24,0x0 + 52: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 53: .stabn N_LBRAC,0x0,0x1,0x3 + 54: .stabn N_SLINE,0x0,0x24,0x25 + 55: .stabn N_RBRAC,0x0,0x1,0x25 + 56: .stabs "__1cPgoogle_breakpadBC2T6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0 + 57: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 58: .stabn N_LBRAC,0x0,0x1,0x3 + 59: .stabn N_SLINE,0x0,0x25,0x3 + 60: .stabn N_RBRAC,0x0,0x1,0x3 + 61: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_:F(0,13);(0,23);(0,3)",N_FUN,0x0,0x27,0x0 + 62: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 63: .stabs "value:p(0,3)",N_PSYM,0x0,0x4,0xc + 64: .stabn N_LBRAC,0x0,0x1,0x3 + 65: .stabn N_SLINE,0x0,0x27,0x3 + 66: .stabn N_SLINE,0x0,0x27,0xc + 67: .stabn N_RBRAC,0x0,0x1,0xc + 68: .stabs "__1cPgoogle_breakpadBCBf6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x2a,0x0 + 69: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 70: .stabn N_LBRAC,0x0,0x1,0x3 + 71: .stabn N_SLINE,0x0,0x2a,0x3 + 72: .stabn N_SLINE,0x0,0x2a,0x1d + 73: .stabn N_RBRAC,0x0,0x1,0x1d + 74: .stabs "__1cPgoogle_breakpadBCBg6M_i_:F(0,3);(0,23)",N_FUN,0x0,0x2b,0x0 + 75: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 76: .stabn N_LBRAC,0x0,0x1,0x6 + 77: .stabn N_SLINE,0x0,0x2b,0x6 + 78: .stabn N_SLINE,0x0,0x2b,0x10 + 79: .stabn N_RBRAC,0x0,0x1,0x10 + 80: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_:F(0,22);(0,24)=&(0,25)=k(0,20)",N_FUN,0x0,0x2c,0x0 + 81: .stabs "that:p(0,24)",N_PSYM,0x0,0x4,0x8 + 82: .stabn N_LBRAC,0x0,0x1,0x6 + 83: .stabn N_SLINE,0x0,0x2c,0x6 + 84: .stabn N_SLINE,0x0,0x2c,0x10 + 85: .stabn N_RBRAC,0x0,0x1,0x10 + 86: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_:F(0,13);(0,23)",N_FUN,0x0,0x25,0x0 + 87: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 88: .stabn N_LBRAC,0x0,0x1,0x3 + 89: .stabn N_SLINE,0x0,0x25,0xf + 90: .stabn N_RBRAC,0x0,0x1,0xf + 91: .stabs "__SLIP.DELETER__A:f(0,13);(0,23);(0,3)",N_FUN,0x0,0x25,0x0 + 92: .stabs "this:p(0,23)",N_PSYM,0x0,0x4,0x8 + 93: .stabs "delete:p(0,3)",N_PSYM,0x0,0x4,0xc + 94: .stabn N_LBRAC,0x0,0x1,0x3 + 95: .stabn N_LBRAC,0x0,0x2,0x3 + 96: .stabn N_RBRAC,0x0,0x2,0x28 + 97: .stabn N_RBRAC,0x0,0x1,0x28 + 98: .stabs "true:l(0,18);1",N_LSYM,0x0,0x4,0x0 + 99: .stabs "false:l(0,18);0",N_LSYM,0x0,0x4,0x0 + 100: .stabs "__1c2k6Fpv_v_:P(0,13);(0,26)=*(0,13)",N_FUN,0x0,0x0,0x0 + 101: .stabs "__1cPgoogle_breakpadBC2t5B6M_v_:F__1cPgoogle_breakpadBC2t6M_v_",N_ALIAS,0x0,0x0,0x0 + 102: .stabs "cbD__RTTI__1nPgoogle_breakpadBC_(0,19):YR(0,20)",N_LSYM,0x0,0x0,0x0 + 103: .stabn N_ENDM,0x0,0x0,0x0 + + +Index Stab table -- 17 entries + + 0: .stabs "dump_syms_regtest.cc",N_UNDF,0x0,0x10,0x3b1 + 1: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/",N_SO,0x0,0x0,0x0 + 2: .stabs "dump_syms_regtest.cc",N_SO,0x0,0x4,0x0 + 3: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata",N_OBJ,0x0,0x0,0x0 + 4: .stabs "dump_syms_regtest.o",N_OBJ,0x0,0x0,0x0 + 5: .stabs "V=9.0;DBG_GEN=5.0.8;dm;cd;backend;ptf;ptx;ptk;s;g;R=5.8<<Sun C++ 5.8 Patch 121018-07 2006/11/01 (ccfe)>>;G=.XAB6Z2hOiL$Gl1b.;A=2",N_OPT,0x0,0x0,0x46fcb88e + 6: .stabs "/export/home/alfred/cvs/breakpad/google-breakpad20070927/src/tools/solaris/dump_syms/testdata/; /ws/on10-tools-prc/SUNWspro/SS11/prod/bin/CC -g -xs -xdebugformat=stabs -I../../.. -I../../../common/solaris -D_REENTRANT -xs dump_syms_regtest.cc -Qoption ccfe -prefix -Qoption ccfe .XAB6Z2hOiL\$Gl1b.",N_CMDLINE,0x0,0x0,0x0 + 7: .stabs "__1nPgoogle_breakpadBC_:U",N_ESYM,0x0,0x0,0x0 + 8: .stabs "main",N_MAIN,0x0,0x0,0x0 + 9: .stabs "main",N_FUN,0x0,0x0,0x0 + 10: .stabs "__1cPgoogle_breakpadBC2t6M_v_",N_FUN,0x0,0x0,0x0 + 11: .stabs "__1cPgoogle_breakpadBC2T6M_v_",N_FUN,0x0,0x0,0x0 + 12: .stabs "__1cPgoogle_breakpadBCKset_member6Mi_v_",N_FUN,0x0,0x0,0x0 + 13: .stabs "__1cPgoogle_breakpadBCBf6M_v_",N_FUN,0x0,0x0,0x0 + 14: .stabs "__1cPgoogle_breakpadBCBg6M_i_",N_FUN,0x0,0x0,0x0 + 15: .stabs "__1cPgoogle_breakpadBCBh6Frk1_pc_",N_FUN,0x0,0x0,0x0 + 16: .stabs "__1cPgoogle_breakpadBC2T5B6M_v_",N_FUN,0x0,0x0,0x0 diff --git a/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym new file mode 100644 index 0000000000..44d3c5391c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/testdata/dump_syms_regtest.sym @@ -0,0 +1,33 @@ +MODULE solaris x86 3DC8191474338D8587339B5FB3E2C62A0 dump_syms_regtest.o +FILE 0 dump_syms_regtest.cc +FUNC 0 156 0 main +12 18 57 0 +1e 12 58 0 +36 24 59 0 +42 12 60 0 +57 21 61 0 +6c 21 63 0 +9c 48 64 0 +FUNC 0 16 0 int google_breakpad::i() +6 6 51 0 +10 10 52 0 +FUNC 0 37 0 google_breakpad::C::C() +25 37 36 0 +FUNC 0 3 0 google_breakpad::C::~C() +3 3 37 0 +FUNC 0 12 0 void google_breakpad::C::set_member(int) +3 3 39 0 +c 9 39 0 +FUNC 0 29 0 void google_breakpad::C::f() +3 3 42 0 +1d 26 42 0 +FUNC 0 16 0 int google_breakpad::C::g() +6 6 43 0 +10 10 43 0 +FUNC 0 16 0 char*google_breakpad::C::h(const google_breakpad::C&) +6 6 44 0 +10 10 44 0 +FUNC 0 15 0 google_breakpad::C::~C #Nvariant 1() +f 15 37 0 +FUNC 0 0 0 __SLIP.DELETER__A +FUNC 0 0 0 void operator delete(void*) diff --git a/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp b/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp new file mode 100644 index 0000000000..e6a4210fec --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/tools.gyp @@ -0,0 +1,38 @@ +# Copyright 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. + +{ + 'conditions': [ + ['OS=="mac"', { + 'includes': ['mac/tools_mac.gypi'], + }], + ['OS=="linux"', { + 'includes': ['linux/tools_linux.gypi'], + }], + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc new file mode 100644 index 0000000000..2b40faeeb5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc @@ -0,0 +1,752 @@ +// Copyright (c) 2007, 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. + +// ms_symbol_server_converter.cc: Obtain symbol files from a Microsoft +// symbol server, and convert them to Breakpad's dumped format. +// +// See ms_symbol_server_converter.h for documentation. +// +// Author: Mark Mentovai + +#include <windows.h> +#include <dbghelp.h> +#include <pathcch.h> + +#include <cassert> +#include <cstdio> + +#include "tools/windows/converter/ms_symbol_server_converter.h" +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/pe_source_line_writer.h" +#include "common/windows/string_utils-inl.h" + +// SYMOPT_NO_PROMPTS is not defined in earlier platform SDKs. Define it +// in that case, in the event that this code is used with a newer version +// of DbgHelp at runtime that recognizes the option. The presence of this +// bit in the symbol options should not harm earlier versions of DbgHelp. +#ifndef SYMOPT_NO_PROMPTS +#define SYMOPT_NO_PROMPTS 0x00080000 +#endif // SYMOPT_NO_PROMPTS + +namespace { + +std::wstring GetExeDirectory() { + wchar_t directory[MAX_PATH]; + + // Get path to this process exe. + DWORD result = GetModuleFileName(/*hModule=*/nullptr, directory, MAX_PATH); + if (result <= 0 || result == MAX_PATH) { + fprintf(stderr, + "GetExeDirectory: failed to get path to process exe.\n"); + return L""; + } + HRESULT hr = PathCchRemoveFileSpec(directory, result + 1); + if (hr != S_OK) { + fprintf(stderr, + "GetExeDirectory: failed to remove basename from path '%ls'.\n", + directory); + return L""; + } + + return std::wstring(directory); +} + +} // namespace + +namespace google_breakpad { + +// Use sscanf_s if it is available, to quench the warning about scanf being +// deprecated. Use scanf where sscanf_is not available. Note that the +// parameters passed to sscanf and sscanf_s are only compatible as long as +// fields of type c, C, s, S, and [ are not used. +#if _MSC_VER >= 1400 // MSVC 2005/8 +#define SSCANF sscanf_s +#else // _MSC_VER >= 1400 +#define SSCANF sscanf +#endif // _MSC_VER >= 1400 + +bool GUIDOrSignatureIdentifier::InitializeFromString( + const string &identifier) { + type_ = TYPE_NONE; + + size_t length = identifier.length(); + + if (length > 32 && length <= 40) { + // GUID + if (SSCANF(identifier.c_str(), + "%08X%04hX%04hX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%X", + &guid_.Data1, &guid_.Data2, &guid_.Data3, + &guid_.Data4[0], &guid_.Data4[1], + &guid_.Data4[2], &guid_.Data4[3], + &guid_.Data4[4], &guid_.Data4[5], + &guid_.Data4[6], &guid_.Data4[7], + &age_) != 12) { + return false; + } + + type_ = TYPE_GUID; + } else if (length > 8 && length <= 15) { + // Signature + if (SSCANF(identifier.c_str(), "%08X%x", &signature_, &age_) != 2) { + return false; + } + + type_ = TYPE_SIGNATURE; + } else { + return false; + } + + return true; +} + +#undef SSCANF + +MSSymbolServerConverter::MSSymbolServerConverter( + const string &local_cache, const vector<string> &symbol_servers) + : symbol_path_(), + fail_dns_(false), + fail_timeout_(false), + fail_not_found_(false) { + // Setting local_cache can be done without verifying that it exists because + // SymSrv will create it if it is missing - any creation failures will occur + // at that time, so there's nothing to check here, making it safe to + // assign this in the constructor. + + assert(symbol_servers.size() > 0); + +#if !defined(NDEBUG) + // These are characters that are interpreted as having special meanings in + // symbol_path_. + const char kInvalidCharacters[] = "*;"; + assert(local_cache.find_first_of(kInvalidCharacters) == string::npos); +#endif // !defined(NDEBUG) + + for (vector<string>::const_iterator symbol_server = symbol_servers.begin(); + symbol_server != symbol_servers.end(); + ++symbol_server) { + // The symbol path format is explained by + // http://msdn.microsoft.com/library/en-us/debug/base/using_symsrv.asp . + // "srv*" is the same as "symsrv*symsrv.dll*", which means that + // symsrv.dll is to be responsible for locating symbols. symsrv.dll + // interprets the rest of the string as a series of symbol stores separated + // by '*'. "srv*local_cache*symbol_server" means to check local_cache + // first for the symbol file, and if it is not found there, to check + // symbol_server. Symbol files found on the symbol server will be placed + // in the local cache, decompressed. + // + // Multiple specifications in this format may be presented, separated by + // semicolons. + + assert((*symbol_server).find_first_of(kInvalidCharacters) == string::npos); + symbol_path_ += "srv*" + local_cache + "*" + *symbol_server + ";"; + } + + // Strip the trailing semicolon. + symbol_path_.erase(symbol_path_.length() - 1); +} + +// A stack-based class that manages SymInitialize and SymCleanup calls. +class AutoSymSrv { + public: + AutoSymSrv() : initialized_(false) {} + + ~AutoSymSrv() { + if (!Cleanup()) { + // Print the error message here, because destructors have no return + // value. + fprintf(stderr, "~AutoSymSrv: SymCleanup: error %lu\n", GetLastError()); + } + } + + bool Initialize(HANDLE process, char *path, bool invade_process) { + process_ = process; + + // TODO(nbilling): Figure out why dbghelp.dll is being loaded from + // system32/SysWOW64 before exe folder. + + // Attempt to locate and load dbghelp.dll beside the process exe. This is + // somewhat of a workaround to loader delay load behavior that is occurring + // when we call into symsrv APIs. dbghelp.dll must be loaded from beside + // the process exe so that we are guaranteed to find symsrv.dll alongside + // dbghelp.dll (a security requirement of dbghelp.dll) and so that the + // symsrv.dll file that is loaded has a symsrv.yes file alongside it (a + // requirement of symsrv.dll when accessing Microsoft-owned symbol + // servers). + // 'static local' because we don't care about the value but we need the + // initialization to happen exactly once. + static HMODULE dbghelp_module = [] () -> HMODULE { + std::wstring exe_directory = GetExeDirectory(); + if (exe_directory.empty()) { + return nullptr; + } + std::wstring dbghelp_path = exe_directory + L"\\dbghelp.dll"; + return LoadLibrary(dbghelp_path.c_str()); + }(); + if (dbghelp_module == nullptr) { + fprintf(stderr, + "AutoSymSrv::Initialize: failed to load dbghelp.dll beside exe."); + return false; + } + + initialized_ = SymInitialize(process, path, invade_process) == TRUE; + return initialized_; + } + + bool Cleanup() { + if (initialized_) { + if (SymCleanup(process_)) { + initialized_ = false; + return true; + } + return false; + } + + return true; + } + + private: + HANDLE process_; + bool initialized_; +}; + +// A stack-based class that "owns" a pathname and deletes it when destroyed, +// unless told not to by having its Release() method called. Early deletions +// are supported by calling Delete(). +class AutoDeleter { + public: + explicit AutoDeleter(const string &path) : path_(path) {} + + ~AutoDeleter() { + int error; + if ((error = Delete()) != 0) { + // Print the error message here, because destructors have no return + // value. + fprintf(stderr, "~AutoDeleter: Delete: error %d for %s\n", + error, path_.c_str()); + } + } + + int Delete() { + if (path_.empty()) + return 0; + + int error = remove(path_.c_str()); + Release(); + return error; + } + + void Release() { + path_.clear(); + } + + private: + string path_; +}; + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateFile(const string &debug_or_code_file, + const string &debug_or_code_id, + const string &version, + string *file_name) { + assert(file_name); + file_name->clear(); + + GUIDOrSignatureIdentifier identifier; + if (!identifier.InitializeFromString(debug_or_code_id)) { + fprintf(stderr, + "LocateFile: Unparseable identifier for %s %s %s\n", + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + HANDLE process = GetCurrentProcess(); // CloseHandle is not needed. + AutoSymSrv symsrv; + if (!symsrv.Initialize(process, + const_cast<char *>(symbol_path_.c_str()), + false)) { + fprintf(stderr, "LocateFile: SymInitialize: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + if (!SymRegisterCallback64(process, SymCallback, + reinterpret_cast<ULONG64>(this))) { + fprintf(stderr, + "LocateFile: SymRegisterCallback64: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + // SYMOPT_DEBUG arranges for SymCallback to be called with additional + // debugging information. This is used to determine the nature of failures. + DWORD options = SymGetOptions() | SYMOPT_DEBUG | SYMOPT_NO_PROMPTS | + SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_SECURE; + SymSetOptions(options); + + // SymCallback will set these as needed inisde the SymFindFileInPath call. + fail_dns_ = false; + fail_timeout_ = false; + fail_not_found_ = false; + + // Do the lookup. + char path[MAX_PATH]; + if (!SymFindFileInPath( + process, NULL, + const_cast<char *>(debug_or_code_file.c_str()), + const_cast<void *>(identifier.guid_or_signature_pointer()), + identifier.age(), 0, + identifier.type() == GUIDOrSignatureIdentifier::TYPE_GUID ? + SSRVOPT_GUIDPTR : SSRVOPT_DWORDPTR, + path, SymFindFileInPathCallback, this)) { + DWORD error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + // This can be returned for a number of reasons. Use the crumbs + // collected by SymCallback to determine which one is relevant. + + // These errors are possibly transient. + if (fail_dns_ || fail_timeout_) { + return LOCATE_RETRY; + } + + // This is an authoritiative file-not-found message. + if (fail_not_found_) { + fprintf(stderr, + "LocateFile: SymFindFileInPath: LOCATE_NOT_FOUND error " + "for %s %s %s\n", + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_NOT_FOUND; + } + + // If the error is FILE_NOT_FOUND but none of the known error + // conditions are matched, fall through to LOCATE_FAILURE. + } + + fprintf(stderr, + "LocateFile: SymFindFileInPath: error %lu for %s %s %s\n", + error, + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + // Making sure path is null-terminated. + path[MAX_PATH - 1] = '\0'; + + // The AutoDeleter ensures that the file is only kept when returning + // LOCATE_SUCCESS. + AutoDeleter deleter(path); + + // Do the cleanup here even though it will happen when symsrv goes out of + // scope, to allow it to influence the return value. + if (!symsrv.Cleanup()) { + fprintf(stderr, "LocateFile: SymCleanup: error %lu for %s %s %s\n", + GetLastError(), + debug_or_code_file.c_str(), + debug_or_code_id.c_str(), + version.c_str()); + return LOCATE_FAILURE; + } + + deleter.Release(); + + printf("Downloaded: %s\n", path); + *file_name = path; + return LOCATE_SUCCESS; +} + + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocatePEFile(const MissingSymbolInfo &missing, + string *pe_file) { + return LocateFile(missing.code_file, missing.code_identifier, + missing.version, pe_file); +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateSymbolFile(const MissingSymbolInfo &missing, + string *symbol_file) { + return LocateFile(missing.debug_file, missing.debug_identifier, + missing.version, symbol_file); +} + + +// static +BOOL CALLBACK MSSymbolServerConverter::SymCallback(HANDLE process, + ULONG action, + ULONG64 data, + ULONG64 context) { + MSSymbolServerConverter *self = + reinterpret_cast<MSSymbolServerConverter *>(context); + + switch (action) { + case CBA_EVENT: { + IMAGEHLP_CBA_EVENT *cba_event = + reinterpret_cast<IMAGEHLP_CBA_EVENT *>(data); + + // Put the string into a string object to be able to use string::find + // for substring matching. This is important because the not-found + // message does not use the entire string but is appended to the URL + // that SymSrv attempted to retrieve. + string desc(cba_event->desc); + + // desc_action maps strings (in desc) to boolean pointers that are to + // be set to true if the string matches. + struct desc_action { + const char *desc; // The substring to match. + bool *action; // On match, this pointer will be set to true. + }; + + static const desc_action desc_actions[] = { + // When a DNS error occurs, it could be indiciative of network + // problems. + { "SYMSRV: The server name or address could not be resolved\n", + &self->fail_dns_ }, + + // This message is produced if no connection is opened. + { "SYMSRV: A connection with the server could not be established\n", + &self->fail_timeout_ }, + + // This message is produced if a connection is established but the + // server fails to respond to the HTTP request. + { "SYMSRV: The operation timed out\n", + &self->fail_timeout_ }, + + // This message is produced when the requested file is not found, + // even if one or more of the above messages are also produced. + // It's trapped to distinguish between not-found and unknown-failure + // conditions. Note that this message will not be produced if a + // connection is established and the server begins to respond to the + // HTTP request but does not finish transmitting the file. + { " not found\n", + &self->fail_not_found_ } + }; + + for (int desc_action_index = 0; + desc_action_index < + static_cast<int>(sizeof(desc_actions) / sizeof(desc_action)); + ++desc_action_index) { + if (desc.find(desc_actions[desc_action_index].desc) != string::npos) { + *(desc_actions[desc_action_index].action) = true; + break; + } + } + + break; + } + } + + // This function is a mere fly on the wall. Treat everything as unhandled. + return FALSE; +} + +// static +BOOL CALLBACK MSSymbolServerConverter::SymFindFileInPathCallback( + const char *filename, void *context) { + // FALSE ends the search, indicating that the located symbol file is + // satisfactory. + return FALSE; +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateAndConvertSymbolFile( + const MissingSymbolInfo &missing, + bool keep_symbol_file, + bool keep_pe_file, + string *converted_symbol_file, + string *symbol_file, + string *out_pe_file) { + assert(converted_symbol_file); + converted_symbol_file->clear(); + if (symbol_file) { + symbol_file->clear(); + } + + string pdb_file; + LocateResult result = LocateSymbolFile(missing, &pdb_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "Fallback to PE-only symbol generation for: %s\n", + missing.debug_file.c_str()); + return LocateAndConvertPEFile(missing, keep_pe_file, converted_symbol_file, + out_pe_file); + } + + if (symbol_file && keep_symbol_file) { + *symbol_file = pdb_file; + } + + // The conversion of a symbol file for a Windows 64-bit module requires + // loading of the executable file. If there is no executable file, convert + // using only the PDB file. Without an executable file, the conversion will + // fail for 64-bit modules but it should succeed for 32-bit modules. + string pe_file; + result = LocatePEFile(missing, &pe_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str()); + } + + if (out_pe_file && keep_pe_file) { + *out_pe_file = pe_file; + } + + // Conversion may fail because the file is corrupt. If a broken file is + // kept in the local cache, LocateSymbolFile will not hit the network again + // to attempt to locate it. To guard against problems like this, the + // symbol file in the local cache will be removed if conversion fails. + AutoDeleter pdb_deleter(pdb_file); + AutoDeleter pe_deleter(pe_file); + + // Be sure that it's a .pdb file, since we'll be replacing .pdb with .sym + // for the converted file's name. + string pdb_extension = pdb_file.substr(pdb_file.length() - 4); + // strcasecmp is called _stricmp here. + if (_stricmp(pdb_extension.c_str(), ".pdb") != 0) { + fprintf(stderr, "LocateAndConvertSymbolFile: " + "no .pdb extension for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pdb_file.c_str()); + return LOCATE_FAILURE; + } + + PDBSourceLineWriter writer; + wstring pe_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) { + fprintf(stderr, + "LocateAndConvertSymbolFile: " + "WindowsStringUtils::safe_mbstowcs failed for %s\n", + pe_file.c_str()); + return LOCATE_FAILURE; + } + wstring pdb_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pdb_file, &pdb_file_w)) { + fprintf(stderr, + "LocateAndConvertSymbolFile: " + "WindowsStringUtils::safe_mbstowcs failed for %ws\n", + pdb_file_w.c_str()); + return LOCATE_FAILURE; + } + if (!writer.Open(pdb_file_w, PDBSourceLineWriter::PDB_FILE)) { + fprintf(stderr, + "ERROR: PDBSourceLineWriter::Open failed for %s %s %s %ws\n", + missing.debug_file.c_str(), missing.debug_identifier.c_str(), + missing.version.c_str(), pdb_file_w.c_str()); + return LOCATE_FAILURE; + } + if (!writer.SetCodeFile(pe_file_w)) { + fprintf(stderr, + "ERROR: PDBSourceLineWriter::SetCodeFile failed for %s %s %s %ws\n", + missing.debug_file.c_str(), missing.debug_identifier.c_str(), + missing.version.c_str(), pe_file_w.c_str()); + return LOCATE_FAILURE; + } + + *converted_symbol_file = pdb_file.substr(0, pdb_file.length() - 4) + ".sym"; + + FILE *converted_output = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) + != 0) { +#else // _MSC_VER >= 1400 + // fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier + // environments. Don't use fopen with MSVC8 and later, because it's + // deprecated. fopen does not provide reliable error codes, so just use + // -1 in the event of a failure. + int err; + if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) { + err = -1; +#endif // _MSC_VER >= 1400 + fprintf(stderr, "LocateAndConvertSymbolFile: " + "fopen_s: error %d for %s %s %s %s\n", + err, + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + converted_symbol_file->c_str()); + return LOCATE_FAILURE; + } + + AutoDeleter sym_deleter(*converted_symbol_file); + + bool success = writer.WriteSymbols(converted_output); + fclose(converted_output); + + if (!success) { + fprintf(stderr, "LocateAndConvertSymbolFile: " + "PDBSourceLineWriter::WriteMap failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pdb_file.c_str()); + return LOCATE_FAILURE; + } + + if (keep_symbol_file) { + pdb_deleter.Release(); + } + + if (keep_pe_file) { + pe_deleter.Release(); + } + + sym_deleter.Release(); + + return LOCATE_SUCCESS; +} + +MSSymbolServerConverter::LocateResult +MSSymbolServerConverter::LocateAndConvertPEFile( + const MissingSymbolInfo &missing, + bool keep_pe_file, + string *converted_symbol_file, + string *out_pe_file) { + assert(converted_symbol_file); + converted_symbol_file->clear(); + + string pe_file; + MSSymbolServerConverter::LocateResult result = LocatePEFile(missing, + &pe_file); + if (result != LOCATE_SUCCESS) { + fprintf(stderr, "WARNING: Could not download: %s\n", pe_file.c_str()); + return result; + } + + if (out_pe_file && keep_pe_file) { + *out_pe_file = pe_file; + } + + // Conversion may fail because the file is corrupt. If a broken file is + // kept in the local cache, LocatePEFile will not hit the network again + // to attempt to locate it. To guard against problems like this, the + // PE file in the local cache will be removed if conversion fails. + AutoDeleter pe_deleter(pe_file); + + // Be sure that it's a .exe or .dll file, since we'll be replacing extension + // with .sym for the converted file's name. + string pe_extension = pe_file.substr(pe_file.length() - 4); + // strcasecmp is called _stricmp here. + if (_stricmp(pe_extension.c_str(), ".exe") != 0 && + _stricmp(pe_extension.c_str(), ".dll") != 0) { + fprintf(stderr, "LocateAndConvertPEFile: " + "no .dll/.exe extension for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + + *converted_symbol_file = pe_file.substr(0, pe_file.length() - 4) + ".sym"; + + FILE *converted_output = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + errno_t err; + if ((err = fopen_s(&converted_output, converted_symbol_file->c_str(), "w")) + != 0) { +#else // _MSC_VER >= 1400 + // fopen_s and errno_t were introduced in MSVC8. Use fopen for earlier + // environments. Don't use fopen with MSVC8 and later, because it's + // deprecated. fopen does not provide reliable error codes, so just use + // -1 in the event of a failure. + int err; + if (!(converted_output = fopen(converted_symbol_file->c_str(), "w"))) { + err = -1; +#endif // _MSC_VER >= 1400 + fprintf(stderr, "LocateAndConvertPEFile: " + "fopen_s: error %d for %s %s %s %s\n", + err, + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + converted_symbol_file->c_str()); + return LOCATE_FAILURE; + } + AutoDeleter sym_deleter(*converted_symbol_file); + + wstring pe_file_w; + if (!WindowsStringUtils::safe_mbstowcs(pe_file, &pe_file_w)) { + fprintf(stderr, + "LocateAndConvertPEFile: " + "WindowsStringUtils::safe_mbstowcs failed for %s\n", + pe_file.c_str()); + return LOCATE_FAILURE; + } + PESourceLineWriter writer(pe_file_w); + PDBModuleInfo module_info; + if (!writer.GetModuleInfo(&module_info)) { + fprintf(stderr, "LocateAndConvertPEFile: " + "PESourceLineWriter::GetModuleInfo failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + if (module_info.cpu.compare(L"x86_64") != 0) { + // This module is not x64 so we cannot generate Breakpad symbols from the + // PE alone. Don't delete PE-- no need to retry download. + pe_deleter.Release(); + return LOCATE_FAILURE; + } + + bool success = writer.WriteSymbols(converted_output); + fclose(converted_output); + + if (!success) { + fprintf(stderr, "LocateAndConvertPEFile: " + "PESourceLineWriter::WriteMap failed for %s %s %s %s\n", + missing.debug_file.c_str(), + missing.debug_identifier.c_str(), + missing.version.c_str(), + pe_file.c_str()); + return LOCATE_FAILURE; + } + + if (keep_pe_file) { + pe_deleter.Release(); + } + + sym_deleter.Release(); + + return LOCATE_SUCCESS; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp new file mode 100644 index 0000000000..57ec790686 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.gyp @@ -0,0 +1,46 @@ +# Copyright 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'ms_symbol_server_converter', + 'type': 'static_library', + 'msvs_guid': '1463C4CD-23FC-4DE9-BFDE-283338200157', + 'sources': [ + 'ms_symbol_server_converter.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h new file mode 100644 index 0000000000..401f7c3443 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h @@ -0,0 +1,235 @@ +// Copyright (c) 2007, 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. + +// ms_symbol_server_converter.h: Obtain symbol files from a Microsoft +// symbol server, and convert them to Breakpad's dumped format. +// +// At runtime, MSSymbolServerConverter and code that it calls depend on being +// able to locate suitable versions of dbghelp.dll and symsrv.dll. For best +// results, place these files in the same directory as the executable. +// dbghelp.dll and symsrv.dll as supplied with Debugging Tools for Windows are +// both redistributable, as indicated by the package's redist.txt file. +// +// When connecting to Microsoft's symbol server at +// http://msdl.microsoft.com/download/symbols/, which provides access to +// symbols for the operating system itself, symsrv.dll requires agreement to +// Microsoft's "Terms of Use for Microsoft Symbols and Binaries." Because this +// library places the symbol engine into a promptless mode, the dialog with the +// terms will not appear, and use of Microsoft's symbol server will not be +// possible. To indicate agreement to the terms, create a file called +// symsrv.yes in the same directory as symsrv.dll. (Note that symsrv.dll will +// also recognize a symsrv.no file as indicating that you do not accept the +// terms; the .yes file takes priority over the .no file.) The terms of use +// are contained within symsrv.dll; they were formerly available online at +// http://www.microsoft.com/whdc/devtools/debugging/symsrvTOU2.mspx , but +// do not appear to be available online any longer as of January, 2007. It is +// possible to view the terms from within WinDbg (Debugging Tools for Windows) +// by removing any symsrv.yes and symsrv.no files from WinDbg's directory, +// setting the symbol path to include Microsoft's symbol server (.sympath), and +// attempting to load symbols from their server (.reload). +// +// This code has been tested with dbghelp.dll 6.5.3.7 and symsrv.dll 6.5.3.8, +// included with Microsoft Visual Studio 8 in Common7/IDE. This has also been +// tested with dbghelp.dll and symsrv.dll versions 6.6.7.5 and 6.12.2.633, +// included with the same versions of Debugging Tools for Windows, available at +// http://www.microsoft.com/whdc/devtools/debugging/ . +// +// Author: Mark Mentovai + +#ifndef TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ +#define TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ + +#include <windows.h> + +#include <string> +#include <vector> + +namespace google_breakpad { + +using std::string; +using std::vector; + +// MissingSymbolInfo contains the subset of the information in the processor's +// CodeModule structure relevant to obtaining a missing symbol file. Only +// debug_file and debug_identifier are relevant in actually obtaining the +// missing file; the other fields are for convenience. +struct MissingSymbolInfo { + string code_file; + string code_identifier; + string debug_file; + string debug_identifier; + string version; +}; + +class GUIDOrSignatureIdentifier { + public: + enum GUIDOrSignatureType { + TYPE_NONE = 0, + TYPE_GUID, + TYPE_SIGNATURE + }; + + GUIDOrSignatureIdentifier() : type_(TYPE_NONE) {} + + // Converts |identifier|, a debug_identifier-formatted string, into its + // component fields: either a GUID and age, or signature and age. If + // successful, sets the relevant fields in the object, including the type + // field, and returns true. On error, returns false. + bool InitializeFromString(const string &identifier); + + GUIDOrSignatureType type() const { return type_; } + GUID guid() const { return guid_; } + DWORD signature() const { return signature_; } + int age() const { return age_; } + const void *guid_or_signature_pointer() const { return &guid_; } + + private: + GUIDOrSignatureType type_; + + // An identifier contains either a 128-bit uuid or a 32-bit signature. + union { + GUID guid_; + DWORD signature_; + }; + + // All identifiers used here have age fields, which indicate a specific + // revision given a uuid or signature. + int age_; +}; + +class MSSymbolServerConverter { + public: + enum LocateResult { + LOCATE_FAILURE = 0, + LOCATE_NOT_FOUND, // Authoritative: the file is not present. + LOCATE_RETRY, // Transient (network?) error, try again later. + LOCATE_SUCCESS + }; + + // Create a new object. local_cache is the location (pathname) of a local + // symbol store used to hold downloaded and converted symbol files. This + // directory will be created by LocateSymbolFile when it successfully + // retrieves a symbol file. symbol_servers contains a list of locations (URLs + // or pathnames) of the upstream symbol server stores, given in order of + // preference, with the first string in the vector identifying the first + // store to try. The vector must contain at least one string. None of the + // strings passed to this constructor may contain asterisk ('*') or semicolon + // (';') characters, as the symbol engine uses these characters as separators. + MSSymbolServerConverter(const string &local_cache, + const vector<string> &symbol_servers); + + // Locates the PE file (DLL or EXE) specified by the identifying information + // in |missing|, by checking the symbol stores identified when the object + // was created. When returning LOCATE_SUCCESS, pe_file is set to + // the pathname of the decompressed PE file as it is stored in the + // local cache. + LocateResult LocatePEFile(const MissingSymbolInfo &missing, string *pe_file); + + // Locates the symbol file specified by the identifying information in + // |missing|, by checking the symbol stores identified when the object + // was created. When returning LOCATE_SUCCESS, symbol_file is set to + // the pathname of the decompressed symbol file as it is stored in the + // local cache. + LocateResult LocateSymbolFile(const MissingSymbolInfo &missing, + string *symbol_file); + + // Calls LocateSymbolFile and converts the returned symbol file to the + // dumped-symbol format, storing it adjacent to the symbol file. The + // only conversion supported is from pdb files. Returns the return + // value of LocateSymbolFile, or if LocateSymbolFile succeeds but + // conversion fails, returns LOCATE_FAILURE. The pathname to the + // pdb file and to the converted symbol file are returned in + // |converted_symbol_file|, |symbol_file|, and |pe_file|. |symbol_file| and + // |pe_file| are optional and may be NULL. If only the converted symbol file + // is desired, set |keep_symbol_file| and |keep_pe_file| to false to indicate + // that the original symbol file (pdb) and executable file (exe, dll) should + // be deleted after conversion. + LocateResult LocateAndConvertSymbolFile(const MissingSymbolInfo &missing, + bool keep_symbol_file, + bool keep_pe_file, + string *converted_symbol_file, + string *symbol_file, + string *pe_file); + + // Calls LocatePEFile and converts the returned PE file to the + // dumped-symbol format, storing it adjacent to the PE file. The + // only conversion supported is from PE files. Returns the return + // value of LocatePEFile, or if LocatePEFile succeeds but + // conversion fails, returns LOCATE_FAILURE. The pathname to the + // PE file and to the converted symbol file are returned in + // |converted_symbol_file| and |pe_file|. |pe_file| is optional and may be + // NULL. If only the converted symbol file is desired, set |keep_pe_file| + // to false to indicate that the executable file (exe, dll) should be deleted + // after conversion. + // NOTE: Currrently only supports x64 PEs. + LocateResult LocateAndConvertPEFile(const MissingSymbolInfo &missing, + bool keep_pe_file, + string *converted_symbol_file, + string *pe_file); + + private: + // Locates the PDB or PE file (DLL or EXE) specified by the identifying + // information in |debug_or_code_file| and |debug_or_code_id|, by checking + // the symbol stores identified when the object was created. When + // returning LOCATE_SUCCESS, file_name is set to the pathname of the + // decompressed PDB or PE file file as it is stored in the local cache. + LocateResult LocateFile(const string &debug_or_code_file, + const string &debug_or_code_id, + const string &version, string *file_name); + + // Called by various SymSrv functions to report status as progress is made + // and to allow the callback to influence processing. Messages sent to this + // callback can be used to distinguish between the various failure modes + // that SymFindFileInPath might encounter. + static BOOL CALLBACK SymCallback(HANDLE process, ULONG action, ULONG64 data, + ULONG64 context); + + // Called by SymFindFileInPath (in LocateSymbolFile) after a candidate + // symbol file is located, when it's present in the local cache. + // SymFindFileInPath actually seems to accept NULL for a callback function + // and behave properly for our needs in that case, but the documentation + // doesn't mention it, so this little callback is provided. + static BOOL CALLBACK SymFindFileInPathCallback(const char *filename, + void *context); + + // The search path used by SymSrv, built based on the arguments to the + // constructor. + string symbol_path_; + + // SymCallback will set at least one of these failure variables if + // SymFindFileInPath fails for an expected reason. + bool fail_dns_; // DNS failures (fail_not_found_ will also be set). + bool fail_timeout_; // Timeouts (fail_not_found_ will also be set). + bool fail_not_found_; // The file could not be found. If this is the only + // fail_* member set, then it is authoritative. +}; + +} // namespace google_breakpad + +#endif // TOOLS_WINDOWS_MS_SYMBOL_SERVER_CONVERTER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj new file mode 100644 index 0000000000..ee1263a147 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.vcproj @@ -0,0 +1,368 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Purify|Win32"> + <Configuration>Purify</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Purify|x64"> + <Configuration>Purify</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{1463C4CD-23FC-4DE9-BFDE-283338200157}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>ms_symbol_server_converter</RootNamespace> + <IgnoreWarnCompileDuplicatedFilename>true</IgnoreWarnCompileDuplicatedFilename> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props"/> + <PropertyGroup Label="Configuration"> + <CharacterSet>Unicode</CharacterSet> + <ConfigurationType>StaticLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props"/> + <ImportGroup Label="ExtensionSettings"/> + <ImportGroup Label="PropertySheets"> + <Import Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"/> + </ImportGroup> + <PropertyGroup Label="UserMacros"/> + <PropertyGroup> + <ExecutablePath>$(ExecutablePath);$(MSBuildProjectDirectory)\..\..\..\third_party\cygwin\bin\;$(MSBuildProjectDirectory)\..\..\..\third_party\python_26\</ExecutablePath> + <OutDir>$(SolutionDir)$(Configuration)\</OutDir> + <IntDir>$(OutDir)obj\$(ProjectName)\</IntDir> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Purify|Win32'">false</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Purify|x64'">false</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> + <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental> + <TargetName>$(ProjectName)</TargetName> + <TargetPath>$(OutDir)lib\$(ProjectName)$(TargetExt)</TargetPath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <BufferSecurityCheck>true</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + <BufferSecurityCheck>true</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_DEBUG;_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Purify|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BufferSecurityCheck>true</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <Optimization>MaxSpeed</Optimization> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Purify|x64'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BufferSecurityCheck>false</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <EnableCOMDATFolding>false</EnableCOMDATFolding> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;PURIFY;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BufferSecurityCheck>true</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <OmitFramePointers>true</OmitFramePointers> + <Optimization>MaxSpeed</Optimization> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <StringPooling>true</StringPooling> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/safeseh /dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <OptimizeReferences>true</OptimizeReferences> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX86</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> + <BufferSecurityCheck>true</BufferSecurityCheck> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <DisableSpecificWarnings>4100;4127;4396;4503;4512;4819;4995;4702;4800;%(DisableSpecificWarnings)</DisableSpecificWarnings> + <ExceptionHandling>false</ExceptionHandling> + <FunctionLevelLinking>true</FunctionLevelLinking> + <MinimalRebuild>false</MinimalRebuild> + <Optimization>MaxSpeed</Optimization> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + <RuntimeTypeInfo>false</RuntimeTypeInfo> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Lib> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/ignore:4221 %(AdditionalOptions)</AdditionalOptions> + <OutputFile>$(OutDir)lib\$(ProjectName)$(TargetExt)</OutputFile> + </Lib> + <Link> + <AdditionalDependencies>wininet.lib;version.lib;msimg32.lib;ws2_32.lib;usp10.lib;psapi.lib;dbghelp.lib;$(VSInstallDir)\DIA SDK\lib\diaguids.lib;imagehlp.lib</AdditionalDependencies> + <AdditionalLibraryDirectories>../../../third_party/platformsdk_win7/files/Lib/x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <AdditionalOptions>/dynamicbase /ignore:4199 /ignore:4221 /nxcompat %(AdditionalOptions)</AdditionalOptions> + <DelayLoadDLLs>dbghelp.dll;dwmapi.dll;uxtheme.dll;%(DelayLoadDLLs)</DelayLoadDLLs> + <FixedBaseAddress>false</FixedBaseAddress> + <GenerateDebugInformation>true</GenerateDebugInformation> + <ImportLibrary>$(OutDir)lib\$(TargetName).lib</ImportLibrary> + <MapFileName>$(OutDir)$(TargetName).map</MapFileName> + <SubSystem>Console</SubSystem> + <TargetMachine>MachineX64</TargetMachine> + </Link> + <Midl> + <DllDataFileName>dlldata.c</DllDataFileName> + <GenerateStublessProxies>true</GenerateStublessProxies> + <HeaderFileName>%(Filename).h</HeaderFileName> + <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName> + <OutputDirectory>$(IntDir)</OutputDirectory> + <ProxyFileName>%(Filename)_p.c</ProxyFileName> + <TypeLibraryName>%(Filename).tlb</TypeLibraryName> + </Midl> + <ResourceCompile> + <AdditionalIncludeDirectories>../../..;..\..\..;$(VSInstallDir)\DIA SDK\include;..\..\..\third_party\platformsdk_win7\files\Include;$(VSInstallDir)\VC\atlmfc\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Culture>0x0409</Culture> + <PreprocessorDefinitions>_WIN32_WINNT=0x0600;WINVER=0x0600;WIN32;_WINDOWS;_HAS_EXCEPTIONS=0;NOMINMAX;_CRT_RAND_S;CERT_CHAIN_PARA_HAS_EXTRA_FIELDS;WIN32_LEAN_AND_MEAN;_SECURE_ATL;CHROMIUM_BUILD;TOOLKIT_VIEWS=1;ENABLE_GPU=1;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;NO_TCMALLOC;NDEBUG;NVALGRIND;%(PreprocessorDefinitions);%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <None Include="ms_symbol_server_converter.gyp"/> + </ItemGroup> + <ItemGroup> + <ClCompile Include="ms_symbol_server_converter.cc"/> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets"/> + <ImportGroup Label="ExtensionTargets"/> +</Project> diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd new file mode 100644 index 0000000000..5464a61ed7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/configure.cmd @@ -0,0 +1,33 @@ +@if "%ECHOON%"=="" @echo off
+SETLOCAL
+
+REM ******************************************************************
+REM Please, make sure to run this in an Elevated Command Prompt.
+REM Usage:
+REM configure.cmd
+REM ******************************************************************
+
+REM ******************************************************************
+REM Initialize
+REM ******************************************************************
+SET SCRIPT_LOCATION=%~dp0
+
+REM ******************************************************************
+REM Go to script location
+REM ******************************************************************
+pushd %SCRIPT_LOCATION%
+
+REM ******************************************************************
+REM Register msdia140.dll.
+REM ******************************************************************
+SET MSG=Failed to register msdia140.dll. Make sure to run this in elevated command prompt.
+%systemroot%\SysWoW64\regsvr32.exe /s msdia140.dll & if errorlevel 1 echo %MSG% & goto :fail
+
+:success
+echo Configuration was successful.
+ENDLOCAL
+exit /b 0
+
+:fail
+ENDLOCAL
+exit /b 1
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc new file mode 100644 index 0000000000..5b70903a4d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.cc @@ -0,0 +1,807 @@ +// Copyright 2019 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.
+
+#pragma comment(lib, "winhttp.lib")
+#pragma comment(lib, "wininet.lib")
+#pragma comment(lib, "diaguids.lib")
+#pragma comment(lib, "imagehlp.lib")
+
+#include <cassert>
+#include <cstdio>
+#include <ctime>
+#include <map>
+#include <regex>
+#include <string>
+#include <vector>
+
+#include "tools/windows/converter_exe/escaping.h"
+#include "tools/windows/converter_exe/http_download.h"
+#include "tools/windows/converter_exe/tokenizer.h"
+#include "common/windows/http_upload.h"
+#include "common/windows/string_utils-inl.h"
+#include "tools/windows/converter/ms_symbol_server_converter.h"
+
+using strings::WebSafeBase64Unescape;
+using strings::WebSafeBase64Escape;
+
+namespace {
+
+using std::map;
+using std::string;
+using std::vector;
+using std::wstring;
+using crash::HTTPDownload;
+using crash::Tokenizer;
+using google_breakpad::HTTPUpload;
+using google_breakpad::MissingSymbolInfo;
+using google_breakpad::MSSymbolServerConverter;
+using google_breakpad::WindowsStringUtils;
+
+const char *kMissingStringDelimiters = "|";
+const char *kLocalCachePath = "c:\\symbols";
+const char *kNoExeMSSSServer = "http://msdl.microsoft.com/download/symbols/";
+
+// Windows stdio doesn't do line buffering. Use this function to flush after
+// writing to stdout and stderr so that a log will be available if the
+// converter crashes.
+static int FprintfFlush(FILE *file, const char *format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ int retval = vfprintf(file, format, arguments);
+ va_end(arguments);
+ fflush(file);
+ return retval;
+}
+
+static string CurrentDateAndTime() {
+ const string kUnknownDateAndTime = R"(????-??-?? ??:??:??)";
+
+ time_t current_time;
+ time(¤t_time);
+
+ // localtime_s is safer but is only available in MSVC8. Use localtime
+ // in earlier environments.
+ struct tm *time_pointer;
+#if _MSC_VER >= 1400 // MSVC 2005/8
+ struct tm time_struct;
+ time_pointer = &time_struct;
+ if (localtime_s(time_pointer, ¤t_time) != 0) {
+ return kUnknownDateAndTime;
+ }
+#else // _MSC_VER >= 1400
+ time_pointer = localtime(¤t_time);
+ if (!time_pointer) {
+ return kUnknownDateAndTime;
+ }
+#endif // _MSC_VER >= 1400
+
+ char buffer[256];
+ if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", time_pointer)) {
+ return kUnknownDateAndTime;
+ }
+
+ return string(buffer);
+}
+
+// ParseMissingString turns |missing_string| into a MissingSymbolInfo
+// structure. It returns true on success, and false if no such conversion
+// is possible.
+static bool ParseMissingString(const string &missing_string,
+ MissingSymbolInfo *missing_info) {
+ assert(missing_info);
+
+ vector<string> tokens;
+ Tokenizer::Tokenize(kMissingStringDelimiters, missing_string, &tokens);
+ if (tokens.size() != 5) {
+ return false;
+ }
+
+ missing_info->debug_file = tokens[0];
+ missing_info->debug_identifier = tokens[1];
+ missing_info->version = tokens[2];
+ missing_info->code_file = tokens[3];
+ missing_info->code_identifier = tokens[4];
+
+ return true;
+}
+
+// StringMapToWStringMap takes each element in a map that associates
+// (narrow) strings to strings and converts the keys and values to wstrings.
+// Returns true on success and false on failure, printing an error message.
+static bool StringMapToWStringMap(const map<string, string> &smap,
+ map<wstring, wstring> *wsmap) {
+ assert(wsmap);
+ wsmap->clear();
+
+ for (map<string, string>::const_iterator iterator = smap.begin();
+ iterator != smap.end();
+ ++iterator) {
+ wstring key;
+ if (!WindowsStringUtils::safe_mbstowcs(iterator->first, &key)) {
+ FprintfFlush(stderr,
+ "StringMapToWStringMap: safe_mbstowcs failed for key %s\n",
+ iterator->first.c_str());
+ return false;
+ }
+
+ wstring value;
+ if (!WindowsStringUtils::safe_mbstowcs(iterator->second, &value)) {
+ FprintfFlush(stderr, "StringMapToWStringMap: safe_mbstowcs failed "
+ "for value %s\n",
+ iterator->second.c_str());
+ return false;
+ }
+
+ wsmap->insert(make_pair(key, value));
+ }
+
+ return true;
+}
+
+// MissingSymbolInfoToParameters turns a MissingSymbolInfo structure into a
+// map of parameters suitable for passing to HTTPDownload or HTTPUpload.
+// Returns true on success and false on failure, printing an error message.
+static bool MissingSymbolInfoToParameters(const MissingSymbolInfo &missing_info,
+ map<wstring, wstring> *wparameters) {
+ assert(wparameters);
+
+ map<string, string> parameters;
+ string encoded_param;
+ // Indicate the params are encoded.
+ parameters["encoded"] = "true"; // The string value here does not matter.
+
+ WebSafeBase64Escape(missing_info.code_file, &encoded_param);
+ parameters["code_file"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.code_identifier, &encoded_param);
+ parameters["code_identifier"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.debug_file, &encoded_param);
+ parameters["debug_file"] = encoded_param;
+
+ WebSafeBase64Escape(missing_info.debug_identifier, &encoded_param);
+ parameters["debug_identifier"] = encoded_param;
+
+ if (!missing_info.version.empty()) {
+ // The version is optional.
+ WebSafeBase64Escape(missing_info.version, &encoded_param);
+ parameters["version"] = encoded_param;
+ }
+
+ WebSafeBase64Escape("WinSymConv", &encoded_param);
+ parameters["product"] = encoded_param;
+
+ if (!StringMapToWStringMap(parameters, wparameters)) {
+ // StringMapToWStringMap will have printed an error.
+ return false;
+ }
+
+ return true;
+}
+
+// UploadSymbolFile sends |converted_file| as identified by |missing_info|
+// to the symbol server rooted at |upload_symbol_url|. Returns true on
+// success and false on failure, printing an error message.
+static bool UploadSymbolFile(const wstring &upload_symbol_url,
+ const MissingSymbolInfo &missing_info,
+ const string &converted_file) {
+ map<wstring, wstring> parameters;
+ if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) {
+ // MissingSymbolInfoToParameters or a callee will have printed an error.
+ return false;
+ }
+
+ wstring converted_file_w;
+
+ if (!WindowsStringUtils::safe_mbstowcs(converted_file, &converted_file_w)) {
+ FprintfFlush(stderr, "UploadSymbolFile: safe_mbstowcs failed for %s\n",
+ converted_file.c_str());
+ return false;
+ }
+ map<wstring, wstring> files;
+ files[L"symbol_file"] = converted_file_w;
+
+ FprintfFlush(stderr, "Uploading %s\n", converted_file.c_str());
+ if (!HTTPUpload::SendMultipartPostRequest(
+ upload_symbol_url, parameters,
+ files, NULL, NULL, NULL)) {
+ FprintfFlush(stderr, "UploadSymbolFile: HTTPUpload::SendRequest failed "
+ "for %s %s %s\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// SendFetchFailedPing informs the symbol server based at
+// |fetch_symbol_failure_url| that the symbol file identified by
+// |missing_info| could authoritatively not be located. Returns
+// true on success and false on failure.
+static bool SendFetchFailedPing(const wstring &fetch_symbol_failure_url,
+ const MissingSymbolInfo &missing_info) {
+ map<wstring, wstring> parameters;
+ if (!MissingSymbolInfoToParameters(missing_info, ¶meters)) {
+ // MissingSymbolInfoToParameters or a callee will have printed an error.
+ return false;
+ }
+
+ string content;
+ if (!HTTPDownload::Download(fetch_symbol_failure_url,
+ ¶meters,
+ &content,
+ NULL)) {
+ FprintfFlush(stderr, "SendFetchFailedPing: HTTPDownload::Download failed "
+ "for %s %s %s\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Returns true if it's safe to make an external request for the symbol
+// file described in missing_info. It's considered safe to make an
+// external request unless the symbol file's debug_file string matches
+// the given blacklist regular expression.
+// The debug_file name is used from the MissingSymbolInfo struct,
+// matched against the blacklist_regex.
+static bool SafeToMakeExternalRequest(const MissingSymbolInfo &missing_info,
+ std::regex blacklist_regex) {
+ string file_name = missing_info.debug_file;
+ // Use regex_search because we want to match substrings.
+ if (std::regex_search(file_name, blacklist_regex)) {
+ FprintfFlush(stderr, "Not safe to make external request for file %s\n",
+ file_name.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+// Converter options derived from command line parameters.
+struct ConverterOptions {
+ ConverterOptions()
+ : report_fetch_failures(true) {
+ }
+
+ ~ConverterOptions() {
+ }
+
+ // Names of MS Symbol Supplier Servers that are internal to Google, and may
+ // have symbols for any request.
+ vector<string> full_internal_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are internal to Google, and
+ // shouldn't be checked for symbols for any .exe files.
+ vector<string> full_external_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are external to Google, and may
+ // have symbols for any request.
+ vector<string> no_exe_internal_msss_servers;
+
+ // Names of MS Symbol Supplier Servers that are external to Google, and
+ // shouldn't be checked for symbols for any .exe files.
+ vector<string> no_exe_external_msss_servers;
+
+ // Temporary local storage for symbols.
+ string local_cache_path;
+
+ // URL for uploading symbols.
+ wstring upload_symbols_url;
+
+ // URL to fetch list of missing symbols.
+ wstring missing_symbols_url;
+
+ // URL to report symbol fetch failure.
+ wstring fetch_symbol_failure_url;
+
+ // Are symbol fetch failures reported.
+ bool report_fetch_failures;
+
+ // File containing the list of missing symbols. Fetch failures are not
+ // reported if such file is provided.
+ string missing_symbols_file;
+
+ // Regex used to blacklist files to prevent external symbol requests.
+ // Owned and cleaned up by this struct.
+ std::regex blacklist_regex;
+
+ private:
+ // DISABLE_COPY_AND_ASSIGN
+ ConverterOptions(const ConverterOptions&);
+ ConverterOptions& operator=(const ConverterOptions&);
+};
+
+// ConverMissingSymbolFile takes a single MissingSymbolInfo structure and
+// attempts to locate it from the symbol servers provided in the
+// |options.*_msss_servers| arguments. "Full" servers are those that will be
+// queried for all symbol files; "No-EXE" servers will only be queried for
+// modules whose missing symbol data indicates are not main program executables.
+// Results will be sent to the |options.upload_symbols_url| on success or
+// |options.fetch_symbol_failure_url| on failure, and the local cache will be
+// stored at |options.local_cache_path|. Because nothing can be done even in
+// the event of a failure, this function returns no value, although it
+// may result in error messages being printed.
+static void ConvertMissingSymbolFile(const MissingSymbolInfo &missing_info,
+ const ConverterOptions &options) {
+ string time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: attempting %s %s %s\n",
+ time_string.c_str(),
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+
+ // The first lookup is always to internal symbol servers.
+ // Always ask the symbol servers identified as "full."
+ vector<string> msss_servers = options.full_internal_msss_servers;
+
+ // If the file is not an .exe file, also ask an additional set of symbol
+ // servers, such as Microsoft's public symbol server.
+ bool is_exe = false;
+
+ if (missing_info.code_file.length() >= 4) {
+ string code_extension =
+ missing_info.code_file.substr(missing_info.code_file.size() - 4);
+
+ // Firefox is a special case: .dll-only servers should be consulted for
+ // its symbols. This enables us to get its symbols from Mozilla's
+ // symbol server when crashes occur in Google extension code hosted by a
+ // Firefox process.
+ if (_stricmp(code_extension.c_str(), ".exe") == 0 &&
+ _stricmp(missing_info.code_file.c_str(), "firefox.exe") != 0) {
+ is_exe = true;
+ }
+ }
+
+ if (!is_exe) {
+ msss_servers.insert(msss_servers.end(),
+ options.no_exe_internal_msss_servers.begin(),
+ options.no_exe_internal_msss_servers.end());
+ }
+
+ // If there are any suitable internal symbol servers, make a request.
+ MSSymbolServerConverter::LocateResult located =
+ MSSymbolServerConverter::LOCATE_FAILURE;
+ string converted_file;
+ if (msss_servers.size() > 0) {
+ // Attempt to fetch the symbol file and convert it.
+ FprintfFlush(stderr, "Making internal request for %s (%s)\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str());
+ MSSymbolServerConverter converter(options.local_cache_path, msss_servers);
+ located = converter.LocateAndConvertSymbolFile(missing_info,
+ false, // keep_symbol_file
+ false, // keep_pe_file
+ &converted_file,
+ NULL, // symbol_file
+ NULL); // pe_file
+ switch (located) {
+ case MSSymbolServerConverter::LOCATE_SUCCESS:
+ FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
+ // Upload it. Don't bother checking the return value. If this
+ // succeeds, it should disappear from the missing symbol list.
+ // If it fails, something will print an error message indicating
+ // the cause of the failure, and the item will remain on the
+ // missing symbol list.
+ UploadSymbolFile(options.upload_symbols_url, missing_info,
+ converted_file);
+ remove(converted_file.c_str());
+
+ // Note: this does leave some directories behind that could be
+ // cleaned up. The directories inside options.local_cache_path for
+ // debug_file/debug_identifier can be removed at this point.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_NOT_FOUND:
+ FprintfFlush(stderr, "LocateResult = LOCATE_NOT_FOUND\n");
+ // The symbol file definitively did not exist. Fall through,
+ // so we can attempt an external query if it's safe to do so.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_RETRY:
+ FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
+ // Fall through in case we should make an external request.
+ // If not, or if an external request fails in the same way,
+ // we'll leave the entry in the symbol file list and
+ // try again on a future pass. Print a message so that there's
+ // a record.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_FAILURE:
+ FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
+ // LocateAndConvertSymbolFile printed an error message.
+ break;
+
+ default:
+ FprintfFlush(
+ stderr,
+ "FATAL: Unexpected return value '%d' from "
+ "LocateAndConvertSymbolFile()\n",
+ located);
+ assert(0);
+ break;
+ }
+ } else {
+ // No suitable internal symbol servers. This is fine because the converter
+ // is mainly used for downloading and converting of external symbols.
+ }
+
+ // Make a request to an external server if the internal request didn't
+ // succeed, and it's safe to do so.
+ if (located != MSSymbolServerConverter::LOCATE_SUCCESS &&
+ SafeToMakeExternalRequest(missing_info, options.blacklist_regex)) {
+ msss_servers = options.full_external_msss_servers;
+ if (!is_exe) {
+ msss_servers.insert(msss_servers.end(),
+ options.no_exe_external_msss_servers.begin(),
+ options.no_exe_external_msss_servers.end());
+ }
+ if (msss_servers.size() > 0) {
+ FprintfFlush(stderr, "Making external request for %s (%s)\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str());
+ MSSymbolServerConverter external_converter(options.local_cache_path,
+ msss_servers);
+ located = external_converter.LocateAndConvertSymbolFile(
+ missing_info,
+ false, // keep_symbol_file
+ false, // keep_pe_file
+ &converted_file,
+ NULL, // symbol_file
+ NULL); // pe_file
+ } else {
+ FprintfFlush(stderr, "ERROR: No suitable external symbol servers.\n");
+ }
+ }
+
+ // Final handling for this symbol file is based on the result from the
+ // external request (if performed above), or on the result from the
+ // previous internal lookup.
+ switch (located) {
+ case MSSymbolServerConverter::LOCATE_SUCCESS:
+ FprintfFlush(stderr, "LocateResult = LOCATE_SUCCESS\n");
+ // Upload it. Don't bother checking the return value. If this
+ // succeeds, it should disappear from the missing symbol list.
+ // If it fails, something will print an error message indicating
+ // the cause of the failure, and the item will remain on the
+ // missing symbol list.
+ UploadSymbolFile(options.upload_symbols_url, missing_info,
+ converted_file);
+ remove(converted_file.c_str());
+
+ // Note: this does leave some directories behind that could be
+ // cleaned up. The directories inside options.local_cache_path for
+ // debug_file/debug_identifier can be removed at this point.
+ break;
+
+ case MSSymbolServerConverter::LOCATE_NOT_FOUND:
+ // The symbol file definitively didn't exist. Inform the server.
+ // If this fails, something will print an error message indicating
+ // the cause of the failure, but there's really nothing more to
+ // do. If this succeeds, the entry should be removed from the
+ // missing symbols list.
+ if (!options.report_fetch_failures) {
+ FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
+ } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
+ missing_info)) {
+ FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
+ } else {
+ FprintfFlush(stderr, "SendFetchFailedPing failed\n");
+ }
+ break;
+
+ case MSSymbolServerConverter::LOCATE_RETRY:
+ FprintfFlush(stderr, "LocateResult = LOCATE_RETRY\n");
+ // Nothing to do but leave the entry in the symbol file list and
+ // try again on a future pass. Print a message so that there's
+ // a record.
+ FprintfFlush(stderr, "ConvertMissingSymbolFile: deferring retry "
+ "for %s %s %s\n",
+ missing_info.debug_file.c_str(),
+ missing_info.debug_identifier.c_str(),
+ missing_info.version.c_str());
+ break;
+
+ case MSSymbolServerConverter::LOCATE_FAILURE:
+ FprintfFlush(stderr, "LocateResult = LOCATE_FAILURE\n");
+ // LocateAndConvertSymbolFile printed an error message.
+
+ // This is due to a bad debug file name, so fetch failed.
+ if (!options.report_fetch_failures) {
+ FprintfFlush(stderr, "SendFetchFailedPing skipped\n");
+ } else if (SendFetchFailedPing(options.fetch_symbol_failure_url,
+ missing_info)) {
+ FprintfFlush(stderr, "SendFetchFailedPing succeeded\n");
+ } else {
+ FprintfFlush(stderr, "SendFetchFailedPing failed\n");
+ }
+ break;
+
+ default:
+ FprintfFlush(
+ stderr,
+ "FATAL: Unexpected return value '%d' from "
+ "LocateAndConvertSymbolFile()\n",
+ located);
+ assert(0);
+ break;
+ }
+}
+
+
+// Reads the contents of file |file_name| and populates |contents|.
+// Returns true on success.
+static bool ReadFile(string file_name, string *contents) {
+ char buffer[1024 * 8];
+ FILE *fp = fopen(file_name.c_str(), "rt");
+ if (!fp) {
+ return false;
+ }
+ contents->clear();
+ while (fgets(buffer, sizeof(buffer), fp) != NULL) {
+ contents->append(buffer);
+ }
+ fclose(fp);
+ return true;
+}
+
+// ConvertMissingSymbolsList obtains a missing symbol list from
+// |options.missing_symbols_url| or |options.missing_symbols_file| and calls
+// ConvertMissingSymbolFile for each missing symbol file in the list.
+static bool ConvertMissingSymbolsList(const ConverterOptions &options) {
+ // Set param to indicate requesting for encoded response.
+ map<wstring, wstring> parameters;
+ parameters[L"product"] = L"WinSymConv";
+ parameters[L"encoded"] = L"true";
+ // Get the missing symbol list.
+ string missing_symbol_list;
+ if (!options.missing_symbols_file.empty()) {
+ if (!ReadFile(options.missing_symbols_file, &missing_symbol_list)) {
+ return false;
+ }
+ } else if (!HTTPDownload::Download(options.missing_symbols_url, ¶meters,
+ &missing_symbol_list, NULL)) {
+ return false;
+ }
+
+ // Tokenize the content into a vector.
+ vector<string> missing_symbol_lines;
+ Tokenizer::Tokenize("\n", missing_symbol_list, &missing_symbol_lines);
+
+ FprintfFlush(stderr, "Found %d missing symbol files in list.\n",
+ missing_symbol_lines.size() - 1); // last line is empty.
+ int convert_attempts = 0;
+ for (vector<string>::const_iterator iterator = missing_symbol_lines.begin();
+ iterator != missing_symbol_lines.end();
+ ++iterator) {
+ // Decode symbol line.
+ const string &encoded_line = *iterator;
+ // Skip lines that are blank.
+ if (encoded_line.empty()) {
+ continue;
+ }
+
+ string line;
+ if (!WebSafeBase64Unescape(encoded_line, &line)) {
+ // If decoding fails, assume the line is not encoded.
+ // This is helpful when the program connects to a debug server without
+ // encoding.
+ line = encoded_line;
+ }
+
+ FprintfFlush(stderr, "\nLine: %s\n", line.c_str());
+
+ // Turn each element into a MissingSymbolInfo structure.
+ MissingSymbolInfo missing_info;
+ if (!ParseMissingString(line, &missing_info)) {
+ FprintfFlush(stderr, "ConvertMissingSymbols: ParseMissingString failed "
+ "for %s from %ws\n",
+ line.c_str(), options.missing_symbols_url.c_str());
+ continue;
+ }
+
+ ++convert_attempts;
+ ConvertMissingSymbolFile(missing_info, options);
+ }
+
+ // Say something reassuring, since ConvertMissingSymbolFile was never called
+ // and therefore never reported any progress.
+ if (convert_attempts == 0) {
+ string current_time = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: nothing to convert\n",
+ current_time.c_str());
+ }
+
+ return true;
+}
+
+// usage prints the usage message. It returns 1 as a convenience, to be used
+// as a return value from main.
+static int usage(const char *program_name) {
+ FprintfFlush(stderr,
+ "usage: %s [options]\n"
+ " -f <full_msss_server> MS servers to ask for all symbols\n"
+ " -n <no_exe_msss_server> same, but prevent asking for EXEs\n"
+ " -l <local_cache_path> Temporary local storage for symbols\n"
+ " -s <upload_url> URL for uploading symbols\n"
+ " -m <missing_symbols_url> URL to fetch list of missing symbols\n"
+ " -mf <missing_symbols_file> File containing the list of missing\n"
+ " symbols. Fetch failures are not\n"
+ " reported if such file is provided.\n"
+ " -t <fetch_failure_url> URL to report symbol fetch failure\n"
+ " -b <regex> Regex used to blacklist files to\n"
+ " prevent external symbol requests\n"
+ " Note that any server specified by -f or -n that starts with \\filer\n"
+ " will be treated as internal, and all others as external.\n",
+ program_name);
+
+ return 1;
+}
+
+// "Internal" servers consist only of those whose names start with
+// the literal string "\\filer\".
+static bool IsInternalServer(const string &server_name) {
+ if (server_name.find("\\\\filer\\") == 0) {
+ return true;
+ }
+ return false;
+}
+
+// Adds a server with the given name to the list of internal or external
+// servers, as appropriate.
+static void AddServer(const string &server_name,
+ vector<string> *internal_servers,
+ vector<string> *external_servers) {
+ if (IsInternalServer(server_name)) {
+ internal_servers->push_back(server_name);
+ } else {
+ external_servers->push_back(server_name);
+ }
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ string time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: starting\n", time_string.c_str());
+
+ ConverterOptions options;
+ options.report_fetch_failures = true;
+
+ // All arguments are paired.
+ if (argc % 2 != 1) {
+ return usage(argv[0]);
+ }
+
+ string blacklist_regex_str;
+ bool have_any_msss_servers = false;
+ for (int argi = 1; argi < argc; argi += 2) {
+ string option = argv[argi];
+ string value = argv[argi + 1];
+
+ if (option == "-f") {
+ AddServer(value, &options.full_internal_msss_servers,
+ &options.full_external_msss_servers);
+ have_any_msss_servers = true;
+ } else if (option == "-n") {
+ AddServer(value, &options.no_exe_internal_msss_servers,
+ &options.no_exe_external_msss_servers);
+ have_any_msss_servers = true;
+ } else if (option == "-l") {
+ if (!options.local_cache_path.empty()) {
+ return usage(argv[0]);
+ }
+ options.local_cache_path = value;
+ } else if (option == "-s") {
+ if (!WindowsStringUtils::safe_mbstowcs(value,
+ &options.upload_symbols_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-m") {
+ if (!WindowsStringUtils::safe_mbstowcs(value,
+ &options.missing_symbols_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-mf") {
+ options.missing_symbols_file = value;
+ printf("Getting the list of missing symbols from a file. Fetch failures"
+ " will not be reported.\n");
+ options.report_fetch_failures = false;
+ } else if (option == "-t") {
+ if (!WindowsStringUtils::safe_mbstowcs(
+ value,
+ &options.fetch_symbol_failure_url)) {
+ FprintfFlush(stderr, "main: safe_mbstowcs failed for %s\n",
+ value.c_str());
+ return 1;
+ }
+ } else if (option == "-b") {
+ blacklist_regex_str = value;
+ } else {
+ return usage(argv[0]);
+ }
+ }
+
+ if (blacklist_regex_str.empty()) {
+ FprintfFlush(stderr, "No blacklist specified.\n");
+ return usage(argv[0]);
+ }
+
+ // Compile the blacklist regular expression for later use.
+ options.blacklist_regex = std::regex(blacklist_regex_str.c_str(),
+ std::regex_constants::icase);
+
+ // Set the defaults. If the user specified any MSSS servers, don't use
+ // any default.
+ if (!have_any_msss_servers) {
+ AddServer(kNoExeMSSSServer, &options.no_exe_internal_msss_servers,
+ &options.no_exe_external_msss_servers);
+ }
+
+ if (options.local_cache_path.empty()) {
+ options.local_cache_path = kLocalCachePath;
+ }
+
+ if (options.upload_symbols_url.empty()) {
+ FprintfFlush(stderr, "No upload symbols URL specified.\n");
+ return usage(argv[0]);
+ }
+ if (options.missing_symbols_url.empty() &&
+ options.missing_symbols_file.empty()) {
+ FprintfFlush(stderr, "No missing symbols URL or file specified.\n");
+ return usage(argv[0]);
+ }
+ if (options.fetch_symbol_failure_url.empty()) {
+ FprintfFlush(stderr, "No fetch symbol failure URL specified.\n");
+ return usage(argv[0]);
+ }
+
+ FprintfFlush(stdout,
+ "# of Symbol Servers (int/ext): %d/%d full, %d/%d no_exe\n",
+ options.full_internal_msss_servers.size(),
+ options.full_external_msss_servers.size(),
+ options.no_exe_internal_msss_servers.size(),
+ options.no_exe_external_msss_servers.size());
+
+ if (!ConvertMissingSymbolsList(options)) {
+ return 1;
+ }
+
+ time_string = CurrentDateAndTime();
+ FprintfFlush(stdout, "converter: %s: finished\n", time_string.c_str());
+ return 0;
+}
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp new file mode 100644 index 0000000000..fe443d1b40 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/converter.gyp @@ -0,0 +1,57 @@ +# Copyright 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'converter_exe', + 'type': 'executable', + 'sources': [ + 'converter.cc', + 'escaping.cc', + 'escaping.h', + 'http_client.h', + 'http_download.cc', + 'http_download.h', + 'tokenizer.cc', + 'tokenizer.h', + 'winhttp_client.cc', + 'winhttp_client.h', + 'wininet_client.cc', + 'wininet_client.h', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + '../converter/ms_symbol_server_converter.gyp:ms_symbol_server_converter', + ], + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc new file mode 100644 index 0000000000..74a7203ab4 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.cc @@ -0,0 +1,757 @@ +// Copyright 2019 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 "tools/windows/converter_exe/escaping.h"
+
+#include <assert.h>
+
+#define kApb kAsciiPropertyBits
+
+const unsigned char kAsciiPropertyBits[256] = {
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00
+ 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+ 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70
+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40,
+};
+
+// Use !! to suppress the warning C4800 of forcing 'int' to 'bool'.
+static inline bool ascii_isspace(unsigned char c) { return !!(kApb[c] & 0x08); }
+
+///////////////////////////////////
+// scoped_array
+///////////////////////////////////
+// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
+// with new [] and the destructor deletes objects with delete [].
+//
+// As with scoped_ptr<C>, a scoped_array<C> either points to an object
+// or is NULL. A scoped_array<C> owns the object that it points to.
+// scoped_array<T> is thread-compatible, and once you index into it,
+// the returned objects have only the threadsafety guarantees of T.
+//
+// Size: sizeof(scoped_array<C>) == sizeof(C*)
+template <class C>
+class scoped_array {
+ public:
+
+ // The element type
+ typedef C element_type;
+
+ // Constructor. Defaults to intializing with NULL.
+ // There is no way to create an uninitialized scoped_array.
+ // The input parameter must be allocated with new [].
+ explicit scoped_array(C* p = NULL) : array_(p) { }
+
+ // Destructor. If there is a C object, delete it.
+ // We don't need to test ptr_ == NULL because C++ does that for us.
+ ~scoped_array() {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ }
+
+ // Reset. Deletes the current owned object, if any.
+ // Then takes ownership of a new object, if given.
+ // this->reset(this->get()) works.
+ void reset(C* p = NULL) {
+ if (p != array_) {
+ enum { type_must_be_complete = sizeof(C) };
+ delete[] array_;
+ array_ = p;
+ }
+ }
+
+ // Get one element of the current object.
+ // Will assert() if there is no current object, or index i is negative.
+ C& operator[](std::ptrdiff_t i) const {
+ assert(i >= 0);
+ assert(array_ != NULL);
+ return array_[i];
+ }
+
+ // Get a pointer to the zeroth element of the current object.
+ // If there is no current object, return NULL.
+ C* get() const {
+ return array_;
+ }
+
+ // Comparison operators.
+ // These return whether a scoped_array and a raw pointer refer to
+ // the same array, not just to two different but equal arrays.
+ bool operator==(const C* p) const { return array_ == p; }
+ bool operator!=(const C* p) const { return array_ != p; }
+
+ // Swap two scoped arrays.
+ void swap(scoped_array& p2) {
+ C* tmp = array_;
+ array_ = p2.array_;
+ p2.array_ = tmp;
+ }
+
+ // Release an array.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ C* release() {
+ C* retVal = array_;
+ array_ = NULL;
+ return retVal;
+ }
+
+ private:
+ C* array_;
+
+ // Forbid comparison of different scoped_array types.
+ template <class C2> bool operator==(scoped_array<C2> const& p2) const;
+ template <class C2> bool operator!=(scoped_array<C2> const& p2) const;
+
+ // Disallow evil constructors
+ scoped_array(const scoped_array&);
+ void operator=(const scoped_array&);
+};
+
+
+///////////////////////////////////
+// Escape methods
+///////////////////////////////////
+
+namespace strings {
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(string* str) {
+ // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+ return str->empty() ? NULL : &*str->begin();
+}
+
+int CalculateBase64EscapedLen(int input_len, bool do_padding) {
+ // these formulae were copied from comments that used to go with the base64
+ // encoding functions
+ int intermediate_result = 8 * input_len + 5;
+ assert(intermediate_result > 0); // make sure we didn't overflow
+ int len = intermediate_result / 6;
+ if (do_padding) len = ((len + 3) / 4) * 4;
+ return len;
+}
+
+// Base64Escape does padding, so this calculation includes padding.
+int CalculateBase64EscapedLen(int input_len) {
+ return CalculateBase64EscapedLen(input_len, true);
+}
+
+// ----------------------------------------------------------------------
+// int Base64Unescape() - base64 decoder
+// int Base64Escape() - base64 encoder
+// int WebSafeBase64Unescape() - Google's variation of base64 decoder
+// int WebSafeBase64Escape() - Google's variation of base64 encoder
+//
+// Check out
+// http://www.cis.ohio-state.edu/htbin/rfc/rfc2045.html for formal
+// description, but what we care about is that...
+// Take the encoded stuff in groups of 4 characters and turn each
+// character into a code 0 to 63 thus:
+// A-Z map to 0 to 25
+// a-z map to 26 to 51
+// 0-9 map to 52 to 61
+// +(- for WebSafe) maps to 62
+// /(_ for WebSafe) maps to 63
+// There will be four numbers, all less than 64 which can be represented
+// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
+// Arrange the 6 digit binary numbers into three bytes as such:
+// aaaaaabb bbbbcccc ccdddddd
+// Equals signs (one or two) are used at the end of the encoded block to
+// indicate that the text was not an integer multiple of three bytes long.
+// ----------------------------------------------------------------------
+
+int Base64UnescapeInternal(const char *src, int szsrc,
+ char *dest, int szdest,
+ const signed char* unbase64) {
+ static const char kPad64 = '=';
+
+ int decode = 0;
+ int destidx = 0;
+ int state = 0;
+ unsigned int ch = 0;
+ unsigned int temp = 0;
+
+ // The GET_INPUT macro gets the next input character, skipping
+ // over any whitespace, and stopping when we reach the end of the
+ // string or when we read any non-data character. The arguments are
+ // an arbitrary identifier (used as a label for goto) and the number
+ // of data bytes that must remain in the input to avoid aborting the
+ // loop.
+#define GET_INPUT(label, remain) \
+ label: \
+ --szsrc; \
+ ch = *src++; \
+ decode = unbase64[ch]; \
+ if (decode < 0) { \
+ if (ascii_isspace((char)ch) && szsrc >= remain) \
+ goto label; \
+ state = 4 - remain; \
+ break; \
+ }
+
+ // if dest is null, we're just checking to see if it's legal input
+ // rather than producing output. (I suspect this could just be done
+ // with a regexp...). We duplicate the loop so this test can be
+ // outside it instead of in every iteration.
+
+ if (dest) {
+ // This loop consumes 4 input bytes and produces 3 output bytes
+ // per iteration. We can't know at the start that there is enough
+ // data left in the string for a full iteration, so the loop may
+ // break out in the middle; if so 'state' will be set to the
+ // number of input bytes read.
+
+ while (szsrc >= 4) {
+ // We'll start by optimistically assuming that the next four
+ // bytes of the string (src[0..3]) are four good data bytes
+ // (that is, no nulls, whitespace, padding chars, or illegal
+ // chars). We need to test src[0..2] for nulls individually
+ // before constructing temp to preserve the property that we
+ // never read past a null in the string (no matter how long
+ // szsrc claims the string is).
+
+ if (!src[0] || !src[1] || !src[2] ||
+ (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
+ (unbase64[static_cast<int>(src[1])] << 12) |
+ (unbase64[static_cast<int>(src[2])] << 6) |
+ (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
+ // Iff any of those four characters was bad (null, illegal,
+ // whitespace, padding), then temp's high bit will be set
+ // (because unbase64[] is -1 for all bad characters).
+ //
+ // We'll back up and resort to the slower decoder, which knows
+ // how to handle those cases.
+
+ GET_INPUT(first, 4);
+ temp = decode;
+ GET_INPUT(second, 3);
+ temp = (temp << 6) | decode;
+ GET_INPUT(third, 2);
+ temp = (temp << 6) | decode;
+ GET_INPUT(fourth, 1);
+ temp = (temp << 6) | decode;
+ } else {
+ // We really did have four good data bytes, so advance four
+ // characters in the string.
+
+ szsrc -= 4;
+ src += 4;
+ decode = -1;
+ ch = '\0';
+ }
+
+ // temp has 24 bits of input, so write that out as three bytes.
+
+ if (destidx+3 > szdest) return -1;
+ dest[destidx+2] = (char)temp;
+ temp >>= 8;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ destidx += 3;
+ }
+ } else {
+ while (szsrc >= 4) {
+ if (!src[0] || !src[1] || !src[2] ||
+ (temp = ((unbase64[static_cast<int>(src[0])] << 18) |
+ (unbase64[static_cast<int>(src[1])] << 12) |
+ (unbase64[static_cast<int>(src[2])] << 6) |
+ (unbase64[static_cast<int>(src[3])]))) & 0x80000000) {
+ GET_INPUT(first_no_dest, 4);
+ GET_INPUT(second_no_dest, 3);
+ GET_INPUT(third_no_dest, 2);
+ GET_INPUT(fourth_no_dest, 1);
+ } else {
+ szsrc -= 4;
+ src += 4;
+ decode = -1;
+ ch = '\0';
+ }
+ destidx += 3;
+ }
+ }
+
+#undef GET_INPUT
+
+ // if the loop terminated because we read a bad character, return
+ // now.
+ if (decode < 0 && ch != '\0' && ch != kPad64 && !ascii_isspace((char)ch))
+ return -1;
+
+ if (ch == kPad64) {
+ // if we stopped by hitting an '=', un-read that character -- we'll
+ // look at it again when we count to check for the proper number of
+ // equals signs at the end.
+ ++szsrc;
+ --src;
+ } else {
+ // This loop consumes 1 input byte per iteration. It's used to
+ // clean up the 0-3 input bytes remaining when the first, faster
+ // loop finishes. 'temp' contains the data from 'state' input
+ // characters read by the first loop.
+ while (szsrc > 0) {
+ --szsrc;
+ ch = *src++;
+ decode = unbase64[ch];
+ if (decode < 0) {
+ if (ascii_isspace((char)ch)) {
+ continue;
+ } else if (ch == '\0') {
+ break;
+ } else if (ch == kPad64) {
+ // back up one character; we'll read it again when we check
+ // for the correct number of equals signs at the end.
+ ++szsrc;
+ --src;
+ break;
+ } else {
+ return -1;
+ }
+ }
+
+ // Each input character gives us six bits of output.
+ temp = (temp << 6) | decode;
+ ++state;
+ if (state == 4) {
+ // If we've accumulated 24 bits of output, write that out as
+ // three bytes.
+ if (dest) {
+ if (destidx+3 > szdest) return -1;
+ dest[destidx+2] = (char)temp;
+ temp >>= 8;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ }
+ destidx += 3;
+ state = 0;
+ temp = 0;
+ }
+ }
+ }
+
+ // Process the leftover data contained in 'temp' at the end of the input.
+ int expected_equals = 0;
+ switch (state) {
+ case 0:
+ // Nothing left over; output is a multiple of 3 bytes.
+ break;
+
+ case 1:
+ // Bad input; we have 6 bits left over.
+ return -1;
+
+ case 2:
+ // Produce one more output byte from the 12 input bits we have left.
+ if (dest) {
+ if (destidx+1 > szdest) return -1;
+ temp >>= 4;
+ dest[destidx] = (char)temp;
+ }
+ ++destidx;
+ expected_equals = 2;
+ break;
+
+ case 3:
+ // Produce two more output bytes from the 18 input bits we have left.
+ if (dest) {
+ if (destidx+2 > szdest) return -1;
+ temp >>= 2;
+ dest[destidx+1] = (char)temp;
+ temp >>= 8;
+ dest[destidx] = (char)temp;
+ }
+ destidx += 2;
+ expected_equals = 1;
+ break;
+
+ default:
+ // state should have no other values at this point.
+ fprintf(stdout, "This can't happen; base64 decoder state = %d", state);
+ }
+
+ // The remainder of the string should be all whitespace, mixed with
+ // exactly 0 equals signs, or exactly 'expected_equals' equals
+ // signs. (Always accepting 0 equals signs is a google extension
+ // not covered in the RFC.)
+
+ int equals = 0;
+ while (szsrc > 0 && *src) {
+ if (*src == kPad64)
+ ++equals;
+ else if (!ascii_isspace(*src))
+ return -1;
+ --szsrc;
+ ++src;
+ }
+
+ return (equals == 0 || equals == expected_equals) ? destidx : -1;
+}
+
+int Base64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+ static const signed char UnBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ // The above array was generated by the following code
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = -1;
+ // else
+ // idx = pos - Base64;
+ // if (idx == -1)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+
+ return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
+}
+
+bool Base64Unescape(const char *src, int slen, string* dest) {
+ // Determine the size of the output string. Base64 encodes every 3 bytes into
+ // 4 characters. any leftover chars are added directly for good measure.
+ // This is documented in the base64 RFC: http://www.ietf.org/rfc/rfc3548.txt
+ const int dest_len = 3 * (slen / 4) + (slen % 4);
+
+ dest->resize(dest_len);
+
+ // We are getting the destination buffer by getting the beginning of the
+ // string and converting it into a char *.
+ const int len = Base64Unescape(src, slen,
+ string_as_array(dest), dest->size());
+ if (len < 0) {
+ return false;
+ }
+
+ // could be shorter if there was padding
+ assert(len <= dest_len);
+ dest->resize(len);
+
+ return true;
+}
+
+// Base64Escape
+//
+// NOTE: We have to use an unsigned type for src because code built
+// in the the /google tree treats characters as signed unless
+// otherwised specified.
+//
+// TODO(who?): Move this function to use the char* type for "src"
+int Base64EscapeInternal(const unsigned char *src, int szsrc,
+ char *dest, int szdest, const char *base64,
+ bool do_padding) {
+ static const char kPad64 = '=';
+
+ if (szsrc <= 0) return 0;
+
+ char *cur_dest = dest;
+ const unsigned char *cur_src = src;
+
+ // Three bytes of data encodes to four characters of cyphertext.
+ // So we can pump through three-byte chunks atomically.
+ while (szsrc > 2) { /* keep going until we have less than 24 bits */
+ if ((szdest -= 4) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+ cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
+ cur_dest[3] = base64[cur_src[2] & 0x3f];
+
+ cur_dest += 4;
+ cur_src += 3;
+ szsrc -= 3;
+ }
+
+ /* now deal with the tail (<=2 bytes) */
+ switch (szsrc) {
+ case 0:
+ // Nothing left; nothing more to do.
+ break;
+ case 1:
+ // One byte left: this encodes to two characters, and (optionally)
+ // two pad characters to round out the four-character cypherblock.
+ if ((szdest -= 2) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
+ cur_dest += 2;
+ if (do_padding) {
+ if ((szdest -= 2) < 0) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest[1] = kPad64;
+ cur_dest += 2;
+ }
+ break;
+ case 2:
+ // Two bytes left: this encodes to three characters, and (optionally)
+ // one pad character to round out the four-character cypherblock.
+ if ((szdest -= 3) < 0) return 0;
+ cur_dest[0] = base64[cur_src[0] >> 2];
+ cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
+ cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
+ cur_dest += 3;
+ if (do_padding) {
+ if ((szdest -= 1) < 0) return 0;
+ cur_dest[0] = kPad64;
+ cur_dest += 1;
+ }
+ break;
+ default:
+ // Should not be reached: blocks of 3 bytes are handled
+ // in the while loop before this switch statement.
+ fprintf(stderr, "Logic problem? szsrc = %d", szsrc);
+ assert(false);
+ break;
+ }
+ return (cur_dest - dest);
+}
+
+static const char kBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static const char kWebSafeBase64Chars[] =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+int Base64Escape(const unsigned char *src, int szsrc, char *dest, int szdest) {
+ return Base64EscapeInternal(src, szsrc, dest, szdest, kBase64Chars, true);
+}
+
+void Base64Escape(const unsigned char *src, int szsrc,
+ string* dest, bool do_padding) {
+ const int max_escaped_size =
+ CalculateBase64EscapedLen(szsrc, do_padding);
+ dest->clear();
+ dest->resize(max_escaped_size + 1, '\0');
+ const int escaped_len = Base64EscapeInternal(src, szsrc,
+ &*dest->begin(), dest->size(),
+ kBase64Chars,
+ do_padding);
+ assert(max_escaped_size <= escaped_len);
+ dest->resize(escaped_len);
+}
+
+void Base64Escape(const string& src, string* dest) {
+ Base64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
+ src.size(), dest, true);
+}
+
+////////////////////////////////////////////////////
+// WebSafe methods
+////////////////////////////////////////////////////
+
+int WebSafeBase64Unescape(const char *src, int szsrc, char *dest, int szdest) {
+ static const signed char UnBase64[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 62/*-*/, -1, -1,
+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1,
+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/,
+ 7/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/,
+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1
+ };
+ // The above array was generated by the following code
+ // #include <sys/time.h>
+ // #include <stdlib.h>
+ // #include <string.h>
+ // main()
+ // {
+ // static const char Base64[] =
+ // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ // char *pos;
+ // int idx, i, j;
+ // printf(" ");
+ // for (i = 0; i < 255; i += 8) {
+ // for (j = i; j < i + 8; j++) {
+ // pos = strchr(Base64, j);
+ // if ((pos == NULL) || (j == 0))
+ // idx = -1;
+ // else
+ // idx = pos - Base64;
+ // if (idx == -1)
+ // printf(" %2d, ", idx);
+ // else
+ // printf(" %2d/*%c*/,", idx, j);
+ // }
+ // printf("\n ");
+ // }
+ // }
+
+ return Base64UnescapeInternal(src, szsrc, dest, szdest, UnBase64);
+}
+
+bool WebSafeBase64Unescape(const char *src, int slen, string* dest) {
+ int dest_len = 3 * (slen / 4) + (slen % 4);
+ dest->clear();
+ dest->resize(dest_len);
+ int len = WebSafeBase64Unescape(src, slen, &*dest->begin(), dest->size());
+ if (len < 0) {
+ dest->clear();
+ return false;
+ }
+ // could be shorter if there was padding
+ assert(len <= dest_len);
+ dest->resize(len);
+ return true;
+}
+
+bool WebSafeBase64Unescape(const string& src, string* dest) {
+ return WebSafeBase64Unescape(src.data(), src.size(), dest);
+}
+
+int WebSafeBase64Escape(const unsigned char *src, int szsrc, char *dest,
+ int szdest, bool do_padding) {
+ return Base64EscapeInternal(src, szsrc, dest, szdest,
+ kWebSafeBase64Chars, do_padding);
+}
+
+void WebSafeBase64Escape(const unsigned char *src, int szsrc,
+ string *dest, bool do_padding) {
+ const int max_escaped_size =
+ CalculateBase64EscapedLen(szsrc, do_padding);
+ dest->clear();
+ dest->resize(max_escaped_size + 1, '\0');
+ const int escaped_len = Base64EscapeInternal(src, szsrc,
+ &*dest->begin(), dest->size(),
+ kWebSafeBase64Chars,
+ do_padding);
+ assert(max_escaped_size <= escaped_len);
+ dest->resize(escaped_len);
+}
+
+void WebSafeBase64EscapeInternal(const string& src,
+ string* dest,
+ bool do_padding) {
+ int encoded_len = CalculateBase64EscapedLen(src.size());
+ scoped_array<char> buf(new char[encoded_len]);
+ int len = WebSafeBase64Escape(reinterpret_cast<const unsigned char*>(src.c_str()),
+ src.size(), buf.get(),
+ encoded_len, do_padding);
+ dest->assign(buf.get(), len);
+}
+
+void WebSafeBase64Escape(const string& src, string* dest) {
+ WebSafeBase64EscapeInternal(src, dest, false);
+}
+
+void WebSafeBase64EscapeWithPadding(const string& src, string* dest) {
+ WebSafeBase64EscapeInternal(src, dest, true);
+}
+
+} // namespace strings
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h new file mode 100644 index 0000000000..c8aa90b7b2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/escaping.h @@ -0,0 +1,99 @@ +// Copyright 2019 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.
+//
+// Base64 escaping methods to encode/decode strings.
+
+#ifndef TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
+
+#include <string>
+
+namespace strings {
+
+using std::string;
+
+// ----------------------------------------------------------------------
+// Base64Escape()
+// WebSafeBase64Escape()
+// Encode "src" to "dest" using base64 encoding.
+// src is not null terminated, instead specify len.
+// 'dest' should have at least CalculateBase64EscapedLen() length.
+// RETURNS the length of dest.
+// The WebSafe variation use '-' instead of '+' and '_' instead of '/'
+// so that we can place the out in the URL or cookies without having
+// to escape them. It also has an extra parameter "do_padding",
+// which when set to false will prevent padding with "=".
+// ----------------------------------------------------------------------
+void Base64Escape(const string& src, string* dest);
+int Base64Escape(const unsigned char* src, int slen, char* dest, int szdest);
+// Encode src into dest with padding.
+void Base64Escape(const unsigned char* src, int szsrc,
+ string* dest, bool do_padding);
+
+int WebSafeBase64Escape(const unsigned char* src, int slen, char* dest,
+ int szdest, bool do_padding);
+// Encode src into dest web-safely without padding.
+void WebSafeBase64Escape(const string& src, string* dest);
+// Encode src into dest web-safely with padding.
+void WebSafeBase64EscapeWithPadding(const string& src, string* dest);
+void WebSafeBase64Escape(const unsigned char* src, int szsrc,
+ string* dest, bool do_padding);
+
+// ----------------------------------------------------------------------
+// Base64Unescape()
+// WebSafeBase64Unescape()
+// Copies "src" to "dest", where src is in base64 and is written to its
+// ASCII equivalents. src is not null terminated, instead specify len.
+// I recommend that slen<szdest, but we honor szdest anyway.
+// RETURNS the length of dest, or -1 if src contains invalid chars.
+// The WebSafe variation use '-' instead of '+' and '_' instead of '/'.
+// The variations that store into a string clear the string first, and
+// return false (with dest empty) if src contains invalid chars; for
+// these versions src and dest must be different strings.
+// ----------------------------------------------------------------------
+int Base64Unescape(const char* src, int slen, char* dest, int szdest);
+bool Base64Unescape(const char* src, int slen, string* dest);
+inline bool Base64Unescape(const string& src, string* dest) {
+ return Base64Unescape(src.data(), src.size(), dest);
+}
+
+
+int WebSafeBase64Unescape(const char* src, int slen, char* dest, int szdest);
+bool WebSafeBase64Unescape(const char* src, int slen, string* dest);
+bool WebSafeBase64Unescape(const string& src, string* dest);
+
+// Return the length to use for the output buffer given to the base64 escape
+// routines. Make sure to use the same value for do_padding in both.
+// This function may return incorrect results if given input_len values that
+// are extremely high, which should happen rarely.
+int CalculateBase64EscapedLen(int input_len, bool do_padding);
+// Use this version when calling Base64Escape without a do_padding arg.
+int CalculateBase64EscapedLen(int input_len);
+} // namespace strings
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_ESCAPING_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_client.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_client.h new file mode 100644 index 0000000000..3e7aa8a764 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_client.h @@ -0,0 +1,96 @@ +// Copyright 2019 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 TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+#define TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
+
+#include <tchar.h>
+#include <windows.h>
+#include <vector>
+
+typedef void* HttpHandle;
+
+namespace crash {
+
+// HttpClient provides an abstract layer for HTTP APIs. The actual
+// implementation can be based on either WinHttp or WinInet.
+class HttpClient {
+ public:
+ enum AccessType {
+ ACCESS_TYPE_PRECONFIG,
+ ACCESS_TYPE_DIRECT,
+ ACCESS_TYPE_PROXY,
+ };
+
+ virtual ~HttpClient() {}
+
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const = 0;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const = 0;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const = 0;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const = 0;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const = 0;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const = 0;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const = 0;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const = 0;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const = 0;
+ virtual bool Close(HttpHandle handle) const = 0;
+
+ static const DWORD kUnknownContentLength = (DWORD)-1;
+};
+
+} // namespace crash
+
+#endif // TOOLS_CRASH_CONVERTER_WINDOWS_HTTP_CLIENT_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc new file mode 100644 index 0000000000..5afc1ccc14 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.cc @@ -0,0 +1,326 @@ +// Copyright 2019 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 <stdio.h>
+#include <Windows.h>
+#include <WinInet.h>
+
+#include <vector>
+
+#include "tools/windows/converter_exe/http_download.h"
+#include "tools/windows/converter_exe/winhttp_client.h"
+#include "tools/windows/converter_exe/wininet_client.h"
+
+namespace crash {
+static const std::vector<char>::size_type kVectorChunkSize = 4096; // 4 KB
+
+using std::vector;
+
+// Class that atuo closes the contained HttpHandle when the object
+// goes out of scope.
+class AutoHttpHandle {
+ public:
+ AutoHttpHandle() : handle_(NULL) {}
+ explicit AutoHttpHandle(HttpHandle handle) : handle_(handle) {}
+ ~AutoHttpHandle() {
+ if (handle_) {
+ InternetCloseHandle(handle_);
+ }
+ }
+
+ HttpHandle get() { return handle_; }
+ HttpHandle* get_handle_addr () { return &handle_; }
+
+ private:
+ HttpHandle handle_;
+};
+
+// Template class for auto releasing the contained pointer when
+// the object goes out of scope.
+template<typename T>
+class AutoPtr {
+ public:
+ explicit AutoPtr(T* ptr) : ptr_(ptr) {}
+ ~AutoPtr() {
+ if (ptr_) {
+ delete ptr_;
+ }
+ }
+
+ T* get() { return ptr_; }
+ T* operator -> () { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+// CheckParameters ensures that the parameters in |parameters| are safe for
+// use in an HTTP URL. Returns true if they are, false if unsafe characters
+// are present.
+static bool CheckParameters(const map<wstring, wstring> *parameters) {
+ for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
+ iterator != parameters->end();
+ ++iterator) {
+ const wstring &key = iterator->first;
+ if (key.empty()) {
+ // Disallow empty parameter names.
+ return false;
+ }
+ for (unsigned int i = 0; i < key.size(); ++i) {
+ wchar_t c = key[i];
+ if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
+ return false;
+ }
+ }
+
+ const wstring &value = iterator->second;
+ for (unsigned int i = 0; i < value.size(); ++i) {
+ wchar_t c = value[i];
+ if (c < 32 || c == '"' || c == '?' || c == '&' || c > 127) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+HttpClient* HTTPDownload::CreateHttpClient(const wchar_t* url) {
+ const TCHAR* kHttpApiPolicyEnvironmentVariable = TEXT("USE_WINHTTP");
+ TCHAR buffer[2] = {0};
+ HttpClient* http_client = NULL;
+
+ if (::GetEnvironmentVariable(kHttpApiPolicyEnvironmentVariable,
+ buffer,
+ sizeof(buffer)/sizeof(buffer[0])) > 0) {
+ fprintf(stdout,
+ "Environment variable [%ws] is set, use WinHttp\n",
+ kHttpApiPolicyEnvironmentVariable);
+ http_client = CreateWinHttpClient(url);
+ if (http_client == NULL) {
+ fprintf(stderr, "WinHttpClient not created, Is the protocol HTTPS? "
+ "Fall back to WinInet API.\n");
+ }
+ } else {
+ fprintf(stderr,
+ "Environment variable [%ws] is NOT set, use WinInet API\n",
+ kHttpApiPolicyEnvironmentVariable);
+ }
+
+ if (http_client == NULL) {
+ return CreateWinInetClient(url);
+ }
+
+ return http_client;
+}
+
+// static
+bool HTTPDownload::Download(const wstring &url,
+ const map<wstring, wstring> *parameters,
+ string *content, int *status_code) {
+ assert(content);
+ AutoPtr<HttpClient> http_client(CreateHttpClient(url.c_str()));
+
+ if (!http_client.get()) {
+ fprintf(stderr, "Failed to create any http client.\n");
+ return false;
+ }
+
+ if (status_code) {
+ *status_code = 0;
+ }
+
+ wchar_t scheme[16] = {0};
+ wchar_t host[256] = {0};
+ wchar_t path[256] = {0};
+ int port = 0;
+ if (!http_client->CrackUrl(url.c_str(),
+ 0,
+ scheme,
+ sizeof(scheme)/sizeof(scheme[0]),
+ host,
+ sizeof(host)/sizeof(host[0]),
+ path,
+ sizeof(path)/sizeof(path[0]),
+ &port)) {
+ fprintf(stderr,
+ "HTTPDownload::Download: InternetCrackUrl: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ bool secure = false;
+ if (_wcsicmp(scheme, L"https") == 0) {
+ secure = true;
+ } else if (wcscmp(scheme, L"http") != 0) {
+ fprintf(stderr,
+ "HTTPDownload::Download: scheme must be http or https for %ws\n",
+ url.c_str());
+ return false;
+ }
+
+ AutoHttpHandle internet;
+ if (!http_client->Open(NULL, // user agent
+ HttpClient::ACCESS_TYPE_PRECONFIG,
+ NULL, // proxy name
+ NULL, // proxy bypass
+ internet.get_handle_addr())) {
+ fprintf(stderr,
+ "HTTPDownload::Download: Open: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ AutoHttpHandle connection;
+ if (!http_client->Connect(internet.get(),
+ host,
+ port,
+ connection.get_handle_addr())) {
+ fprintf(stderr,
+ "HTTPDownload::Download: InternetConnect: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ wstring request_string = path;
+ if (parameters) {
+ // TODO(mmentovai): escape bad characters in parameters instead of
+ // forbidding them.
+ if (!CheckParameters(parameters)) {
+ fprintf(stderr,
+ "HTTPDownload::Download: invalid characters in parameters\n");
+ return false;
+ }
+
+ bool added_parameter = false;
+ for (map<wstring, wstring>::const_iterator iterator = parameters->begin();
+ iterator != parameters->end();
+ ++iterator) {
+ request_string.append(added_parameter ? L"&" : L"?");
+ request_string.append(iterator->first);
+ request_string.append(L"=");
+ request_string.append(iterator->second);
+ added_parameter = true;
+ }
+ }
+
+ AutoHttpHandle request;
+ if (!http_client->OpenRequest(connection.get(),
+ L"GET",
+ request_string.c_str(),
+ NULL, // version
+ NULL, // referer
+ secure,
+ request.get_handle_addr())) {
+ fprintf(stderr,
+ "HttpClient::OpenRequest: error %lu for %ws, request: %ws\n",
+ GetLastError(), url.c_str(), request_string.c_str());
+ return false;
+ }
+
+ if (!http_client->SendRequest(request.get(), NULL, 0)) {
+ fprintf(stderr,
+ "HttpClient::SendRequest: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ if (!http_client->ReceiveResponse(request.get())) {
+ fprintf(stderr,
+ "HttpClient::ReceiveResponse: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+
+ int http_status = 0;
+ if (!http_client->GetHttpStatusCode(request.get(), &http_status)) {
+ fprintf(stderr,
+ "HttpClient::GetHttpStatusCode: error %lu for %ws\n",
+ GetLastError(), url.c_str());
+ return false;
+ }
+ if (http_status != 200) {
+ fprintf(stderr,
+ "HTTPDownload::Download: HTTP status code %d for %ws\n",
+ http_status, url.c_str());
+ return false;
+ }
+
+ DWORD content_length = 0;
+ vector<char>::size_type buffer_size = 0;
+ http_client->GetContentLength(request.get(), &content_length);
+ if (content_length == HttpClient::kUnknownContentLength) {
+ buffer_size = kVectorChunkSize;
+ } else {
+ buffer_size = content_length;
+ }
+
+ if (content_length != 0) {
+ vector<char> response_buffer = vector<char>(buffer_size+1);
+ DWORD size_read;
+ DWORD total_read = 0;
+ bool read_result;
+ do {
+ if (content_length == HttpClient::kUnknownContentLength
+ && buffer_size == total_read) {
+ // The content length wasn't specified in the response header, so we
+ // have to keep growing the buffer until we're done reading.
+ buffer_size += kVectorChunkSize;
+ response_buffer.resize(buffer_size);
+ }
+ read_result = !!http_client->ReadData(
+ request.get(),
+ &response_buffer[total_read],
+ static_cast<DWORD>(buffer_size) - total_read,
+ &size_read);
+ total_read += size_read;
+ } while (read_result && (size_read != 0));
+
+ if (!read_result) {
+ fprintf(stderr,
+ "HttpClient::ReadData: error %lu for %ws\n",
+ GetLastError(),
+ url.c_str());
+ return false;
+ } else if (size_read != 0) {
+ fprintf(stderr,
+ "HttpClient::ReadData: error %lu/%lu for %ws\n",
+ total_read,
+ content_length,
+ url.c_str());
+ return false;
+ }
+ content->assign(&response_buffer[0], total_read);
+ } else {
+ content->clear();
+ }
+ return true;
+}
+
+} // namespace crash
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h new file mode 100644 index 0000000000..2d705d5ece --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/http_download.h @@ -0,0 +1,62 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
+
+#include <map>
+#include <string>
+#include "tools/windows/converter_exe/winhttp_client.h"
+
+namespace crash {
+
+using std::map;
+using std::string;
+using std::wstring;
+
+class HTTPDownload {
+ public:
+ // Retrieves the resource located at |url|, a http or https URL, via WinInet.
+ // The request is fetched with GET request; the optional |parameters| are
+ // appended to the URL. Returns true on success, placing the content of the
+ // retrieved resource in |content|. Returns false on failure. HTTP status
+ // codes other than 200 cause Download to return false. If |status_code| is
+ // supplied, it will be set to the value of the HTTP status code, if an HTTP
+ // transaction occurs. If Download fails before a transaction can occur,
+ // |status_code| will be set to 0. Any failures will result in messages
+ // being printed to stderr.
+ static bool Download(const wstring &url,
+ const map<wstring, wstring> *parameters,
+ string *content, int *status_code);
+ private:
+ static HttpClient* CreateHttpClient(const wchar_t*);
+};
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_HTTP_DOWNLOAD_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt new file mode 100644 index 0000000000..91641fca96 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/missing_symbols_test.txt @@ -0,0 +1,5 @@ +msctf.pdb|6A5BABB8E88644C696530BFE3C90F32F2|6.1.7600.16385|msctf.dll|4A5BDFAA109000
+imm32.pdb|98F27BA5AEE541ECBEE00CD03AD50FEE2|6.1.7600.16385|imm32.dll|4A5BDF402e000
+amd_opencl64.pdb|3D306D0FCCB14F47AF322A5ACDF5EEA81||amd_opencl64.dll|587901FB1E000
+igd10iumd64.pdb|B2B72475BB0846D8ADE4344FAE0CCE361 ||igd10iumd64.dll|568D69FBD99000
+NvCameraWhitelisting64.pdb|3C364C4D3FBF4180B021D52D469C6DAB1||NvCameraWhitelisting64.dll|5B8ED23485000
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes new file mode 100644 index 0000000000..1d01dda71b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/symsrv.yes @@ -0,0 +1,2 @@ +See breakpad/tools/windows/converter/ms_symbol_server_converter.h for a
+description of this file's function.
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc new file mode 100644 index 0000000000..992694cd0c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.cc @@ -0,0 +1,61 @@ +// Copyright 2019 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 "tools/windows/converter_exe/tokenizer.h"
+
+namespace crash {
+
+// static
+void Tokenizer::Tokenize(const string &delimiters, const string &input,
+ vector<string> *output) {
+ assert(output);
+ output->clear();
+
+ string::size_type position = 0; // Where to begin looking for a delimiter
+ string::size_type new_position; // Position of found delimiter
+ string token;
+
+ while ((new_position = input.find_first_of(delimiters, position)) !=
+ string::npos) {
+ token = input.substr(position, new_position - position);
+ output->push_back(token);
+
+ // Next time, begin looking right after this delimiter.
+ position = new_position + 1;
+ }
+
+ // There are no more delimiters in the string. Take everything from the
+ // final delimiter up to the end of the string as a token. This may be
+ // an empty string.
+ token = input.substr(position);
+ output->push_back(token);
+}
+
+} // namespace crash
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h new file mode 100644 index 0000000000..f4bbcfd0e8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/tokenizer.h @@ -0,0 +1,51 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
+
+#include <string>
+#include <vector>
+
+namespace crash {
+
+using std::string;
+using std::vector;
+
+class Tokenizer {
+ public:
+ // Splits |input| into a series of tokens delimited in the input string by
+ // any of the characters in |delimiters|. The tokens are passed back in the
+ // |output| vector.
+ static void Tokenize(const string &delimiters, const string &input,
+ vector<string> *output);
+};
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_TOKENIZER_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc new file mode 100644 index 0000000000..8a8ade3b6c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.cc @@ -0,0 +1,307 @@ +// Copyright 2019 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 "tools/windows/converter_exe/winhttp_client.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <winhttp.h>
+#include <vector>
+
+namespace crash {
+
+namespace internal {
+
+// This class implements HttpClient based on WinInet APIs.
+class WinHttpClient : public HttpClient {
+ public:
+ virtual ~WinHttpClient() {}
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const;
+ virtual bool Close(HttpHandle handle) const;
+
+ private:
+ static DWORD MapAccessType(DWORD access_type);
+ static HINTERNET ToHINTERNET(HttpHandle handle);
+ static HttpHandle FromHINTERNET(HINTERNET handle);
+};
+
+bool WinHttpClient::CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const {
+ assert(url);
+ assert(scheme);
+ assert(host);
+ assert(uri);
+ assert(port);
+
+ URL_COMPONENTS url_comp = {0};
+ url_comp.dwStructSize = sizeof(url_comp);
+ url_comp.lpszScheme = scheme;
+ url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
+ url_comp.lpszHostName = host;
+ url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
+ url_comp.lpszUrlPath = uri;
+ url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
+
+ bool result = !!::WinHttpCrackUrl(url, 0, flags, &url_comp);
+ if (result) {
+ *port = static_cast<int>(url_comp.nPort);
+ }
+ return result;
+}
+
+bool WinHttpClient::Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const {
+ *session_handle = FromHINTERNET(::WinHttpOpen(user_agent,
+ MapAccessType(access_type),
+ proxy_name,
+ proxy_bypass,
+ 0));
+
+ return !!(*session_handle);
+}
+
+bool WinHttpClient::Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const {
+ assert(server);
+
+ // Uses NULL user name and password to connect.
+ *connection_handle = FromHINTERNET(::WinHttpConnect(
+ ToHINTERNET(session_handle),
+ server,
+ static_cast<INTERNET_PORT>(port),
+ NULL));
+ return !!(*connection_handle);
+}
+
+bool WinHttpClient::OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const {
+ assert(connection_handle);
+ assert(verb);
+ assert(uri);
+ assert(request_handle);
+
+ *request_handle = FromHINTERNET(::WinHttpOpenRequest(
+ ToHINTERNET(connection_handle),
+ verb,
+ uri,
+ version,
+ referrer,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ is_secure ? WINHTTP_FLAG_SECURE : 0));
+ return !!(*request_handle);
+}
+
+bool WinHttpClient::SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const {
+ assert(request_handle);
+
+ return !!::WinHttpSendRequest(ToHINTERNET(request_handle),
+ headers,
+ headers_length,
+ NULL,
+ 0,
+ WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
+ NULL);
+}
+
+bool WinHttpClient::ReceiveResponse(HttpHandle request_handle) const {
+ assert(request_handle);
+
+ return !!::WinHttpReceiveResponse(ToHINTERNET(request_handle), NULL);
+}
+
+bool WinHttpClient::GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const {
+ TCHAR http_status_string[4] = {0};
+ DWORD http_status_string_size = sizeof(http_status_string);
+ if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
+ WINHTTP_QUERY_STATUS_CODE,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ static_cast<void *>(&http_status_string),
+ &http_status_string_size, 0)) {
+ return false;
+ }
+
+ *status_code = static_cast<DWORD>(_tcstol(http_status_string, NULL, 10));
+ return true;
+}
+
+bool WinHttpClient::GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const {
+ assert(request_handle);
+ assert(content_length);
+
+ TCHAR content_length_string[11] = {0};
+ DWORD content_length_string_size = sizeof(content_length_string);
+ if (!::WinHttpQueryHeaders(ToHINTERNET(request_handle),
+ WINHTTP_QUERY_CONTENT_LENGTH,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ static_cast<void *>(&content_length_string),
+ &content_length_string_size, 0)) {
+ *content_length = kUnknownContentLength;
+ } else {
+ *content_length =
+ static_cast<DWORD>(wcstol(content_length_string, NULL, 10));
+ }
+ return true;
+}
+
+bool WinHttpClient::ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const {
+ assert(request_handle);
+ assert(buffer);
+ assert(bytes_read);
+
+ DWORD bytes_read_local = 0;
+ if (!::WinHttpReadData(ToHINTERNET(request_handle),
+ buffer,
+ buffer_length,
+ &bytes_read_local)) {
+ return false;
+ }
+ *bytes_read = bytes_read_local;
+ return true;
+}
+
+bool WinHttpClient::Close(HttpHandle handle) const {
+ assert(handle);
+ return !!::WinHttpCloseHandle(ToHINTERNET(handle));
+}
+
+DWORD WinHttpClient::MapAccessType(DWORD access_type) {
+ switch (static_cast<AccessType>(access_type)) {
+ case ACCESS_TYPE_PRECONFIG:
+ default:
+ return WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
+ case ACCESS_TYPE_DIRECT:
+ return WINHTTP_ACCESS_TYPE_NO_PROXY;
+ case ACCESS_TYPE_PROXY:
+ return WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+ }
+}
+
+
+HINTERNET WinHttpClient::ToHINTERNET(HttpHandle handle) {
+ return static_cast<HINTERNET>(handle);
+}
+
+HttpHandle WinHttpClient::FromHINTERNET(HINTERNET handle) {
+ return static_cast<HttpHandle>(handle);
+}
+
+} // namespace internal
+
+HttpClient* CreateWinHttpClient(const TCHAR* url) {
+ assert(url);
+
+ internal::WinHttpClient winhttp;
+ wchar_t scheme[16] = {0};
+ wchar_t host[256] = {0};
+ wchar_t path[256] = {0};
+ int port = 0;
+
+ if (!winhttp.CrackUrl(url,
+ 0,
+ scheme,
+ sizeof(scheme)/sizeof(scheme[0]),
+ host,
+ sizeof(host)/sizeof(host[0]),
+ path,
+ sizeof(path)/sizeof(path[0]),
+ &port)) {
+ return NULL;
+ }
+
+ if (_wcsicmp(scheme, L"https") == 0) {
+ // Winhttp under WINE doesn't support wildcard certificates, so avoid
+ // to use it if the scheme is https. The caller should fall back to
+ // use wininet if NULL is returned.
+ return NULL;
+ }
+
+ return new internal::WinHttpClient();
+}
+
+} // namespace crash
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h new file mode 100644 index 0000000000..819d610f1c --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winhttp_client.h @@ -0,0 +1,40 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
+
+#include "tools/windows/converter_exe/http_client.h"
+
+namespace crash {
+
+HttpClient* CreateWinHttpClient(const TCHAR* url);
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_WINHTTP_CLIENT_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc new file mode 100644 index 0000000000..3e542db25f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.cc @@ -0,0 +1,278 @@ +// Copyright 2019 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 "tools/windows/converter_exe/wininet_client.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <wininet.h>
+
+namespace crash {
+
+namespace internal {
+
+// This class implements HttpClient based on WinInet APIs.
+class WinInetClient : public HttpClient {
+ public:
+ virtual ~WinInetClient() {}
+ virtual bool CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const;
+ virtual bool Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const;
+ virtual bool Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const;
+ virtual bool OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const;
+ virtual bool SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const;
+ virtual bool ReceiveResponse(HttpHandle request_handle) const;
+ virtual bool GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const;
+ virtual bool GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const;
+ virtual bool ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const;
+ virtual bool Close(HttpHandle handle) const;
+
+ private:
+ static DWORD MapAccessType(DWORD access_type);
+ static HINTERNET ToHINTERNET(HttpHandle handle);
+ static HttpHandle FromHINTERNET(HINTERNET handle);
+};
+
+bool WinInetClient::CrackUrl(const TCHAR* url,
+ DWORD flags,
+ TCHAR* scheme,
+ size_t scheme_buffer_length,
+ TCHAR* host,
+ size_t host_buffer_length,
+ TCHAR* uri,
+ size_t uri_buffer_length,
+ int* port) const {
+ assert(url);
+ assert(scheme);
+ assert(host);
+ assert(uri);
+ assert(port);
+
+ URL_COMPONENTS url_comp = {0};
+ url_comp.dwStructSize = sizeof(url_comp);
+ url_comp.lpszScheme = scheme;
+ url_comp.dwSchemeLength = static_cast<DWORD>(scheme_buffer_length);
+ url_comp.lpszHostName = host;
+ url_comp.dwHostNameLength = static_cast<DWORD>(host_buffer_length);
+ url_comp.lpszUrlPath = uri;
+ url_comp.dwUrlPathLength = static_cast<DWORD>(uri_buffer_length);
+
+ bool result = !!::InternetCrackUrl(url, 0, flags, &url_comp);
+ if (result) {
+ *port = static_cast<int>(url_comp.nPort);
+ }
+ return result;
+}
+
+bool WinInetClient::Open(const TCHAR* user_agent,
+ DWORD access_type,
+ const TCHAR* proxy_name,
+ const TCHAR* proxy_bypass,
+ HttpHandle* session_handle) const {
+ *session_handle = FromHINTERNET(::InternetOpen(user_agent,
+ MapAccessType(access_type),
+ proxy_name,
+ proxy_bypass,
+ 0));
+ return !!(*session_handle);
+}
+
+bool WinInetClient::Connect(HttpHandle session_handle,
+ const TCHAR* server,
+ int port,
+ HttpHandle* connection_handle) const {
+ assert(server);
+
+ // Uses NULL user name and password to connect. Always uses http service.
+ *connection_handle = FromHINTERNET(::InternetConnect(
+ ToHINTERNET(session_handle),
+ server,
+ static_cast<INTERNET_PORT>(port),
+ NULL,
+ NULL,
+ INTERNET_SERVICE_HTTP,
+ 0,
+ 0));
+ return !!(*connection_handle);
+}
+
+bool WinInetClient::OpenRequest(HttpHandle connection_handle,
+ const TCHAR* verb,
+ const TCHAR* uri,
+ const TCHAR* version,
+ const TCHAR* referrer,
+ bool is_secure,
+ HttpHandle* request_handle) const {
+ assert(connection_handle);
+ assert(verb);
+ assert(uri);
+
+ *request_handle = FromHINTERNET(::HttpOpenRequest(
+ ToHINTERNET(connection_handle),
+ verb,
+ uri,
+ version,
+ referrer,
+ NULL,
+ is_secure ? INTERNET_FLAG_SECURE : 0,
+ NULL));
+ return !!(*request_handle);
+}
+
+bool WinInetClient::SendRequest(HttpHandle request_handle,
+ const TCHAR* headers,
+ DWORD headers_length) const {
+ assert(request_handle);
+
+ return !!::HttpSendRequest(ToHINTERNET(request_handle),
+ headers,
+ headers_length,
+ NULL,
+ 0);
+}
+
+bool WinInetClient::ReceiveResponse(HttpHandle) const {
+ return true;
+}
+
+bool WinInetClient::GetHttpStatusCode(HttpHandle request_handle,
+ int* status_code) const {
+ assert(request_handle);
+
+ TCHAR http_status_string[4] = {0};
+ DWORD http_status_string_size = sizeof(http_status_string);
+ if (!::HttpQueryInfo(ToHINTERNET(request_handle),
+ HTTP_QUERY_STATUS_CODE,
+ static_cast<void *>(&http_status_string),
+ &http_status_string_size,
+ 0)) {
+ return false;
+ }
+
+ *status_code = _tcstol(http_status_string, NULL, 10);
+ return true;
+}
+
+bool WinInetClient::GetContentLength(HttpHandle request_handle,
+ DWORD* content_length) const {
+ assert(request_handle);
+ assert(content_length);
+
+ TCHAR content_length_string[11];
+ DWORD content_length_string_size = sizeof(content_length_string);
+ if (!::HttpQueryInfo(ToHINTERNET(request_handle),
+ HTTP_QUERY_CONTENT_LENGTH,
+ static_cast<void *>(&content_length_string),
+ &content_length_string_size,
+ 0)) {
+ *content_length = kUnknownContentLength;
+ } else {
+ *content_length = wcstol(content_length_string, NULL, 10);
+ }
+ return true;
+}
+
+bool WinInetClient::ReadData(HttpHandle request_handle,
+ void* buffer,
+ DWORD buffer_length,
+ DWORD* bytes_read) const {
+ assert(request_handle);
+ assert(buffer);
+ assert(bytes_read);
+
+ DWORD bytes_read_local = 0;
+ if (!::InternetReadFile(ToHINTERNET(request_handle),
+ buffer,
+ buffer_length,
+ &bytes_read_local)) {
+ return false;
+ }
+ *bytes_read = bytes_read_local;
+ return true;
+}
+
+bool WinInetClient::Close(HttpHandle handle) const {
+ assert(handle);
+ return !!::InternetCloseHandle(ToHINTERNET(handle));
+}
+
+DWORD WinInetClient::MapAccessType(DWORD access_type) {
+ switch (static_cast<AccessType>(access_type)) {
+ case ACCESS_TYPE_PRECONFIG:
+ default:
+ return INTERNET_OPEN_TYPE_PRECONFIG;
+ case ACCESS_TYPE_DIRECT:
+ return INTERNET_OPEN_TYPE_DIRECT;
+ case ACCESS_TYPE_PROXY:
+ return INTERNET_OPEN_TYPE_PROXY;
+ }
+}
+
+HINTERNET WinInetClient::ToHINTERNET(HttpHandle handle) {
+ return static_cast<HINTERNET>(handle);
+}
+
+HttpHandle WinInetClient::FromHINTERNET(HINTERNET handle) {
+ return static_cast<HttpHandle>(handle);
+}
+
+} // namespace internal
+
+HttpClient* CreateWinInetClient(const TCHAR*) {
+ return new internal::WinInetClient();
+}
+
+} // namespace crash
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h new file mode 100644 index 0000000000..bd04b605dc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/wininet_client.h @@ -0,0 +1,40 @@ +// Copyright 2019 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 TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+#define TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
+
+#include "tools/windows/converter_exe/http_client.h"
+
+namespace crash {
+
+HttpClient* CreateWinInetClient(const TCHAR* url);
+
+} // namespace crash
+
+#endif // TOOLS_WINDOWS_CONVERTER_EXE_WININET_CLIENT_H_
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd new file mode 100644 index 0000000000..bea84b589f --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv.cmd @@ -0,0 +1,86 @@ +@if "%ECHOON%"=="" @echo off
+SETLOCAL
+
+REM ******************************************************************
+REM Usage:
+REM winsymconv
+REM ******************************************************************
+
+REM ******************************************************************
+REM Initialize
+REM ******************************************************************
+SET SCRIPT_LOCATION=%~dp0
+SET DBGHELP_WINHTTP=
+SET USE_WINHTTP=
+
+REM ******************************************************************
+REM Go to script location
+REM ******************************************************************
+pushd %SCRIPT_LOCATION%
+
+REM ******************************************************************
+REM Make sure the symbol file directory exists
+REM ******************************************************************
+SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol
+if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR%
+if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail
+
+:restart
+
+REM ******************************************************************
+REM Convert missing Windows symbols on the staging instance.
+REM ******************************************************************
+echo Converting missing Windows symbols on staging instance ...
+
+google_converter.exe ^
+ -n http://msdl.microsoft.com/download/symbols ^
+ -n http://symbols.mozilla.org/firefox ^
+ -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
+ -n https://download.amd.com/dir/bin ^
+ -n https://driver-symbols.nvidia.com ^
+ -n https://software.intel.com/sites/downloads/symbols ^
+ -l %SYMBOL_DIR% ^
+ -s https://clients2.google.com/cr/staging_symbol ^
+ -m https://clients2.google.com/cr/staging_symbol/missingsymbols ^
+ -t https://clients2.google.com/cr/staging_symbol/fetchfailed ^
+ -b "google|chrome|internal|private" ^
+ > %SCRIPT_LOCATION%last_cycle_staging.txt
+
+REM ******************************************************************
+REM Convert missing Windows symbols on the production instance.
+REM ******************************************************************
+echo Converting missing Windows symbols on production instance ...
+
+google_converter.exe ^
+ -n http://msdl.microsoft.com/download/symbols ^
+ -n http://symbols.mozilla.org/firefox ^
+ -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
+ -n https://download.amd.com/dir/bin ^
+ -n https://driver-symbols.nvidia.com ^
+ -n https://software.intel.com/sites/downloads/symbols ^
+ -l %SYMBOL_DIR% ^
+ -s https://clients2.google.com/cr/symbol ^
+ -m https://clients2.google.com/cr/symbol/missingsymbols ^
+ -t https://clients2.google.com/cr/symbol/fetchfailed ^
+ -b "google|chrome|internal|private" ^
+ > %SCRIPT_LOCATION%last_cycle_prod.txt
+
+REM ******************************************************************
+REM Sleep for 5 minutes ...
+REM ******************************************************************
+echo Sleeping for 5 minutes ...
+
+%SCRIPT_LOCATION%sleep.exe 300
+
+REM ******************************************
+REM Restart work loop ...
+REM ******************************************
+goto :restart
+
+:success
+ENDLOCAL
+exit /b 0
+
+:fail
+ENDLOCAL
+exit /b 1
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd new file mode 100644 index 0000000000..c177706608 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter_exe/winsymconv_test.cmd @@ -0,0 +1,72 @@ +@if "%ECHOON%"=="" @echo off
+SETLOCAL
+
+REM ******************************************************************
+REM Usage:
+REM winsymconv_test
+REM ******************************************************************
+
+REM ******************************************************************
+REM Initialize
+REM ******************************************************************
+SET SCRIPT_LOCATION=%~dp0
+SET DBGHELP_WINHTTP=
+SET USE_WINHTTP=
+
+REM ******************************************************************
+REM Go to script location
+REM ******************************************************************
+pushd %SCRIPT_LOCATION%
+
+REM ******************************************************************
+REM Make sure the symbol file directory exists
+REM ******************************************************************
+SET SYMBOL_DIR=%SCRIPT_LOCATION%symbol
+if NOT EXIST %SYMBOL_DIR% MKDIR %SYMBOL_DIR%
+if NOT EXIST %SYMBOL_DIR% echo Failed to create directory '%SYMBOL_DIR%' & goto :fail
+
+REM ******************************************************************
+REM Testing on the staging instance.
+REM ******************************************************************
+echo Testing on the staging instance ...
+
+google_converter.exe ^
+ -n http://msdl.microsoft.com/download/symbols ^
+ -n http://symbols.mozilla.org/firefox ^
+ -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
+ -n https://download.amd.com/dir/bin ^
+ -n https://driver-symbols.nvidia.com ^
+ -n https://software.intel.com/sites/downloads/symbols ^
+ -l %SYMBOL_DIR% ^
+ -s https://clients2.google.com/cr/staging_symbol ^
+ -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^
+ -t https://clients2.google.com/cr/staging_symbol/fetchfailed ^
+ -b "google|chrome|internal|private" ^
+ > %SCRIPT_LOCATION%last_cycle_staging.txt
+
+REM ******************************************************************
+REM Testing on the production instance.
+REM ******************************************************************
+echo Testing on the production instance ...
+
+google_converter.exe ^
+ -n http://msdl.microsoft.com/download/symbols ^
+ -n http://symbols.mozilla.org/firefox ^
+ -n http://chromium-browser-symsrv.commondatastorage.googleapis.com ^
+ -n https://download.amd.com/dir/bin ^
+ -n https://driver-symbols.nvidia.com ^
+ -n https://software.intel.com/sites/downloads/symbols ^
+ -l %SYMBOL_DIR% ^
+ -s https://clients2.google.com/cr/symbol ^
+ -mf %SCRIPT_LOCATION%missing_symbols_test.txt ^
+ -t https://clients2.google.com/cr/symbol/fetchfailed ^
+ -b "google|chrome|internal|private" ^
+ > %SCRIPT_LOCATION%last_cycle_prod.txt
+
+:success
+ENDLOCAL
+exit /b 0
+
+:fail
+ENDLOCAL
+exit /b 1
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc new file mode 100644 index 0000000000..5b7d177753 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc @@ -0,0 +1,73 @@ +// Copyright (c) 2006, 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. + +// Windows utility to dump the line number data from a pdb file to +// a text-based format that we can use from the minidump processor. + +#include <stdio.h> +#include <wchar.h> + +#include <string> + +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/pe_source_line_writer.h" + +using std::wstring; +using google_breakpad::PDBSourceLineWriter; +using google_breakpad::PESourceLineWriter; +using std::unique_ptr; + +int wmain(int argc, wchar_t **argv) { + bool success; + if (argc == 2) { + PDBSourceLineWriter pdb_writer; + if (!pdb_writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) { + fprintf(stderr, "Open failed.\n"); + return 1; + } + success = pdb_writer.WriteSymbols(stdout); + } else if (argc == 3 && wcscmp(argv[1], L"--pe") == 0) { + PESourceLineWriter pe_writer(argv[2]); + success = pe_writer.WriteSymbols(stdout); + } else { + fprintf(stderr, "Usage: %ws [--pe] <file.[pdb|exe|dll]>\n", argv[0]); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "--pe:\tRead debugging information from PE file and do " + "not attempt to locate matching PDB file.\n" + "\tThis is only supported for PE32+ (64 bit) PE files.\n"); + return 1; + } + + if (!success) { + fprintf(stderr, "WriteSymbols failed.\n"); + return 1; + } + + return 0; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp new file mode 100644 index 0000000000..b815574b29 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.gyp @@ -0,0 +1,64 @@ +# Copyright 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'dump_syms', + 'type': 'executable', + 'sources': [ + 'dump_syms.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + }, + { + 'target_name': 'dump_syms_unittest', + 'type': 'executable', + 'sources': [ + 'dump_syms_unittest.cc', + ], + 'dependencies': [ + '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', + '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', + 'dump_syms', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'AdditionalDependencies': [ + 'shell32.lib', + ], + }, + }, + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj new file mode 100644 index 0000000000..2fbe301ed8 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.vcproj @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="UTF-8"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="dump_syms" + ProjectGUID="{792E1530-E2C5-4289-992E-317BA30E9D9F}" + RootNamespace="dumpsyms" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories=""$(VSInstallDir)\DIA SDK\include";..\..\.." + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib" imagehlp.lib" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(VSInstallDir)\DIA SDK\include";..\..\.." + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies=""$(VSInstallDir)\DIA SDK\lib\diaguids.lib" imagehlp.lib" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\..\..\common\windows\dia_util.h" + > + </File> + <File + RelativePath="..\..\..\common\windows\guid_string.h" + > + </File> + <File + RelativePath="..\..\..\common\windows\omap_internal.h" + > + </File> + <File + RelativePath="..\..\..\common\windows\omap.h" + > + </File> + <File + RelativePath="..\..\..\common\windows\pdb_source_line_writer.h" + > + </File> + <File + RelativePath="..\..\..\common\windows\string_utils-inl.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\..\common\windows\dia_util.cc" + > + </File> + <File + RelativePath=".\dump_syms.cc" + > + </File> + <File + RelativePath="..\..\..\common\windows\guid_string.cc" + > + </File> + <File + RelativePath="..\..\..\common\windows\omap.cc" + > + </File> + <File + RelativePath="..\..\..\common\windows\pdb_source_line_writer.cc" + > + </File> + <File + RelativePath="..\..\..\common\windows\string_utils.cc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject>
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc new file mode 100644 index 0000000000..766e5c09d0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -0,0 +1,244 @@ +// Copyright 2003 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 <Windows.h>
+#include <shellapi.h>
+
+#include <string>
+#include <utility>
+
+#include "breakpad_googletest_includes.h"
+
+namespace tools {
+namespace windows {
+namespace dump_syms {
+
+namespace {
+
+// Root names of PDB and dumped symbol files to be regression tested. These are
+// specified in complexity of the resulting dumped symbol files.
+const wchar_t* kRootNames[] = {
+ // A PDB file with no OMAP data.
+ L"dump_syms_regtest",
+ // A PDB file with OMAP data for an image that has been function-level
+ // reordered.
+ L"omap_reorder_funcs",
+ // A PDB file with OMAP data for an image that had new content injected, all
+ // of it with source data.
+ L"omap_stretched_filled",
+ // A PDB file with OMAP data for an image that had new content injected, but
+ // without source data.
+ L"omap_stretched",
+ // A PDB file with OMAP data for an image that has been basic block reordered.
+ L"omap_reorder_bbs",
+ // A 64bit PDB file with no OMAP data.
+ L"dump_syms_regtest64",
+};
+
+const wchar_t* kPEOnlyRootNames[] = {
+ L"pe_only_symbol_test",
+};
+
+void TrimLastComponent(const std::wstring& path,
+ std::wstring* trimmed,
+ std::wstring* component) {
+ size_t len = path.size();
+ while (len > 0 && path[len - 1] != '\\')
+ --len;
+
+ if (component != NULL)
+ component->assign(path.c_str() + len, path.c_str() + path.size());
+
+ while (len > 0 && path[len - 1] == '\\')
+ --len;
+
+ if (trimmed != NULL)
+ trimmed->assign(path.c_str(), len);
+}
+
+// Get the directory of the current executable.
+bool GetSelfDirectory(std::wstring* self_dir) {
+ std::wstring command_line = GetCommandLineW();
+
+ int num_args = 0;
+ wchar_t** args = NULL;
+ args = ::CommandLineToArgvW(command_line.c_str(), &num_args);
+ if (args == NULL)
+ return false;
+
+ *self_dir = args[0];
+ TrimLastComponent(*self_dir, self_dir, NULL);
+
+ return true;
+}
+
+void RunCommand(const std::wstring& command_line,
+ std::string* stdout_string) {
+ // Create a PIPE for the child process stdout.
+ HANDLE child_stdout_read = 0;
+ HANDLE child_stdout_write = 0;
+ SECURITY_ATTRIBUTES sec_attr_stdout = {};
+ sec_attr_stdout.nLength = sizeof(sec_attr_stdout);
+ sec_attr_stdout.bInheritHandle = TRUE;
+ ASSERT_TRUE(::CreatePipe(&child_stdout_read, &child_stdout_write,
+ &sec_attr_stdout, 0));
+ ASSERT_TRUE(::SetHandleInformation(child_stdout_read, HANDLE_FLAG_INHERIT,
+ 0));
+
+ // Create a PIPE for the child process stdin.
+ HANDLE child_stdin_read = 0;
+ HANDLE child_stdin_write = 0;
+ SECURITY_ATTRIBUTES sec_attr_stdin = {};
+ sec_attr_stdin.nLength = sizeof(sec_attr_stdin);
+ sec_attr_stdin.bInheritHandle = TRUE;
+ ASSERT_TRUE(::CreatePipe(&child_stdin_read, &child_stdin_write,
+ &sec_attr_stdin, 0));
+ ASSERT_TRUE(::SetHandleInformation(child_stdin_write, HANDLE_FLAG_INHERIT,
+ 0));
+
+ // Startup the child.
+ STARTUPINFO startup_info = {};
+ PROCESS_INFORMATION process_info = {};
+ startup_info.cb = sizeof(STARTUPINFO);
+ startup_info.hStdError = NULL;
+ startup_info.hStdInput = child_stdin_read;
+ startup_info.hStdOutput = child_stdout_write;
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ ASSERT_TRUE(::CreateProcessW(NULL, (LPWSTR)command_line.c_str(), NULL, NULL,
+ TRUE, 0, NULL, NULL,
+ &startup_info, &process_info));
+
+ // Collect the output.
+ ASSERT_TRUE(::CloseHandle(child_stdout_write));
+ char buffer[4096] = {};
+ DWORD bytes_read = 0;
+ while (::ReadFile(child_stdout_read, buffer, sizeof(buffer), &bytes_read,
+ NULL) && bytes_read > 0) {
+ stdout_string->append(buffer, bytes_read);
+ }
+
+ // Wait for the process to finish.
+ ::WaitForSingleObject(process_info.hProcess, INFINITE);
+
+ // Shut down all of our handles.
+ ASSERT_TRUE(::CloseHandle(process_info.hThread));
+ ASSERT_TRUE(::CloseHandle(process_info.hProcess));
+ ASSERT_TRUE(::CloseHandle(child_stdin_write));
+ ASSERT_TRUE(::CloseHandle(child_stdin_read));
+ ASSERT_TRUE(::CloseHandle(child_stdout_read));
+}
+
+void GetFileContents(const std::wstring& path, std::string* content) {
+ FILE* f = ::_wfopen(path.c_str(), L"rb");
+ ASSERT_TRUE(f != NULL);
+
+ char buffer[4096] = {};
+ while (true) {
+ size_t bytes_read = ::fread(buffer, 1, sizeof(buffer), f);
+ if (bytes_read == 0)
+ break;
+ content->append(buffer, bytes_read);
+ }
+}
+
+class DumpSymsRegressionTest : public testing::TestWithParam<const wchar_t *> {
+ public:
+ virtual void SetUp() {
+ std::wstring self_dir;
+ ASSERT_TRUE(GetSelfDirectory(&self_dir));
+ dump_syms_exe = self_dir + L"\\dump_syms.exe";
+
+ TrimLastComponent(self_dir, &testdata_dir, NULL);
+ testdata_dir += L"\\testdata";
+ }
+
+ std::wstring dump_syms_exe;
+ std::wstring testdata_dir;
+};
+
+class DumpSymsPEOnlyRegressionTest : public testing::TestWithParam<const wchar_t *> {
+public:
+ virtual void SetUp() {
+ std::wstring self_dir;
+ ASSERT_TRUE(GetSelfDirectory(&self_dir));
+ dump_syms_exe = self_dir + L"\\dump_syms.exe";
+
+ TrimLastComponent(self_dir, &testdata_dir, NULL);
+ testdata_dir += L"\\testdata";
+ }
+
+ std::wstring dump_syms_exe;
+ std::wstring testdata_dir;
+};
+
+} //namespace
+
+TEST_P(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
+ const wchar_t* root_name = GetParam();
+ std::wstring root_path = testdata_dir + L"\\" + root_name;
+
+ std::wstring sym_path = root_path + L".sym";
+ std::string expected_symbols;
+ ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
+
+ std::wstring pdb_path = root_path + L".pdb";
+ std::wstring command_line = L"\"" + dump_syms_exe + L"\" \"" +
+ pdb_path + L"\"";
+ std::string symbols;
+ ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
+
+ EXPECT_EQ(expected_symbols, symbols);
+}
+
+INSTANTIATE_TEST_CASE_P(DumpSyms, DumpSymsRegressionTest,
+ testing::ValuesIn(kRootNames));
+
+TEST_P(DumpSymsPEOnlyRegressionTest, EnsurePEOnlyDumpedSymbolsMatch) {
+ const wchar_t* root_name = GetParam();
+ std::wstring root_path = testdata_dir + L"\\" + root_name;
+
+ std::wstring sym_path = root_path + L".sym";
+ std::string expected_symbols;
+ ASSERT_NO_FATAL_FAILURE(GetFileContents(sym_path, &expected_symbols));
+
+ std::wstring dll_path = root_path + L".dll";
+ std::wstring command_line = L"\"" + dump_syms_exe + L"\" --pe \"" +
+ dll_path + L"\"";
+ std::string symbols;
+ ASSERT_NO_FATAL_FAILURE(RunCommand(command_line, &symbols));
+
+ EXPECT_EQ(expected_symbols, symbols);
+}
+
+INSTANTIATE_TEST_CASE_P(PEOnlyDumpSyms, DumpSymsPEOnlyRegressionTest,
+ testing::ValuesIn(kPEOnlyRootNames));
+
+
+} // namespace dump_syms
+} // namespace windows
+} // namespace tools
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh new file mode 100755 index 0000000000..1f20f64fd5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/run_regtest.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +# Copyright (c) 2006, 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. + +Release/dump_syms.exe testdata/dump_syms_regtest.pdb | \ + tr -d '\015' > \ + testdata/dump_syms_regtest.new +status=$? + +if [ $status -ne 0 ] ; then + echo "FAIL, dump_syms.exe failed" + exit $status +fi + +diff -u testdata/dump_syms_regtest.new testdata/dump_syms_regtest.sym > \ + testdata/dump_syms_regtest.diff +status=$? + +if [ $status -eq 0 ] ; then + rm testdata/dump_syms_regtest.diff testdata/dump_syms_regtest.new + echo "PASS" +else + echo "FAIL, see testdata/dump_syms_regtest.[new|diff]" +fi + +exit $status diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat b/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat new file mode 100644 index 0000000000..bf18d5079d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat @@ -0,0 +1,23 @@ +REM This batch file is meant to facilitate regenerating prebuilt binaries for
+REM the Windows tools.
+REM You MUST run it from a Visual Studio xxxx Command Prompt. To do this,
+REM navigate to:
+REM
+REM Start->Programs->Microsoft Visual Studio XXXX->Tools->
+REM Visual Studio Command Prompt
+REM
+REM Then run this batch file. It performs an SVN update, edits the
+REM README.binaries file to contain
+REM the revision number, and builds the tools. You must run 'svn commit' to
+REM commit the pending edits to the repository.
+
+pushd %~dp0
+if %VisualStudioVersion% == 14.0 set GYP_MSVS_VERSION=2015
+gyp tools_windows.gyp
+msbuild tools_windows.sln /p:Configuration=Release /t:Clean,Build
+copy Release\symupload.exe binaries\
+copy Release\dump_syms.exe binaries\
+git add binaries
+git commit -m "Built Windows binaries"
+echo Done!
+popd
diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc new file mode 100644 index 0000000000..7e3029326d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc @@ -0,0 +1,394 @@ +// Copyright (c) 2006, 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. + +// Tool to upload an exe/dll and its associated symbols to an HTTP server. +// The PDB file is located automatically, using the path embedded in the +// executable. The upload is sent as a multipart/form-data POST request, +// with the following parameters: +// code_file: the basename of the module, e.g. "app.exe" +// debug_file: the basename of the debugging file, e.g. "app.pdb" +// debug_identifier: the debug file's identifier, usually consisting of +// the guid and age embedded in the pdb, e.g. +// "11111111BBBB3333DDDD555555555555F" +// product: the HTTP-friendly product name, e.g. "MyApp" +// version: the file version of the module, e.g. "1.2.3.4" +// os: the operating system that the module was built for, always +// "windows" in this implementation. +// cpu: the CPU that the module was built for, typically "x86". +// symbol_file: the contents of the breakpad-format symbol file + +#include <windows.h> +#include <dbghelp.h> +#include <wininet.h> + +#include <cstdio> +#include <map> +#include <string> +#include <vector> + +#include "common/windows/string_utils-inl.h" + +#include "common/windows/http_upload.h" +#include "common/windows/pdb_source_line_writer.h" +#include "common/windows/symbol_collector_client.h" + +using std::string; +using std::wstring; +using std::vector; +using std::map; +using google_breakpad::HTTPUpload; +using google_breakpad::SymbolCollectorClient; +using google_breakpad::SymbolStatus; +using google_breakpad::UploadUrlResponse; +using google_breakpad::CompleteUploadResult; +using google_breakpad::PDBModuleInfo; +using google_breakpad::PDBSourceLineWriter; +using google_breakpad::WindowsStringUtils; + +// Extracts the file version information for the given filename, +// as a string, for example, "1.2.3.4". Returns true on success. +static bool GetFileVersionString(const wchar_t *filename, wstring *version) { + DWORD handle; + DWORD version_size = GetFileVersionInfoSize(filename, &handle); + if (version_size < sizeof(VS_FIXEDFILEINFO)) { + return false; + } + + vector<char> version_info(version_size); + if (!GetFileVersionInfo(filename, handle, version_size, &version_info[0])) { + return false; + } + + void *file_info_buffer = NULL; + unsigned int file_info_length; + if (!VerQueryValue(&version_info[0], L"\\", + &file_info_buffer, &file_info_length)) { + return false; + } + + // The maximum value of each version component is 65535 (0xffff), + // so the max length is 24, including the terminating null. + wchar_t ver_string[24]; + VS_FIXEDFILEINFO *file_info = + reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer); + swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]), + L"%d.%d.%d.%d", + file_info->dwFileVersionMS >> 16, + file_info->dwFileVersionMS & 0xffff, + file_info->dwFileVersionLS >> 16, + file_info->dwFileVersionLS & 0xffff); + + // remove when VC++7.1 is no longer supported + ver_string[sizeof(ver_string) / sizeof(ver_string[0]) - 1] = L'\0'; + + *version = ver_string; + return true; +} + +// Creates a new temporary file and writes the symbol data from the given +// exe/dll file to it. Returns the path to the temp file in temp_file_path +// and information about the pdb in pdb_info. +static bool DumpSymbolsToTempFile(const wchar_t *file, + wstring *temp_file_path, + PDBModuleInfo *pdb_info) { + google_breakpad::PDBSourceLineWriter writer; + // Use EXE_FILE to get information out of the exe/dll in addition to the + // pdb. The name and version number of the exe/dll are of value, and + // there's no way to locate an exe/dll given a pdb. + if (!writer.Open(file, PDBSourceLineWriter::EXE_FILE)) { + return false; + } + + wchar_t temp_path[_MAX_PATH]; + if (GetTempPath(_MAX_PATH, temp_path) == 0) { + return false; + } + + wchar_t temp_filename[_MAX_PATH]; + if (GetTempFileName(temp_path, L"sym", 0, temp_filename) == 0) { + return false; + } + + FILE *temp_file = NULL; +#if _MSC_VER >= 1400 // MSVC 2005/8 + if (_wfopen_s(&temp_file, temp_filename, L"w") != 0) +#else // _MSC_VER >= 1400 + // _wfopen_s was introduced in MSVC8. Use _wfopen for earlier environments. + // Don't use it with MSVC8 and later, because it's deprecated. + if (!(temp_file = _wfopen(temp_filename, L"w"))) +#endif // _MSC_VER >= 1400 + { + return false; + } + + bool success = writer.WriteSymbols(temp_file); + fclose(temp_file); + if (!success) { + _wunlink(temp_filename); + return false; + } + + *temp_file_path = temp_filename; + + return writer.GetModuleInfo(pdb_info); +} + +static bool DoSymUploadV2( + const wchar_t* api_url, + const wchar_t* api_key, + const wstring& debug_file, + const wstring& debug_id, + const wstring& symbol_file, + bool force) { + wstring url(api_url); + wstring key(api_key); + + if (!force) { + SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( + url, + key, + debug_file, + debug_id); + if (symbolStatus == SymbolStatus::Found) { + wprintf(L"Symbol file already exists, upload aborted." + L" Use \"-f\" to overwrite.\n"); + return true; + } + else if (symbolStatus == SymbolStatus::Unknown) { + wprintf(L"Failed to get check for existing symbol.\n"); + return false; + } + } + + UploadUrlResponse uploadUrlResponse; + if (!SymbolCollectorClient::CreateUploadUrl( + url, + key, + &uploadUrlResponse)) { + wprintf(L"Failed to create upload URL.\n"); + return false; + } + + wstring signed_url = uploadUrlResponse.upload_url; + wstring upload_key = uploadUrlResponse.upload_key; + wstring response; + int response_code; + bool success = HTTPUpload::SendPutRequest( + signed_url, + symbol_file, + /* timeout = */ NULL, + &response, + &response_code); + if (!success) { + wprintf(L"Failed to send symbol file.\n"); + wprintf(L"Response code: %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + else if (response_code == 0) { + wprintf(L"Failed to send symbol file: No response code\n"); + return false; + } + else if (response_code != 200) { + wprintf(L"Failed to send symbol file: Response code %ld\n", response_code); + wprintf(L"Response:\n"); + wprintf(L"%s\n", response.c_str()); + return false; + } + + CompleteUploadResult completeUploadResult = + SymbolCollectorClient::CompleteUpload( + url, + key, + upload_key, + debug_file, + debug_id); + if (completeUploadResult == CompleteUploadResult::Error) { + wprintf(L"Failed to complete upload.\n"); + return false; + } + else if (completeUploadResult == CompleteUploadResult::DuplicateData) { + wprintf(L"Uploaded file checksum matched existing file checksum," + L" no change necessary.\n"); + } + else { + wprintf(L"Successfully sent the symbol file.\n"); + } + + return true; +} + +__declspec(noreturn) void printUsageAndExit() { + wprintf(L"Usage:\n\n" + L" symupload [--timeout NN] [--product product_name] ^\n" + L" <file.exe|file.dll> <symbol upload URL> ^\n" + L" [...<symbol upload URLs>]\n\n"); + wprintf(L" - Timeout is in milliseconds, or can be 0 to be unlimited.\n"); + wprintf(L" - product_name is an HTTP-friendly product name. It must only\n" + L" contain an ascii subset: alphanumeric and punctuation.\n" + L" This string is case-sensitive.\n\n"); + wprintf(L"Example:\n\n" + L" symupload.exe --timeout 0 --product Chrome ^\n" + L" chrome.dll http://no.free.symbol.server.for.you\n"); + wprintf(L"\n"); + wprintf(L"sym-upload-v2 usage:\n" + L" symupload -p [-f] <file.exe|file.dll> <API-URL> <API-key>\n"); + wprintf(L"\n"); + wprintf(L"sym_upload_v2 Options:\n"); + wprintf(L" <API-URL> is the sym_upload_v2 API URL.\n"); + wprintf(L" <API-key> is a secret used to authenticate with the API.\n"); + wprintf(L" -p:\t Use sym_upload_v2 protocol.\n"); + wprintf(L" -f:\t Force symbol upload if already exists.\n"); + + exit(0); +} + +int wmain(int argc, wchar_t *argv[]) { + const wchar_t *module; + const wchar_t *product = nullptr; + int timeout = -1; + int currentarg = 1; + bool use_sym_upload_v2 = false; + bool force = false; + const wchar_t* api_url = nullptr; + const wchar_t* api_key = nullptr; + while (argc > currentarg + 1) { + if (!wcscmp(L"--timeout", argv[currentarg])) { + timeout = _wtoi(argv[currentarg + 1]); + currentarg += 2; + continue; + } + if (!wcscmp(L"--product", argv[currentarg])) { + product = argv[currentarg + 1]; + currentarg += 2; + continue; + } + if (!wcscmp(L"-p", argv[currentarg])) { + use_sym_upload_v2 = true; + ++currentarg; + continue; + } + if (!wcscmp(L"-f", argv[currentarg])) { + force = true; + ++currentarg; + continue; + } + break; + } + + if (argc >= currentarg + 2) + module = argv[currentarg++]; + else + printUsageAndExit(); + + wstring symbol_file; + PDBModuleInfo pdb_info; + if (!DumpSymbolsToTempFile(module, &symbol_file, &pdb_info)) { + fwprintf(stderr, L"Could not get symbol data from %s\n", module); + return 1; + } + + wstring code_file = WindowsStringUtils::GetBaseName(wstring(module)); + wstring file_version; + // Don't make a missing version a hard error. Issue a warning, and let the + // server decide whether to reject files without versions. + if (!GetFileVersionString(module, &file_version)) { + fwprintf(stderr, L"Warning: Could not get file version for %s\n", module); + } + + bool success = true; + + if (use_sym_upload_v2) { + if (argc >= currentarg + 2) { + api_url = argv[currentarg++]; + api_key = argv[currentarg++]; + + success = DoSymUploadV2( + api_url, + api_key, + pdb_info.debug_file, + pdb_info.debug_identifier, + symbol_file, + force); + } else { + printUsageAndExit(); + } + } else { + map<wstring, wstring> parameters; + parameters[L"code_file"] = code_file; + parameters[L"debug_file"] = pdb_info.debug_file; + parameters[L"debug_identifier"] = pdb_info.debug_identifier; + parameters[L"os"] = L"windows"; // This version of symupload is Windows-only + parameters[L"cpu"] = pdb_info.cpu; + + map<wstring, wstring> files; + files[L"symbol_file"] = symbol_file; + + if (!file_version.empty()) { + parameters[L"version"] = file_version; + } + + // Don't make a missing product name a hard error. Issue a warning and let + // the server decide whether to reject files without product name. + if (product) { + parameters[L"product"] = product; + } + else { + fwprintf( + stderr, + L"Warning: No product name (flag --product) was specified for %s\n", + module); + } + + while (currentarg < argc) { + int response_code; + if (!HTTPUpload::SendMultipartPostRequest(argv[currentarg], parameters, files, + timeout == -1 ? NULL : &timeout, + nullptr, &response_code)) { + success = false; + fwprintf(stderr, + L"Symbol file upload to %s failed. Response code = %ld\n", + argv[currentarg], response_code); + } + currentarg++; + } + } + + _wunlink(symbol_file.c_str()); + + if (success) { + wprintf(L"Uploaded breakpad symbols for windows-%s/%s/%s (%s %s)\n", + pdb_info.cpu.c_str(), pdb_info.debug_file.c_str(), + pdb_info.debug_identifier.c_str(), code_file.c_str(), + file_version.c_str()); + } + + return success ? 0 : 1; +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp new file mode 100644 index 0000000000..4567a4bdfd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp @@ -0,0 +1,50 @@ +# Copyright 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. + +{ + 'includes': [ + '../../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'symupload', + 'type': 'executable', + 'sources': [ + 'symupload.cc', + ], + 'dependencies': [ + '../../../common/windows/common_windows.gyp:common_windows_lib', + ], + 'msvs_settings': { + 'VCLinkerTool': { + 'LargeAddressAware': '2', + }, + }, + }, + ], +} diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp b/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp new file mode 100644 index 0000000000..17b88b4a7a --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/tools_windows.gyp @@ -0,0 +1,46 @@ +# Copyright 2017 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. + + +{ + 'includes': [ + '../../build/common.gypi', + ], + 'targets': [ + { + 'target_name': 'build_all', + 'type': 'none', + 'dependencies': [ + './converter/ms_symbol_server_converter.gyp:*', + './converter_exe/converter.gyp:*', + './dump_syms/dump_syms.gyp:*', + './symupload/symupload.gyp:*', + ], + }, + ], +} |