Home | History | Annotate | Download | only in md2core
      1 // Copyright (c) 2009, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // Converts a minidump file to a core file which gdb can read.
     31 // Large parts lifted from the userspace core dumper:
     32 //   http://code.google.com/p/google-coredumper/
     33 //
     34 // Usage: minidump-2-core [-v] 1234.dmp > core
     35 
     36 #include <elf.h>
     37 #include <errno.h>
     38 #include <inttypes.h>
     39 #include <link.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <sys/user.h>
     44 #include <unistd.h>
     45 
     46 #include <map>
     47 #include <string>
     48 #include <vector>
     49 
     50 #include "common/linux/memory_mapped_file.h"
     51 #include "common/minidump_type_helper.h"
     52 #include "common/scoped_ptr.h"
     53 #include "google_breakpad/common/minidump_format.h"
     54 #include "third_party/lss/linux_syscall_support.h"
     55 #include "tools/linux/md2core/minidump_memory_range.h"
     56 
     57 #if __WORDSIZE == 64
     58   #define ELF_CLASS ELFCLASS64
     59 #else
     60   #define ELF_CLASS ELFCLASS32
     61 #endif
     62 #define Ehdr   ElfW(Ehdr)
     63 #define Phdr   ElfW(Phdr)
     64 #define Shdr   ElfW(Shdr)
     65 #define Nhdr   ElfW(Nhdr)
     66 #define auxv_t ElfW(auxv_t)
     67 
     68 
     69 #if defined(__x86_64__)
     70   #define ELF_ARCH  EM_X86_64
     71 #elif defined(__i386__)
     72   #define ELF_ARCH  EM_386
     73 #elif defined(__arm__)
     74   #define ELF_ARCH  EM_ARM
     75 #elif defined(__mips__)
     76   #define ELF_ARCH  EM_MIPS
     77 #endif
     78 
     79 #if defined(__arm__)
     80 // GLibc/ARM and Android/ARM both use 'user_regs' for the structure type
     81 // containing core registers, while they use 'user_regs_struct' on other
     82 // architectures. This file-local typedef simplifies the source code.
     83 typedef user_regs user_regs_struct;
     84 #endif
     85 
     86 using google_breakpad::MDTypeHelper;
     87 using google_breakpad::MemoryMappedFile;
     88 using google_breakpad::MinidumpMemoryRange;
     89 
     90 typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawDebug MDRawDebug;
     91 typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap;
     92 
     93 static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
     94 static bool verbose;
     95 static std::string g_custom_so_basedir;
     96 
     97 static int usage(const char* argv0) {
     98   fprintf(stderr, "Usage: %s [-v] <minidump file>\n", argv0);
     99   return 1;
    100 }
    101 
    102 // Write all of the given buffer, handling short writes and EINTR. Return true
    103 // iff successful.
    104 static bool
    105 writea(int fd, const void* idata, size_t length) {
    106   const uint8_t* data = (const uint8_t*) idata;
    107 
    108   size_t done = 0;
    109   while (done < length) {
    110     ssize_t r;
    111     do {
    112       r = write(fd, data + done, length - done);
    113     } while (r == -1 && errno == EINTR);
    114 
    115     if (r < 1)
    116       return false;
    117     done += r;
    118   }
    119 
    120   return true;
    121 }
    122 
    123 /* Dynamically determines the byte sex of the system. Returns non-zero
    124  * for big-endian machines.
    125  */
    126 static inline int sex() {
    127   int probe = 1;
    128   return !*(char *)&probe;
    129 }
    130 
    131 typedef struct elf_timeval {    /* Time value with microsecond resolution    */
    132   long tv_sec;                  /* Seconds                                   */
    133   long tv_usec;                 /* Microseconds                              */
    134 } elf_timeval;
    135 
    136 typedef struct elf_siginfo {    /* Information about signal (unused)         */
    137   int32_t si_signo;             /* Signal number                             */
    138   int32_t si_code;              /* Extra code                                */
    139   int32_t si_errno;             /* Errno                                     */
    140 } elf_siginfo;
    141 
    142 typedef struct prstatus {       /* Information about thread; includes CPU reg*/
    143   elf_siginfo    pr_info;       /* Info associated with signal               */
    144   uint16_t       pr_cursig;     /* Current signal                            */
    145   unsigned long  pr_sigpend;    /* Set of pending signals                    */
    146   unsigned long  pr_sighold;    /* Set of held signals                       */
    147   pid_t          pr_pid;        /* Process ID                                */
    148   pid_t          pr_ppid;       /* Parent's process ID                       */
    149   pid_t          pr_pgrp;       /* Group ID                                  */
    150   pid_t          pr_sid;        /* Session ID                                */
    151   elf_timeval    pr_utime;      /* User time                                 */
    152   elf_timeval    pr_stime;      /* System time                               */
    153   elf_timeval    pr_cutime;     /* Cumulative user time                      */
    154   elf_timeval    pr_cstime;     /* Cumulative system time                    */
    155   user_regs_struct pr_reg;      /* CPU registers                             */
    156   uint32_t       pr_fpvalid;    /* True if math co-processor being used      */
    157 } prstatus;
    158 
    159 typedef struct prpsinfo {       /* Information about process                 */
    160   unsigned char  pr_state;      /* Numeric process state                     */
    161   char           pr_sname;      /* Char for pr_state                         */
    162   unsigned char  pr_zomb;       /* Zombie                                    */
    163   signed char    pr_nice;       /* Nice val                                  */
    164   unsigned long  pr_flag;       /* Flags                                     */
    165 #if defined(__x86_64__) || defined(__mips__)
    166   uint32_t       pr_uid;        /* User ID                                   */
    167   uint32_t       pr_gid;        /* Group ID                                  */
    168 #else
    169   uint16_t       pr_uid;        /* User ID                                   */
    170   uint16_t       pr_gid;        /* Group ID                                  */
    171 #endif
    172   pid_t          pr_pid;        /* Process ID                                */
    173   pid_t          pr_ppid;       /* Parent's process ID                       */
    174   pid_t          pr_pgrp;       /* Group ID                                  */
    175   pid_t          pr_sid;        /* Session ID                                */
    176   char           pr_fname[16];  /* Filename of executable                    */
    177   char           pr_psargs[80]; /* Initial part of arg list                  */
    178 } prpsinfo;
    179 
    180 // We parse the minidump file and keep the parsed information in this structure
    181 struct CrashedProcess {
    182   CrashedProcess()
    183       : crashing_tid(-1),
    184         auxv(NULL),
    185         auxv_length(0) {
    186     memset(&prps, 0, sizeof(prps));
    187     prps.pr_sname = 'R';
    188     memset(&debug, 0, sizeof(debug));
    189   }
    190 
    191   struct Mapping {
    192     Mapping()
    193       : permissions(0xFFFFFFFF),
    194         start_address(0),
    195         end_address(0),
    196         offset(0) {
    197     }
    198 
    199     uint32_t permissions;
    200     uint64_t start_address, end_address, offset;
    201     std::string filename;
    202     std::string data;
    203   };
    204   std::map<uint64_t, Mapping> mappings;
    205 
    206   pid_t crashing_tid;
    207   int fatal_signal;
    208 
    209   struct Thread {
    210     pid_t tid;
    211     user_regs_struct regs;
    212 #if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
    213     user_fpregs_struct fpregs;
    214 #endif
    215 #if defined(__i386__)
    216     user_fpxregs_struct fpxregs;
    217 #endif
    218     uintptr_t stack_addr;
    219     const uint8_t* stack;
    220     size_t stack_length;
    221   };
    222   std::vector<Thread> threads;
    223 
    224   const uint8_t* auxv;
    225   size_t auxv_length;
    226 
    227   prpsinfo prps;
    228 
    229   std::map<uintptr_t, std::string> signatures;
    230 
    231   std::string dynamic_data;
    232   MDRawDebug debug;
    233   std::vector<MDRawLinkMap> link_map;
    234 };
    235 
    236 #if defined(__i386__)
    237 static uint32_t
    238 U32(const uint8_t* data) {
    239   uint32_t v;
    240   memcpy(&v, data, sizeof(v));
    241   return v;
    242 }
    243 
    244 static uint16_t
    245 U16(const uint8_t* data) {
    246   uint16_t v;
    247   memcpy(&v, data, sizeof(v));
    248   return v;
    249 }
    250 
    251 static void
    252 ParseThreadRegisters(CrashedProcess::Thread* thread,
    253                      const MinidumpMemoryRange& range) {
    254   const MDRawContextX86* rawregs = range.GetData<MDRawContextX86>(0);
    255 
    256   thread->regs.ebx = rawregs->ebx;
    257   thread->regs.ecx = rawregs->ecx;
    258   thread->regs.edx = rawregs->edx;
    259   thread->regs.esi = rawregs->esi;
    260   thread->regs.edi = rawregs->edi;
    261   thread->regs.ebp = rawregs->ebp;
    262   thread->regs.eax = rawregs->eax;
    263   thread->regs.xds = rawregs->ds;
    264   thread->regs.xes = rawregs->es;
    265   thread->regs.xfs = rawregs->fs;
    266   thread->regs.xgs = rawregs->gs;
    267   thread->regs.orig_eax = rawregs->eax;
    268   thread->regs.eip = rawregs->eip;
    269   thread->regs.xcs = rawregs->cs;
    270   thread->regs.eflags = rawregs->eflags;
    271   thread->regs.esp = rawregs->esp;
    272   thread->regs.xss = rawregs->ss;
    273 
    274   thread->fpregs.cwd = rawregs->float_save.control_word;
    275   thread->fpregs.swd = rawregs->float_save.status_word;
    276   thread->fpregs.twd = rawregs->float_save.tag_word;
    277   thread->fpregs.fip = rawregs->float_save.error_offset;
    278   thread->fpregs.fcs = rawregs->float_save.error_selector;
    279   thread->fpregs.foo = rawregs->float_save.data_offset;
    280   thread->fpregs.fos = rawregs->float_save.data_selector;
    281   memcpy(thread->fpregs.st_space, rawregs->float_save.register_area,
    282          10 * 8);
    283 
    284   thread->fpxregs.cwd = rawregs->float_save.control_word;
    285   thread->fpxregs.swd = rawregs->float_save.status_word;
    286   thread->fpxregs.twd = rawregs->float_save.tag_word;
    287   thread->fpxregs.fop = U16(rawregs->extended_registers + 6);
    288   thread->fpxregs.fip = U16(rawregs->extended_registers + 8);
    289   thread->fpxregs.fcs = U16(rawregs->extended_registers + 12);
    290   thread->fpxregs.foo = U16(rawregs->extended_registers + 16);
    291   thread->fpxregs.fos = U16(rawregs->extended_registers + 20);
    292   thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24);
    293   memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128);
    294   memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128);
    295 }
    296 #elif defined(__x86_64__)
    297 static void
    298 ParseThreadRegisters(CrashedProcess::Thread* thread,
    299                      const MinidumpMemoryRange& range) {
    300   const MDRawContextAMD64* rawregs = range.GetData<MDRawContextAMD64>(0);
    301 
    302   thread->regs.r15 = rawregs->r15;
    303   thread->regs.r14 = rawregs->r14;
    304   thread->regs.r13 = rawregs->r13;
    305   thread->regs.r12 = rawregs->r12;
    306   thread->regs.rbp = rawregs->rbp;
    307   thread->regs.rbx = rawregs->rbx;
    308   thread->regs.r11 = rawregs->r11;
    309   thread->regs.r10 = rawregs->r10;
    310   thread->regs.r9 = rawregs->r9;
    311   thread->regs.r8 = rawregs->r8;
    312   thread->regs.rax = rawregs->rax;
    313   thread->regs.rcx = rawregs->rcx;
    314   thread->regs.rdx = rawregs->rdx;
    315   thread->regs.rsi = rawregs->rsi;
    316   thread->regs.rdi = rawregs->rdi;
    317   thread->regs.orig_rax = rawregs->rax;
    318   thread->regs.rip = rawregs->rip;
    319   thread->regs.cs  = rawregs->cs;
    320   thread->regs.eflags = rawregs->eflags;
    321   thread->regs.rsp = rawregs->rsp;
    322   thread->regs.ss = rawregs->ss;
    323   thread->regs.fs_base = 0;
    324   thread->regs.gs_base = 0;
    325   thread->regs.ds = rawregs->ds;
    326   thread->regs.es = rawregs->es;
    327   thread->regs.fs = rawregs->fs;
    328   thread->regs.gs = rawregs->gs;
    329 
    330   thread->fpregs.cwd = rawregs->flt_save.control_word;
    331   thread->fpregs.swd = rawregs->flt_save.status_word;
    332   thread->fpregs.ftw = rawregs->flt_save.tag_word;
    333   thread->fpregs.fop = rawregs->flt_save.error_opcode;
    334   thread->fpregs.rip = rawregs->flt_save.error_offset;
    335   thread->fpregs.rdp = rawregs->flt_save.data_offset;
    336   thread->fpregs.mxcsr = rawregs->flt_save.mx_csr;
    337   thread->fpregs.mxcr_mask = rawregs->flt_save.mx_csr_mask;
    338   memcpy(thread->fpregs.st_space, rawregs->flt_save.float_registers, 8 * 16);
    339   memcpy(thread->fpregs.xmm_space, rawregs->flt_save.xmm_registers, 16 * 16);
    340 }
    341 #elif defined(__arm__)
    342 static void
    343 ParseThreadRegisters(CrashedProcess::Thread* thread,
    344                      const MinidumpMemoryRange& range) {
    345   const MDRawContextARM* rawregs = range.GetData<MDRawContextARM>(0);
    346 
    347   thread->regs.uregs[0] = rawregs->iregs[0];
    348   thread->regs.uregs[1] = rawregs->iregs[1];
    349   thread->regs.uregs[2] = rawregs->iregs[2];
    350   thread->regs.uregs[3] = rawregs->iregs[3];
    351   thread->regs.uregs[4] = rawregs->iregs[4];
    352   thread->regs.uregs[5] = rawregs->iregs[5];
    353   thread->regs.uregs[6] = rawregs->iregs[6];
    354   thread->regs.uregs[7] = rawregs->iregs[7];
    355   thread->regs.uregs[8] = rawregs->iregs[8];
    356   thread->regs.uregs[9] = rawregs->iregs[9];
    357   thread->regs.uregs[10] = rawregs->iregs[10];
    358   thread->regs.uregs[11] = rawregs->iregs[11];
    359   thread->regs.uregs[12] = rawregs->iregs[12];
    360   thread->regs.uregs[13] = rawregs->iregs[13];
    361   thread->regs.uregs[14] = rawregs->iregs[14];
    362   thread->regs.uregs[15] = rawregs->iregs[15];
    363 
    364   thread->regs.uregs[16] = rawregs->cpsr;
    365   thread->regs.uregs[17] = 0;  // what is ORIG_r0 exactly?
    366 }
    367 #elif defined(__mips__)
    368 static void
    369 ParseThreadRegisters(CrashedProcess::Thread* thread,
    370                      const MinidumpMemoryRange& range) {
    371   const MDRawContextMIPS* rawregs = range.GetData<MDRawContextMIPS>(0);
    372 
    373   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
    374     thread->regs.regs[i] = rawregs->iregs[i];
    375 
    376   thread->regs.lo = rawregs->mdlo;
    377   thread->regs.hi = rawregs->mdhi;
    378   thread->regs.epc = rawregs->epc;
    379   thread->regs.badvaddr = rawregs->badvaddr;
    380   thread->regs.status = rawregs->status;
    381   thread->regs.cause = rawregs->cause;
    382 
    383   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
    384     thread->fpregs.regs[i] = rawregs->float_save.regs[i];
    385 
    386   thread->fpregs.fpcsr = rawregs->float_save.fpcsr;
    387 #if _MIPS_SIM == _ABIO32
    388   thread->fpregs.fir = rawregs->float_save.fir;
    389 #endif
    390 }
    391 #else
    392 #error "This code has not been ported to your platform yet"
    393 #endif
    394 
    395 static void
    396 ParseThreadList(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
    397                 const MinidumpMemoryRange& full_file) {
    398   const uint32_t num_threads = *range.GetData<uint32_t>(0);
    399   if (verbose) {
    400     fprintf(stderr,
    401             "MD_THREAD_LIST_STREAM:\n"
    402             "Found %d threads\n"
    403             "\n\n",
    404             num_threads);
    405   }
    406   for (unsigned i = 0; i < num_threads; ++i) {
    407     CrashedProcess::Thread thread;
    408     memset(&thread, 0, sizeof(thread));
    409     const MDRawThread* rawthread =
    410         range.GetArrayElement<MDRawThread>(sizeof(uint32_t), i);
    411     thread.tid = rawthread->thread_id;
    412     thread.stack_addr = rawthread->stack.start_of_memory_range;
    413     MinidumpMemoryRange stack_range =
    414         full_file.Subrange(rawthread->stack.memory);
    415     thread.stack = stack_range.data();
    416     thread.stack_length = rawthread->stack.memory.data_size;
    417 
    418     ParseThreadRegisters(&thread,
    419                          full_file.Subrange(rawthread->thread_context));
    420 
    421     crashinfo->threads.push_back(thread);
    422   }
    423 }
    424 
    425 static void
    426 ParseSystemInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
    427                 const MinidumpMemoryRange& full_file) {
    428   const MDRawSystemInfo* sysinfo = range.GetData<MDRawSystemInfo>(0);
    429   if (!sysinfo) {
    430     fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n");
    431     _exit(1);
    432   }
    433 #if defined(__i386__)
    434   if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) {
    435     fprintf(stderr,
    436             "This version of minidump-2-core only supports x86 (32bit)%s.\n",
    437             sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ?
    438             ",\nbut the minidump file is from a 64bit machine" : "");
    439     _exit(1);
    440   }
    441 #elif defined(__x86_64__)
    442   if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) {
    443     fprintf(stderr,
    444             "This version of minidump-2-core only supports x86 (64bit)%s.\n",
    445             sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ?
    446             ",\nbut the minidump file is from a 32bit machine" : "");
    447     _exit(1);
    448   }
    449 #elif defined(__arm__)
    450   if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) {
    451     fprintf(stderr,
    452             "This version of minidump-2-core only supports ARM (32bit).\n");
    453     _exit(1);
    454   }
    455 #elif defined(__mips__)
    456   if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) {
    457     fprintf(stderr,
    458             "This version of minidump-2-core only supports mips (32bit).\n");
    459     _exit(1);
    460   }
    461 #else
    462 #error "This code has not been ported to your platform yet"
    463 #endif
    464   if (!strstr(full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str(),
    465               "Linux") &&
    466       sysinfo->platform_id != MD_OS_NACL) {
    467     fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n");
    468     _exit(1);
    469   }
    470 
    471   if (verbose) {
    472     fprintf(stderr,
    473             "MD_SYSTEM_INFO_STREAM:\n"
    474             "Architecture: %s\n"
    475             "Number of processors: %d\n"
    476             "Processor level: %d\n"
    477             "Processor model: %d\n"
    478             "Processor stepping: %d\n",
    479             sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86
    480             ? "i386"
    481             : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64
    482             ? "x86-64"
    483             : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_ARM
    484             ? "ARM"
    485             : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS
    486             ? "MIPS"
    487             : "???",
    488             sysinfo->number_of_processors,
    489             sysinfo->processor_level,
    490             sysinfo->processor_revision >> 8,
    491             sysinfo->processor_revision & 0xFF);
    492     if (sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
    493         sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) {
    494       fputs("Vendor id: ", stderr);
    495       const char *nul =
    496         (const char *)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0,
    497                              sizeof(sysinfo->cpu.x86_cpu_info.vendor_id));
    498       fwrite(sysinfo->cpu.x86_cpu_info.vendor_id,
    499              nul ? nul - (const char *)&sysinfo->cpu.x86_cpu_info.vendor_id[0]
    500              : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr);
    501       fputs("\n", stderr);
    502     }
    503     fprintf(stderr, "OS: %s\n",
    504             full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str());
    505     fputs("\n\n", stderr);
    506   }
    507 }
    508 
    509 static void
    510 ParseCPUInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    511   if (verbose) {
    512     fputs("MD_LINUX_CPU_INFO:\n", stderr);
    513     fwrite(range.data(), range.length(), 1, stderr);
    514     fputs("\n\n\n", stderr);
    515   }
    516 }
    517 
    518 static void
    519 ParseProcessStatus(CrashedProcess* crashinfo,
    520                    const MinidumpMemoryRange& range) {
    521   if (verbose) {
    522     fputs("MD_LINUX_PROC_STATUS:\n", stderr);
    523     fwrite(range.data(), range.length(), 1, stderr);
    524     fputs("\n\n", stderr);
    525   }
    526 }
    527 
    528 static void
    529 ParseLSBRelease(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    530   if (verbose) {
    531     fputs("MD_LINUX_LSB_RELEASE:\n", stderr);
    532     fwrite(range.data(), range.length(), 1, stderr);
    533     fputs("\n\n", stderr);
    534   }
    535 }
    536 
    537 static void
    538 ParseMaps(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    539   if (verbose) {
    540     fputs("MD_LINUX_MAPS:\n", stderr);
    541     fwrite(range.data(), range.length(), 1, stderr);
    542   }
    543   for (const uint8_t* ptr = range.data();
    544        ptr < range.data() + range.length();) {
    545     const uint8_t* eol = (uint8_t*)memchr(ptr, '\n',
    546                                        range.data() + range.length() - ptr);
    547     std::string line((const char*)ptr,
    548                      eol ? eol - ptr : range.data() + range.length() - ptr);
    549     ptr = eol ? eol + 1 : range.data() + range.length();
    550     unsigned long long start, stop, offset;
    551     char* permissions = NULL;
    552     char* filename = NULL;
    553     sscanf(line.c_str(), "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
    554            &start, &stop, &permissions, &offset, &filename);
    555     if (filename && *filename == '/') {
    556       CrashedProcess::Mapping mapping;
    557       mapping.permissions = 0;
    558       if (strchr(permissions, 'r')) {
    559         mapping.permissions |= PF_R;
    560       }
    561       if (strchr(permissions, 'w')) {
    562         mapping.permissions |= PF_W;
    563       }
    564       if (strchr(permissions, 'x')) {
    565         mapping.permissions |= PF_X;
    566       }
    567       mapping.start_address = start;
    568       mapping.end_address = stop;
    569       mapping.offset = offset;
    570       if (filename) {
    571         mapping.filename = filename;
    572       }
    573       crashinfo->mappings[mapping.start_address] = mapping;
    574     }
    575     free(permissions);
    576     free(filename);
    577   }
    578   if (verbose) {
    579     fputs("\n\n\n", stderr);
    580   }
    581 }
    582 
    583 static void
    584 ParseEnvironment(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    585   if (verbose) {
    586     fputs("MD_LINUX_ENVIRON:\n", stderr);
    587     char* env = new char[range.length()];
    588     memcpy(env, range.data(), range.length());
    589     int nul_count = 0;
    590     for (char *ptr = env;;) {
    591       ptr = (char *)memchr(ptr, '\000', range.length() - (ptr - env));
    592       if (!ptr) {
    593         break;
    594       }
    595       if (ptr > env && ptr[-1] == '\n') {
    596         if (++nul_count > 5) {
    597           // Some versions of Chrome try to rewrite the process' command line
    598           // in a way that causes the environment to be corrupted. Afterwards,
    599           // part of the environment will contain the trailing bit of the
    600           // command line. The rest of the environment will be filled with
    601           // NUL bytes.
    602           // We detect this corruption by counting the number of consecutive
    603           // NUL bytes. Normally, we would not expect any consecutive NUL
    604           // bytes. But we are conservative and only suppress printing of
    605           // the environment if we see at least five consecutive NULs.
    606           fputs("Environment has been corrupted; no data available", stderr);
    607           goto env_corrupted;
    608         }
    609       } else {
    610         nul_count = 0;
    611       }
    612       *ptr = '\n';
    613     }
    614     fwrite(env, range.length(), 1, stderr);
    615   env_corrupted:
    616     delete[] env;
    617     fputs("\n\n\n", stderr);
    618   }
    619 }
    620 
    621 static void
    622 ParseAuxVector(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    623   // Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value
    624   // when dumping /proc/$x/maps
    625   if (range.length() > 17) {
    626     // The AUXV vector contains binary data, whereas the maps always begin
    627     // with an 8+ digit hex address followed by a hyphen and another 8+ digit
    628     // address.
    629     char addresses[18];
    630     memcpy(addresses, range.data(), 17);
    631     addresses[17] = '\000';
    632     if (strspn(addresses, "0123456789abcdef-") == 17) {
    633       ParseMaps(crashinfo, range);
    634       return;
    635     }
    636   }
    637 
    638   crashinfo->auxv = range.data();
    639   crashinfo->auxv_length = range.length();
    640 }
    641 
    642 static void
    643 ParseCmdLine(CrashedProcess* crashinfo, const MinidumpMemoryRange& range) {
    644   // The command line is supposed to use NUL bytes to separate arguments.
    645   // As Chrome rewrites its own command line and (incorrectly) substitutes
    646   // spaces, this is often not the case in our minidump files.
    647   const char* cmdline = (const char*) range.data();
    648   if (verbose) {
    649     fputs("MD_LINUX_CMD_LINE:\n", stderr);
    650     unsigned i = 0;
    651     for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { }
    652     fputs("argv[0] = \"", stderr);
    653     fwrite(cmdline, i, 1, stderr);
    654     fputs("\"\n", stderr);
    655     for (unsigned j = ++i, argc = 1; j < range.length(); ++j) {
    656       if (!cmdline[j] || cmdline[j] == ' ') {
    657         fprintf(stderr, "argv[%d] = \"", argc++);
    658         fwrite(cmdline + i, j - i, 1, stderr);
    659         fputs("\"\n", stderr);
    660         i = j + 1;
    661       }
    662     }
    663     fputs("\n\n", stderr);
    664   }
    665 
    666   const char *binary_name = cmdline;
    667   for (size_t i = 0; i < range.length(); ++i) {
    668     if (cmdline[i] == '/') {
    669       binary_name = cmdline + i + 1;
    670     } else if (cmdline[i] == 0 || cmdline[i] == ' ') {
    671       static const size_t fname_len = sizeof(crashinfo->prps.pr_fname) - 1;
    672       static const size_t args_len = sizeof(crashinfo->prps.pr_psargs) - 1;
    673       memset(crashinfo->prps.pr_fname, 0, fname_len + 1);
    674       memset(crashinfo->prps.pr_psargs, 0, args_len + 1);
    675       unsigned len = cmdline + i - binary_name;
    676       memcpy(crashinfo->prps.pr_fname, binary_name,
    677                len > fname_len ? fname_len : len);
    678 
    679       len = range.length() > args_len ? args_len : range.length();
    680       memcpy(crashinfo->prps.pr_psargs, cmdline, len);
    681       for (unsigned j = 0; j < len; ++j) {
    682         if (crashinfo->prps.pr_psargs[j] == 0)
    683           crashinfo->prps.pr_psargs[j] = ' ';
    684       }
    685       break;
    686     }
    687   }
    688 }
    689 
    690 static void
    691 ParseDSODebugInfo(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
    692                   const MinidumpMemoryRange& full_file) {
    693   const MDRawDebug* debug = range.GetData<MDRawDebug>(0);
    694   if (!debug) {
    695     return;
    696   }
    697   if (verbose) {
    698     fprintf(stderr,
    699             "MD_LINUX_DSO_DEBUG:\n"
    700             "Version: %d\n"
    701             "Number of DSOs: %d\n"
    702             "Brk handler: 0x%" PRIx64 "\n"
    703             "Dynamic loader at: 0x%" PRIx64 "\n"
    704             "_DYNAMIC: 0x%" PRIx64 "\n",
    705             debug->version,
    706             debug->dso_count,
    707             static_cast<uint64_t>(debug->brk),
    708             static_cast<uint64_t>(debug->ldbase),
    709             static_cast<uint64_t>(debug->dynamic));
    710   }
    711   crashinfo->debug = *debug;
    712   if (range.length() > sizeof(MDRawDebug)) {
    713     char* dynamic_data = (char*)range.data() + sizeof(MDRawDebug);
    714     crashinfo->dynamic_data.assign(dynamic_data,
    715                                    range.length() - sizeof(MDRawDebug));
    716   }
    717   if (debug->map != kInvalidMDRVA) {
    718     for (unsigned int i = 0; i < debug->dso_count; ++i) {
    719       const MDRawLinkMap* link_map =
    720           full_file.GetArrayElement<MDRawLinkMap>(debug->map, i);
    721       if (link_map) {
    722         if (verbose) {
    723           fprintf(stderr,
    724                   "#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n",
    725                   i, static_cast<uint64_t>(link_map->addr),
    726                   static_cast<uint64_t>(link_map->ld),
    727                   full_file.GetAsciiMDString(link_map->name).c_str());
    728         }
    729         crashinfo->link_map.push_back(*link_map);
    730       }
    731     }
    732   }
    733   if (verbose) {
    734     fputs("\n\n", stderr);
    735   }
    736 }
    737 
    738 static void
    739 ParseExceptionStream(CrashedProcess* crashinfo,
    740                      const MinidumpMemoryRange& range) {
    741   const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0);
    742   crashinfo->crashing_tid = exp->thread_id;
    743   crashinfo->fatal_signal = (int) exp->exception_record.exception_code;
    744 }
    745 
    746 static bool
    747 WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
    748   struct prstatus pr;
    749   memset(&pr, 0, sizeof(pr));
    750 
    751   pr.pr_info.si_signo = fatal_signal;
    752   pr.pr_cursig = fatal_signal;
    753   pr.pr_pid = thread.tid;
    754   memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
    755 
    756   Nhdr nhdr;
    757   memset(&nhdr, 0, sizeof(nhdr));
    758   nhdr.n_namesz = 5;
    759   nhdr.n_descsz = sizeof(struct prstatus);
    760   nhdr.n_type = NT_PRSTATUS;
    761   if (!writea(1, &nhdr, sizeof(nhdr)) ||
    762       !writea(1, "CORE\0\0\0\0", 8) ||
    763       !writea(1, &pr, sizeof(struct prstatus))) {
    764     return false;
    765   }
    766 
    767 #if defined(__i386__) || defined(__x86_64__)
    768   nhdr.n_descsz = sizeof(user_fpregs_struct);
    769   nhdr.n_type = NT_FPREGSET;
    770   if (!writea(1, &nhdr, sizeof(nhdr)) ||
    771       !writea(1, "CORE\0\0\0\0", 8) ||
    772       !writea(1, &thread.fpregs, sizeof(user_fpregs_struct))) {
    773     return false;
    774   }
    775 #endif
    776 
    777 #if defined(__i386__)
    778   nhdr.n_descsz = sizeof(user_fpxregs_struct);
    779   nhdr.n_type = NT_PRXFPREG;
    780   if (!writea(1, &nhdr, sizeof(nhdr)) ||
    781       !writea(1, "LINUX\0\0\0", 8) ||
    782       !writea(1, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
    783     return false;
    784   }
    785 #endif
    786 
    787   return true;
    788 }
    789 
    790 static void
    791 ParseModuleStream(CrashedProcess* crashinfo, const MinidumpMemoryRange& range,
    792                   const MinidumpMemoryRange& full_file) {
    793   if (verbose) {
    794     fputs("MD_MODULE_LIST_STREAM:\n", stderr);
    795   }
    796   const uint32_t num_mappings = *range.GetData<uint32_t>(0);
    797   for (unsigned i = 0; i < num_mappings; ++i) {
    798     CrashedProcess::Mapping mapping;
    799     const MDRawModule* rawmodule = reinterpret_cast<const MDRawModule*>(
    800         range.GetArrayElement(sizeof(uint32_t), MD_MODULE_SIZE, i));
    801     mapping.start_address = rawmodule->base_of_image;
    802     mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image;
    803 
    804     if (crashinfo->mappings.find(mapping.start_address) ==
    805         crashinfo->mappings.end()) {
    806       // We prefer data from MD_LINUX_MAPS over MD_MODULE_LIST_STREAM, as
    807       // the former is a strict superset of the latter.
    808       crashinfo->mappings[mapping.start_address] = mapping;
    809     }
    810 
    811     const MDCVInfoPDB70* record = reinterpret_cast<const MDCVInfoPDB70*>(
    812         full_file.GetData(rawmodule->cv_record.rva, MDCVInfoPDB70_minsize));
    813     char guid[40];
    814     sprintf(guid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
    815             record->signature.data1, record->signature.data2,
    816             record->signature.data3,
    817             record->signature.data4[0], record->signature.data4[1],
    818             record->signature.data4[2], record->signature.data4[3],
    819             record->signature.data4[4], record->signature.data4[5],
    820             record->signature.data4[6], record->signature.data4[7]);
    821     std::string filename =
    822         full_file.GetAsciiMDString(rawmodule->module_name_rva);
    823     size_t slash = filename.find_last_of('/');
    824     std::string basename = slash == std::string::npos ?
    825       filename : filename.substr(slash + 1);
    826     if (strcmp(guid, "00000000-0000-0000-0000-000000000000")) {
    827       std::string prefix;
    828       if (!g_custom_so_basedir.empty())
    829         prefix = g_custom_so_basedir;
    830       else
    831         prefix = std::string("/var/lib/breakpad/") + guid + "-" + basename;
    832 
    833       crashinfo->signatures[rawmodule->base_of_image] = prefix + basename;
    834     }
    835 
    836     if (verbose) {
    837       fprintf(stderr, "0x%08llX-0x%08llX, ChkSum: 0x%08X, GUID: %s, \"%s\"\n",
    838               (unsigned long long)rawmodule->base_of_image,
    839               (unsigned long long)rawmodule->base_of_image +
    840               rawmodule->size_of_image,
    841               rawmodule->checksum, guid, filename.c_str());
    842     }
    843   }
    844   if (verbose) {
    845     fputs("\n\n", stderr);
    846   }
    847 }
    848 
    849 static void
    850 AddDataToMapping(CrashedProcess* crashinfo, const std::string& data,
    851                  uintptr_t addr) {
    852   for (std::map<uint64_t, CrashedProcess::Mapping>::iterator
    853          iter = crashinfo->mappings.begin();
    854        iter != crashinfo->mappings.end();
    855        ++iter) {
    856     if (addr >= iter->second.start_address &&
    857         addr < iter->second.end_address) {
    858       CrashedProcess::Mapping mapping = iter->second;
    859       if ((addr & ~4095) != iter->second.start_address) {
    860         // If there are memory pages in the mapping prior to where the
    861         // data starts, truncate the existing mapping so that it ends with
    862         // the page immediately preceding the data region.
    863         iter->second.end_address = addr & ~4095;
    864         if (!mapping.filename.empty()) {
    865           // "mapping" is a copy of "iter->second". We are splitting the
    866           // existing mapping into two separate ones when we write the data
    867           // to the core file. The first one does not have any associated
    868           // data in the core file, the second one is backed by data that is
    869           // included with the core file.
    870           // If this mapping wasn't supposed to be anonymous, then we also
    871           // have to update the file offset upon splitting the mapping.
    872           mapping.offset += iter->second.end_address -
    873             iter->second.start_address;
    874         }
    875       }
    876       // Create a new mapping that contains the data contents. We often
    877       // limit the amount of data that is actually written to the core
    878       // file. But it is OK if the mapping itself extends past the end of
    879       // the data.
    880       mapping.start_address = addr & ~4095;
    881       mapping.data.assign(addr & 4095, 0).append(data);
    882       mapping.data.append(-mapping.data.size() & 4095, 0);
    883       crashinfo->mappings[mapping.start_address] = mapping;
    884       return;
    885     }
    886   }
    887   // Didn't find a suitable existing mapping for the data. Create a new one.
    888   CrashedProcess::Mapping mapping;
    889   mapping.permissions = PF_R | PF_W;
    890   mapping.start_address = addr & ~4095;
    891   mapping.end_address =
    892     (addr + data.size() + 4095) & ~4095;
    893   mapping.data.assign(addr & 4095, 0).append(data);
    894   mapping.data.append(-mapping.data.size() & 4095, 0);
    895   crashinfo->mappings[mapping.start_address] = mapping;
    896 }
    897 
    898 static void
    899 AugmentMappings(CrashedProcess* crashinfo,
    900                 const MinidumpMemoryRange& full_file) {
    901   // For each thread, find the memory mapping that matches the thread's stack.
    902   // Then adjust the mapping to include the stack dump.
    903   for (unsigned i = 0; i < crashinfo->threads.size(); ++i) {
    904     const CrashedProcess::Thread& thread = crashinfo->threads[i];
    905     AddDataToMapping(crashinfo,
    906                      std::string((char *)thread.stack, thread.stack_length),
    907                      thread.stack_addr);
    908   }
    909 
    910   // Create a new link map with information about DSOs. We move this map to
    911   // the beginning of the address space, as this area should always be
    912   // available.
    913   static const uintptr_t start_addr = 4096;
    914   std::string data;
    915   struct r_debug debug = { 0 };
    916   debug.r_version = crashinfo->debug.version;
    917   debug.r_brk = (ElfW(Addr))crashinfo->debug.brk;
    918   debug.r_state = r_debug::RT_CONSISTENT;
    919   debug.r_ldbase = (ElfW(Addr))crashinfo->debug.ldbase;
    920   debug.r_map = crashinfo->debug.dso_count > 0 ?
    921     (struct link_map*)(start_addr + sizeof(debug)) : 0;
    922   data.append((char*)&debug, sizeof(debug));
    923 
    924   struct link_map* prev = 0;
    925   for (std::vector<MDRawLinkMap>::iterator iter = crashinfo->link_map.begin();
    926        iter != crashinfo->link_map.end();
    927        ++iter) {
    928     struct link_map link_map = { 0 };
    929     link_map.l_addr = (ElfW(Addr))iter->addr;
    930     link_map.l_name = (char*)(start_addr + data.size() + sizeof(link_map));
    931     link_map.l_ld = (ElfW(Dyn)*)iter->ld;
    932     link_map.l_prev = prev;
    933     prev = (struct link_map*)(start_addr + data.size());
    934     std::string filename = full_file.GetAsciiMDString(iter->name);
    935 
    936     // Look up signature for this filename. If available, change filename
    937     // to point to GUID, instead.
    938     std::map<uintptr_t, std::string>::const_iterator guid =
    939       crashinfo->signatures.find((uintptr_t)iter->addr);
    940     if (guid != crashinfo->signatures.end()) {
    941       filename = guid->second;
    942     }
    943 
    944     if (std::distance(iter, crashinfo->link_map.end()) == 1) {
    945       link_map.l_next = 0;
    946     } else {
    947       link_map.l_next = (struct link_map*)(start_addr + data.size() +
    948                                            sizeof(link_map) +
    949                                            ((filename.size() + 8) & ~7));
    950     }
    951     data.append((char*)&link_map, sizeof(link_map));
    952     data.append(filename);
    953     data.append(8 - (filename.size() & 7), 0);
    954   }
    955   AddDataToMapping(crashinfo, data, start_addr);
    956 
    957   // Map the page containing the _DYNAMIC array
    958   if (!crashinfo->dynamic_data.empty()) {
    959     // Make _DYNAMIC DT_DEBUG entry point to our link map
    960     for (int i = 0;; ++i) {
    961       ElfW(Dyn) dyn;
    962       if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) {
    963       no_dt_debug:
    964         if (verbose) {
    965           fprintf(stderr, "No DT_DEBUG entry found\n");
    966         }
    967         return;
    968       }
    969       memcpy(&dyn, crashinfo->dynamic_data.c_str() + i*sizeof(dyn),
    970              sizeof(dyn));
    971       if (dyn.d_tag == DT_DEBUG) {
    972         crashinfo->dynamic_data.replace(i*sizeof(dyn) +
    973                                        offsetof(ElfW(Dyn), d_un.d_ptr),
    974                                        sizeof(start_addr),
    975                                        (char*)&start_addr, sizeof(start_addr));
    976         break;
    977       } else if (dyn.d_tag == DT_NULL) {
    978         goto no_dt_debug;
    979       }
    980     }
    981     AddDataToMapping(crashinfo, crashinfo->dynamic_data,
    982                      (uintptr_t)crashinfo->debug.dynamic);
    983   }
    984 }
    985 
    986 int
    987 main(int argc, char** argv) {
    988   int argi = 1;
    989   while (argi < argc && argv[argi][0] == '-') {
    990     if (!strcmp(argv[argi], "-v")) {
    991       verbose = true;
    992     } else if (!strcmp(argv[argi], "--sobasedir")) {
    993       argi++;
    994       if (argi >= argc) {
    995         fprintf(stderr, "--sobasedir expects an argument.");
    996         return usage(argv[0]);
    997       }
    998 
    999       g_custom_so_basedir = argv[argi];
   1000     } else {
   1001       return usage(argv[0]);
   1002     }
   1003     argi++;
   1004   }
   1005 
   1006   if (argc != argi + 1)
   1007     return usage(argv[0]);
   1008 
   1009   MemoryMappedFile mapped_file(argv[argi], 0);
   1010   if (!mapped_file.data()) {
   1011     fprintf(stderr, "Failed to mmap dump file\n");
   1012     return 1;
   1013   }
   1014 
   1015   MinidumpMemoryRange dump(mapped_file.data(), mapped_file.size());
   1016 
   1017   const MDRawHeader* header = dump.GetData<MDRawHeader>(0);
   1018 
   1019   CrashedProcess crashinfo;
   1020 
   1021   // Always check the system info first, as that allows us to tell whether
   1022   // this is a minidump file that is compatible with our converter.
   1023   bool ok = false;
   1024   for (unsigned i = 0; i < header->stream_count; ++i) {
   1025     const MDRawDirectory* dirent =
   1026         dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
   1027     switch (dirent->stream_type) {
   1028       case MD_SYSTEM_INFO_STREAM:
   1029         ParseSystemInfo(&crashinfo, dump.Subrange(dirent->location), dump);
   1030         ok = true;
   1031         break;
   1032       default:
   1033         break;
   1034     }
   1035   }
   1036   if (!ok) {
   1037     fprintf(stderr, "Cannot determine input file format.\n");
   1038     _exit(1);
   1039   }
   1040 
   1041   for (unsigned i = 0; i < header->stream_count; ++i) {
   1042     const MDRawDirectory* dirent =
   1043         dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
   1044     switch (dirent->stream_type) {
   1045       case MD_THREAD_LIST_STREAM:
   1046         ParseThreadList(&crashinfo, dump.Subrange(dirent->location), dump);
   1047         break;
   1048       case MD_LINUX_CPU_INFO:
   1049         ParseCPUInfo(&crashinfo, dump.Subrange(dirent->location));
   1050         break;
   1051       case MD_LINUX_PROC_STATUS:
   1052         ParseProcessStatus(&crashinfo, dump.Subrange(dirent->location));
   1053         break;
   1054       case MD_LINUX_LSB_RELEASE:
   1055         ParseLSBRelease(&crashinfo, dump.Subrange(dirent->location));
   1056         break;
   1057       case MD_LINUX_ENVIRON:
   1058         ParseEnvironment(&crashinfo, dump.Subrange(dirent->location));
   1059         break;
   1060       case MD_LINUX_MAPS:
   1061         ParseMaps(&crashinfo, dump.Subrange(dirent->location));
   1062         break;
   1063       case MD_LINUX_AUXV:
   1064         ParseAuxVector(&crashinfo, dump.Subrange(dirent->location));
   1065         break;
   1066       case MD_LINUX_CMD_LINE:
   1067         ParseCmdLine(&crashinfo, dump.Subrange(dirent->location));
   1068         break;
   1069       case MD_LINUX_DSO_DEBUG:
   1070         ParseDSODebugInfo(&crashinfo, dump.Subrange(dirent->location), dump);
   1071         break;
   1072       case MD_EXCEPTION_STREAM:
   1073         ParseExceptionStream(&crashinfo, dump.Subrange(dirent->location));
   1074         break;
   1075       case MD_MODULE_LIST_STREAM:
   1076         ParseModuleStream(&crashinfo, dump.Subrange(dirent->location), dump);
   1077         break;
   1078       default:
   1079         if (verbose)
   1080           fprintf(stderr, "Skipping %x\n", dirent->stream_type);
   1081     }
   1082   }
   1083 
   1084   AugmentMappings(&crashinfo, dump);
   1085 
   1086   // Write the ELF header. The file will look like:
   1087   //   ELF header
   1088   //   Phdr for the PT_NOTE
   1089   //   Phdr for each of the thread stacks
   1090   //   PT_NOTE
   1091   //   each of the thread stacks
   1092   Ehdr ehdr;
   1093   memset(&ehdr, 0, sizeof(Ehdr));
   1094   ehdr.e_ident[0] = ELFMAG0;
   1095   ehdr.e_ident[1] = ELFMAG1;
   1096   ehdr.e_ident[2] = ELFMAG2;
   1097   ehdr.e_ident[3] = ELFMAG3;
   1098   ehdr.e_ident[4] = ELF_CLASS;
   1099   ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB;
   1100   ehdr.e_ident[6] = EV_CURRENT;
   1101   ehdr.e_type     = ET_CORE;
   1102   ehdr.e_machine  = ELF_ARCH;
   1103   ehdr.e_version  = EV_CURRENT;
   1104   ehdr.e_phoff    = sizeof(Ehdr);
   1105   ehdr.e_ehsize   = sizeof(Ehdr);
   1106   ehdr.e_phentsize= sizeof(Phdr);
   1107   ehdr.e_phnum    = 1 +                         // PT_NOTE
   1108                     crashinfo.mappings.size();  // memory mappings
   1109   ehdr.e_shentsize= sizeof(Shdr);
   1110   if (!writea(1, &ehdr, sizeof(Ehdr)))
   1111     return 1;
   1112 
   1113   size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr);
   1114   size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) +
   1115                   // sizeof(Nhdr) + 8 + sizeof(user) +
   1116                   sizeof(Nhdr) + 8 + crashinfo.auxv_length +
   1117                   crashinfo.threads.size() * (
   1118                     (sizeof(Nhdr) + 8 + sizeof(prstatus))
   1119 #if defined(__i386__) || defined(__x86_64__)
   1120                    + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct)
   1121 #endif
   1122 #if defined(__i386__)
   1123                    + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct)
   1124 #endif
   1125                     );
   1126 
   1127   Phdr phdr;
   1128   memset(&phdr, 0, sizeof(Phdr));
   1129   phdr.p_type = PT_NOTE;
   1130   phdr.p_offset = offset;
   1131   phdr.p_filesz = filesz;
   1132   if (!writea(1, &phdr, sizeof(phdr)))
   1133     return 1;
   1134 
   1135   phdr.p_type = PT_LOAD;
   1136   phdr.p_align = 4096;
   1137   size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align);
   1138   if (note_align == phdr.p_align)
   1139     note_align = 0;
   1140   offset += note_align;
   1141 
   1142   for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter =
   1143          crashinfo.mappings.begin();
   1144        iter != crashinfo.mappings.end(); ++iter) {
   1145     const CrashedProcess::Mapping& mapping = iter->second;
   1146     if (mapping.permissions == 0xFFFFFFFF) {
   1147       // This is a map that we found in MD_MODULE_LIST_STREAM (as opposed to
   1148       // MD_LINUX_MAPS). It lacks some of the information that we would like
   1149       // to include.
   1150       phdr.p_flags = PF_R;
   1151     } else {
   1152       phdr.p_flags = mapping.permissions;
   1153     }
   1154     phdr.p_vaddr = mapping.start_address;
   1155     phdr.p_memsz = mapping.end_address - mapping.start_address;
   1156     if (mapping.data.size()) {
   1157       offset += filesz;
   1158       filesz = mapping.data.size();
   1159       phdr.p_filesz = mapping.data.size();
   1160       phdr.p_offset = offset;
   1161     } else {
   1162       phdr.p_filesz = 0;
   1163       phdr.p_offset = 0;
   1164     }
   1165     if (!writea(1, &phdr, sizeof(phdr)))
   1166       return 1;
   1167   }
   1168 
   1169   Nhdr nhdr;
   1170   memset(&nhdr, 0, sizeof(nhdr));
   1171   nhdr.n_namesz = 5;
   1172   nhdr.n_descsz = sizeof(prpsinfo);
   1173   nhdr.n_type = NT_PRPSINFO;
   1174   if (!writea(1, &nhdr, sizeof(nhdr)) ||
   1175       !writea(1, "CORE\0\0\0\0", 8) ||
   1176       !writea(1, &crashinfo.prps, sizeof(prpsinfo))) {
   1177     return 1;
   1178   }
   1179 
   1180   nhdr.n_descsz = crashinfo.auxv_length;
   1181   nhdr.n_type = NT_AUXV;
   1182   if (!writea(1, &nhdr, sizeof(nhdr)) ||
   1183       !writea(1, "CORE\0\0\0\0", 8) ||
   1184       !writea(1, crashinfo.auxv, crashinfo.auxv_length)) {
   1185     return 1;
   1186   }
   1187 
   1188   for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
   1189     if (crashinfo.threads[i].tid == crashinfo.crashing_tid) {
   1190       WriteThread(crashinfo.threads[i], crashinfo.fatal_signal);
   1191       break;
   1192     }
   1193   }
   1194 
   1195   for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
   1196     if (crashinfo.threads[i].tid != crashinfo.crashing_tid)
   1197       WriteThread(crashinfo.threads[i], 0);
   1198   }
   1199 
   1200   if (note_align) {
   1201     google_breakpad::scoped_array<char> scratch(new char[note_align]);
   1202     memset(scratch.get(), 0, note_align);
   1203     if (!writea(1, scratch.get(), note_align))
   1204       return 1;
   1205   }
   1206 
   1207   for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter =
   1208          crashinfo.mappings.begin();
   1209        iter != crashinfo.mappings.end(); ++iter) {
   1210     const CrashedProcess::Mapping& mapping = iter->second;
   1211     if (mapping.data.size()) {
   1212       if (!writea(1, mapping.data.c_str(), mapping.data.size()))
   1213         return 1;
   1214     }
   1215   }
   1216 
   1217   return 0;
   1218 }
   1219