diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc')
-rw-r--r-- | toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc | 1276 |
1 files changed, 0 insertions, 1276 deletions
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 deleted file mode 100644 index 6f637845e..000000000 --- a/toolkit/crashreporter/google-breakpad/src/tools/linux/md2core/minidump-2-core.cc +++ /dev/null @@ -1,1276 +0,0 @@ -// Copyright (c) 2009, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// 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; -} |