Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: breakpad/src/tools/linux/md2core/minidump-2-core.cc

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

Powered by Google App Engine
This is Rietveld 408576698