PageRenderTime 125ms CodeModel.GetById 16ms app.highlight 98ms RepoModel.GetById 1ms app.codeStats 1ms

/thirdparty/breakpad/client/linux/minidump_writer/minidump_writer.cc

http://github.com/tomahawk-player/tomahawk
C++ | 1349 lines | 1029 code | 171 blank | 149 comment | 140 complexity | 2727c7e250cf00f39f471e45993a31d8 MD5 | raw file
   1// Copyright (c) 2010, 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// This code writes out minidump files:
  31//   http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
  32//
  33// Minidumps are a Microsoft format which Breakpad uses for recording crash
  34// dumps. This code has to run in a compromised environment (the address space
  35// may have received SIGSEGV), thus the following rules apply:
  36//   * You may not enter the dynamic linker. This means that we cannot call
  37//     any symbols in a shared library (inc libc). Because of this we replace
  38//     libc functions in linux_libc_support.h.
  39//   * You may not call syscalls via the libc wrappers. This rule is a subset
  40//     of the first rule but it bears repeating. We have direct wrappers
  41//     around the system calls in linux_syscall_support.h.
  42//   * You may not malloc. There's an alternative allocator in memory.h and
  43//     a canonical instance in the LinuxDumper object. We use the placement
  44//     new form to allocate objects and we don't delete them.
  45
  46#include "client/linux/minidump_writer/minidump_writer.h"
  47#include "client/minidump_file_writer-inl.h"
  48
  49#include <ctype.h>
  50#include <errno.h>
  51#include <fcntl.h>
  52#if !defined(__ANDROID__)
  53#include <link.h>
  54#endif
  55#include <stdio.h>
  56#if !defined(__ANDROID__)
  57#include <sys/ucontext.h>
  58#include <sys/user.h>
  59#endif
  60#include <sys/utsname.h>
  61#include <unistd.h>
  62
  63#include <algorithm>
  64
  65#include "client/minidump_file_writer.h"
  66#include "google_breakpad/common/minidump_format.h"
  67
  68#if defined(__ANDROID__)
  69#include "client/linux/android_link.h"
  70#include "client/linux/android_ucontext.h"
  71#endif
  72#include "client/linux/handler/exception_handler.h"
  73#include "client/linux/minidump_writer/line_reader.h"
  74#include "client/linux/minidump_writer/linux_dumper.h"
  75#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
  76#include "client/linux/minidump_writer/minidump_extension_linux.h"
  77#include "client/minidump_file_writer.h"
  78#include "common/linux/linux_libc_support.h"
  79#include "google_breakpad/common/minidump_format.h"
  80#include "third_party/lss/linux_syscall_support.h"
  81
  82// Minidump defines register structures which are different from the raw
  83// structures which we get from the kernel. These are platform specific
  84// functions to juggle the ucontext and user structures into minidump format.
  85#if defined(__i386)
  86typedef MDRawContextX86 RawContextCPU;
  87
  88// Write a uint16_t to memory
  89//   out: memory location to write to
  90//   v: value to write.
  91static void U16(void* out, uint16_t v) {
  92  memcpy(out, &v, sizeof(v));
  93}
  94
  95// Write a uint32_t to memory
  96//   out: memory location to write to
  97//   v: value to write.
  98static void U32(void* out, uint32_t v) {
  99  memcpy(out, &v, sizeof(v));
 100}
 101
 102// Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
 103//   out: the minidump structure
 104//   info: the collection of register structures.
 105static void CPUFillFromThreadInfo(MDRawContextX86 *out,
 106                                  const google_breakpad::ThreadInfo &info) {
 107  out->context_flags = MD_CONTEXT_X86_ALL;
 108
 109  out->dr0 = info.dregs[0];
 110  out->dr1 = info.dregs[1];
 111  out->dr2 = info.dregs[2];
 112  out->dr3 = info.dregs[3];
 113  // 4 and 5 deliberatly omitted because they aren't included in the minidump
 114  // format.
 115  out->dr6 = info.dregs[6];
 116  out->dr7 = info.dregs[7];
 117
 118  out->gs = info.regs.xgs;
 119  out->fs = info.regs.xfs;
 120  out->es = info.regs.xes;
 121  out->ds = info.regs.xds;
 122
 123  out->edi = info.regs.edi;
 124  out->esi = info.regs.esi;
 125  out->ebx = info.regs.ebx;
 126  out->edx = info.regs.edx;
 127  out->ecx = info.regs.ecx;
 128  out->eax = info.regs.eax;
 129
 130  out->ebp = info.regs.ebp;
 131  out->eip = info.regs.eip;
 132  out->cs = info.regs.xcs;
 133  out->eflags = info.regs.eflags;
 134  out->esp = info.regs.esp;
 135  out->ss = info.regs.xss;
 136
 137  out->float_save.control_word = info.fpregs.cwd;
 138  out->float_save.status_word = info.fpregs.swd;
 139  out->float_save.tag_word = info.fpregs.twd;
 140  out->float_save.error_offset = info.fpregs.fip;
 141  out->float_save.error_selector = info.fpregs.fcs;
 142  out->float_save.data_offset = info.fpregs.foo;
 143  out->float_save.data_selector = info.fpregs.fos;
 144
 145  // 8 registers * 10 bytes per register.
 146  memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
 147
 148  // This matches the Intel fpsave format.
 149  U16(out->extended_registers + 0, info.fpregs.cwd);
 150  U16(out->extended_registers + 2, info.fpregs.swd);
 151  U16(out->extended_registers + 4, info.fpregs.twd);
 152  U16(out->extended_registers + 6, info.fpxregs.fop);
 153  U32(out->extended_registers + 8, info.fpxregs.fip);
 154  U16(out->extended_registers + 12, info.fpxregs.fcs);
 155  U32(out->extended_registers + 16, info.fpregs.foo);
 156  U16(out->extended_registers + 20, info.fpregs.fos);
 157  U32(out->extended_registers + 24, info.fpxregs.mxcsr);
 158
 159  memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
 160  memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
 161}
 162
 163// Juggle an x86 ucontext into minidump format
 164//   out: the minidump structure
 165//   info: the collection of register structures.
 166static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
 167                                const struct _libc_fpstate* fp) {
 168  const greg_t* regs = uc->uc_mcontext.gregs;
 169
 170  out->context_flags = MD_CONTEXT_X86_FULL |
 171                       MD_CONTEXT_X86_FLOATING_POINT;
 172
 173  out->gs = regs[REG_GS];
 174  out->fs = regs[REG_FS];
 175  out->es = regs[REG_ES];
 176  out->ds = regs[REG_DS];
 177
 178  out->edi = regs[REG_EDI];
 179  out->esi = regs[REG_ESI];
 180  out->ebx = regs[REG_EBX];
 181  out->edx = regs[REG_EDX];
 182  out->ecx = regs[REG_ECX];
 183  out->eax = regs[REG_EAX];
 184
 185  out->ebp = regs[REG_EBP];
 186  out->eip = regs[REG_EIP];
 187  out->cs = regs[REG_CS];
 188  out->eflags = regs[REG_EFL];
 189  out->esp = regs[REG_UESP];
 190  out->ss = regs[REG_SS];
 191
 192  out->float_save.control_word = fp->cw;
 193  out->float_save.status_word = fp->sw;
 194  out->float_save.tag_word = fp->tag;
 195  out->float_save.error_offset = fp->ipoff;
 196  out->float_save.error_selector = fp->cssel;
 197  out->float_save.data_offset = fp->dataoff;
 198  out->float_save.data_selector = fp->datasel;
 199
 200  // 8 registers * 10 bytes per register.
 201  memcpy(out->float_save.register_area, fp->_st, 10 * 8);
 202}
 203
 204#elif defined(__x86_64)
 205typedef MDRawContextAMD64 RawContextCPU;
 206
 207static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
 208                                  const google_breakpad::ThreadInfo &info) {
 209  out->context_flags = MD_CONTEXT_AMD64_FULL |
 210                       MD_CONTEXT_AMD64_SEGMENTS;
 211
 212  out->cs = info.regs.cs;
 213
 214  out->ds = info.regs.ds;
 215  out->es = info.regs.es;
 216  out->fs = info.regs.fs;
 217  out->gs = info.regs.gs;
 218
 219  out->ss = info.regs.ss;
 220  out->eflags = info.regs.eflags;
 221
 222  out->dr0 = info.dregs[0];
 223  out->dr1 = info.dregs[1];
 224  out->dr2 = info.dregs[2];
 225  out->dr3 = info.dregs[3];
 226  // 4 and 5 deliberatly omitted because they aren't included in the minidump
 227  // format.
 228  out->dr6 = info.dregs[6];
 229  out->dr7 = info.dregs[7];
 230
 231  out->rax = info.regs.rax;
 232  out->rcx = info.regs.rcx;
 233  out->rdx = info.regs.rdx;
 234  out->rbx = info.regs.rbx;
 235
 236  out->rsp = info.regs.rsp;
 237
 238  out->rbp = info.regs.rbp;
 239  out->rsi = info.regs.rsi;
 240  out->rdi = info.regs.rdi;
 241  out->r8 = info.regs.r8;
 242  out->r9 = info.regs.r9;
 243  out->r10 = info.regs.r10;
 244  out->r11 = info.regs.r11;
 245  out->r12 = info.regs.r12;
 246  out->r13 = info.regs.r13;
 247  out->r14 = info.regs.r14;
 248  out->r15 = info.regs.r15;
 249
 250  out->rip = info.regs.rip;
 251
 252  out->flt_save.control_word = info.fpregs.cwd;
 253  out->flt_save.status_word = info.fpregs.swd;
 254  out->flt_save.tag_word = info.fpregs.ftw;
 255  out->flt_save.error_opcode = info.fpregs.fop;
 256  out->flt_save.error_offset = info.fpregs.rip;
 257  out->flt_save.error_selector = 0;  // We don't have this.
 258  out->flt_save.data_offset = info.fpregs.rdp;
 259  out->flt_save.data_selector = 0;   // We don't have this.
 260  out->flt_save.mx_csr = info.fpregs.mxcsr;
 261  out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
 262  memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
 263  memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
 264}
 265
 266static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
 267                                const struct _libc_fpstate* fpregs) {
 268  const greg_t* regs = uc->uc_mcontext.gregs;
 269
 270  out->context_flags = MD_CONTEXT_AMD64_FULL;
 271
 272  out->cs = regs[REG_CSGSFS] & 0xffff;
 273
 274  out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
 275  out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
 276
 277  out->eflags = regs[REG_EFL];
 278
 279  out->rax = regs[REG_RAX];
 280  out->rcx = regs[REG_RCX];
 281  out->rdx = regs[REG_RDX];
 282  out->rbx = regs[REG_RBX];
 283
 284  out->rsp = regs[REG_RSP];
 285  out->rbp = regs[REG_RBP];
 286  out->rsi = regs[REG_RSI];
 287  out->rdi = regs[REG_RDI];
 288  out->r8 = regs[REG_R8];
 289  out->r9 = regs[REG_R9];
 290  out->r10 = regs[REG_R10];
 291  out->r11 = regs[REG_R11];
 292  out->r12 = regs[REG_R12];
 293  out->r13 = regs[REG_R13];
 294  out->r14 = regs[REG_R14];
 295  out->r15 = regs[REG_R15];
 296
 297  out->rip = regs[REG_RIP];
 298
 299  out->flt_save.control_word = fpregs->cwd;
 300  out->flt_save.status_word = fpregs->swd;
 301  out->flt_save.tag_word = fpregs->ftw;
 302  out->flt_save.error_opcode = fpregs->fop;
 303  out->flt_save.error_offset = fpregs->rip;
 304  out->flt_save.data_offset = fpregs->rdp;
 305  out->flt_save.error_selector = 0;  // We don't have this.
 306  out->flt_save.data_selector = 0;  // We don't have this.
 307  out->flt_save.mx_csr = fpregs->mxcsr;
 308  out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
 309  memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
 310  memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
 311}
 312
 313#elif defined(__ARMEL__)
 314typedef MDRawContextARM RawContextCPU;
 315
 316static void CPUFillFromThreadInfo(MDRawContextARM *out,
 317                                  const google_breakpad::ThreadInfo &info) {
 318  out->context_flags = MD_CONTEXT_ARM_FULL;
 319
 320  for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
 321    out->iregs[i] = info.regs.uregs[i];
 322  // No CPSR register in ThreadInfo(it's not accessible via ptrace)
 323  out->cpsr = 0;
 324#if !defined(__ANDROID__)
 325  out->float_save.fpscr = info.fpregs.fpsr |
 326    (static_cast<u_int64_t>(info.fpregs.fpcr) << 32);
 327  // TODO: sort this out, actually collect floating point registers
 328  memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
 329  memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
 330#endif
 331}
 332
 333static void CPUFillFromUContext(MDRawContextARM *out, const ucontext *uc,
 334                                const struct _libc_fpstate* fpregs) {
 335  out->context_flags = MD_CONTEXT_ARM_FULL;
 336
 337  out->iregs[0] = uc->uc_mcontext.arm_r0;
 338  out->iregs[1] = uc->uc_mcontext.arm_r1;
 339  out->iregs[2] = uc->uc_mcontext.arm_r2;
 340  out->iregs[3] = uc->uc_mcontext.arm_r3;
 341  out->iregs[4] = uc->uc_mcontext.arm_r4;
 342  out->iregs[5] = uc->uc_mcontext.arm_r5;
 343  out->iregs[6] = uc->uc_mcontext.arm_r6;
 344  out->iregs[7] = uc->uc_mcontext.arm_r7;
 345  out->iregs[8] = uc->uc_mcontext.arm_r8;
 346  out->iregs[9] = uc->uc_mcontext.arm_r9;
 347  out->iregs[10] = uc->uc_mcontext.arm_r10;
 348
 349  out->iregs[11] = uc->uc_mcontext.arm_fp;
 350  out->iregs[12] = uc->uc_mcontext.arm_ip;
 351  out->iregs[13] = uc->uc_mcontext.arm_sp;
 352  out->iregs[14] = uc->uc_mcontext.arm_lr;
 353  out->iregs[15] = uc->uc_mcontext.arm_pc;
 354
 355  out->cpsr = uc->uc_mcontext.arm_cpsr;
 356
 357  // TODO: fix this after fixing ExceptionHandler
 358  out->float_save.fpscr = 0;
 359  memset(&out->float_save.regs, 0, sizeof(out->float_save.regs));
 360  memset(&out->float_save.extra, 0, sizeof(out->float_save.extra));
 361}
 362
 363#else
 364#error "This code has not been ported to your platform yet."
 365#endif
 366
 367namespace google_breakpad {
 368
 369class MinidumpWriter {
 370 public:
 371  MinidumpWriter(const char* filename,
 372                 const ExceptionHandler::CrashContext* context,
 373                 const MappingList& mappings,
 374                 LinuxDumper* dumper)
 375      : filename_(filename),
 376        ucontext_(context ? &context->context : NULL),
 377#if !defined(__ARM_EABI__)
 378        float_state_(context ? &context->float_state : NULL),
 379#else
 380        // TODO: fix this after fixing ExceptionHandler
 381        float_state_(NULL),
 382#endif
 383        dumper_(dumper),
 384        memory_blocks_(dumper_->allocator()),
 385        mapping_list_(mappings) {
 386  }
 387
 388  bool Init() {
 389    return dumper_->Init() && minidump_writer_.Open(filename_) &&
 390           dumper_->ThreadsSuspend();
 391  }
 392
 393  ~MinidumpWriter() {
 394    minidump_writer_.Close();
 395    dumper_->ThreadsResume();
 396  }
 397
 398  bool Dump() {
 399    // The dynamic linker makes information available that helps gdb find all
 400    // DSOs loaded into the program. If we can access this information, we dump
 401    // it to a MD_LINUX_DSO_DEBUG stream.
 402    struct r_debug* r_debug = NULL;
 403    uint32_t dynamic_length = 0;
 404#if !defined(__ANDROID__)
 405    // This code assumes the crashing process is the same as this process and
 406    // may hang or take a long time to complete if not so.
 407    // Thus, we skip this code for a post-mortem based dump.
 408    if (!dumper_->IsPostMortem()) {
 409      // The Android NDK is missing structure definitions for most of this.
 410      // For now, it's simpler just to skip it.
 411      for (int i = 0;;) {
 412        ElfW(Dyn) dyn;
 413        dynamic_length += sizeof(dyn);
 414        // NOTE: Use of _DYNAMIC assumes this is the same process as the
 415        // crashing process. This loop will go forever if it's out of bounds.
 416        dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
 417                                 sizeof(dyn));
 418        if (dyn.d_tag == DT_DEBUG) {
 419          r_debug = (struct r_debug*)dyn.d_un.d_ptr;
 420          continue;
 421        } else if (dyn.d_tag == DT_NULL) {
 422          break;
 423        }
 424      }
 425    }
 426#endif
 427
 428    // A minidump file contains a number of tagged streams. This is the number
 429    // of stream which we write.
 430    unsigned kNumWriters = 12;
 431    if (r_debug)
 432      ++kNumWriters;
 433
 434    TypedMDRVA<MDRawHeader> header(&minidump_writer_);
 435    TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
 436    if (!header.Allocate())
 437      return false;
 438    if (!dir.AllocateArray(kNumWriters))
 439      return false;
 440    memset(header.get(), 0, sizeof(MDRawHeader));
 441
 442    header.get()->signature = MD_HEADER_SIGNATURE;
 443    header.get()->version = MD_HEADER_VERSION;
 444    header.get()->time_date_stamp = time(NULL);
 445    header.get()->stream_count = kNumWriters;
 446    header.get()->stream_directory_rva = dir.position();
 447
 448    unsigned dir_index = 0;
 449    MDRawDirectory dirent;
 450
 451    if (!WriteThreadListStream(&dirent))
 452      return false;
 453    dir.CopyIndex(dir_index++, &dirent);
 454
 455    if (!WriteMappings(&dirent))
 456      return false;
 457    dir.CopyIndex(dir_index++, &dirent);
 458
 459    if (!WriteMemoryListStream(&dirent))
 460      return false;
 461    dir.CopyIndex(dir_index++, &dirent);
 462
 463    if (!WriteExceptionStream(&dirent))
 464      return false;
 465    dir.CopyIndex(dir_index++, &dirent);
 466
 467    if (!WriteSystemInfoStream(&dirent))
 468      return false;
 469    dir.CopyIndex(dir_index++, &dirent);
 470
 471    dirent.stream_type = MD_LINUX_CPU_INFO;
 472    if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
 473      NullifyDirectoryEntry(&dirent);
 474    dir.CopyIndex(dir_index++, &dirent);
 475
 476    dirent.stream_type = MD_LINUX_PROC_STATUS;
 477    if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
 478      NullifyDirectoryEntry(&dirent);
 479    dir.CopyIndex(dir_index++, &dirent);
 480
 481    dirent.stream_type = MD_LINUX_LSB_RELEASE;
 482    if (!WriteFile(&dirent.location, "/etc/lsb-release"))
 483      NullifyDirectoryEntry(&dirent);
 484    dir.CopyIndex(dir_index++, &dirent);
 485
 486    dirent.stream_type = MD_LINUX_CMD_LINE;
 487    if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
 488      NullifyDirectoryEntry(&dirent);
 489    dir.CopyIndex(dir_index++, &dirent);
 490
 491    dirent.stream_type = MD_LINUX_ENVIRON;
 492    if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
 493      NullifyDirectoryEntry(&dirent);
 494    dir.CopyIndex(dir_index++, &dirent);
 495
 496    dirent.stream_type = MD_LINUX_AUXV;
 497    if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
 498      NullifyDirectoryEntry(&dirent);
 499    dir.CopyIndex(dir_index++, &dirent);
 500
 501    dirent.stream_type = MD_LINUX_MAPS;
 502    if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
 503      NullifyDirectoryEntry(&dirent);
 504    dir.CopyIndex(dir_index++, &dirent);
 505
 506    if (r_debug) {
 507      dirent.stream_type = MD_LINUX_DSO_DEBUG;
 508      if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
 509        NullifyDirectoryEntry(&dirent);
 510      dir.CopyIndex(dir_index++, &dirent);
 511    }
 512
 513    // If you add more directory entries, don't forget to update kNumWriters,
 514    // above.
 515
 516    dumper_->ThreadsResume();
 517    return true;
 518  }
 519
 520  // Check if the top of the stack is part of a system call that has been
 521  // redirected by the seccomp sandbox. If so, try to pop the stack frames
 522  // all the way back to the point where the interception happened.
 523  void PopSeccompStackFrame(RawContextCPU* cpu, const MDRawThread& thread,
 524                            uint8_t* stack_copy) {
 525#if defined(__x86_64)
 526    u_int64_t bp = cpu->rbp;
 527    u_int64_t top = thread.stack.start_of_memory_range;
 528    for (int i = 4; i--; ) {
 529      if (bp < top ||
 530          bp + sizeof(bp) > thread.stack.start_of_memory_range +
 531          thread.stack.memory.data_size ||
 532          bp & 1) {
 533        break;
 534      }
 535      uint64_t old_top = top;
 536      top = bp;
 537      u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
 538      memcpy(&bp, bp_addr, sizeof(bp));
 539      if (bp == 0xDEADBEEFDEADBEEFull) {
 540        struct {
 541          uint64_t r15;
 542          uint64_t r14;
 543          uint64_t r13;
 544          uint64_t r12;
 545          uint64_t r11;
 546          uint64_t r10;
 547          uint64_t r9;
 548          uint64_t r8;
 549          uint64_t rdi;
 550          uint64_t rsi;
 551          uint64_t rdx;
 552          uint64_t rcx;
 553          uint64_t rbx;
 554          uint64_t deadbeef;
 555          uint64_t rbp;
 556          uint64_t fakeret;
 557          uint64_t ret;
 558          /* char redzone[128]; */
 559        } seccomp_stackframe;
 560        if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
 561            top - offsetof(typeof(seccomp_stackframe), deadbeef) +
 562            sizeof(seccomp_stackframe) >
 563            thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
 564          break;
 565        }
 566        memcpy(&seccomp_stackframe,
 567               bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
 568               sizeof(seccomp_stackframe));
 569        cpu->rbx = seccomp_stackframe.rbx;
 570        cpu->rcx = seccomp_stackframe.rcx;
 571        cpu->rdx = seccomp_stackframe.rdx;
 572        cpu->rsi = seccomp_stackframe.rsi;
 573        cpu->rdi = seccomp_stackframe.rdi;
 574        cpu->rbp = seccomp_stackframe.rbp;
 575        cpu->rsp = top + 4*sizeof(uint64_t) + 128;
 576        cpu->r8  = seccomp_stackframe.r8;
 577        cpu->r9  = seccomp_stackframe.r9;
 578        cpu->r10 = seccomp_stackframe.r10;
 579        cpu->r11 = seccomp_stackframe.r11;
 580        cpu->r12 = seccomp_stackframe.r12;
 581        cpu->r13 = seccomp_stackframe.r13;
 582        cpu->r14 = seccomp_stackframe.r14;
 583        cpu->r15 = seccomp_stackframe.r15;
 584        cpu->rip = seccomp_stackframe.fakeret;
 585        return;
 586      }
 587    }
 588#elif defined(__i386)
 589    u_int32_t bp = cpu->ebp;
 590    u_int32_t top = thread.stack.start_of_memory_range;
 591    for (int i = 4; i--; ) {
 592      if (bp < top ||
 593          bp + sizeof(bp) > thread.stack.start_of_memory_range +
 594          thread.stack.memory.data_size ||
 595          bp & 1) {
 596        break;
 597      }
 598      uint32_t old_top = top;
 599      top = bp;
 600      u_int8_t* bp_addr = stack_copy + bp - thread.stack.start_of_memory_range;
 601      memcpy(&bp, bp_addr, sizeof(bp));
 602      if (bp == 0xDEADBEEFu) {
 603        struct {
 604          uint32_t edi;
 605          uint32_t esi;
 606          uint32_t edx;
 607          uint32_t ecx;
 608          uint32_t ebx;
 609          uint32_t deadbeef;
 610          uint32_t ebp;
 611          uint32_t fakeret;
 612          uint32_t ret;
 613        } seccomp_stackframe;
 614        if (top - offsetof(typeof(seccomp_stackframe), deadbeef) < old_top ||
 615            top - offsetof(typeof(seccomp_stackframe), deadbeef) +
 616            sizeof(seccomp_stackframe) >
 617            thread.stack.start_of_memory_range+thread.stack.memory.data_size) {
 618          break;
 619        }
 620        memcpy(&seccomp_stackframe,
 621               bp_addr - offsetof(typeof(seccomp_stackframe), deadbeef),
 622               sizeof(seccomp_stackframe));
 623        cpu->ebx = seccomp_stackframe.ebx;
 624        cpu->ecx = seccomp_stackframe.ecx;
 625        cpu->edx = seccomp_stackframe.edx;
 626        cpu->esi = seccomp_stackframe.esi;
 627        cpu->edi = seccomp_stackframe.edi;
 628        cpu->ebp = seccomp_stackframe.ebp;
 629        cpu->esp = top + 4*sizeof(void*);
 630        cpu->eip = seccomp_stackframe.fakeret;
 631        return;
 632      }
 633    }
 634#endif
 635  }
 636
 637  // Write information about the threads.
 638  bool WriteThreadListStream(MDRawDirectory* dirent) {
 639    const unsigned num_threads = dumper_->threads().size();
 640
 641    TypedMDRVA<uint32_t> list(&minidump_writer_);
 642    if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
 643      return false;
 644
 645    dirent->stream_type = MD_THREAD_LIST_STREAM;
 646    dirent->location = list.location();
 647
 648    *list.get() = num_threads;
 649
 650    for (unsigned i = 0; i < num_threads; ++i) {
 651      MDRawThread thread;
 652      my_memset(&thread, 0, sizeof(thread));
 653      thread.thread_id = dumper_->threads()[i];
 654      // We have a different source of information for the crashing thread. If
 655      // we used the actual state of the thread we would find it running in the
 656      // signal handler with the alternative stack, which would be deeply
 657      // unhelpful.
 658      if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
 659          !dumper_->IsPostMortem()) {
 660        const void* stack;
 661        size_t stack_len;
 662        if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
 663          return false;
 664        UntypedMDRVA memory(&minidump_writer_);
 665        if (!memory.Allocate(stack_len))
 666          return false;
 667        uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
 668        dumper_->CopyFromProcess(stack_copy, thread.thread_id, stack,
 669                                 stack_len);
 670        memory.Copy(stack_copy, stack_len);
 671        thread.stack.start_of_memory_range = (uintptr_t) (stack);
 672        thread.stack.memory = memory.location();
 673        memory_blocks_.push_back(thread.stack);
 674
 675        // Copy 256 bytes around crashing instruction pointer to minidump.
 676        const size_t kIPMemorySize = 256;
 677        u_int64_t ip = GetInstructionPointer();
 678        // Bound it to the upper and lower bounds of the memory map
 679        // it's contained within. If it's not in mapped memory,
 680        // don't bother trying to write it.
 681        bool ip_is_mapped = false;
 682        MDMemoryDescriptor ip_memory_d;
 683        for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
 684          const MappingInfo& mapping = *dumper_->mappings()[j];
 685          if (ip >= mapping.start_addr &&
 686              ip < mapping.start_addr + mapping.size) {
 687            ip_is_mapped = true;
 688            // Try to get 128 bytes before and after the IP, but
 689            // settle for whatever's available.
 690            ip_memory_d.start_of_memory_range =
 691              std::max(mapping.start_addr,
 692                       uintptr_t(ip - (kIPMemorySize / 2)));
 693            uintptr_t end_of_range =
 694              std::min(uintptr_t(ip + (kIPMemorySize / 2)),
 695                       uintptr_t(mapping.start_addr + mapping.size));
 696            ip_memory_d.memory.data_size =
 697              end_of_range - ip_memory_d.start_of_memory_range;
 698            break;
 699          }
 700        }
 701
 702        if (ip_is_mapped) {
 703          UntypedMDRVA ip_memory(&minidump_writer_);
 704          if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
 705            return false;
 706          uint8_t* memory_copy =
 707              reinterpret_cast<uint8_t*>(Alloc(ip_memory_d.memory.data_size));
 708          dumper_->CopyFromProcess(
 709              memory_copy,
 710              thread.thread_id,
 711              reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
 712              ip_memory_d.memory.data_size);
 713          ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
 714          ip_memory_d.memory = ip_memory.location();
 715          memory_blocks_.push_back(ip_memory_d);
 716        }
 717
 718        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
 719        if (!cpu.Allocate())
 720          return false;
 721        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
 722        CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
 723        PopSeccompStackFrame(cpu.get(), thread, stack_copy);
 724        thread.thread_context = cpu.location();
 725        crashing_thread_context_ = cpu.location();
 726      } else {
 727        ThreadInfo info;
 728        if (!dumper_->GetThreadInfoByIndex(i, &info))
 729          return false;
 730        UntypedMDRVA memory(&minidump_writer_);
 731        if (!memory.Allocate(info.stack_len))
 732          return false;
 733        uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(info.stack_len));
 734        dumper_->CopyFromProcess(stack_copy, thread.thread_id, info.stack,
 735                                 info.stack_len);
 736        memory.Copy(stack_copy, info.stack_len);
 737        thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
 738        thread.stack.memory = memory.location();
 739        memory_blocks_.push_back(thread.stack);
 740
 741        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
 742        if (!cpu.Allocate())
 743          return false;
 744        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
 745        CPUFillFromThreadInfo(cpu.get(), info);
 746        PopSeccompStackFrame(cpu.get(), thread, stack_copy);
 747        thread.thread_context = cpu.location();
 748        if (dumper_->threads()[i] == GetCrashThread()) {
 749          assert(dumper_->IsPostMortem());
 750          crashing_thread_context_ = cpu.location();
 751        }
 752      }
 753
 754      list.CopyIndexAfterObject(i, &thread, sizeof(thread));
 755    }
 756
 757    return true;
 758  }
 759
 760  static bool ShouldIncludeMapping(const MappingInfo& mapping) {
 761    if (mapping.name[0] == 0 ||  // only want modules with filenames.
 762        mapping.offset ||  // only want to include one mapping per shared lib.
 763        mapping.size < 4096) {  // too small to get a signature for.
 764      return false;
 765    }
 766
 767    return true;
 768  }
 769
 770  // If there is caller-provided information about this mapping
 771  // in the mapping_list_ list, return true. Otherwise, return false.
 772  bool HaveMappingInfo(const MappingInfo& mapping) {
 773    for (MappingList::const_iterator iter = mapping_list_.begin();
 774         iter != mapping_list_.end();
 775         ++iter) {
 776      // Ignore any mappings that are wholly contained within
 777      // mappings in the mapping_info_ list.
 778      if (mapping.start_addr >= iter->first.start_addr &&
 779          (mapping.start_addr + mapping.size) <=
 780          (iter->first.start_addr + iter->first.size)) {
 781        return true;
 782      }
 783    }
 784    return false;
 785  }
 786
 787  // Write information about the mappings in effect. Because we are using the
 788  // minidump format, the information about the mappings is pretty limited.
 789  // Because of this, we also include the full, unparsed, /proc/$x/maps file in
 790  // another stream in the file.
 791  bool WriteMappings(MDRawDirectory* dirent) {
 792    const unsigned num_mappings = dumper_->mappings().size();
 793    unsigned num_output_mappings = mapping_list_.size();
 794
 795    for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
 796      const MappingInfo& mapping = *dumper_->mappings()[i];
 797      if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
 798        num_output_mappings++;
 799    }
 800
 801    TypedMDRVA<uint32_t> list(&minidump_writer_);
 802    if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
 803      return false;
 804
 805    dirent->stream_type = MD_MODULE_LIST_STREAM;
 806    dirent->location = list.location();
 807    *list.get() = num_output_mappings;
 808
 809    // First write all the mappings from the dumper
 810    unsigned int j = 0;
 811    for (unsigned i = 0; i < num_mappings; ++i) {
 812      const MappingInfo& mapping = *dumper_->mappings()[i];
 813      if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
 814        continue;
 815
 816      MDRawModule mod;
 817      if (!FillRawModule(mapping, true, i, mod, NULL))
 818        return false;
 819      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
 820    }
 821    // Next write all the mappings provided by the caller
 822    for (MappingList::const_iterator iter = mapping_list_.begin();
 823         iter != mapping_list_.end();
 824         ++iter) {
 825      MDRawModule mod;
 826      if (!FillRawModule(iter->first, false, 0, mod, iter->second))
 827        return false;
 828      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
 829    }
 830
 831    return true;
 832  }
 833
 834  // Fill the MDRawModule |mod| with information about the provided
 835  // |mapping|. If |identifier| is non-NULL, use it instead of calculating
 836  // a file ID from the mapping.
 837  bool FillRawModule(const MappingInfo& mapping,
 838                     bool member,
 839                     unsigned int mapping_id,
 840                     MDRawModule& mod,
 841                     const u_int8_t* identifier) {
 842    my_memset(&mod, 0, MD_MODULE_SIZE);
 843
 844    mod.base_of_image = mapping.start_addr;
 845    mod.size_of_image = mapping.size;
 846    const size_t filepath_len = my_strlen(mapping.name);
 847
 848    // Figure out file name from path
 849    const char* filename_ptr = mapping.name + filepath_len - 1;
 850    while (filename_ptr >= mapping.name) {
 851      if (*filename_ptr == '/')
 852        break;
 853      filename_ptr--;
 854    }
 855    filename_ptr++;
 856
 857    const size_t filename_len = mapping.name + filepath_len - filename_ptr;
 858
 859    uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
 860    uint8_t* cv_ptr = cv_buf;
 861    UntypedMDRVA cv(&minidump_writer_);
 862    if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
 863      return false;
 864
 865    const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
 866    memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
 867    cv_ptr += sizeof(cv_signature);
 868    uint8_t* signature = cv_ptr;
 869    cv_ptr += sizeof(MDGUID);
 870    if (identifier) {
 871      // GUID was provided by caller.
 872      memcpy(signature, identifier, sizeof(MDGUID));
 873    } else {
 874      dumper_->ElfFileIdentifierForMapping(mapping, member,
 875                                           mapping_id, signature);
 876    }
 877    my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
 878    cv_ptr += sizeof(uint32_t);
 879
 880    // Write pdb_file_name
 881    memcpy(cv_ptr, filename_ptr, filename_len + 1);
 882    cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
 883
 884    mod.cv_record = cv.location();
 885
 886    MDLocationDescriptor ld;
 887    if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
 888      return false;
 889    mod.module_name_rva = ld.rva;
 890    return true;
 891  }
 892
 893  bool WriteMemoryListStream(MDRawDirectory* dirent) {
 894    TypedMDRVA<uint32_t> list(&minidump_writer_);
 895    if (!list.AllocateObjectAndArray(memory_blocks_.size(),
 896                                     sizeof(MDMemoryDescriptor)))
 897      return false;
 898
 899    dirent->stream_type = MD_MEMORY_LIST_STREAM;
 900    dirent->location = list.location();
 901
 902    *list.get() = memory_blocks_.size();
 903
 904    for (size_t i = 0; i < memory_blocks_.size(); ++i) {
 905      list.CopyIndexAfterObject(i, &memory_blocks_[i],
 906                                sizeof(MDMemoryDescriptor));
 907    }
 908    return true;
 909  }
 910
 911  bool WriteExceptionStream(MDRawDirectory* dirent) {
 912    TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
 913    if (!exc.Allocate())
 914      return false;
 915    my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
 916
 917    dirent->stream_type = MD_EXCEPTION_STREAM;
 918    dirent->location = exc.location();
 919
 920    exc.get()->thread_id = GetCrashThread();
 921    exc.get()->exception_record.exception_code = dumper_->crash_signal();
 922    exc.get()->exception_record.exception_address = dumper_->crash_address();
 923    exc.get()->thread_context = crashing_thread_context_;
 924
 925    return true;
 926  }
 927
 928  bool WriteSystemInfoStream(MDRawDirectory* dirent) {
 929    TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
 930    if (!si.Allocate())
 931      return false;
 932    my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
 933
 934    dirent->stream_type = MD_SYSTEM_INFO_STREAM;
 935    dirent->location = si.location();
 936
 937    WriteCPUInformation(si.get());
 938    WriteOSInformation(si.get());
 939
 940    return true;
 941  }
 942
 943  bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
 944                           uint32_t dynamic_length) {
 945#if defined(__ANDROID__)
 946    return false;
 947#else
 948    // The caller provided us with a pointer to "struct r_debug". We can
 949    // look up the "r_map" field to get a linked list of all loaded DSOs.
 950    // Our list of DSOs potentially is different from the ones in the crashing
 951    // process. So, we have to be careful to never dereference pointers
 952    // directly. Instead, we use CopyFromProcess() everywhere.
 953    // See <link.h> for a more detailed discussion of the how the dynamic
 954    // loader communicates with debuggers.
 955
 956    // Count the number of loaded DSOs
 957    int dso_count = 0;
 958    struct r_debug debug_entry;
 959    dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
 960                             sizeof(debug_entry));
 961    for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
 962      struct link_map map;
 963      dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
 964      ptr = map.l_next;
 965      dso_count++;
 966    }
 967
 968    MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA;
 969    if (dso_count > 0) {
 970      // If we have at least one DSO, create an array of MDRawLinkMap
 971      // entries in the minidump file.
 972      TypedMDRVA<MDRawLinkMap> linkmap(&minidump_writer_);
 973      if (!linkmap.AllocateArray(dso_count))
 974        return false;
 975      linkmap_rva = linkmap.location().rva;
 976      int idx = 0;
 977
 978      // Iterate over DSOs and write their information to mini dump
 979      for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
 980        struct link_map map;
 981        dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
 982        ptr = map.l_next;
 983        char filename[257] = { 0 };
 984        if (map.l_name) {
 985          dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
 986                                   sizeof(filename) - 1);
 987        }
 988        MDLocationDescriptor location;
 989        if (!minidump_writer_.WriteString(filename, 0, &location))
 990          return false;
 991        MDRawLinkMap entry;
 992        entry.name = location.rva;
 993        entry.addr = (void*)map.l_addr;
 994        entry.ld = (void*)map.l_ld;
 995        linkmap.CopyIndex(idx++, &entry);
 996      }
 997    }
 998
 999    // Write MD_LINUX_DSO_DEBUG record
1000    TypedMDRVA<MDRawDebug> debug(&minidump_writer_);
1001    if (!debug.AllocateObjectAndArray(1, dynamic_length))
1002      return false;
1003    my_memset(debug.get(), 0, sizeof(MDRawDebug));
1004    dirent->stream_type = MD_LINUX_DSO_DEBUG;
1005    dirent->location = debug.location();
1006
1007    debug.get()->version = debug_entry.r_version;
1008    debug.get()->map = linkmap_rva;
1009    debug.get()->dso_count = dso_count;
1010    debug.get()->brk = (void*)debug_entry.r_brk;
1011    debug.get()->ldbase = (void*)debug_entry.r_ldbase;
1012    debug.get()->dynamic = (void*)&_DYNAMIC;
1013
1014    char *dso_debug_data = new char[dynamic_length];
1015    dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
1016                             dynamic_length);
1017    debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
1018    delete[] dso_debug_data;
1019
1020    return true;
1021#endif
1022  }
1023
1024 private:
1025  void* Alloc(unsigned bytes) {
1026    return dumper_->allocator()->Alloc(bytes);
1027  }
1028
1029  pid_t GetCrashThread() const {
1030    return dumper_->crash_thread();
1031  }
1032
1033#if defined(__i386)
1034  uintptr_t GetStackPointer() {
1035    return ucontext_->uc_mcontext.gregs[REG_ESP];
1036  }
1037
1038  uintptr_t GetInstructionPointer() {
1039    return ucontext_->uc_mcontext.gregs[REG_EIP];
1040  }
1041#elif defined(__x86_64)
1042  uintptr_t GetStackPointer() {
1043    return ucontext_->uc_mcontext.gregs[REG_RSP];
1044  }
1045
1046  uintptr_t GetInstructionPointer() {
1047    return ucontext_->uc_mcontext.gregs[REG_RIP];
1048  }
1049#elif defined(__ARM_EABI__)
1050  uintptr_t GetStackPointer() {
1051    return ucontext_->uc_mcontext.arm_sp;
1052  }
1053
1054  uintptr_t GetInstructionPointer() {
1055    return ucontext_->uc_mcontext.arm_ip;
1056  }
1057#else
1058#error "This code has not been ported to your platform yet."
1059#endif
1060
1061  void NullifyDirectoryEntry(MDRawDirectory* dirent) {
1062    dirent->stream_type = 0;
1063    dirent->location.data_size = 0;
1064    dirent->location.rva = 0;
1065  }
1066
1067  bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
1068    char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
1069    static const char vendor_id_name[] = "vendor_id";
1070    static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
1071
1072    struct CpuInfoEntry {
1073      const char* info_name;
1074      int value;
1075      bool found;
1076    } cpu_info_table[] = {
1077      { "processor", -1, false },
1078      { "model", 0, false },
1079      { "stepping",  0, false },
1080      { "cpu family", 0, false },
1081    };
1082
1083    // processor_architecture should always be set, do this first
1084    sys_info->processor_architecture =
1085#if defined(__i386)
1086        MD_CPU_ARCHITECTURE_X86;
1087#elif defined(__x86_64)
1088        MD_CPU_ARCHITECTURE_AMD64;
1089#elif defined(__arm__)
1090        MD_CPU_ARCHITECTURE_ARM;
1091#else
1092#error "Unknown CPU arch"
1093#endif
1094
1095    const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
1096    if (fd < 0)
1097      return false;
1098
1099    {
1100      PageAllocator allocator;
1101      LineReader* const line_reader = new(allocator) LineReader(fd);
1102      const char* line;
1103      unsigned line_len;
1104      while (line_reader->GetNextLine(&line, &line_len)) {
1105        for (size_t i = 0;
1106             i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1107             i++) {
1108          CpuInfoEntry* entry = &cpu_info_table[i];
1109          if (entry->found && i)
1110            continue;
1111          if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
1112            const char* value = strchr(line, ':');
1113            if (!value)
1114              continue;
1115
1116            // the above strncmp only matches the prefix, it might be the wrong
1117            // line. i.e. we matched "model name" instead of "model".
1118            // check and make sure there is only spaces between the prefix and
1119            // the colon.
1120            const char* space_ptr = line + strlen(entry->info_name);
1121            for (; space_ptr < value; space_ptr++) {
1122              if (!isspace(*space_ptr)) {
1123                break;
1124              }
1125            }
1126            if (space_ptr != value)
1127              continue;
1128
1129            sscanf(++value, " %d", &(entry->value));
1130            entry->found = true;
1131          }
1132        }
1133
1134        // special case for vendor_id
1135        if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
1136          const char* value = strchr(line, ':');
1137          if (!value)
1138            goto popline;
1139
1140          // skip ':" and all the spaces that follows
1141          do {
1142            value++;
1143          } while (isspace(*value));
1144
1145          if (*value) {
1146            size_t length = strlen(value);
1147            if (length == 0)
1148              goto popline;
1149            // we don't want the trailing newline
1150            if (value[length - 1] == '\n')
1151              length--;
1152            // ensure we have space for the value
1153            if (length < sizeof(vendor_id))
1154              strncpy(vendor_id, value, length);
1155          }
1156        }
1157
1158 popline:
1159        line_reader->PopLine(line_len);
1160      }
1161      sys_close(fd);
1162    }
1163
1164    // make sure we got everything we wanted
1165    for (size_t i = 0;
1166         i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
1167         i++) {
1168      if (!cpu_info_table[i].found) {
1169        return false;
1170      }
1171    }
1172    // /proc/cpuinfo contains cpu id, change it into number by adding one.
1173    cpu_info_table[0].value++;
1174
1175    sys_info->number_of_processors = cpu_info_table[0].value;
1176    sys_info->processor_level      = cpu_info_table[3].value;
1177    sys_info->processor_revision   = cpu_info_table[1].value << 8 |
1178                                     cpu_info_table[2].value;
1179
1180    if (vendor_id[0] != '\0') {
1181      memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
1182             sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
1183    }
1184    return true;
1185  }
1186
1187  bool WriteFile(MDLocationDescriptor* result, const char* filename) {
1188    const int fd = sys_open(filename, O_RDONLY, 0);
1189    if (fd < 0)
1190      return false;
1191
1192    // We can't stat the files because several of the files that we want to
1193    // read are kernel seqfiles, which always have a length of zero. So we have
1194    // to read as much as we can into a buffer.
1195    static const unsigned kBufSize = 1024 - 2*sizeof(void*);
1196    struct Buffers {
1197      Buffers* next;
1198      size_t len;
1199      uint8_t data[kBufSize];
1200    } *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1201    buffers->next = NULL;
1202    buffers->len = 0;
1203
1204    size_t total = 0;
1205    for (Buffers* bufptr = buffers;;) {
1206      ssize_t r;
1207      do {
1208        r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
1209      } while (r == -1 && errno == EINTR);
1210
1211      if (r < 1)
1212        break;
1213
1214      total += r;
1215      bufptr->len += r;
1216      if (bufptr->len == kBufSize) {
1217        bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
1218        bufptr = bufptr->next;
1219        bufptr->next = NULL;
1220        bufptr->len = 0;
1221      }
1222    }
1223    sys_close(fd);
1224
1225    if (!total)
1226      return false;
1227
1228    UntypedMDRVA memory(&minidump_writer_);
1229    if (!memory.Allocate(total))
1230      return false;
1231    for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) {
1232      // Check for special case of a zero-length buffer.  This should only
1233      // occur if a file's size happens to be a multiple of the buffer's
1234      // size, in which case the final sys_read() will have resulted in
1235      // zero bytes being read after the final buffer was just allocated.
1236      if (buffers->len == 0) {
1237        // This can only occur with final buffer.
1238        assert(buffers->next == NULL);
1239        continue;
1240      }
1241      memory.Copy(pos, &buffers->data, buffers->len);
1242      pos += buffers->len;
1243    }
1244    *result = memory.location();
1245    return true;
1246  }
1247
1248  bool WriteOSInformation(MDRawSystemInfo* sys_info) {
1249    sys_info->platform_id = MD_OS_LINUX;
1250
1251    struct utsname uts;
1252    if (uname(&uts))
1253      return false;
1254
1255    static const size_t buf_len = 512;
1256    char buf[buf_len] = {0};
1257    size_t space_left = buf_len - 1;
1258    const char* info_table[] = {
1259      uts.sysname,
1260      uts.release,
1261      uts.version,
1262      uts.machine,
1263      NULL
1264    };
1265    bool first_item = true;
1266    for (const char** cur_info = info_table; *cur_info; cur_info++) {
1267      static const char* separator = " ";
1268      size_t separator_len = strlen(separator);
1269      size_t info_len = strlen(*cur_info);
1270      if (info_len == 0)
1271        continue;
1272
1273      if (space_left < info_len + (first_item ? 0 : separator_len))
1274        break;
1275
1276      if (!first_item) {
1277        strcat(buf, separator);
1278        space_left -= separator_len;
1279      }
1280
1281      first_item = false;
1282      strcat(buf, *cur_info);
1283      space_left -= info_len;
1284    }
1285
1286    MDLocationDescriptor location;
1287    if (!minidump_writer_.WriteString(buf, 0, &location))
1288      return false;
1289    sys_info->csd_version_rva = location.rva;
1290
1291    return true;
1292  }
1293
1294  bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
1295                     const char* filename) {
1296    char buf[NAME_MAX];
1297    if (!dumper_->BuildProcPath(buf, pid, filename))
1298      return false;
1299    return WriteFile(result, buf);
1300  }
1301
1302  const char* const filename_;  // output filename
1303  const struct ucontext* const ucontext_;  // also from the signal handler
1304  const struct _libc_fpstate* const float_state_;  // ditto
1305  LinuxDumper* dumper_;
1306  MinidumpFileWriter minidump_writer_;
1307  MDLocationDescriptor crashing_thread_context_;
1308  // Blocks of memory written to the dump. These are all currently
1309  // written while writing the thread list stream, but saved here
1310  // so a memory list stream can be written afterwards.
1311  wasteful_vector<MDMemoryDescriptor> memory_blocks_;
1312  // Additional information about some mappings provided by the caller.
1313  const MappingList& mapping_list_;
1314};
1315
1316bool WriteMinidump(const char* filename, pid_t crashing_process,
1317                   const void* blob, size_t blob_size) {
1318  MappingList m;
1319  return WriteMinidump(filename, crashing_process, blob, blob_size, m);
1320}
1321
1322bool WriteMinidump(const char* filename, pid_t crashing_process,
1323                   const void* blob, size_t blob_size,
1324                   const MappingList& mappings) {
1325  if (blob_size != sizeof(ExceptionHandler::CrashContext))
1326    return false;
1327  const ExceptionHandler::CrashContext* context =
1328      reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
1329  LinuxPtraceDumper dumper(crashing_process);
1330  dumper.set_crash_address(
1331      reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
1332  dumper.set_crash_signal(context->siginfo.si_signo);
1333  dumper.set_crash_thread(context->tid);
1334  MinidumpWriter writer(filename, context, mappings, &dumper);
1335  if (!writer.Init())
1336    return false;
1337  return writer.Dump();
1338}
1339
1340bool WriteMinidump(const char* filename,
1341                   const MappingList& mappings,
1342                   LinuxDumper* dumper) {
1343  MinidumpWriter writer(filename, NULL, mappings, dumper);
1344  if (!writer.Init())
1345    return false;
1346  return writer.Dump();
1347}
1348
1349}  // namespace google_breakpad