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