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