/ src / tools / linux / md2core / minidump-2-core.cc
minidump-2-core.cc
   1  // Copyright 2009 Google LLC
   2  //
   3  // Redistribution and use in source and binary forms, with or without
   4  // modification, are permitted provided that the following conditions are
   5  // met:
   6  //
   7  //     * Redistributions of source code must retain the above copyright
   8  // notice, this list of conditions and the following disclaimer.
   9  //     * Redistributions in binary form must reproduce the above
  10  // copyright notice, this list of conditions and the following disclaimer
  11  // in the documentation and/or other materials provided with the
  12  // distribution.
  13  //     * Neither the name of Google LLC nor the names of its
  14  // contributors may be used to endorse or promote products derived from
  15  // this software without specific prior written permission.
  16  //
  17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28  
  29  // Converts a minidump file to a core file which gdb can read.
  30  // Large parts lifted from the userspace core dumper:
  31  //   http://code.google.com/p/google-coredumper/
  32  
  33  #ifdef HAVE_CONFIG_H
  34  #include <config.h>  // Must come first
  35  #endif
  36  
  37  #include <elf.h>
  38  #include <errno.h>
  39  #include <limits.h>
  40  #include <link.h>
  41  #include <stdio.h>
  42  #include <stdlib.h>
  43  #include <string.h>
  44  #include <sys/user.h>
  45  #include <unistd.h>
  46  
  47  #include <map>
  48  #include <string>
  49  #include <vector>
  50  
  51  #include "common/linux/memory_mapped_file.h"
  52  #include "common/minidump_type_helper.h"
  53  #include "common/path_helper.h"
  54  #include "common/scoped_ptr.h"
  55  #include "common/using_std_string.h"
  56  #include "google_breakpad/common/breakpad_types.h"
  57  #include "google_breakpad/common/minidump_format.h"
  58  #include "third_party/lss/linux_syscall_support.h"
  59  #include "tools/linux/md2core/minidump_memory_range.h"
  60  
  61  #if ULONG_MAX == 0xffffffffffffffff
  62    #define ELF_CLASS ELFCLASS64
  63  #else
  64    #define ELF_CLASS ELFCLASS32
  65  #endif
  66  #define Ehdr   ElfW(Ehdr)
  67  #define Phdr   ElfW(Phdr)
  68  #define Shdr   ElfW(Shdr)
  69  #define Nhdr   ElfW(Nhdr)
  70  #define auxv_t ElfW(auxv_t)
  71  
  72  
  73  #if defined(__x86_64__)
  74    #define ELF_ARCH  EM_X86_64
  75  #elif defined(__i386__)
  76    #define ELF_ARCH  EM_386
  77  #elif defined(__arm__)
  78    #define ELF_ARCH  EM_ARM
  79  #elif defined(__mips__)
  80    #define ELF_ARCH  EM_MIPS
  81  #elif defined(__aarch64__)
  82    #define ELF_ARCH  EM_AARCH64
  83  #elif defined(__riscv)
  84    #define ELF_ARCH  EM_RISCV
  85  #endif
  86  
  87  #if defined(__arm__)
  88  // GLibc/ARM and Android/ARM both use 'user_regs' for the structure type
  89  // containing core registers, while they use 'user_regs_struct' on other
  90  // architectures. This file-local typedef simplifies the source code.
  91  typedef user_regs user_regs_struct;
  92  #elif defined (__mips__) || defined(__riscv)
  93  // This file-local typedef simplifies the source code.
  94  typedef gregset_t user_regs_struct;
  95  #endif
  96  
  97  using google_breakpad::MDTypeHelper;
  98  using google_breakpad::MemoryMappedFile;
  99  using google_breakpad::MinidumpMemoryRange;
 100  
 101  typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawDebug MDRawDebug;
 102  typedef MDTypeHelper<sizeof(ElfW(Addr))>::MDRawLinkMap MDRawLinkMap;
 103  
 104  static const MDRVA kInvalidMDRVA = static_cast<MDRVA>(-1);
 105  
 106  struct Options {
 107    string minidump_path;
 108    bool verbose;
 109    int out_fd;
 110    bool use_filename;
 111    bool inc_guid;
 112    string so_basedir;
 113  };
 114  
 115  static void
 116  Usage(int argc, const char* argv[]) {
 117    fprintf(stderr,
 118            "Usage: %s [options] <minidump file>\n"
 119            "\n"
 120            "Convert a minidump file into a core file (often for use by gdb).\n"
 121            "\n"
 122            "The shared library list will by default have filenames as the runtime expects.\n"
 123            "There are many flags to control the output names though to make it easier to\n"
 124            "integrate with your debug environment (e.g. gdb).\n"
 125            " Default:    /lib64/libpthread.so.0\n"
 126            " -f:         /lib64/libpthread-2.19.so\n"
 127            " -i:         /lib64/<module id>-libpthread.so.0\n"
 128            " -f -i:      /lib64/<module id>-libpthread-2.19.so\n"
 129            " -S /foo/:   /foo/libpthread.so.0\n"
 130            "\n"
 131            "Options:\n"
 132            "  -v         Enable verbose output\n"
 133            "  -o <file>  Write coredump to specified file (otherwise use stdout).\n"
 134            "  -f         Use the filename rather than the soname in the sharedlib list.\n"
 135            "             The soname is what the runtime system uses, but the filename is\n"
 136            "             how it's stored on disk.\n"
 137            "  -i         Prefix sharedlib names with ID (when available).  This makes it\n"
 138            "             easier to have a single directory full of symbols.\n"
 139            "  -S <dir>   Set soname base directory.  This will force all debug/symbol\n"
 140            "             lookups to be done in this directory rather than the filesystem\n"
 141            "             layout as it exists in the crashing image.  This path should end\n"
 142            "             with a slash if it's a directory.  e.g. /var/lib/breakpad/\n"
 143            "", google_breakpad::BaseName(argv[0]).c_str());
 144  }
 145  
 146  static void
 147  SetupOptions(int argc, const char* argv[], Options* options) {
 148    extern int optind;
 149    int ch;
 150    const char* output_file = NULL;
 151  
 152    // Initialize the options struct as needed.
 153    options->verbose = false;
 154    options->use_filename = false;
 155    options->inc_guid = false;
 156  
 157    while ((ch = getopt(argc, (char * const*)argv, "fhio:S:v")) != -1) {
 158      switch (ch) {
 159        case 'h':
 160          Usage(argc, argv);
 161          exit(0);
 162        case '?':
 163          Usage(argc, argv);
 164          exit(1);
 165  
 166        case 'f':
 167          options->use_filename = true;
 168          break;
 169        case 'i':
 170          options->inc_guid = true;
 171          break;
 172        case 'o':
 173          output_file = optarg;
 174          break;
 175        case 'S':
 176          options->so_basedir = optarg;
 177          break;
 178        case 'v':
 179          options->verbose = true;
 180          break;
 181      }
 182    }
 183  
 184    if ((argc - optind) != 1) {
 185      fprintf(stderr, "%s: Missing minidump file\n", argv[0]);
 186      Usage(argc, argv);
 187      exit(1);
 188    }
 189  
 190    if (output_file == NULL || !strcmp(output_file, "-")) {
 191      options->out_fd = STDOUT_FILENO;
 192    } else {
 193      options->out_fd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);
 194      if (options->out_fd == -1) {
 195        fprintf(stderr, "%s: could not open output %s: %s\n", argv[0],
 196                output_file, strerror(errno));
 197        exit(1);
 198      }
 199    }
 200  
 201    options->minidump_path = argv[optind];
 202  }
 203  
 204  // Write all of the given buffer, handling short writes and EINTR. Return true
 205  // iff successful.
 206  static bool
 207  writea(int fd, const void* idata, size_t length) {
 208    const uint8_t* data = (const uint8_t*) idata;
 209  
 210    size_t done = 0;
 211    while (done < length) {
 212      ssize_t r;
 213      do {
 214        r = write(fd, data + done, length - done);
 215      } while (r == -1 && errno == EINTR);
 216  
 217      if (r < 1)
 218        return false;
 219      done += r;
 220    }
 221  
 222    return true;
 223  }
 224  
 225  /* Dynamically determines the byte sex of the system. Returns non-zero
 226   * for big-endian machines.
 227   */
 228  static inline int sex() {
 229    int probe = 1;
 230    return !*(char*)&probe;
 231  }
 232  
 233  typedef struct elf_timeval {    /* Time value with microsecond resolution    */
 234    long tv_sec;                  /* Seconds                                   */
 235    long tv_usec;                 /* Microseconds                              */
 236  } elf_timeval;
 237  
 238  typedef struct _elf_siginfo {   /* Information about signal (unused)         */
 239    int32_t si_signo;             /* Signal number                             */
 240    int32_t si_code;              /* Extra code                                */
 241    int32_t si_errno;             /* Errno                                     */
 242  } _elf_siginfo;
 243  
 244  typedef struct prstatus {       /* Information about thread; includes CPU reg*/
 245    _elf_siginfo   pr_info;       /* Info associated with signal               */
 246    uint16_t       pr_cursig;     /* Current signal                            */
 247    unsigned long  pr_sigpend;    /* Set of pending signals                    */
 248    unsigned long  pr_sighold;    /* Set of held signals                       */
 249    pid_t          pr_pid;        /* Process ID                                */
 250    pid_t          pr_ppid;       /* Parent's process ID                       */
 251    pid_t          pr_pgrp;       /* Group ID                                  */
 252    pid_t          pr_sid;        /* Session ID                                */
 253    elf_timeval    pr_utime;      /* User time                                 */
 254    elf_timeval    pr_stime;      /* System time                               */
 255    elf_timeval    pr_cutime;     /* Cumulative user time                      */
 256    elf_timeval    pr_cstime;     /* Cumulative system time                    */
 257    user_regs_struct pr_reg;      /* CPU registers                             */
 258    uint32_t       pr_fpvalid;    /* True if math co-processor being used      */
 259  } prstatus;
 260  
 261  typedef struct prpsinfo {       /* Information about process                 */
 262    unsigned char  pr_state;      /* Numeric process state                     */
 263    char           pr_sname;      /* Char for pr_state                         */
 264    unsigned char  pr_zomb;       /* Zombie                                    */
 265    signed char    pr_nice;       /* Nice val                                  */
 266    unsigned long  pr_flag;       /* Flags                                     */
 267  #if defined(__x86_64__) || defined(__mips__) || defined(__riscv)
 268    uint32_t       pr_uid;        /* User ID                                   */
 269    uint32_t       pr_gid;        /* Group ID                                  */
 270  #else
 271    uint16_t       pr_uid;        /* User ID                                   */
 272    uint16_t       pr_gid;        /* Group ID                                  */
 273  #endif
 274    pid_t          pr_pid;        /* Process ID                                */
 275    pid_t          pr_ppid;       /* Parent's process ID                       */
 276    pid_t          pr_pgrp;       /* Group ID                                  */
 277    pid_t          pr_sid;        /* Session ID                                */
 278    char           pr_fname[16];  /* Filename of executable                    */
 279    char           pr_psargs[80]; /* Initial part of arg list                  */
 280  } prpsinfo;
 281  
 282  // We parse the minidump file and keep the parsed information in this structure
 283  struct CrashedProcess {
 284    CrashedProcess()
 285        : exception{-1},
 286          auxv(NULL),
 287          auxv_length(0) {
 288      memset(&prps, 0, sizeof(prps));
 289      prps.pr_sname = 'R';
 290      memset(&debug, 0, sizeof(debug));
 291    }
 292  
 293    struct Mapping {
 294      Mapping()
 295        : permissions(0xFFFFFFFF),
 296          start_address(0),
 297          end_address(0),
 298          offset(0) {
 299      }
 300  
 301      uint32_t permissions;
 302      uint64_t start_address, end_address, offset;
 303      // The name we write out to the core.
 304      string filename;
 305      string data;
 306    };
 307    std::map<uint64_t, Mapping> mappings;
 308  
 309    int fatal_signal;
 310  
 311    struct Thread {
 312      pid_t tid;
 313  #if defined(__mips__) || defined(__riscv)
 314      mcontext_t mcontext;
 315  #else
 316      user_regs_struct regs;
 317  #endif
 318  #if defined(__i386__) || defined(__x86_64__)
 319      user_fpregs_struct fpregs;
 320  #endif
 321  #if defined(__i386__)
 322      user_fpxregs_struct fpxregs;
 323  #endif
 324  #if defined(__aarch64__)
 325      user_fpsimd_struct fpregs;
 326  #endif
 327      uintptr_t stack_addr;
 328      const uint8_t* stack;
 329      size_t stack_length;
 330    };
 331    std::vector<Thread> threads;
 332    Thread exception;
 333  
 334    const uint8_t* auxv;
 335    size_t auxv_length;
 336  
 337    prpsinfo prps;
 338  
 339    // The GUID/filename from MD_MODULE_LIST_STREAM entries.
 340    // We gather them for merging later on into the list of maps.
 341    struct Signature {
 342      char guid[40];
 343      string filename;
 344    };
 345    std::map<uintptr_t, Signature> signatures;
 346  
 347    string dynamic_data;
 348    MDRawDebug debug;
 349    std::vector<MDRawLinkMap> link_map;
 350  };
 351  
 352  #if defined(__i386__)
 353  static uint32_t
 354  U32(const uint8_t* data) {
 355    uint32_t v;
 356    memcpy(&v, data, sizeof(v));
 357    return v;
 358  }
 359  
 360  static uint16_t
 361  U16(const uint8_t* data) {
 362    uint16_t v;
 363    memcpy(&v, data, sizeof(v));
 364    return v;
 365  }
 366  
 367  static void
 368  ParseThreadRegisters(CrashedProcess::Thread* thread,
 369                       const MinidumpMemoryRange& range) {
 370    const MDRawContextX86* rawregs = range.GetData<MDRawContextX86>(0);
 371  
 372    thread->regs.ebx = rawregs->ebx;
 373    thread->regs.ecx = rawregs->ecx;
 374    thread->regs.edx = rawregs->edx;
 375    thread->regs.esi = rawregs->esi;
 376    thread->regs.edi = rawregs->edi;
 377    thread->regs.ebp = rawregs->ebp;
 378    thread->regs.eax = rawregs->eax;
 379    thread->regs.xds = rawregs->ds;
 380    thread->regs.xes = rawregs->es;
 381    thread->regs.xfs = rawregs->fs;
 382    thread->regs.xgs = rawregs->gs;
 383    thread->regs.orig_eax = rawregs->eax;
 384    thread->regs.eip = rawregs->eip;
 385    thread->regs.xcs = rawregs->cs;
 386    thread->regs.eflags = rawregs->eflags;
 387    thread->regs.esp = rawregs->esp;
 388    thread->regs.xss = rawregs->ss;
 389  
 390    thread->fpregs.cwd = rawregs->float_save.control_word;
 391    thread->fpregs.swd = rawregs->float_save.status_word;
 392    thread->fpregs.twd = rawregs->float_save.tag_word;
 393    thread->fpregs.fip = rawregs->float_save.error_offset;
 394    thread->fpregs.fcs = rawregs->float_save.error_selector;
 395    thread->fpregs.foo = rawregs->float_save.data_offset;
 396    thread->fpregs.fos = rawregs->float_save.data_selector;
 397    memcpy(thread->fpregs.st_space, rawregs->float_save.register_area,
 398           10 * 8);
 399  
 400    thread->fpxregs.cwd = rawregs->float_save.control_word;
 401    thread->fpxregs.swd = rawregs->float_save.status_word;
 402    thread->fpxregs.twd = rawregs->float_save.tag_word;
 403    thread->fpxregs.fop = U16(rawregs->extended_registers + 6);
 404    thread->fpxregs.fip = U16(rawregs->extended_registers + 8);
 405    thread->fpxregs.fcs = U16(rawregs->extended_registers + 12);
 406    thread->fpxregs.foo = U16(rawregs->extended_registers + 16);
 407    thread->fpxregs.fos = U16(rawregs->extended_registers + 20);
 408    thread->fpxregs.mxcsr = U32(rawregs->extended_registers + 24);
 409    memcpy(thread->fpxregs.st_space, rawregs->extended_registers + 32, 128);
 410    memcpy(thread->fpxregs.xmm_space, rawregs->extended_registers + 160, 128);
 411  }
 412  #elif defined(__x86_64__)
 413  static void
 414  ParseThreadRegisters(CrashedProcess::Thread* thread,
 415                       const MinidumpMemoryRange& range) {
 416    const MDRawContextAMD64* rawregs = range.GetData<MDRawContextAMD64>(0);
 417  
 418    thread->regs.r15 = rawregs->r15;
 419    thread->regs.r14 = rawregs->r14;
 420    thread->regs.r13 = rawregs->r13;
 421    thread->regs.r12 = rawregs->r12;
 422    thread->regs.rbp = rawregs->rbp;
 423    thread->regs.rbx = rawregs->rbx;
 424    thread->regs.r11 = rawregs->r11;
 425    thread->regs.r10 = rawregs->r10;
 426    thread->regs.r9 = rawregs->r9;
 427    thread->regs.r8 = rawregs->r8;
 428    thread->regs.rax = rawregs->rax;
 429    thread->regs.rcx = rawregs->rcx;
 430    thread->regs.rdx = rawregs->rdx;
 431    thread->regs.rsi = rawregs->rsi;
 432    thread->regs.rdi = rawregs->rdi;
 433    thread->regs.orig_rax = rawregs->rax;
 434    thread->regs.rip = rawregs->rip;
 435    thread->regs.cs  = rawregs->cs;
 436    thread->regs.eflags = rawregs->eflags;
 437    thread->regs.rsp = rawregs->rsp;
 438    thread->regs.ss = rawregs->ss;
 439    thread->regs.fs_base = 0;
 440    thread->regs.gs_base = 0;
 441    thread->regs.ds = rawregs->ds;
 442    thread->regs.es = rawregs->es;
 443    thread->regs.fs = rawregs->fs;
 444    thread->regs.gs = rawregs->gs;
 445  
 446    thread->fpregs.cwd = rawregs->flt_save.control_word;
 447    thread->fpregs.swd = rawregs->flt_save.status_word;
 448    thread->fpregs.ftw = rawregs->flt_save.tag_word;
 449    thread->fpregs.fop = rawregs->flt_save.error_opcode;
 450    thread->fpregs.rip = rawregs->flt_save.error_offset;
 451    thread->fpregs.rdp = rawregs->flt_save.data_offset;
 452    thread->fpregs.mxcsr = rawregs->flt_save.mx_csr;
 453    thread->fpregs.mxcr_mask = rawregs->flt_save.mx_csr_mask;
 454    memcpy(thread->fpregs.st_space, rawregs->flt_save.float_registers, 8 * 16);
 455    memcpy(thread->fpregs.xmm_space, rawregs->flt_save.xmm_registers, 16 * 16);
 456  }
 457  #elif defined(__arm__)
 458  static void
 459  ParseThreadRegisters(CrashedProcess::Thread* thread,
 460                       const MinidumpMemoryRange& range) {
 461    const MDRawContextARM* rawregs = range.GetData<MDRawContextARM>(0);
 462  
 463    thread->regs.uregs[0] = rawregs->iregs[0];
 464    thread->regs.uregs[1] = rawregs->iregs[1];
 465    thread->regs.uregs[2] = rawregs->iregs[2];
 466    thread->regs.uregs[3] = rawregs->iregs[3];
 467    thread->regs.uregs[4] = rawregs->iregs[4];
 468    thread->regs.uregs[5] = rawregs->iregs[5];
 469    thread->regs.uregs[6] = rawregs->iregs[6];
 470    thread->regs.uregs[7] = rawregs->iregs[7];
 471    thread->regs.uregs[8] = rawregs->iregs[8];
 472    thread->regs.uregs[9] = rawregs->iregs[9];
 473    thread->regs.uregs[10] = rawregs->iregs[10];
 474    thread->regs.uregs[11] = rawregs->iregs[11];
 475    thread->regs.uregs[12] = rawregs->iregs[12];
 476    thread->regs.uregs[13] = rawregs->iregs[13];
 477    thread->regs.uregs[14] = rawregs->iregs[14];
 478    thread->regs.uregs[15] = rawregs->iregs[15];
 479  
 480    thread->regs.uregs[16] = rawregs->cpsr;
 481    thread->regs.uregs[17] = 0;  // what is ORIG_r0 exactly?
 482  }
 483  #elif defined(__aarch64__)
 484  static void
 485  ParseThreadRegisters(CrashedProcess::Thread* thread,
 486                       const MinidumpMemoryRange& range) {
 487  #define COPY_REGS(rawregs)                                          \
 488    do {                                                              \
 489      for (int i = 0; i < 31; ++i)                                    \
 490        thread->regs.regs[i] = rawregs->iregs[i];                     \
 491      thread->regs.sp = rawregs->iregs[MD_CONTEXT_ARM64_REG_SP];      \
 492      thread->regs.pc = rawregs->iregs[MD_CONTEXT_ARM64_REG_PC];      \
 493      thread->regs.pstate = rawregs->cpsr;                            \
 494                                                                      \
 495      memcpy(thread->fpregs.vregs, rawregs->float_save.regs, 8 * 32); \
 496      thread->fpregs.fpsr = rawregs->float_save.fpsr;                 \
 497      thread->fpregs.fpcr = rawregs->float_save.fpcr;                 \
 498    } while (false)
 499  
 500    if (range.length() == sizeof(MDRawContextARM64_Old)) {
 501      const MDRawContextARM64_Old* rawregs =
 502          range.GetData<MDRawContextARM64_Old>(0);
 503      COPY_REGS(rawregs);
 504    } else {
 505      const MDRawContextARM64* rawregs = range.GetData<MDRawContextARM64>(0);
 506      COPY_REGS(rawregs);
 507    }
 508  #undef COPY_REGS
 509  }
 510  #elif defined(__mips__)
 511  static void
 512  ParseThreadRegisters(CrashedProcess::Thread* thread,
 513                       const MinidumpMemoryRange& range) {
 514    const MDRawContextMIPS* rawregs = range.GetData<MDRawContextMIPS>(0);
 515  
 516    for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
 517      thread->mcontext.gregs[i] = rawregs->iregs[i];
 518  
 519    thread->mcontext.pc = rawregs->epc;
 520  
 521    thread->mcontext.mdlo = rawregs->mdlo;
 522    thread->mcontext.mdhi = rawregs->mdhi;
 523  
 524    thread->mcontext.hi1 = rawregs->hi[0];
 525    thread->mcontext.lo1 = rawregs->lo[0];
 526    thread->mcontext.hi2 = rawregs->hi[1];
 527    thread->mcontext.lo2 = rawregs->lo[1];
 528    thread->mcontext.hi3 = rawregs->hi[2];
 529    thread->mcontext.lo3 = rawregs->lo[2];
 530  
 531    for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) {
 532      thread->mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs =
 533          rawregs->float_save.regs[i];
 534    }
 535  
 536    thread->mcontext.fpc_csr = rawregs->float_save.fpcsr;
 537  #if _MIPS_SIM == _ABIO32
 538    thread->mcontext.fpc_eir = rawregs->float_save.fir;
 539  #endif
 540  }
 541  #elif defined(__riscv)
 542  static void
 543  ParseThreadRegisters(CrashedProcess::Thread* thread,
 544                      const MinidumpMemoryRange& range) {
 545  # if __riscv_xlen == 32
 546    const MDRawContextRISCV* rawregs = range.GetData<MDRawContextRISCV>(0);
 547  # elif __riscv_xlen == 64
 548    const MDRawContextRISCV64* rawregs = range.GetData<MDRawContextRISCV64>(0);
 549  # else
 550  #  error "Unexpected __riscv_xlen"
 551  # endif
 552  
 553    thread->mcontext.__gregs[0]  = rawregs->pc;
 554    thread->mcontext.__gregs[1]  = rawregs->ra;
 555    thread->mcontext.__gregs[2]  = rawregs->sp;
 556    thread->mcontext.__gregs[3]  = rawregs->gp;
 557    thread->mcontext.__gregs[4]  = rawregs->tp;
 558    thread->mcontext.__gregs[5]  = rawregs->t0;
 559    thread->mcontext.__gregs[6]  = rawregs->t1;
 560    thread->mcontext.__gregs[7]  = rawregs->t2;
 561    thread->mcontext.__gregs[8]  = rawregs->s0;
 562    thread->mcontext.__gregs[9]  = rawregs->s1;
 563    thread->mcontext.__gregs[10] = rawregs->a0;
 564    thread->mcontext.__gregs[11] = rawregs->a1;
 565    thread->mcontext.__gregs[12] = rawregs->a2;
 566    thread->mcontext.__gregs[13] = rawregs->a3;
 567    thread->mcontext.__gregs[14] = rawregs->a4;
 568    thread->mcontext.__gregs[15] = rawregs->a5;
 569    thread->mcontext.__gregs[16] = rawregs->a6;
 570    thread->mcontext.__gregs[17] = rawregs->a7;
 571    thread->mcontext.__gregs[18] = rawregs->s2;
 572    thread->mcontext.__gregs[19] = rawregs->s3;
 573    thread->mcontext.__gregs[20] = rawregs->s4;
 574    thread->mcontext.__gregs[21] = rawregs->s5;
 575    thread->mcontext.__gregs[22] = rawregs->s6;
 576    thread->mcontext.__gregs[23] = rawregs->s7;
 577    thread->mcontext.__gregs[24] = rawregs->s8;
 578    thread->mcontext.__gregs[25] = rawregs->s9;
 579    thread->mcontext.__gregs[26] = rawregs->s10;
 580    thread->mcontext.__gregs[27] = rawregs->s11;
 581    thread->mcontext.__gregs[28] = rawregs->t3;
 582    thread->mcontext.__gregs[29] = rawregs->t4;
 583    thread->mcontext.__gregs[30] = rawregs->t5;
 584    thread->mcontext.__gregs[31] = rawregs->t6;
 585  
 586    // Breakpad only supports RISCV32 with 32 bit floating point.
 587    // Breakpad only supports RISCV64 with 64 bit floating point.
 588  #if __riscv_xlen == 32
 589    for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) {
 590      thread->mcontext.__fpregs.__f.__f[i] = rawregs->fpregs[i];
 591    }
 592    thread->mcontext.__fpregs.__f.__fcsr = rawregs->fcsr;
 593  #elif __riscv_xlen == 64
 594    for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; ++i) {
 595      thread->mcontext.__fpregs.__d.__f[i] = rawregs->fpregs[i];
 596    }
 597    thread->mcontext.__fpregs.__d.__fcsr = rawregs->fcsr;
 598  #else
 599  #error "Unexpected __riscv_xlen"
 600  #endif
 601  }
 602  #else
 603  #error "This code has not been ported to your platform yet"
 604  #endif
 605  
 606  static void
 607  ParseThreadList(const Options& options, CrashedProcess* crashinfo,
 608                  const MinidumpMemoryRange& range,
 609                  const MinidumpMemoryRange& full_file) {
 610    const uint32_t num_threads = *range.GetData<uint32_t>(0);
 611    if (options.verbose) {
 612      fprintf(stderr,
 613              "MD_THREAD_LIST_STREAM:\n"
 614              "Found %d threads\n"
 615              "\n\n",
 616              num_threads);
 617    }
 618    for (unsigned i = 0; i < num_threads; ++i) {
 619      CrashedProcess::Thread thread;
 620      memset(&thread, 0, sizeof(thread));
 621      const MDRawThread* rawthread =
 622          range.GetArrayElement<MDRawThread>(sizeof(uint32_t), i);
 623      thread.tid = rawthread->thread_id;
 624      thread.stack_addr = rawthread->stack.start_of_memory_range;
 625      MinidumpMemoryRange stack_range =
 626          full_file.Subrange(rawthread->stack.memory);
 627      thread.stack = stack_range.data();
 628      thread.stack_length = rawthread->stack.memory.data_size;
 629  
 630      ParseThreadRegisters(&thread,
 631                           full_file.Subrange(rawthread->thread_context));
 632  
 633      crashinfo->threads.push_back(thread);
 634    }
 635  }
 636  
 637  static void
 638  ParseSystemInfo(const Options& options, CrashedProcess* crashinfo,
 639                  const MinidumpMemoryRange& range,
 640                  const MinidumpMemoryRange& full_file) {
 641    const MDRawSystemInfo* sysinfo = range.GetData<MDRawSystemInfo>(0);
 642    if (!sysinfo) {
 643      fprintf(stderr, "Failed to access MD_SYSTEM_INFO_STREAM\n");
 644      exit(1);
 645    }
 646  #if defined(__i386__)
 647    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_X86) {
 648      fprintf(stderr,
 649              "This version of minidump-2-core only supports x86 (32bit)%s.\n",
 650              sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64 ?
 651              ",\nbut the minidump file is from a 64bit machine" : "");
 652      exit(1);
 653    }
 654  #elif defined(__x86_64__)
 655    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_AMD64) {
 656      fprintf(stderr,
 657              "This version of minidump-2-core only supports x86 (64bit)%s.\n",
 658              sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ?
 659              ",\nbut the minidump file is from a 32bit machine" : "");
 660      exit(1);
 661    }
 662  #elif defined(__arm__)
 663    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM) {
 664      fprintf(stderr,
 665              "This version of minidump-2-core only supports ARM (32bit).\n");
 666      exit(1);
 667    }
 668  #elif defined(__aarch64__)
 669    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64_OLD &&
 670        sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_ARM64) {
 671      fprintf(stderr,
 672              "This version of minidump-2-core only supports ARM (64bit).\n");
 673      exit(1);
 674    }
 675  #elif defined(__mips__)
 676  # if _MIPS_SIM == _ABIO32
 677    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS) {
 678      fprintf(stderr,
 679              "This version of minidump-2-core only supports mips o32 (32bit).\n");
 680      exit(1);
 681    }
 682  # elif _MIPS_SIM == _ABI64
 683    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_MIPS64) {
 684      fprintf(stderr,
 685              "This version of minidump-2-core only supports mips n64 (64bit).\n");
 686      exit(1);
 687    }
 688  # else
 689  #  error "This mips ABI is currently not supported (n32)"
 690  # endif
 691  #elif defined(__riscv)
 692  # if __riscv_xlen == 32
 693    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV) {
 694      fprintf(stderr,
 695              "This version of minidump-2-core only supports RISCV.\n");
 696      exit(1);
 697    }
 698  # elif __riscv_xlen == 64
 699    if (sysinfo->processor_architecture != MD_CPU_ARCHITECTURE_RISCV64) {
 700      fprintf(stderr,
 701              "This version of minidump-2-core only supports RISCV64.\n");
 702      exit(1);
 703    }
 704  # else
 705  #  error "Unexpected __riscv_xlen"
 706  # endif
 707  #else
 708  #error "This code has not been ported to your platform yet"
 709  #endif
 710    if (sysinfo->platform_id != MD_OS_LINUX &&
 711        sysinfo->platform_id != MD_OS_NACL) {
 712      fprintf(stderr, "This minidump was not generated by Linux or NaCl.\n");
 713      exit(1);
 714    }
 715  
 716    if (options.verbose) {
 717      fprintf(stderr,
 718              "MD_SYSTEM_INFO_STREAM:\n"
 719              "Architecture: %s\n"
 720              "Number of processors: %d\n"
 721              "Processor level: %d\n"
 722              "Processor model: %d\n"
 723              "Processor stepping: %d\n",
 724              sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86
 725              ? "i386"
 726              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64
 727              ? "x86-64"
 728              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_ARM
 729              ? "ARM"
 730              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS
 731              ? "MIPS"
 732              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_MIPS64
 733              ? "MIPS64"
 734              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV
 735              ? "RISCV"
 736              : sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_RISCV64
 737              ? "RISCV64"
 738              : "???",
 739              sysinfo->number_of_processors,
 740              sysinfo->processor_level,
 741              sysinfo->processor_revision >> 8,
 742              sysinfo->processor_revision & 0xFF);
 743      if (sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
 744          sysinfo->processor_architecture == MD_CPU_ARCHITECTURE_AMD64) {
 745        fputs("Vendor id: ", stderr);
 746        const char *nul =
 747          (const char*)memchr(sysinfo->cpu.x86_cpu_info.vendor_id, 0,
 748                               sizeof(sysinfo->cpu.x86_cpu_info.vendor_id));
 749        fwrite(sysinfo->cpu.x86_cpu_info.vendor_id,
 750               nul ? nul - (const char*)&sysinfo->cpu.x86_cpu_info.vendor_id[0]
 751               : sizeof(sysinfo->cpu.x86_cpu_info.vendor_id), 1, stderr);
 752        fputs("\n", stderr);
 753      }
 754      fprintf(stderr, "OS: %s\n",
 755              full_file.GetAsciiMDString(sysinfo->csd_version_rva).c_str());
 756      fputs("\n\n", stderr);
 757    }
 758  }
 759  
 760  static void
 761  ParseCPUInfo(const Options& options, CrashedProcess* crashinfo,
 762               const MinidumpMemoryRange& range) {
 763    if (options.verbose) {
 764      fputs("MD_LINUX_CPU_INFO:\n", stderr);
 765      fwrite(range.data(), range.length(), 1, stderr);
 766      fputs("\n\n\n", stderr);
 767    }
 768  }
 769  
 770  static void
 771  ParseProcessStatus(const Options& options, CrashedProcess* crashinfo,
 772                     const MinidumpMemoryRange& range) {
 773    if (options.verbose) {
 774      fputs("MD_LINUX_PROC_STATUS:\n", stderr);
 775      fwrite(range.data(), range.length(), 1, stderr);
 776      fputs("\n\n", stderr);
 777    }
 778  }
 779  
 780  static void
 781  ParseLSBRelease(const Options& options, CrashedProcess* crashinfo,
 782                  const MinidumpMemoryRange& range) {
 783    if (options.verbose) {
 784      fputs("MD_LINUX_LSB_RELEASE:\n", stderr);
 785      fwrite(range.data(), range.length(), 1, stderr);
 786      fputs("\n\n", stderr);
 787    }
 788  }
 789  
 790  static void
 791  ParseMaps(const Options& options, CrashedProcess* crashinfo,
 792            const MinidumpMemoryRange& range) {
 793    if (options.verbose) {
 794      fputs("MD_LINUX_MAPS:\n", stderr);
 795      fwrite(range.data(), range.length(), 1, stderr);
 796    }
 797    for (const uint8_t* ptr = range.data();
 798         ptr < range.data() + range.length();) {
 799      const uint8_t* eol = (uint8_t*)memchr(ptr, '\n',
 800                                         range.data() + range.length() - ptr);
 801      string line((const char*)ptr,
 802                  eol ? eol - ptr : range.data() + range.length() - ptr);
 803      ptr = eol ? eol + 1 : range.data() + range.length();
 804      unsigned long long start, stop, offset;
 805      char* permissions = NULL;
 806      char* filename = NULL;
 807      sscanf(line.c_str(), "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
 808             &start, &stop, &permissions, &offset, &filename);
 809      if (filename && *filename == '/') {
 810        CrashedProcess::Mapping mapping;
 811        mapping.permissions = 0;
 812        if (strchr(permissions, 'r')) {
 813          mapping.permissions |= PF_R;
 814        }
 815        if (strchr(permissions, 'w')) {
 816          mapping.permissions |= PF_W;
 817        }
 818        if (strchr(permissions, 'x')) {
 819          mapping.permissions |= PF_X;
 820        }
 821        mapping.start_address = start;
 822        mapping.end_address = stop;
 823        mapping.offset = offset;
 824        if (filename) {
 825          mapping.filename = filename;
 826        }
 827        crashinfo->mappings[mapping.start_address] = mapping;
 828      }
 829      free(permissions);
 830      free(filename);
 831    }
 832    if (options.verbose) {
 833      fputs("\n\n\n", stderr);
 834    }
 835  }
 836  
 837  static void
 838  ParseEnvironment(const Options& options, CrashedProcess* crashinfo,
 839                   const MinidumpMemoryRange& range) {
 840    if (options.verbose) {
 841      fputs("MD_LINUX_ENVIRON:\n", stderr);
 842      char* env = new char[range.length()];
 843      memcpy(env, range.data(), range.length());
 844      int nul_count = 0;
 845      for (char *ptr = env;;) {
 846        ptr = (char*)memchr(ptr, '\000', range.length() - (ptr - env));
 847        if (!ptr) {
 848          break;
 849        }
 850        if (ptr > env && ptr[-1] == '\n') {
 851          if (++nul_count > 5) {
 852            // Some versions of Chrome try to rewrite the process' command line
 853            // in a way that causes the environment to be corrupted. Afterwards,
 854            // part of the environment will contain the trailing bit of the
 855            // command line. The rest of the environment will be filled with
 856            // NUL bytes.
 857            // We detect this corruption by counting the number of consecutive
 858            // NUL bytes. Normally, we would not expect any consecutive NUL
 859            // bytes. But we are conservative and only suppress printing of
 860            // the environment if we see at least five consecutive NULs.
 861            fputs("Environment has been corrupted; no data available", stderr);
 862            goto env_corrupted;
 863          }
 864        } else {
 865          nul_count = 0;
 866        }
 867        *ptr = '\n';
 868      }
 869      fwrite(env, range.length(), 1, stderr);
 870    env_corrupted:
 871      delete[] env;
 872      fputs("\n\n\n", stderr);
 873    }
 874  }
 875  
 876  static void
 877  ParseAuxVector(const Options& options, CrashedProcess* crashinfo,
 878                 const MinidumpMemoryRange& range) {
 879    // Some versions of Chrome erroneously used the MD_LINUX_AUXV stream value
 880    // when dumping /proc/$x/maps
 881    if (range.length() > 17) {
 882      // The AUXV vector contains binary data, whereas the maps always begin
 883      // with an 8+ digit hex address followed by a hyphen and another 8+ digit
 884      // address.
 885      char addresses[18];
 886      memcpy(addresses, range.data(), 17);
 887      addresses[17] = '\000';
 888      if (strspn(addresses, "0123456789abcdef-") == 17) {
 889        ParseMaps(options, crashinfo, range);
 890        return;
 891      }
 892    }
 893  
 894    crashinfo->auxv = range.data();
 895    crashinfo->auxv_length = range.length();
 896  }
 897  
 898  static void
 899  ParseCmdLine(const Options& options, CrashedProcess* crashinfo,
 900               const MinidumpMemoryRange& range) {
 901    // The command line is supposed to use NUL bytes to separate arguments.
 902    // As Chrome rewrites its own command line and (incorrectly) substitutes
 903    // spaces, this is often not the case in our minidump files.
 904    const char* cmdline = (const char*) range.data();
 905    if (options.verbose) {
 906      fputs("MD_LINUX_CMD_LINE:\n", stderr);
 907      unsigned i = 0;
 908      for (; i < range.length() && cmdline[i] && cmdline[i] != ' '; ++i) { }
 909      fputs("argv[0] = \"", stderr);
 910      fwrite(cmdline, i, 1, stderr);
 911      fputs("\"\n", stderr);
 912      for (unsigned j = ++i, argc = 1; j < range.length(); ++j) {
 913        if (!cmdline[j] || cmdline[j] == ' ') {
 914          fprintf(stderr, "argv[%d] = \"", argc++);
 915          fwrite(cmdline + i, j - i, 1, stderr);
 916          fputs("\"\n", stderr);
 917          i = j + 1;
 918        }
 919      }
 920      fputs("\n\n", stderr);
 921    }
 922  
 923    const char *binary_name = cmdline;
 924    for (size_t i = 0; i < range.length(); ++i) {
 925      if (cmdline[i] == '/') {
 926        binary_name = cmdline + i + 1;
 927      } else if (cmdline[i] == 0 || cmdline[i] == ' ') {
 928        static const size_t fname_len = sizeof(crashinfo->prps.pr_fname) - 1;
 929        static const size_t args_len = sizeof(crashinfo->prps.pr_psargs) - 1;
 930        memset(crashinfo->prps.pr_fname, 0, fname_len + 1);
 931        memset(crashinfo->prps.pr_psargs, 0, args_len + 1);
 932        unsigned len = cmdline + i - binary_name;
 933        memcpy(crashinfo->prps.pr_fname, binary_name,
 934                 len > fname_len ? fname_len : len);
 935  
 936        len = range.length() > args_len ? args_len : range.length();
 937        memcpy(crashinfo->prps.pr_psargs, cmdline, len);
 938        for (unsigned j = 0; j < len; ++j) {
 939          if (crashinfo->prps.pr_psargs[j] == 0)
 940            crashinfo->prps.pr_psargs[j] = ' ';
 941        }
 942        break;
 943      }
 944    }
 945  }
 946  
 947  static void
 948  ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo,
 949                    const MinidumpMemoryRange& range,
 950                    const MinidumpMemoryRange& full_file) {
 951    const MDRawDebug* debug = range.GetData<MDRawDebug>(0);
 952    if (!debug) {
 953      return;
 954    }
 955    if (options.verbose) {
 956      fprintf(stderr,
 957              "MD_LINUX_DSO_DEBUG:\n"
 958              "Version: %d\n"
 959              "Number of DSOs: %d\n"
 960              "Brk handler: 0x%" PRIx64 "\n"
 961              "Dynamic loader at: 0x%" PRIx64 "\n"
 962              "_DYNAMIC: 0x%" PRIx64 "\n",
 963              debug->version,
 964              debug->dso_count,
 965              static_cast<uint64_t>(debug->brk),
 966              static_cast<uint64_t>(debug->ldbase),
 967              static_cast<uint64_t>(debug->dynamic));
 968    }
 969    crashinfo->debug = *debug;
 970    if (range.length() > sizeof(MDRawDebug)) {
 971      char* dynamic_data = (char*)range.data() + sizeof(MDRawDebug);
 972      crashinfo->dynamic_data.assign(dynamic_data,
 973                                     range.length() - sizeof(MDRawDebug));
 974    }
 975    if (debug->map != kInvalidMDRVA) {
 976      for (unsigned int i = 0; i < debug->dso_count; ++i) {
 977        const MDRawLinkMap* link_map =
 978            full_file.GetArrayElement<MDRawLinkMap>(debug->map, i);
 979        if (link_map) {
 980          if (options.verbose) {
 981            fprintf(stderr,
 982                    "#%03d: %" PRIx64 ", %" PRIx64 ", \"%s\"\n",
 983                    i, static_cast<uint64_t>(link_map->addr),
 984                    static_cast<uint64_t>(link_map->ld),
 985                    full_file.GetAsciiMDString(link_map->name).c_str());
 986          }
 987          crashinfo->link_map.push_back(*link_map);
 988        }
 989      }
 990    }
 991    if (options.verbose) {
 992      fputs("\n\n", stderr);
 993    }
 994  }
 995  
 996  static void
 997  ParseExceptionStream(const Options& options, CrashedProcess* crashinfo,
 998                       const MinidumpMemoryRange& range,
 999                       const MinidumpMemoryRange& full_file) {
1000    const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0);
1001    if (!exp) {
1002      return;
1003    }
1004    if (options.verbose) {
1005      fprintf(stderr,
1006              "MD_EXCEPTION_STREAM:\n"
1007              "Found exception thread %" PRIu32 " \n"
1008              "\n\n",
1009              exp->thread_id);
1010    }
1011    crashinfo->fatal_signal = (int) exp->exception_record.exception_code;
1012    crashinfo->exception = {};
1013    crashinfo->exception.tid = exp->thread_id;
1014    // crashinfo->threads[].tid == crashinfo->exception.tid provides the stack.
1015    ParseThreadRegisters(&crashinfo->exception,
1016                         full_file.Subrange(exp->thread_context));
1017  }
1018  
1019  static bool
1020  WriteThread(const Options& options, const CrashedProcess::Thread& thread,
1021              int fatal_signal) {
1022    struct prstatus pr;
1023    memset(&pr, 0, sizeof(pr));
1024  
1025    pr.pr_info.si_signo = fatal_signal;
1026    pr.pr_cursig = fatal_signal;
1027    pr.pr_pid = thread.tid;
1028  #if defined(__mips__)
1029    memcpy(&pr.pr_reg, &thread.mcontext.gregs, sizeof(user_regs_struct));
1030  #elif defined(__riscv)
1031    memcpy(&pr.pr_reg, &thread.mcontext.__gregs, sizeof(user_regs_struct));
1032  #else
1033    memcpy(&pr.pr_reg, &thread.regs, sizeof(user_regs_struct));
1034  #endif
1035  
1036    Nhdr nhdr;
1037    memset(&nhdr, 0, sizeof(nhdr));
1038    nhdr.n_namesz = 5;
1039    nhdr.n_descsz = sizeof(struct prstatus);
1040    nhdr.n_type = NT_PRSTATUS;
1041    if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
1042        !writea(options.out_fd, "CORE\0\0\0\0", 8) ||
1043        !writea(options.out_fd, &pr, sizeof(struct prstatus))) {
1044      return false;
1045    }
1046  
1047  #if defined(__i386__) || defined(__x86_64__)
1048    nhdr.n_descsz = sizeof(user_fpregs_struct);
1049    nhdr.n_type = NT_FPREGSET;
1050    if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
1051        !writea(options.out_fd, "CORE\0\0\0\0", 8) ||
1052        !writea(options.out_fd, &thread.fpregs, sizeof(user_fpregs_struct))) {
1053      return false;
1054    }
1055  #endif
1056  
1057  #if defined(__i386__)
1058    nhdr.n_descsz = sizeof(user_fpxregs_struct);
1059    nhdr.n_type = NT_PRXFPREG;
1060    if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
1061        !writea(options.out_fd, "LINUX\0\0\0", 8) ||
1062        !writea(options.out_fd, &thread.fpxregs, sizeof(user_fpxregs_struct))) {
1063      return false;
1064    }
1065  #endif
1066  
1067    return true;
1068  }
1069  
1070  static void
1071  ParseModuleStream(const Options& options, CrashedProcess* crashinfo,
1072                    const MinidumpMemoryRange& range,
1073                    const MinidumpMemoryRange& full_file) {
1074    if (options.verbose) {
1075      fputs("MD_MODULE_LIST_STREAM:\n", stderr);
1076    }
1077    const uint32_t num_mappings = *range.GetData<uint32_t>(0);
1078    for (unsigned i = 0; i < num_mappings; ++i) {
1079      CrashedProcess::Mapping mapping;
1080      const MDRawModule* rawmodule = reinterpret_cast<const MDRawModule*>(
1081          range.GetArrayElement(sizeof(uint32_t), MD_MODULE_SIZE, i));
1082      mapping.start_address = rawmodule->base_of_image;
1083      mapping.end_address = rawmodule->size_of_image + rawmodule->base_of_image;
1084  
1085      if (crashinfo->mappings.find(mapping.start_address) ==
1086          crashinfo->mappings.end()) {
1087        // We prefer data from MD_LINUX_MAPS over MD_MODULE_LIST_STREAM, as
1088        // the former is a strict superset of the latter.
1089        crashinfo->mappings[mapping.start_address] = mapping;
1090      }
1091  
1092      const MDCVInfoPDB70* record = reinterpret_cast<const MDCVInfoPDB70*>(
1093          full_file.GetData(rawmodule->cv_record.rva, MDCVInfoPDB70_minsize));
1094      char guid[40];
1095      sprintf(guid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1096              record->signature.data1, record->signature.data2,
1097              record->signature.data3,
1098              record->signature.data4[0], record->signature.data4[1],
1099              record->signature.data4[2], record->signature.data4[3],
1100              record->signature.data4[4], record->signature.data4[5],
1101              record->signature.data4[6], record->signature.data4[7]);
1102  
1103      string filename = full_file.GetAsciiMDString(rawmodule->module_name_rva);
1104  
1105      CrashedProcess::Signature signature;
1106      strcpy(signature.guid, guid);
1107      signature.filename = filename;
1108      crashinfo->signatures[rawmodule->base_of_image] = signature;
1109  
1110      if (options.verbose) {
1111        fprintf(stderr, "0x%" PRIx64 "-0x%" PRIx64 ", ChkSum: 0x%08X, GUID: %s, "
1112                " \"%s\"\n",
1113                rawmodule->base_of_image,
1114                rawmodule->base_of_image + rawmodule->size_of_image,
1115                rawmodule->checksum, guid, filename.c_str());
1116      }
1117    }
1118    if (options.verbose) {
1119      fputs("\n\n", stderr);
1120    }
1121  }
1122  
1123  static void
1124  AddDataToMapping(CrashedProcess* crashinfo, const string& data,
1125                   uintptr_t addr) {
1126    for (std::map<uint64_t, CrashedProcess::Mapping>::iterator
1127           iter = crashinfo->mappings.begin();
1128         iter != crashinfo->mappings.end();
1129         ++iter) {
1130      if (addr >= iter->second.start_address &&
1131          addr < iter->second.end_address) {
1132        CrashedProcess::Mapping mapping = iter->second;
1133        if ((addr & ~4095) != iter->second.start_address) {
1134          // If there are memory pages in the mapping prior to where the
1135          // data starts, truncate the existing mapping so that it ends with
1136          // the page immediately preceding the data region.
1137          iter->second.end_address = addr & ~4095;
1138          if (!mapping.filename.empty()) {
1139            // "mapping" is a copy of "iter->second". We are splitting the
1140            // existing mapping into two separate ones when we write the data
1141            // to the core file. The first one does not have any associated
1142            // data in the core file, the second one is backed by data that is
1143            // included with the core file.
1144            // If this mapping wasn't supposed to be anonymous, then we also
1145            // have to update the file offset upon splitting the mapping.
1146            mapping.offset += iter->second.end_address -
1147              iter->second.start_address;
1148          }
1149        }
1150        // Create a new mapping that contains the data contents. We often
1151        // limit the amount of data that is actually written to the core
1152        // file. But it is OK if the mapping itself extends past the end of
1153        // the data.
1154        mapping.start_address = addr & ~4095;
1155        mapping.data.assign(addr & 4095, 0).append(data);
1156        mapping.data.append(-mapping.data.size() & 4095, 0);
1157        crashinfo->mappings[mapping.start_address] = mapping;
1158        return;
1159      }
1160    }
1161    // Didn't find a suitable existing mapping for the data. Create a new one.
1162    CrashedProcess::Mapping mapping;
1163    mapping.permissions = PF_R | PF_W;
1164    mapping.start_address = addr & ~4095;
1165    mapping.end_address =
1166      (addr + data.size() + 4095) & ~4095;
1167    mapping.data.assign(addr & 4095, 0).append(data);
1168    mapping.data.append(-mapping.data.size() & 4095, 0);
1169    crashinfo->mappings[mapping.start_address] = mapping;
1170  }
1171  
1172  static void
1173  AugmentMappings(const Options& options, CrashedProcess* crashinfo,
1174                  const MinidumpMemoryRange& full_file) {
1175    // For each thread, find the memory mapping that matches the thread's stack.
1176    // Then adjust the mapping to include the stack dump.
1177    for (unsigned i = 0; i < crashinfo->threads.size(); ++i) {
1178      const CrashedProcess::Thread& thread = crashinfo->threads[i];
1179      AddDataToMapping(crashinfo,
1180                       string((char*)thread.stack, thread.stack_length),
1181                       thread.stack_addr);
1182    }
1183  
1184    // Create a new link map with information about DSOs. We move this map to
1185    // the beginning of the address space, as this area should always be
1186    // available.
1187    static const uintptr_t start_addr = 4096;
1188    string data;
1189    struct r_debug debug = { 0 };
1190    debug.r_version = crashinfo->debug.version;
1191    debug.r_brk = (ElfW(Addr))crashinfo->debug.brk;
1192    debug.r_state = r_debug::RT_CONSISTENT;
1193    debug.r_ldbase = (ElfW(Addr))crashinfo->debug.ldbase;
1194    debug.r_map = crashinfo->debug.dso_count > 0 ?
1195      (struct link_map*)(start_addr + sizeof(debug)) : 0;
1196    data.append((char*)&debug, sizeof(debug));
1197  
1198    struct link_map* prev = 0;
1199    for (std::vector<MDRawLinkMap>::iterator iter = crashinfo->link_map.begin();
1200         iter != crashinfo->link_map.end();
1201         ++iter) {
1202      struct link_map link_map = { 0 };
1203      link_map.l_addr = (ElfW(Addr))iter->addr;
1204      link_map.l_name = (char*)(start_addr + data.size() + sizeof(link_map));
1205      link_map.l_ld = (ElfW(Dyn)*)iter->ld;
1206      link_map.l_prev = prev;
1207      prev = (struct link_map*)(start_addr + data.size());
1208      string filename = full_file.GetAsciiMDString(iter->name);
1209  
1210      // Look up signature for this filename. If available, change filename
1211      // to point to GUID, instead.
1212      std::map<uintptr_t, CrashedProcess::Signature>::const_iterator sig =
1213        crashinfo->signatures.find((uintptr_t)iter->addr);
1214      if (sig != crashinfo->signatures.end()) {
1215        // At this point, we have:
1216        // old_filename: The path as found via SONAME (e.g. /lib/libpthread.so.0).
1217        // sig_filename: The path on disk (e.g. /lib/libpthread-2.19.so).
1218        const char* guid = sig->second.guid;
1219        string sig_filename = sig->second.filename;
1220        string old_filename = filename.empty() ? sig_filename : filename;
1221        string new_filename;
1222  
1223        // First set up the leading path.  We assume dirname always ends with a
1224        // trailing slash (as needed), so we won't be appending one manually.
1225        if (options.so_basedir.empty()) {
1226          string dirname;
1227          if (options.use_filename) {
1228            dirname = sig_filename;
1229          } else {
1230            dirname = old_filename;
1231          }
1232          size_t slash = dirname.find_last_of('/');
1233          if (slash != string::npos) {
1234            new_filename = dirname.substr(0, slash + 1);
1235          }
1236        } else {
1237          new_filename = options.so_basedir;
1238        }
1239  
1240        // Insert the module ID if requested.
1241        if (options.inc_guid &&
1242            strcmp(guid, "00000000-0000-0000-0000-000000000000") != 0) {
1243          new_filename += guid;
1244          new_filename += "-";
1245        }
1246  
1247        // Decide whether we use the filename or the SONAME (where the SONAME tends
1248        // to be a symlink to the actual file).
1249        new_filename += google_breakpad::BaseName(
1250            options.use_filename ? sig_filename : old_filename);
1251  
1252        if (filename != new_filename) {
1253          if (options.verbose) {
1254            fprintf(stderr, "0x%" PRIx64": rewriting mapping \"%s\" to \"%s\"\n",
1255                    static_cast<uint64_t>(link_map.l_addr),
1256                    filename.c_str(), new_filename.c_str());
1257          }
1258          filename = new_filename;
1259        }
1260      }
1261  
1262      if (std::distance(iter, crashinfo->link_map.end()) == 1) {
1263        link_map.l_next = 0;
1264      } else {
1265        link_map.l_next = (struct link_map*)(start_addr + data.size() +
1266                                             sizeof(link_map) +
1267                                             ((filename.size() + 8) & ~7));
1268      }
1269      data.append((char*)&link_map, sizeof(link_map));
1270      data.append(filename);
1271      data.append(8 - (filename.size() & 7), 0);
1272    }
1273    AddDataToMapping(crashinfo, data, start_addr);
1274  
1275    // Map the page containing the _DYNAMIC array
1276    if (!crashinfo->dynamic_data.empty()) {
1277      // Make _DYNAMIC DT_DEBUG entry point to our link map
1278      for (int i = 0;; ++i) {
1279        ElfW(Dyn) dyn;
1280        if ((i+1)*sizeof(dyn) > crashinfo->dynamic_data.length()) {
1281        no_dt_debug:
1282          if (options.verbose) {
1283            fprintf(stderr, "No DT_DEBUG entry found\n");
1284          }
1285          return;
1286        }
1287        memcpy(&dyn, crashinfo->dynamic_data.c_str() + i*sizeof(dyn),
1288               sizeof(dyn));
1289        if (dyn.d_tag == DT_DEBUG) {
1290          crashinfo->dynamic_data.replace(i*sizeof(dyn) +
1291                                         offsetof(ElfW(Dyn), d_un.d_ptr),
1292                                         sizeof(start_addr),
1293                                         (char*)&start_addr, sizeof(start_addr));
1294          break;
1295        } else if (dyn.d_tag == DT_NULL) {
1296          goto no_dt_debug;
1297        }
1298      }
1299      AddDataToMapping(crashinfo, crashinfo->dynamic_data,
1300                       (uintptr_t)crashinfo->debug.dynamic);
1301    }
1302  }
1303  
1304  int
1305  main(int argc, const char* argv[]) {
1306    Options options;
1307    SetupOptions(argc, argv, &options);
1308  
1309    MemoryMappedFile mapped_file(options.minidump_path.c_str(), 0);
1310    if (!mapped_file.data()) {
1311      fprintf(stderr, "Failed to mmap dump file: %s: %s\n",
1312              options.minidump_path.c_str(), strerror(errno));
1313      return 1;
1314    }
1315  
1316    MinidumpMemoryRange dump(mapped_file.data(), mapped_file.size());
1317  
1318    const MDRawHeader* header = dump.GetData<MDRawHeader>(0);
1319  
1320    CrashedProcess crashinfo;
1321  
1322    // Always check the system info first, as that allows us to tell whether
1323    // this is a minidump file that is compatible with our converter.
1324    bool ok = false;
1325    for (unsigned i = 0; i < header->stream_count; ++i) {
1326      const MDRawDirectory* dirent =
1327          dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
1328      switch (dirent->stream_type) {
1329        case MD_SYSTEM_INFO_STREAM:
1330          ParseSystemInfo(options, &crashinfo, dump.Subrange(dirent->location),
1331                          dump);
1332          ok = true;
1333          break;
1334        default:
1335          break;
1336      }
1337    }
1338    if (!ok) {
1339      fprintf(stderr, "Cannot determine input file format.\n");
1340      exit(1);
1341    }
1342  
1343    for (unsigned i = 0; i < header->stream_count; ++i) {
1344      const MDRawDirectory* dirent =
1345          dump.GetArrayElement<MDRawDirectory>(header->stream_directory_rva, i);
1346      switch (dirent->stream_type) {
1347        case MD_THREAD_LIST_STREAM:
1348          ParseThreadList(options, &crashinfo, dump.Subrange(dirent->location),
1349                          dump);
1350          break;
1351        case MD_LINUX_CPU_INFO:
1352          ParseCPUInfo(options, &crashinfo, dump.Subrange(dirent->location));
1353          break;
1354        case MD_LINUX_PROC_STATUS:
1355          ParseProcessStatus(options, &crashinfo,
1356                             dump.Subrange(dirent->location));
1357          break;
1358        case MD_LINUX_LSB_RELEASE:
1359          ParseLSBRelease(options, &crashinfo, dump.Subrange(dirent->location));
1360          break;
1361        case MD_LINUX_ENVIRON:
1362          ParseEnvironment(options, &crashinfo, dump.Subrange(dirent->location));
1363          break;
1364        case MD_LINUX_MAPS:
1365          ParseMaps(options, &crashinfo, dump.Subrange(dirent->location));
1366          break;
1367        case MD_LINUX_AUXV:
1368          ParseAuxVector(options, &crashinfo, dump.Subrange(dirent->location));
1369          break;
1370        case MD_LINUX_CMD_LINE:
1371          ParseCmdLine(options, &crashinfo, dump.Subrange(dirent->location));
1372          break;
1373        case MD_LINUX_DSO_DEBUG:
1374          ParseDSODebugInfo(options, &crashinfo, dump.Subrange(dirent->location),
1375                            dump);
1376          break;
1377        case MD_EXCEPTION_STREAM:
1378          ParseExceptionStream(options, &crashinfo,
1379                               dump.Subrange(dirent->location), dump);
1380          break;
1381        case MD_MODULE_LIST_STREAM:
1382          ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location),
1383                            dump);
1384          break;
1385        default:
1386          if (options.verbose)
1387            fprintf(stderr, "Skipping %x\n", dirent->stream_type);
1388      }
1389    }
1390  
1391    AugmentMappings(options, &crashinfo, dump);
1392  
1393    // Write the ELF header. The file will look like:
1394    //   ELF header
1395    //   Phdr for the PT_NOTE
1396    //   Phdr for each of the thread stacks
1397    //   PT_NOTE
1398    //   each of the thread stacks
1399    Ehdr ehdr;
1400    memset(&ehdr, 0, sizeof(Ehdr));
1401    ehdr.e_ident[0] = ELFMAG0;
1402    ehdr.e_ident[1] = ELFMAG1;
1403    ehdr.e_ident[2] = ELFMAG2;
1404    ehdr.e_ident[3] = ELFMAG3;
1405    ehdr.e_ident[4] = ELF_CLASS;
1406    ehdr.e_ident[5] = sex() ? ELFDATA2MSB : ELFDATA2LSB;
1407    ehdr.e_ident[6] = EV_CURRENT;
1408    ehdr.e_type     = ET_CORE;
1409    ehdr.e_machine  = ELF_ARCH;
1410    ehdr.e_version  = EV_CURRENT;
1411    ehdr.e_phoff    = sizeof(Ehdr);
1412    ehdr.e_ehsize   = sizeof(Ehdr);
1413    ehdr.e_phentsize= sizeof(Phdr);
1414    ehdr.e_phnum    = 1 +                         // PT_NOTE
1415                      crashinfo.mappings.size();  // memory mappings
1416    ehdr.e_shentsize= sizeof(Shdr);
1417    if (!writea(options.out_fd, &ehdr, sizeof(Ehdr)))
1418      return 1;
1419  
1420    size_t offset = sizeof(Ehdr) + ehdr.e_phnum * sizeof(Phdr);
1421    size_t filesz = sizeof(Nhdr) + 8 + sizeof(prpsinfo) +
1422                    // sizeof(Nhdr) + 8 + sizeof(user) +
1423                    sizeof(Nhdr) + 8 + crashinfo.auxv_length +
1424                    crashinfo.threads.size() * (
1425                      (sizeof(Nhdr) + 8 + sizeof(prstatus))
1426  #if defined(__i386__) || defined(__x86_64__)
1427                     + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct)
1428  #endif
1429  #if defined(__i386__)
1430                     + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct)
1431  #endif
1432                      );
1433  
1434    Phdr phdr;
1435    memset(&phdr, 0, sizeof(Phdr));
1436    phdr.p_type = PT_NOTE;
1437    phdr.p_offset = offset;
1438    phdr.p_filesz = filesz;
1439    if (!writea(options.out_fd, &phdr, sizeof(phdr)))
1440      return 1;
1441  
1442    phdr.p_type = PT_LOAD;
1443    phdr.p_align = 4096;
1444    size_t note_align = phdr.p_align - ((offset+filesz) % phdr.p_align);
1445    if (note_align == phdr.p_align)
1446      note_align = 0;
1447    offset += note_align;
1448  
1449    for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter =
1450           crashinfo.mappings.begin();
1451         iter != crashinfo.mappings.end(); ++iter) {
1452      const CrashedProcess::Mapping& mapping = iter->second;
1453      if (mapping.permissions == 0xFFFFFFFF) {
1454        // This is a map that we found in MD_MODULE_LIST_STREAM (as opposed to
1455        // MD_LINUX_MAPS). It lacks some of the information that we would like
1456        // to include.
1457        phdr.p_flags = PF_R;
1458      } else {
1459        phdr.p_flags = mapping.permissions;
1460      }
1461      phdr.p_vaddr = mapping.start_address;
1462      phdr.p_memsz = mapping.end_address - mapping.start_address;
1463      if (mapping.data.size()) {
1464        offset += filesz;
1465        filesz = mapping.data.size();
1466        phdr.p_filesz = mapping.data.size();
1467        phdr.p_offset = offset;
1468      } else {
1469        phdr.p_filesz = 0;
1470        phdr.p_offset = 0;
1471      }
1472      if (!writea(options.out_fd, &phdr, sizeof(phdr)))
1473        return 1;
1474    }
1475  
1476    Nhdr nhdr;
1477    memset(&nhdr, 0, sizeof(nhdr));
1478    nhdr.n_namesz = 5;
1479    nhdr.n_descsz = sizeof(prpsinfo);
1480    nhdr.n_type = NT_PRPSINFO;
1481    if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
1482        !writea(options.out_fd, "CORE\0\0\0\0", 8) ||
1483        !writea(options.out_fd, &crashinfo.prps, sizeof(prpsinfo))) {
1484      return 1;
1485    }
1486  
1487    nhdr.n_descsz = crashinfo.auxv_length;
1488    nhdr.n_type = NT_AUXV;
1489    if (!writea(options.out_fd, &nhdr, sizeof(nhdr)) ||
1490        !writea(options.out_fd, "CORE\0\0\0\0", 8) ||
1491        !writea(options.out_fd, crashinfo.auxv, crashinfo.auxv_length)) {
1492      return 1;
1493    }
1494  
1495    for (const auto& current_thread : crashinfo.threads) {
1496      if (current_thread.tid == crashinfo.exception.tid) {
1497        // Use the exception record's context for the crashed thread instead of
1498        // the thread's own context. For the crashed thread the thread's own
1499        // context is the state inside the exception handler. Using it would not
1500        // result in the expected stack trace from the time of the crash.
1501        // The stack memory has already been provided by current_thread.
1502        WriteThread(options, crashinfo.exception, crashinfo.fatal_signal);
1503        break;
1504      }
1505    }
1506  
1507    for (const auto& current_thread : crashinfo.threads) {
1508      if (current_thread.tid != crashinfo.exception.tid)
1509        WriteThread(options, current_thread, 0);
1510    }
1511  
1512    if (note_align) {
1513      google_breakpad::scoped_array<char> scratch(new char[note_align]);
1514      memset(scratch.get(), 0, note_align);
1515      if (!writea(options.out_fd, scratch.get(), note_align))
1516        return 1;
1517    }
1518  
1519    for (std::map<uint64_t, CrashedProcess::Mapping>::const_iterator iter =
1520           crashinfo.mappings.begin();
1521         iter != crashinfo.mappings.end(); ++iter) {
1522      const CrashedProcess::Mapping& mapping = iter->second;
1523      if (mapping.data.size()) {
1524        if (!writea(options.out_fd, mapping.data.c_str(), mapping.data.size()))
1525          return 1;
1526      }
1527    }
1528  
1529    if (options.out_fd != STDOUT_FILENO) {
1530      close(options.out_fd);
1531    }
1532  
1533    return 0;
1534  }