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

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

Issue 414049: Linux: Use upstream google-breakpad instead of our fork.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 1 month 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/linux/memory_unittest.cc ('k') | breakpad/linux/minidump_file_writer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 1234.dmp > core
35
36 #include <vector>
37
38 #include <stdio.h>
39 #include <string.h>
40
41 #include <elf.h>
42 #include <errno.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <sys/user.h>
46 #include <sys/mman.h>
47
48 #include "google_breakpad/common/minidump_format.h"
49 #include "google_breakpad/common/minidump_cpu_x86.h"
50 #include "breakpad/linux/linux_syscall_support.h"
51 #include "breakpad/linux/minidump_format_linux.h"
52
53 #if __WORDSIZE == 64
54 #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
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
68
69
70 #if defined(__x86_64__)
71 #define ELF_ARCH EM_X86_64
72 #elif defined(__i386__)
73 #define ELF_ARCH EM_386
74 #elif defined(__ARM_ARCH_3__)
75 #define ELF_ARCH EM_ARM
76 #elif defined(__mips__)
77 #define ELF_ARCH EM_MIPS
78 #endif
79
80 static int usage(const char* argv0) {
81 fprintf(stderr, "Usage: %s <minidump file>\n", argv0);
82 return 1;
83 }
84
85 // Write all of the given buffer, handling short writes and EINTR. Return true
86 // iff successful.
87 static bool
88 writea(int fd, const void* idata, size_t length) {
89 const uint8_t* data = (const uint8_t*) idata;
90
91 size_t done = 0;
92 while (done < length) {
93 ssize_t r;
94 do {
95 r = write(fd, data + done, length - done);
96 } while (r == -1 && errno == EINTR);
97
98 if (r < 1)
99 return false;
100 done += r;
101 }
102
103 return true;
104 }
105
106 // A range of a mmaped file.
107 class MMappedRange {
108 public:
109 MMappedRange(const void* data, size_t length)
110 : data_(reinterpret_cast<const uint8_t*>(data)),
111 length_(length) {
112 }
113
114 // Get an object of |length| bytes at |offset| and return a pointer to it
115 // unless it's out of bounds.
116 const void* GetObject(size_t offset, size_t length) {
117 if (offset + length < offset)
118 return NULL;
119 if (offset + length > length_)
120 return NULL;
121 return data_ + offset;
122 }
123
124 // Get element |index| of an array of objects of length |length| starting at
125 // |offset| bytes. Return NULL if out of bounds.
126 const void* GetArrayElement(size_t offset, size_t length, unsigned index) {
127 const size_t element_offset = offset + index * length;
128 return GetObject(element_offset, length);
129 }
130
131 // Return a new range which is a subset of this range.
132 MMappedRange Subrange(const MDLocationDescriptor& location) const {
133 if (location.rva > length_ ||
134 location.rva + location.data_size < location.rva ||
135 location.rva + location.data_size > length_) {
136 return MMappedRange(NULL, 0);
137 }
138
139 return MMappedRange(data_ + location.rva, location.data_size);
140 }
141
142 const uint8_t* data() const { return data_; }
143 size_t length() const { return length_; }
144
145 private:
146 const uint8_t* const data_;
147 const size_t length_;
148 };
149
150 /* Dynamically determines the byte sex of the system. Returns non-zero
151 * for big-endian machines.
152 */
153 static inline int sex() {
154 int probe = 1;
155 return !*(char *)&probe;
156 }
157
158 typedef struct elf_timeval { /* Time value with microsecond resolution */
159 long tv_sec; /* Seconds */
160 long tv_usec; /* Microseconds */
161 } elf_timeval;
162
163 typedef struct elf_siginfo { /* Information about signal (unused) */
164 int32_t si_signo; /* Signal number */
165 int32_t si_code; /* Extra code */
166 int32_t si_errno; /* Errno */
167 } elf_siginfo;
168
169 typedef struct prstatus { /* Information about thread; includes CPU reg*/
170 elf_siginfo pr_info; /* Info associated with signal */
171 uint16_t pr_cursig; /* Current signal */
172 unsigned long pr_sigpend; /* Set of pending signals */
173 unsigned long pr_sighold; /* Set of held signals */
174 pid_t pr_pid; /* Process ID */
175 pid_t pr_ppid; /* Parent's process ID */
176 pid_t pr_pgrp; /* Group ID */
177 pid_t pr_sid; /* Session ID */
178 elf_timeval pr_utime; /* User time */
179 elf_timeval pr_stime; /* System time */
180 elf_timeval pr_cutime; /* Cumulative user time */
181 elf_timeval pr_cstime; /* Cumulative system time */
182 user_regs_struct pr_reg; /* CPU registers */
183 uint32_t pr_fpvalid; /* True if math co-processor being used */
184 } prstatus;
185
186 typedef struct prpsinfo { /* Information about process */
187 unsigned char pr_state; /* Numeric process state */
188 char pr_sname; /* Char for pr_state */
189 unsigned char pr_zomb; /* Zombie */
190 signed char pr_nice; /* Nice val */
191 unsigned long pr_flag; /* Flags */
192 #if defined(__x86_64__) || defined(__mips__)
193 uint32_t pr_uid; /* User ID */
194 uint32_t pr_gid; /* Group ID */
195 #else
196 uint16_t pr_uid; /* User ID */
197 uint16_t pr_gid; /* Group ID */
198 #endif
199 pid_t pr_pid; /* Process ID */
200 pid_t pr_ppid; /* Parent's process ID */
201 pid_t pr_pgrp; /* Group ID */
202 pid_t pr_sid; /* Session ID */
203 char pr_fname[16]; /* Filename of executable */
204 char pr_psargs[80]; /* Initial part of arg list */
205 } prpsinfo;
206
207 // We parse the minidump file and keep the parsed information in this structure.
208 struct CrashedProcess {
209 CrashedProcess()
210 : crashing_tid(-1),
211 auxv(NULL),
212 auxv_length(0) {
213 memset(&prps, 0, sizeof(prps));
214 prps.pr_sname = 'R';
215 }
216
217 struct Mapping {
218 uint64_t start_address, end_address;
219 };
220 std::vector<Mapping> mappings;
221
222 pid_t crashing_tid;
223 int fatal_signal;
224
225 struct Thread {
226 pid_t tid;
227 user_regs_struct regs;
228 user_fpregs_struct fpregs;
229 user_fpxregs_struct fpxregs;
230 uintptr_t stack_addr;
231 const uint8_t* stack;
232 size_t stack_length;
233 };
234 std::vector<Thread> threads;
235
236 const uint8_t* auxv;
237 size_t auxv_length;
238
239 prpsinfo prps;
240 };
241
242 static uint32_t
243 U32(const uint8_t* data) {
244 uint32_t v;
245 memcpy(&v, data, sizeof(v));
246 return v;
247 }
248
249 static uint16_t
250 U16(const uint8_t* data) {
251 uint16_t v;
252 memcpy(&v, data, sizeof(v));
253 return v;
254 }
255
256 #if defined(__i386__)
257 static void
258 ParseThreadRegisters(CrashedProcess::Thread* thread, MMappedRange range) {
259 const MDRawContextX86* rawregs =
260 (const MDRawContextX86*) range.GetObject(0, sizeof(MDRawContextX86));
261
262 thread->regs.ebx = rawregs->ebx;
263 thread->regs.ecx = rawregs->ecx;
264 thread->regs.edx = rawregs->edx;
265 thread->regs.esi = rawregs->esi;
266 thread->regs.edi = rawregs->edi;
267 thread->regs.ebp = rawregs->ebp;
268 thread->regs.eax = rawregs->eax;
269 thread->regs.xds = rawregs->ds;
270 thread->regs.xes = rawregs->es;
271 thread->regs.xfs = rawregs->fs;
272 thread->regs.xgs = rawregs->gs;
273 thread->regs.orig_eax = rawregs->eax;
274 thread->regs.eip = rawregs->eip;
275 thread->regs.xcs = rawregs->cs;
276 thread->regs.eflags = rawregs->eflags;
277 thread->regs.esp = rawregs->esp;
278 thread->regs.xss = rawregs->ss;
279
280 thread->fpregs.cwd = rawregs->float_save.control_word;
281 thread->fpregs.swd = rawregs->float_save.status_word;
282 thread->fpregs.twd = rawregs->float_save.tag_word;
283 thread->fpregs.fip = rawregs->float_save.error_offset;
284 thread->fpregs.fcs = rawregs->float_save.error_selector;
285 thread->fpregs.foo = rawregs->float_save.data_offset;
286 thread->fpregs.fos = rawregs->float_save.data_selector;
287 memcpy(thread->fpregs.st_space, rawregs->float_save.register_area,
288 10 * 8);
289
290 thread->fpxregs.cwd = rawregs->float_save.control_word;
291 thread->fpxregs.swd = rawregs->float_save.status_word;
292 thread->fpxregs.twd = rawregs->float_save.tag_word;
293 thread->fpxregs.fop = U16(rawregs->extended_registers + 6);
294 thread->fpxregs.fip = U16(rawregs->extended_registers + 8);
295 thread->fpxregs.fcs = U16(rawregs->extended_registers + 12);
296 thread->fpxregs.foo = U16(rawregs->extended_registers + 16);
297 thread->fpxregs.fos = U16(rawregs->extended_registers + 20);
298 thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24);
299 memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128);
300 memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128);
301 }
302 #else
303 #error "This code has not been ported to your platform yet"
304 #endif
305
306 static void
307 ParseThreadList(CrashedProcess* crashinfo, MMappedRange range,
308 const MMappedRange& full_file) {
309 const uint32_t num_threads =
310 *(const uint32_t*) range.GetObject(0, sizeof(uint32_t));
311 for (unsigned i = 0; i < num_threads; ++i) {
312 CrashedProcess::Thread thread;
313 memset(&thread, 0, sizeof(thread));
314 const MDRawThread* rawthread =
315 (MDRawThread*) range.GetArrayElement(sizeof(uint32_t),
316 sizeof(MDRawThread), i);
317 thread.tid = rawthread->thread_id;
318 thread.stack_addr = rawthread->stack.start_of_memory_range;
319 MMappedRange stack_range = full_file.Subrange(rawthread->stack.memory);
320 thread.stack = stack_range.data();
321 thread.stack_length = rawthread->stack.memory.data_size;
322
323 ParseThreadRegisters(&thread,
324 full_file.Subrange(rawthread->thread_context));
325
326 crashinfo->threads.push_back(thread);
327 }
328 }
329
330 static void
331 ParseAuxVector(CrashedProcess* crashinfo, MMappedRange range) {
332 crashinfo->auxv = range.data();
333 crashinfo->auxv_length = range.length();
334 }
335
336 static void
337 ParseCmdLine(CrashedProcess* crashinfo, MMappedRange range) {
338 const char* cmdline = (const char*) range.data();
339 for (size_t i = 0; i < range.length(); ++i) {
340 if (cmdline[i] == 0) {
341 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;
343 memset(crashinfo->prps.pr_fname, 0, fname_len + 1);
344 memset(crashinfo->prps.pr_psargs, 0, args_len + 1);
345 const char* binary_name = strrchr(cmdline, '/');
346 if (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);
351 } else {
352 memcpy(crashinfo->prps.pr_fname, cmdline,
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);
359 for (unsigned i = 0; i < len; ++i) {
360 if (crashinfo->prps.pr_psargs[i] == 0)
361 crashinfo->prps.pr_psargs[i] = ' ';
362 }
363 }
364 }
365 }
366
367 static void
368 ParseExceptionStream(CrashedProcess* crashinfo, MMappedRange range) {
369 const MDRawExceptionStream* exp =
370 (MDRawExceptionStream*) range.GetObject(0, sizeof(MDRawExceptionStream));
371 crashinfo->crashing_tid = exp->thread_id;
372 crashinfo->fatal_signal = (int) exp->exception_record.exception_code;
373 }
374
375 static bool
376 WriteThread(const CrashedProcess::Thread& thread, int fatal_signal) {
377 struct prstatus pr;
378 memset(&pr, 0, sizeof(pr));
379
380 pr.pr_info.si_signo = fatal_signal;
381 pr.pr_cursig = fatal_signal;
382 pr.pr_pid = thread.tid;
383 memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
384
385 Nhdr nhdr;
386 memset(&nhdr, 0, sizeof(nhdr));
387 nhdr.n_namesz = 5;
388 nhdr.n_descsz = sizeof(struct prstatus);
389 nhdr.n_type = NT_PRSTATUS;
390 if (!writea(1, &nhdr, sizeof(nhdr)) ||
391 !writea(1, "CORE\0\0\0\0", 8) ||
392 !writea(1, &pr, sizeof(struct prstatus))) {
393 return false;
394 }
395
396 nhdr.n_descsz = sizeof(user_fpregs_struct);
397 nhdr.n_type = NT_FPREGSET;
398 if (!writea(1, &nhdr, sizeof(nhdr)) ||
399 !writea(1, "CORE\0\0\0\0", 8) ||
400 !writea(1, &thread.fpregs, sizeof(user_fpregs_struct))) {
401 return false;
402 }
403
404 nhdr.n_descsz = sizeof(user_fpxregs_struct);
405 nhdr.n_type = NT_PRXFPREG;
406 if (!writea(1, &nhdr, sizeof(nhdr)) ||
407 !writea(1, "LINUX\0\0\0", 8) ||
408 !writea(1, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
409 return false;
410 }
411
412 return true;
413 }
414
415 static void
416 ParseModuleStream(CrashedProcess* crashinfo, MMappedRange range) {
417 const uint32_t num_mappings =
418 *(const uint32_t*) range.GetObject(0, sizeof(uint32_t));
419 for (unsigned i = 0; i < num_mappings; ++i) {
420 CrashedProcess::Mapping mapping;
421 const MDRawModule* rawmodule =
422 (MDRawModule*) range.GetArrayElement(sizeof(uint32_t),
423 MD_MODULE_SIZE, i);
424 mapping.start_address = rawmodule->base_of_image;
425 mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image;
426
427 crashinfo->mappings.push_back(mapping);
428 }
429 }
430
431 int
432 main(int argc, char** argv) {
433 if (argc != 2)
434 return usage(argv[0]);
435
436 const int fd = open(argv[1], O_RDONLY);
437 if (fd < 0)
438 return usage(argv[0]);
439
440 struct stat st;
441 fstat(fd, &st);
442
443 const void* bytes = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
444 close(fd);
445 if (bytes == MAP_FAILED) {
446 perror("Failed to mmap dump file");
447 return 1;
448 }
449
450 MMappedRange dump(bytes, st.st_size);
451
452 const MDRawHeader* header =
453 (const MDRawHeader*) dump.GetObject(0, sizeof(MDRawHeader));
454
455 CrashedProcess crashinfo;
456
457 for (unsigned i = 0; i < header->stream_count; ++i) {
458 const MDRawDirectory* dirent =
459 (const MDRawDirectory*) dump.GetArrayElement(
460 header->stream_directory_rva, sizeof(MDRawDirectory), i);
461 switch (dirent->stream_type) {
462 case MD_THREAD_LIST_STREAM:
463 ParseThreadList(&crashinfo, dump.Subrange(dirent->location), dump);
464 break;
465 case MD_LINUX_AUXV:
466 ParseAuxVector(&crashinfo, dump.Subrange(dirent->location));
467 break;
468 case MD_LINUX_CMD_LINE:
469 ParseCmdLine(&crashinfo, dump.Subrange(dirent->location));
470 break;
471 case MD_EXCEPTION_STREAM:
472 ParseExceptionStream(&crashinfo, dump.Subrange(dirent->location));
473 break;
474 case MD_MODULE_LIST_STREAM:
475 ParseModuleStream(&crashinfo, dump.Subrange(dirent->location));
476 default:
477 fprintf(stderr, "Skipping %x\n", dirent->stream_type);
478 }
479 }
480
481 // Write the ELF header. The file will look like:
482 // ELF header
483 // Phdr for the PT_NOTE
484 // Phdr for each of the thread stacks
485 // PT_NOTE
486 // each of the thread stacks
487 Ehdr ehdr;
488 memset(&ehdr, 0, sizeof(Ehdr));
489 ehdr.e_ident[0] = ELFMAG0;
490 ehdr.e_ident[1] = ELFMAG1;
491 ehdr.e_ident[2] = ELFMAG2;
492 ehdr.e_ident[3] = ELFMAG3;
493 ehdr.e_ident[4] = ELF_CLASS;
494 ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB;
495 ehdr.e_ident[6] = EV_CURRENT;
496 ehdr.e_type = ET_CORE;
497 ehdr.e_machine = ELF_ARCH;
498 ehdr.e_version = EV_CURRENT;
499 ehdr.e_phoff = sizeof(Ehdr);
500 ehdr.e_ehsize = sizeof(Ehdr);
501 ehdr.e_phentsize= sizeof(Phdr);
502 ehdr.e_phnum = 1 + crashinfo.threads.size() + crashinfo.mappings.size();
503 ehdr.e_shentsize= sizeof(Shdr);
504 if (!writea(1, &ehdr, sizeof(Ehdr)))
505 return 1;
506
507 size_t offset = sizeof(Ehdr) +
508 (1 + crashinfo.threads.size() +
509 crashinfo.mappings.size()) * sizeof(Phdr);
510 size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) +
511 // sizeof(Nhdr) + 8 + sizeof(user) +
512 sizeof(Nhdr) + 8 + crashinfo.auxv_length +
513 crashinfo.threads.size() * (
514 (sizeof(Nhdr) + 8 + sizeof(prstatus)) +
515 sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) +
516 sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct));
517
518 Phdr phdr;
519 memset(&phdr, 0, sizeof(Phdr));
520 phdr.p_type = PT_NOTE;
521 phdr.p_offset = offset;
522 phdr.p_filesz = filesz;
523 if (!writea(1, &phdr, sizeof(phdr)))
524 return 1;
525
526 phdr.p_type = PT_LOAD;
527 phdr.p_align = getpagesize();
528 size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align);
529 if (note_align == phdr.p_align)
530 note_align = 0;
531 offset += note_align;
532
533 for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
534 const CrashedProcess::Thread& thread = crashinfo.threads[i];
535 offset += filesz;
536 filesz = thread.stack_length;
537 phdr.p_offset = offset;
538 phdr.p_vaddr = thread.stack_addr;
539 phdr.p_filesz = phdr.p_memsz = filesz;
540 phdr.p_flags = PF_R | PF_W;
541 if (!writea(1, &phdr, sizeof(phdr)))
542 return 1;
543 }
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
556 Nhdr nhdr;
557 memset(&nhdr, 0, sizeof(nhdr));
558 nhdr.n_namesz = 5;
559 nhdr.n_descsz = sizeof(prpsinfo);
560 nhdr.n_type = NT_PRPSINFO;
561 if (!writea(1, &nhdr, sizeof(nhdr)) ||
562 !writea(1, "CORE\0\0\0\0", 8) ||
563 !writea(1, &crashinfo.prps, sizeof(prpsinfo))) {
564 return 1;
565 }
566
567 nhdr.n_descsz = crashinfo.auxv_length;
568 nhdr.n_type = NT_AUXV;
569 if (!writea(1, &nhdr, sizeof(nhdr)) ||
570 !writea(1, "CORE\0\0\0\0", 8) ||
571 !writea(1, &crashinfo.auxv, crashinfo.auxv_length)) {
572 return 1;
573 }
574
575 for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
576 if (crashinfo.threads[i].tid == crashinfo.crashing_tid) {
577 WriteThread(crashinfo.threads[i], crashinfo.fatal_signal);
578 break;
579 }
580 }
581
582 for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
583 if (crashinfo.threads[i].tid != crashinfo.crashing_tid)
584 WriteThread(crashinfo.threads[i], 0);
585 }
586
587 if (note_align) {
588 char scratch[note_align];
589 memset(scratch, 0, sizeof(scratch));
590 if (!writea(1, scratch, sizeof(scratch)))
591 return 1;
592 }
593
594 for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
595 const CrashedProcess::Thread& thread = crashinfo.threads[i];
596 if (!writea(1, thread.stack, thread.stack_length))
597 return 1;
598 }
599
600 munmap(const_cast<void*>(bytes), st.st_size);
601
602 return 0;
603 }
OLDNEW
« no previous file with comments | « breakpad/linux/memory_unittest.cc ('k') | breakpad/linux/minidump_file_writer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698