diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/tools')
48 files changed, 9606 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 000000000..a0e8f8ba2 --- /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)) { + fprintf(stderr, "Unable to generate minidump.\n"); + 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 000000000..84953172e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/dump_syms.cc @@ -0,0 +1,113 @@ +// 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"); + 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; + 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 { + 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 (header_only) { + if (!WriteSymbolFileHeader(binary, 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, 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/dump_syms/moz.build b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/moz.build new file mode 100644 index 000000000..643020e84 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/dump_syms/moz.build @@ -0,0 +1,33 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HOST_SOURCES += [ + 'dump_syms.cc', +] + +HOST_CXXFLAGS += [ + '-O2', + '-g', +] + +# host_breakpad_linux_common_s needs to come first +HOST_USE_LIBS += [ + 'host_breakpad_linux_common_s', +] +HOST_USE_LIBS += [ + 'host_breakpad_common_s', + 'host_breakpad_dwarf_s', +] + +# The HostProgram template may append 'host_stdc++compat' to +# HOST_USE_LIBS, which needs to appear after the entries above. +HostProgram('dump_syms') + +LOCAL_INCLUDES += [ + '../../../common/linux', +] + +include('/toolkit/crashreporter/crashreporter.mozbuild') 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 000000000..6f637845e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc @@ -0,0 +1,1276 @@ +// 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/ +// +// Usage: minidump-2-core [-v] 1234.dmp > core + +#include <elf.h> +#include <errno.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/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 __WORDSIZE == 64 + #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); +static bool verbose; +static string g_custom_so_basedir; + +static int usage(const char* argv0) { + fprintf(stderr, "Usage: %s [-v] <minidump file>\n", argv0); + return 1; +} + +// 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; + 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; + + std::map<uintptr_t, string> 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) { + const MDRawContextARM64* rawregs = range.GetData<MDRawContextARM64>(0); + + 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; +} +#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(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const uint32_t num_threads = *range.GetData<uint32_t>(0); + if (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(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) { + 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 (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(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { + if (verbose) { + fputs("MD_LINUX_CPU_INFO:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n\n", stderr); + } +} + +static void +ParseProcessStatus(CrashedProcess* crashinfo, + const MinidumpMemoryRange& range) { + if (verbose) { + fputs("MD_LINUX_PROC_STATUS:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseLSBRelease(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { + if (verbose) { + fputs("MD_LINUX_LSB_RELEASE:\n", stderr); + fwrite(range.data(), range.length(), 1, stderr); + fputs("\n\n", stderr); + } +} + +static void +ParseMaps(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { + if (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 (verbose) { + fputs("\n\n\n", stderr); + } +} + +static void +ParseEnvironment(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) { + if (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(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(crashinfo, range); + return; + } + } + + crashinfo->auxv = range.data(); + crashinfo->auxv_length = range.length(); +} + +static void +ParseCmdLine(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 (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(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + const MDRawDebug* debug = range.GetData<MDRawDebug>(0); + if (!debug) { + return; + } + if (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 (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 (verbose) { + fputs("\n\n", stderr); + } +} + +static void +ParseExceptionStream(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 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(1, &nhdr, sizeof(nhdr)) || + !writea(1, "CORE\0\0\0\0", 8) || + !writea(1, &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(1, &nhdr, sizeof(nhdr)) || + !writea(1, "CORE\0\0\0\0", 8) || + !writea(1, &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(1, &nhdr, sizeof(nhdr)) || + !writea(1, "LINUX\0\0\0", 8) || + !writea(1, &thread.fpxregs, sizeof(user_fpxregs_struct))) { + return false; + } +#endif + + return true; +} + +static void +ParseModuleStream(CrashedProcess* crashinfo, const MinidumpMemoryRange& range, + const MinidumpMemoryRange& full_file) { + if (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); + size_t slash = filename.find_last_of('/'); + string basename = slash == string::npos ? + filename : filename.substr(slash + 1); + if (strcmp(guid, "00000000-0000-0000-0000-000000000000")) { + string prefix; + if (!g_custom_so_basedir.empty()) + prefix = g_custom_so_basedir; + else + prefix = string("/var/lib/breakpad/") + guid + "-" + basename; + + crashinfo->signatures[rawmodule->base_of_image] = prefix + basename; + } + + if (verbose) { + fprintf(stderr, "0x%08llX-0x%08llX, ChkSum: 0x%08X, GUID: %s, \"%s\"\n", + (unsigned long long)rawmodule->base_of_image, + (unsigned long long)rawmodule->base_of_image + + rawmodule->size_of_image, + rawmodule->checksum, guid, filename.c_str()); + } + } + if (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(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, string>::const_iterator guid = + crashinfo->signatures.find((uintptr_t)iter->addr); + if (guid != crashinfo->signatures.end()) { + filename = guid->second; + } + + 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 (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, char** argv) { + int argi = 1; + while (argi < argc && argv[argi][0] == '-') { + if (!strcmp(argv[argi], "-v")) { + verbose = true; + } else if (!strcmp(argv[argi], "--sobasedir")) { + argi++; + if (argi >= argc) { + fprintf(stderr, "--sobasedir expects an argument."); + return usage(argv[0]); + } + + g_custom_so_basedir = argv[argi]; + } else { + return usage(argv[0]); + } + argi++; + } + + if (argc != argi + 1) + return usage(argv[0]); + + MemoryMappedFile mapped_file(argv[argi], 0); + if (!mapped_file.data()) { + fprintf(stderr, "Failed to mmap dump file\n"); + 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(&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(&crashinfo, dump.Subrange(dirent->location), dump); + break; + case MD_LINUX_CPU_INFO: + ParseCPUInfo(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_PROC_STATUS: + ParseProcessStatus(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_LSB_RELEASE: + ParseLSBRelease(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_ENVIRON: + ParseEnvironment(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_MAPS: + ParseMaps(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_AUXV: + ParseAuxVector(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_CMD_LINE: + ParseCmdLine(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_LINUX_DSO_DEBUG: + ParseDSODebugInfo(&crashinfo, dump.Subrange(dirent->location), dump); + break; + case MD_EXCEPTION_STREAM: + ParseExceptionStream(&crashinfo, dump.Subrange(dirent->location)); + break; + case MD_MODULE_LIST_STREAM: + ParseModuleStream(&crashinfo, dump.Subrange(dirent->location), dump); + break; + default: + if (verbose) + fprintf(stderr, "Skipping %x\n", dirent->stream_type); + } + } + + AugmentMappings(&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(1, &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(1, &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(1, &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(1, &nhdr, sizeof(nhdr)) || + !writea(1, "CORE\0\0\0\0", 8) || + !writea(1, &crashinfo.prps, sizeof(prpsinfo))) { + return 1; + } + + nhdr.n_descsz = crashinfo.auxv_length; + nhdr.n_type = NT_AUXV; + if (!writea(1, &nhdr, sizeof(nhdr)) || + !writea(1, "CORE\0\0\0\0", 8) || + !writea(1, 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(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(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(1, 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(1, mapping.data.c_str(), mapping.data.size())) + return 1; + } + } + + 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 000000000..a793e2cfb --- /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 000000000..fe4ded83d --- /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 000000000..19f17450a --- /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 000000000..9eeb2d447 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/linux/symupload/sym_upload.cc @@ -0,0 +1,112 @@ +// 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 <unistd.h> + +#include "common/linux/symbol_upload.h" + +using google_breakpad::sym_upload::Options; + +//============================================================================= +static void +Usage(int argc, const char *argv[]) { + fprintf(stderr, "Submit symbol information.\n"); + fprintf(stderr, "Usage: %s [options...] <symbols> <upload-URL>\n", argv[0]); + fprintf(stderr, "Options:\n"); + 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, "-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"); +} + +//============================================================================= +static void +SetupOptions(int argc, const char *argv[], Options *options) { + extern int optind; + int ch; + + while ((ch = getopt(argc, (char * const *)argv, "u:v:x:h?")) != -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; + + 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->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 000000000..1c15992e1 --- /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.m', + ], + '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 000000000..f68200c7c --- /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 000000000..d32837cbd --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj @@ -0,0 +1,587 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.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.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.mm */; }; + 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 */; }; + 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>"; }; + 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.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; 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>"; }; + 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 = ( + 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.mm */, + 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 */, + 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 */, + ); + 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 */, + 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; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */; + compatibilityVersion = "Xcode 3.1"; + 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 */, + 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 */, + 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */, + 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */, + 9BDF21A70B1E825400F8391B /* dump_syms.mm 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 */, + 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 */, + 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 */, + 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 = { + HEADER_SEARCH_PATHS = ../../../../src; + PRODUCT_NAME = crash_report; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + 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 000000000..3fbe108eb --- /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 000000000..ebbca87a0 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/crash_report/on_demand_symbol_supplier.mm @@ -0,0 +1,316 @@ +// 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. + +#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) { + NSString *module_str = [[NSFileManager defaultManager] + stringWithFileSystemRepresentation:module_path.c_str() + length:module_path.length()]; + DumpSymbols dump(ALL_SYMBOL_DATA, false); + if (dump.Read(module_str)) { + // 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_str UTF8String]); + 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 000000000..2e6bd9e10 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj @@ -0,0 +1,1839 @@ +// !$*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 */; }; + 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 */; }; +/* 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>"; }; + 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/gtest/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/gtest/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/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; }; + 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 */, + 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 */, + 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 = ( + 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 = ( + 162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */, + B88FAE2C1166606200407530 /* macho_reader.cc in Sources */, + 8BCAAA4C1CE3A7980046090B /* elf_reader.cc in Sources */, + B8C5B5171166534700D34F4E /* dwarf2reader.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 */, + 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 = { + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8B3102D511F0D60300FCF3E4 /* BreakpadRelease.xcconfig */; + buildSettings = { + HEADER_SEARCH_PATHS = ( + ../../.., + ../../../common/mac/include/, + ../../../third_party/musl/include/, + ); + }; + name = Release; + }; + B84A91F6116CF784006C210E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Debug; + }; + B84A91F7116CF784006C210E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = stabs_to_module_unittest; + }; + name = Release; + }; + B88FAF31116A591F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = stabs_reader_unittest; + }; + name = Release; + }; + B88FB025116BE00100407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Debug; + }; + B88FB026116BE00100407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = gtestmockall; + }; + name = Release; + }; + B88FB0BB116CEAC000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Debug; + }; + B88FB0BC116CEAC000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = module_unittest; + }; + name = Release; + }; + B88FB0E1116CEEA800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Debug; + }; + B88FB0E2116CEEA800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf2diehandler_unittest; + }; + name = Release; + }; + B88FB0F4116CEF1900407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Debug; + }; + B88FB0F5116CEF1900407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_line_to_module_unittest; + }; + name = Release; + }; + B88FB10C116CF07A00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Debug; + }; + B88FB10D116CF07A00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_cu_to_module_unittest; + }; + name = Release; + }; + B88FB121116CF28000407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Debug; + }; + B88FB122116CF28000407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = dwarf_cfi_to_module_unittest; + }; + name = Release; + }; + B88FB137116CF30F00407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Debug; + }; + B88FB138116CF30F00407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = bytereader_unittest; + }; + name = Release; + }; + B88FB14D116CF4A800407530 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = byte_cursor_unittest; + }; + name = Debug; + }; + B88FB14E116CF4A800407530 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = macho_reader_unittest; + }; + name = Debug; + }; + B89E0E9811665A6400DD08C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/include, + ); + PRODUCT_NAME = test_assembler_unittest; + }; + name = Debug; + }; + D21F97D511CBA0F200239E38 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + $inherited, + ../../../testing, + ../../../testing/include, + ../../../testing/gtest, + ../../../testing/gtest/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 000000000..6f68457b4 --- /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 000000000..d882bbe88 --- /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 <libgen.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" + +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 = 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/dump_syms/moz.build b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/moz.build new file mode 100644 index 000000000..99ae82aa7 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/dump_syms/moz.build @@ -0,0 +1,40 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HOST_SOURCES += [ + 'dump_syms_tool.cc', +] + +HOST_CXXFLAGS += [ + '-O2', + '-g', + '-pthread', + '-stdlib=libc++', +] + +# Order matters here, but HOST_USE_LIBS must be sorted. +HOST_USE_LIBS += [ + 'host_breakpad_mac_common_s', +] +HOST_USE_LIBS += [ + 'host_breakpad_common_s', + 'host_breakpad_dwarf_s', +] + +# The HostProgram template may append 'host_stdc++compat' to +# HOST_USE_LIBS, which needs to appear after the entries above. +HostProgram('dump_syms') + +LOCAL_INCLUDES += [ + '../../../common/mac', +] + +if CONFIG['HOST_OS_ARCH'] != 'Darwin': + HOST_CXXFLAGS += [ + '-I%s/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/' % TOPSRCDIR, + ] + +include('/toolkit/crashreporter/crashreporter.mozbuild') 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 000000000..741ad765e --- /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 000000000..a7cce7b00 --- /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 000000000..a6a78dc5f --- /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 000000000..7457573b4 --- /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 000000000..2115e54e6 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_constants.h @@ -0,0 +1,61 @@ +/* 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 + +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_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; 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 000000000..f60648230 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/arch_reader.go @@ -0,0 +1,65 @@ +/* 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_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 +) 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 000000000..355612086 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/mac/upload_system_symbols/upload_system_symbols.go @@ -0,0 +1,420 @@ +/* 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{ + "/Library/QuickTime", + "/System/Library/Components", + "/System/Library/Frameworks", + "/System/Library/PrivateFrameworks", + "/usr/lib", + } + + // 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.Fatal("-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.Fatal("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.Fatal("Error creating symbol file:", 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.Fatal("Could not open directory to upload: %v", err) + } + defer d.Close() + + entries, err := d.Readdirnames(0) + if err != nil { + log.Fatal("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)) + } + + 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) { + d, err := os.Open(loc) + if err != nil { + log.Fatal("Could not open %s: %v", loc, err) + } + defer d.Close() + + for { + fis, err := d.Readdir(100) + if err != nil && err != io.EOF { + log.Fatal("Error reading directory %s: %v", loc, err) + } + + for _, fi := range fis { + fp := path.Join(loc, fi.Name()) + if fi.IsDir() { + fq.findLibsInPath(fp) + 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 { + 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/filter_syms.py b/toolkit/crashreporter/google-breakpad/src/tools/python/filter_syms.py new file mode 100644 index 000000000..abddf7893 --- /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 000000000..b111f3498 --- /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 000000000..ff77105c6 --- /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 000000000..7bef51e07 --- /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 000000000..54cea57e7 --- /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/moz.build b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/moz.build new file mode 100644 index 000000000..3efeac039 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/solaris/dump_syms/moz.build @@ -0,0 +1,29 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HOST_SOURCES += [ + 'dump_syms.cc', +] + +HOST_CXXFLAGS += [ + '-O2', + '-g', +] + +HOST_USE_LIBS += [ + 'host_breakpad_common_s', + 'host_breakpad_solaris_common_s', +] + +# The HostProgram template may append 'host_stdc++compat' to +# HOST_USE_LIBS, which needs to appear after the entries above. +HostProgram('dump_syms') + +LOCAL_INCLUDES += [ + '../../../common/solaris', +] + +include('/toolkit/crashreporter/crashreporter.mozbuild') 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 000000000..ffb343306 --- /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 000000000..e617a23b8 --- /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 000000000..c5f93ef78 --- /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 000000000..44d3c5391 --- /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 000000000..e6a4210fe --- /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/binaries/dump_syms.exe b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe Binary files differnew file mode 100644 index 000000000..ca4676f50 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/dump_syms.exe diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe Binary files differnew file mode 100644 index 000000000..ba319b269 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/binaries/symupload.exe 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 000000000..dd3f770f5 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.cc @@ -0,0 +1,576 @@ +// 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 <cassert> +#include <cstdio> + +#include "tools/windows/converter/ms_symbol_server_converter.h" +#include "common/windows/pdb_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 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%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%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 %d\n", GetLastError()); + } + } + + bool Initialize(HANDLE process, char *path, bool invade_process) { + process_ = process; + 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 %d 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 %d 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 %d 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 %d 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 < 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) { + return result; + } + + 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 %s\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.WriteMap(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; +} + +} // 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 000000000..57ec79068 --- /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 000000000..d601b4333 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/converter/ms_symbol_server_converter.h @@ -0,0 +1,219 @@ +// 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); + + 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/dump_syms/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc new file mode 100644 index 000000000..3e8827b61 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms.cc @@ -0,0 +1,61 @@ +// 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 <string> + +#include "common/windows/pdb_source_line_writer.h" + +using std::wstring; +using google_breakpad::PDBSourceLineWriter; + +int wmain(int argc, wchar_t **argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %ws <file.[pdb|exe|dll]>\n", argv[0]); + return 1; + } + + PDBSourceLineWriter writer; + if (!writer.Open(wstring(argv[1]), PDBSourceLineWriter::ANY_FILE)) { + fprintf(stderr, "Open failed\n"); + return 1; + } + + if (!writer.WriteMap(stdout)) { + fprintf(stderr, "WriteMap failed\n"); + return 1; + } + + writer.Close(); + 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 000000000..b815574b2 --- /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_unittest.cc b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc new file mode 100644 index 000000000..61f84431e --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/dump_syms_unittest.cc @@ -0,0 +1,204 @@ +// 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 "gmock/gmock.h"
+#include "gtest/gtest.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",
+};
+
+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 = child_stdout_write;
+ 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::Test {
+ 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_F(DumpSymsRegressionTest, EnsureDumpedSymbolsMatch) {
+ for (size_t i = 0; i < sizeof(kRootNames) / sizeof(kRootNames[0]); ++i) {
+ const wchar_t* root_name = kRootNames[i];
+ 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);
+ }
+}
+
+} // namespace dump_syms
+} // namespace windows
+} // namespace tools
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/moz.build b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/moz.build new file mode 100644 index 000000000..2a286da53 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/dump_syms/moz.build @@ -0,0 +1,31 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +HostProgram('dump_syms') + +HOST_SOURCES += [ + '../../../common/windows/dia_util.cc', + '../../../common/windows/guid_string.cc', + '../../../common/windows/omap.cc', + '../../../common/windows/pdb_source_line_writer.cc', + '../../../common/windows/string_utils.cc', + 'dump_syms.cc', +] + +HOST_CXXFLAGS += [ + '-O2', + '-EHsc', + '-MD' +] + +HOST_OS_LIBS += [ + 'diaguids', + 'imagehlp' +] + +LOCAL_INCLUDES += [ + '../../..' +] 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 000000000..1f20f64fd --- /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 000000000..d881ae64b --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/refresh_binaries.bat @@ -0,0 +1,27 @@ +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\..\..\
+call svn update --accept postpone
+cd tools\windows
+devenv symupload\symupload.vcproj /rebuild Release
+copy symupload\Release\symupload.exe binaries\
+REM switch back to top level so that 'svn info' displays useful information.
+cd ..\..\
+echo This checkin of the binaries was created by refresh_binaries.bat. > %TEMP%\checkin.txt
+echo Date: %DATE% %TIME% >> %TEMP%\checkin.txt
+echo Repository information (output of 'svn info') follows: >> %TEMP%\checkin.txt
+call svn info >> %TEMP%\checkin.txt
+echo Done!
+echo type 'svn commit -F %%TEMP%%\checkin.txt' to commit.
+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 000000000..fa5294ded --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.cc @@ -0,0 +1,259 @@ +// 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" + +using std::string; +using std::wstring; +using std::vector; +using std::map; +using google_breakpad::HTTPUpload; +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.WriteMap(temp_file); + fclose(temp_file); + if (!success) { + _wunlink(temp_filename); + return false; + } + + *temp_file_path = temp_filename; + + return writer.GetModuleInfo(pdb_info); +} + +__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"); + exit(0); +} +int wmain(int argc, wchar_t *argv[]) { + const wchar_t *module; + const wchar_t *product = nullptr; + int timeout = -1; + int currentarg = 1; + 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; + } + 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)); + + 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; + + // 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); + } + + // Don't make a missing version a hard error. Issue a warning, and let the + // server decide whether to reject files without versions. + wstring file_version; + if (GetFileVersionString(module, &file_version)) { + parameters[L"version"] = file_version; + } else { + fwprintf(stderr, L"Warning: Could not get file version for %s\n", module); + } + + map<wstring, wstring> files; + files[L"symbol_file"] = symbol_file; + + bool success = true; + + while (currentarg < argc) { + int response_code; + if (!HTTPUpload::SendRequest(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 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 000000000..d7e5fb7b9 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/tools/windows/symupload/symupload.gyp @@ -0,0 +1,45 @@ +# 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', + ], + }, + ], +} |