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