toolkit/crashreporter/google-breakpad/src/processor/minidump.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,4343 @@
     1.4 +// Copyright (c) 2010 Google Inc.
     1.5 +// All rights reserved.
     1.6 +//
     1.7 +// Redistribution and use in source and binary forms, with or without
     1.8 +// modification, are permitted provided that the following conditions are
     1.9 +// met:
    1.10 +//
    1.11 +//     * Redistributions of source code must retain the above copyright
    1.12 +// notice, this list of conditions and the following disclaimer.
    1.13 +//     * Redistributions in binary form must reproduce the above
    1.14 +// copyright notice, this list of conditions and the following disclaimer
    1.15 +// in the documentation and/or other materials provided with the
    1.16 +// distribution.
    1.17 +//     * Neither the name of Google Inc. nor the names of its
    1.18 +// contributors may be used to endorse or promote products derived from
    1.19 +// this software without specific prior written permission.
    1.20 +//
    1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 +
    1.33 +// minidump.cc: A minidump reader.
    1.34 +//
    1.35 +// See minidump.h for documentation.
    1.36 +//
    1.37 +// Author: Mark Mentovai
    1.38 +
    1.39 +#include "google_breakpad/processor/minidump.h"
    1.40 +
    1.41 +#include <assert.h>
    1.42 +#include <fcntl.h>
    1.43 +#include <stddef.h>
    1.44 +#include <stdio.h>
    1.45 +#include <string.h>
    1.46 +#include <time.h>
    1.47 +
    1.48 +#ifdef _WIN32
    1.49 +#include <io.h>
    1.50 +#define PRIx64 "llx"
    1.51 +#define PRIx32 "lx"
    1.52 +#define snprintf _snprintf
    1.53 +#else  // _WIN32
    1.54 +#include <unistd.h>
    1.55 +#define O_BINARY 0
    1.56 +#endif  // _WIN32
    1.57 +
    1.58 +#include <fstream>
    1.59 +#include <iostream>
    1.60 +#include <limits>
    1.61 +#include <map>
    1.62 +#include <vector>
    1.63 +
    1.64 +#include "processor/range_map-inl.h"
    1.65 +
    1.66 +#include "common/scoped_ptr.h"
    1.67 +#include "processor/basic_code_module.h"
    1.68 +#include "processor/basic_code_modules.h"
    1.69 +#include "common/logging.h"
    1.70 +
    1.71 +
    1.72 +
    1.73 +namespace google_breakpad {
    1.74 +
    1.75 +
    1.76 +using std::istream;
    1.77 +using std::ifstream;
    1.78 +using std::numeric_limits;
    1.79 +using std::vector;
    1.80 +
    1.81 +
    1.82 +//
    1.83 +// Swapping routines
    1.84 +//
    1.85 +// Inlining these doesn't increase code size significantly, and it saves
    1.86 +// a whole lot of unnecessary jumping back and forth.
    1.87 +//
    1.88 +
    1.89 +
    1.90 +// Swapping an 8-bit quantity is a no-op.  This function is only provided
    1.91 +// to account for certain templatized operations that require swapping for
    1.92 +// wider types but handle uint8_t too
    1.93 +// (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
    1.94 +static inline void Swap(uint8_t* value) {
    1.95 +}
    1.96 +
    1.97 +
    1.98 +// Optimization: don't need to AND the furthest right shift, because we're
    1.99 +// shifting an unsigned quantity.  The standard requires zero-filling in this
   1.100 +// case.  If the quantities were signed, a bitmask whould be needed for this
   1.101 +// right shift to avoid an arithmetic shift (which retains the sign bit).
   1.102 +// The furthest left shift never needs to be ANDed bitmask.
   1.103 +
   1.104 +
   1.105 +static inline void Swap(uint16_t* value) {
   1.106 +  *value = (*value >> 8) |
   1.107 +           (*value << 8);
   1.108 +}
   1.109 +
   1.110 +
   1.111 +static inline void Swap(uint32_t* value) {
   1.112 +  *value =  (*value >> 24) |
   1.113 +           ((*value >> 8)  & 0x0000ff00) |
   1.114 +           ((*value << 8)  & 0x00ff0000) |
   1.115 +            (*value << 24);
   1.116 +}
   1.117 +
   1.118 +
   1.119 +static inline void Swap(uint64_t* value) {
   1.120 +  uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
   1.121 +  Swap(&value32[0]);
   1.122 +  Swap(&value32[1]);
   1.123 +  uint32_t temp = value32[0];
   1.124 +  value32[0] = value32[1];
   1.125 +  value32[1] = temp;
   1.126 +}
   1.127 +
   1.128 +
   1.129 +// Given a pointer to a 128-bit int in the minidump data, set the "low"
   1.130 +// and "high" fields appropriately.
   1.131 +static void Normalize128(uint128_struct* value, bool is_big_endian) {
   1.132 +  // The struct format is [high, low], so if the format is big-endian,
   1.133 +  // the most significant bytes will already be in the high field.
   1.134 +  if (!is_big_endian) {
   1.135 +    uint64_t temp = value->low;
   1.136 +    value->low = value->high;
   1.137 +    value->high = temp;
   1.138 +  }
   1.139 +}
   1.140 +
   1.141 +// This just swaps each int64 half of the 128-bit value.
   1.142 +// The value should also be normalized by calling Normalize128().
   1.143 +static void Swap(uint128_struct* value) {
   1.144 +  Swap(&value->low);
   1.145 +  Swap(&value->high);
   1.146 +}
   1.147 +
   1.148 +
   1.149 +static inline void Swap(MDLocationDescriptor* location_descriptor) {
   1.150 +  Swap(&location_descriptor->data_size);
   1.151 +  Swap(&location_descriptor->rva);
   1.152 +}
   1.153 +
   1.154 +
   1.155 +static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
   1.156 +  Swap(&memory_descriptor->start_of_memory_range);
   1.157 +  Swap(&memory_descriptor->memory);
   1.158 +}
   1.159 +
   1.160 +
   1.161 +static inline void Swap(MDGUID* guid) {
   1.162 +  Swap(&guid->data1);
   1.163 +  Swap(&guid->data2);
   1.164 +  Swap(&guid->data3);
   1.165 +  // Don't swap guid->data4[] because it contains 8-bit quantities.
   1.166 +}
   1.167 +
   1.168 +
   1.169 +//
   1.170 +// Character conversion routines
   1.171 +//
   1.172 +
   1.173 +
   1.174 +// Standard wide-character conversion routines depend on the system's own
   1.175 +// idea of what width a wide character should be: some use 16 bits, and
   1.176 +// some use 32 bits.  For the purposes of a minidump, wide strings are
   1.177 +// always represented with 16-bit UTF-16 chracters.  iconv isn't available
   1.178 +// everywhere, and its interface varies where it is available.  iconv also
   1.179 +// deals purely with char* pointers, so in addition to considering the swap
   1.180 +// parameter, a converter that uses iconv would also need to take the host
   1.181 +// CPU's endianness into consideration.  It doesn't seems worth the trouble
   1.182 +// of making it a dependency when we don't care about anything but UTF-16.
   1.183 +static string* UTF16ToUTF8(const vector<uint16_t>& in,
   1.184 +                           bool                     swap) {
   1.185 +  scoped_ptr<string> out(new string());
   1.186 +
   1.187 +  // Set the string's initial capacity to the number of UTF-16 characters,
   1.188 +  // because the UTF-8 representation will always be at least this long.
   1.189 +  // If the UTF-8 representation is longer, the string will grow dynamically.
   1.190 +  out->reserve(in.size());
   1.191 +
   1.192 +  for (vector<uint16_t>::const_iterator iterator = in.begin();
   1.193 +       iterator != in.end();
   1.194 +       ++iterator) {
   1.195 +    // Get a 16-bit value from the input
   1.196 +    uint16_t in_word = *iterator;
   1.197 +    if (swap)
   1.198 +      Swap(&in_word);
   1.199 +
   1.200 +    // Convert the input value (in_word) into a Unicode code point (unichar).
   1.201 +    uint32_t unichar;
   1.202 +    if (in_word >= 0xdc00 && in_word <= 0xdcff) {
   1.203 +      BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
   1.204 +                      HexString(in_word) << " without high";
   1.205 +      return NULL;
   1.206 +    } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
   1.207 +      // High surrogate.
   1.208 +      unichar = (in_word - 0xd7c0) << 10;
   1.209 +      if (++iterator == in.end()) {
   1.210 +        BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
   1.211 +                        HexString(in_word) << " at end of string";
   1.212 +        return NULL;
   1.213 +      }
   1.214 +      uint32_t high_word = in_word;
   1.215 +      in_word = *iterator;
   1.216 +      if (in_word < 0xdc00 || in_word > 0xdcff) {
   1.217 +        BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
   1.218 +                        HexString(high_word) << " without low " <<
   1.219 +                        HexString(in_word);
   1.220 +        return NULL;
   1.221 +      }
   1.222 +      unichar |= in_word & 0x03ff;
   1.223 +    } else {
   1.224 +      // The ordinary case, a single non-surrogate Unicode character encoded
   1.225 +      // as a single 16-bit value.
   1.226 +      unichar = in_word;
   1.227 +    }
   1.228 +
   1.229 +    // Convert the Unicode code point (unichar) into its UTF-8 representation,
   1.230 +    // appending it to the out string.
   1.231 +    if (unichar < 0x80) {
   1.232 +      (*out) += unichar;
   1.233 +    } else if (unichar < 0x800) {
   1.234 +      (*out) += 0xc0 | (unichar >> 6);
   1.235 +      (*out) += 0x80 | (unichar & 0x3f);
   1.236 +    } else if (unichar < 0x10000) {
   1.237 +      (*out) += 0xe0 | (unichar >> 12);
   1.238 +      (*out) += 0x80 | ((unichar >> 6) & 0x3f);
   1.239 +      (*out) += 0x80 | (unichar & 0x3f);
   1.240 +    } else if (unichar < 0x200000) {
   1.241 +      (*out) += 0xf0 | (unichar >> 18);
   1.242 +      (*out) += 0x80 | ((unichar >> 12) & 0x3f);
   1.243 +      (*out) += 0x80 | ((unichar >> 6) & 0x3f);
   1.244 +      (*out) += 0x80 | (unichar & 0x3f);
   1.245 +    } else {
   1.246 +      BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
   1.247 +                      HexString(unichar) << " in UTF-8";
   1.248 +      return NULL;
   1.249 +    }
   1.250 +  }
   1.251 +
   1.252 +  return out.release();
   1.253 +}
   1.254 +
   1.255 +// Return the smaller of the number of code units in the UTF-16 string,
   1.256 +// not including the terminating null word, or maxlen.
   1.257 +static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) {
   1.258 +  size_t count = 0;
   1.259 +  while (count < maxlen && string[count] != 0)
   1.260 +    count++;
   1.261 +  return count;
   1.262 +}
   1.263 +
   1.264 +
   1.265 +//
   1.266 +// MinidumpObject
   1.267 +//
   1.268 +
   1.269 +
   1.270 +MinidumpObject::MinidumpObject(Minidump* minidump)
   1.271 +    : minidump_(minidump),
   1.272 +      valid_(false) {
   1.273 +}
   1.274 +
   1.275 +
   1.276 +//
   1.277 +// MinidumpStream
   1.278 +//
   1.279 +
   1.280 +
   1.281 +MinidumpStream::MinidumpStream(Minidump* minidump)
   1.282 +    : MinidumpObject(minidump) {
   1.283 +}
   1.284 +
   1.285 +
   1.286 +//
   1.287 +// MinidumpContext
   1.288 +//
   1.289 +
   1.290 +
   1.291 +MinidumpContext::MinidumpContext(Minidump* minidump)
   1.292 +    : MinidumpStream(minidump),
   1.293 +      context_(),
   1.294 +      context_flags_(0) {
   1.295 +}
   1.296 +
   1.297 +
   1.298 +MinidumpContext::~MinidumpContext() {
   1.299 +  FreeContext();
   1.300 +}
   1.301 +
   1.302 +
   1.303 +bool MinidumpContext::Read(uint32_t expected_size) {
   1.304 +  valid_ = false;
   1.305 +
   1.306 +  FreeContext();
   1.307 +
   1.308 +  // First, figure out what type of CPU this context structure is for.
   1.309 +  // For some reason, the AMD64 Context doesn't have context_flags
   1.310 +  // at the beginning of the structure, so special case it here.
   1.311 +  if (expected_size == sizeof(MDRawContextAMD64)) {
   1.312 +    BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
   1.313 +
   1.314 +    scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
   1.315 +    if (!minidump_->ReadBytes(context_amd64.get(),
   1.316 +                              sizeof(MDRawContextAMD64))) {
   1.317 +      BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
   1.318 +      return false;
   1.319 +    }
   1.320 +
   1.321 +    if (minidump_->swap())
   1.322 +      Swap(&context_amd64->context_flags);
   1.323 +
   1.324 +    uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
   1.325 +    if (cpu_type == 0) {
   1.326 +      if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
   1.327 +        context_amd64->context_flags |= cpu_type;
   1.328 +      } else {
   1.329 +        BPLOG(ERROR) << "Failed to preserve the current stream position";
   1.330 +        return false;
   1.331 +      }
   1.332 +    }
   1.333 +
   1.334 +    if (cpu_type != MD_CONTEXT_AMD64) {
   1.335 +      //TODO: fall through to switch below?
   1.336 +      // need a Tell method to be able to SeekSet back to beginning
   1.337 +      // http://code.google.com/p/google-breakpad/issues/detail?id=224
   1.338 +      BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
   1.339 +      return false;
   1.340 +    }
   1.341 +
   1.342 +    // Do this after reading the entire MDRawContext structure because
   1.343 +    // GetSystemInfo may seek minidump to a new position.
   1.344 +    if (!CheckAgainstSystemInfo(cpu_type)) {
   1.345 +      BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
   1.346 +      return false;
   1.347 +    }
   1.348 +
   1.349 +    // Normalize the 128-bit types in the dump.
   1.350 +    // Since this is AMD64, by definition, the values are little-endian.
   1.351 +    for (unsigned int vr_index = 0;
   1.352 +         vr_index < MD_CONTEXT_AMD64_VR_COUNT;
   1.353 +         ++vr_index)
   1.354 +      Normalize128(&context_amd64->vector_register[vr_index], false);
   1.355 +
   1.356 +    if (minidump_->swap()) {
   1.357 +      Swap(&context_amd64->p1_home);
   1.358 +      Swap(&context_amd64->p2_home);
   1.359 +      Swap(&context_amd64->p3_home);
   1.360 +      Swap(&context_amd64->p4_home);
   1.361 +      Swap(&context_amd64->p5_home);
   1.362 +      Swap(&context_amd64->p6_home);
   1.363 +      // context_flags is already swapped
   1.364 +      Swap(&context_amd64->mx_csr);
   1.365 +      Swap(&context_amd64->cs);
   1.366 +      Swap(&context_amd64->ds);
   1.367 +      Swap(&context_amd64->es);
   1.368 +      Swap(&context_amd64->fs);
   1.369 +      Swap(&context_amd64->ss);
   1.370 +      Swap(&context_amd64->eflags);
   1.371 +      Swap(&context_amd64->dr0);
   1.372 +      Swap(&context_amd64->dr1);
   1.373 +      Swap(&context_amd64->dr2);
   1.374 +      Swap(&context_amd64->dr3);
   1.375 +      Swap(&context_amd64->dr6);
   1.376 +      Swap(&context_amd64->dr7);
   1.377 +      Swap(&context_amd64->rax);
   1.378 +      Swap(&context_amd64->rcx);
   1.379 +      Swap(&context_amd64->rdx);
   1.380 +      Swap(&context_amd64->rbx);
   1.381 +      Swap(&context_amd64->rsp);
   1.382 +      Swap(&context_amd64->rbp);
   1.383 +      Swap(&context_amd64->rsi);
   1.384 +      Swap(&context_amd64->rdi);
   1.385 +      Swap(&context_amd64->r8);
   1.386 +      Swap(&context_amd64->r9);
   1.387 +      Swap(&context_amd64->r10);
   1.388 +      Swap(&context_amd64->r11);
   1.389 +      Swap(&context_amd64->r12);
   1.390 +      Swap(&context_amd64->r13);
   1.391 +      Swap(&context_amd64->r14);
   1.392 +      Swap(&context_amd64->r15);
   1.393 +      Swap(&context_amd64->rip);
   1.394 +      //FIXME: I'm not sure what actually determines
   1.395 +      // which member of the union {flt_save, sse_registers}
   1.396 +      // is valid.  We're not currently using either,
   1.397 +      // but it would be good to have them swapped properly.
   1.398 +
   1.399 +      for (unsigned int vr_index = 0;
   1.400 +           vr_index < MD_CONTEXT_AMD64_VR_COUNT;
   1.401 +           ++vr_index)
   1.402 +        Swap(&context_amd64->vector_register[vr_index]);
   1.403 +      Swap(&context_amd64->vector_control);
   1.404 +      Swap(&context_amd64->debug_control);
   1.405 +      Swap(&context_amd64->last_branch_to_rip);
   1.406 +      Swap(&context_amd64->last_branch_from_rip);
   1.407 +      Swap(&context_amd64->last_exception_to_rip);
   1.408 +      Swap(&context_amd64->last_exception_from_rip);
   1.409 +    }
   1.410 +
   1.411 +    context_flags_ = context_amd64->context_flags;
   1.412 +
   1.413 +    context_.amd64 = context_amd64.release();
   1.414 +  }
   1.415 +  else {
   1.416 +    uint32_t context_flags;
   1.417 +    if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
   1.418 +      BPLOG(ERROR) << "MinidumpContext could not read context flags";
   1.419 +      return false;
   1.420 +    }
   1.421 +    if (minidump_->swap())
   1.422 +      Swap(&context_flags);
   1.423 +
   1.424 +    uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
   1.425 +    if (cpu_type == 0) {
   1.426 +      // Unfortunately the flag for MD_CONTEXT_ARM that was taken
   1.427 +      // from a Windows CE SDK header conflicts in practice with
   1.428 +      // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
   1.429 +      // but handle dumps with the legacy value gracefully here.
   1.430 +      if (context_flags & MD_CONTEXT_ARM_OLD) {
   1.431 +        context_flags |= MD_CONTEXT_ARM;
   1.432 +        context_flags &= ~MD_CONTEXT_ARM_OLD;
   1.433 +        cpu_type = MD_CONTEXT_ARM;
   1.434 +      }
   1.435 +    }
   1.436 +
   1.437 +    if (cpu_type == 0) {
   1.438 +      if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
   1.439 +        context_flags |= cpu_type;
   1.440 +      } else {
   1.441 +        BPLOG(ERROR) << "Failed to preserve the current stream position";
   1.442 +        return false;
   1.443 +      }
   1.444 +    }
   1.445 +
   1.446 +    // Allocate the context structure for the correct CPU and fill it.  The
   1.447 +    // casts are slightly unorthodox, but it seems better to do that than to
   1.448 +    // maintain a separate pointer for each type of CPU context structure
   1.449 +    // when only one of them will be used.
   1.450 +    switch (cpu_type) {
   1.451 +      case MD_CONTEXT_X86: {
   1.452 +        if (expected_size != sizeof(MDRawContextX86)) {
   1.453 +          BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
   1.454 +            expected_size << " != " << sizeof(MDRawContextX86);
   1.455 +          return false;
   1.456 +        }
   1.457 +
   1.458 +        scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
   1.459 +
   1.460 +        // Set the context_flags member, which has already been read, and
   1.461 +        // read the rest of the structure beginning with the first member
   1.462 +        // after context_flags.
   1.463 +        context_x86->context_flags = context_flags;
   1.464 +
   1.465 +        size_t flags_size = sizeof(context_x86->context_flags);
   1.466 +        uint8_t* context_after_flags =
   1.467 +          reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
   1.468 +        if (!minidump_->ReadBytes(context_after_flags,
   1.469 +                                  sizeof(MDRawContextX86) - flags_size)) {
   1.470 +          BPLOG(ERROR) << "MinidumpContext could not read x86 context";
   1.471 +          return false;
   1.472 +        }
   1.473 +
   1.474 +        // Do this after reading the entire MDRawContext structure because
   1.475 +        // GetSystemInfo may seek minidump to a new position.
   1.476 +        if (!CheckAgainstSystemInfo(cpu_type)) {
   1.477 +          BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
   1.478 +          return false;
   1.479 +        }
   1.480 +
   1.481 +        if (minidump_->swap()) {
   1.482 +          // context_x86->context_flags was already swapped.
   1.483 +          Swap(&context_x86->dr0);
   1.484 +          Swap(&context_x86->dr1);
   1.485 +          Swap(&context_x86->dr2);
   1.486 +          Swap(&context_x86->dr3);
   1.487 +          Swap(&context_x86->dr6);
   1.488 +          Swap(&context_x86->dr7);
   1.489 +          Swap(&context_x86->float_save.control_word);
   1.490 +          Swap(&context_x86->float_save.status_word);
   1.491 +          Swap(&context_x86->float_save.tag_word);
   1.492 +          Swap(&context_x86->float_save.error_offset);
   1.493 +          Swap(&context_x86->float_save.error_selector);
   1.494 +          Swap(&context_x86->float_save.data_offset);
   1.495 +          Swap(&context_x86->float_save.data_selector);
   1.496 +          // context_x86->float_save.register_area[] contains 8-bit quantities
   1.497 +          // and does not need to be swapped.
   1.498 +          Swap(&context_x86->float_save.cr0_npx_state);
   1.499 +          Swap(&context_x86->gs);
   1.500 +          Swap(&context_x86->fs);
   1.501 +          Swap(&context_x86->es);
   1.502 +          Swap(&context_x86->ds);
   1.503 +          Swap(&context_x86->edi);
   1.504 +          Swap(&context_x86->esi);
   1.505 +          Swap(&context_x86->ebx);
   1.506 +          Swap(&context_x86->edx);
   1.507 +          Swap(&context_x86->ecx);
   1.508 +          Swap(&context_x86->eax);
   1.509 +          Swap(&context_x86->ebp);
   1.510 +          Swap(&context_x86->eip);
   1.511 +          Swap(&context_x86->cs);
   1.512 +          Swap(&context_x86->eflags);
   1.513 +          Swap(&context_x86->esp);
   1.514 +          Swap(&context_x86->ss);
   1.515 +          // context_x86->extended_registers[] contains 8-bit quantities and
   1.516 +          // does not need to be swapped.
   1.517 +        }
   1.518 +
   1.519 +        context_.x86 = context_x86.release();
   1.520 +
   1.521 +        break;
   1.522 +      }
   1.523 +
   1.524 +      case MD_CONTEXT_PPC: {
   1.525 +        if (expected_size != sizeof(MDRawContextPPC)) {
   1.526 +          BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
   1.527 +            expected_size << " != " << sizeof(MDRawContextPPC);
   1.528 +          return false;
   1.529 +        }
   1.530 +
   1.531 +        scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
   1.532 +
   1.533 +        // Set the context_flags member, which has already been read, and
   1.534 +        // read the rest of the structure beginning with the first member
   1.535 +        // after context_flags.
   1.536 +        context_ppc->context_flags = context_flags;
   1.537 +
   1.538 +        size_t flags_size = sizeof(context_ppc->context_flags);
   1.539 +        uint8_t* context_after_flags =
   1.540 +          reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
   1.541 +        if (!minidump_->ReadBytes(context_after_flags,
   1.542 +                                  sizeof(MDRawContextPPC) - flags_size)) {
   1.543 +          BPLOG(ERROR) << "MinidumpContext could not read ppc context";
   1.544 +          return false;
   1.545 +        }
   1.546 +
   1.547 +        // Do this after reading the entire MDRawContext structure because
   1.548 +        // GetSystemInfo may seek minidump to a new position.
   1.549 +        if (!CheckAgainstSystemInfo(cpu_type)) {
   1.550 +          BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
   1.551 +          return false;
   1.552 +        }
   1.553 +
   1.554 +        // Normalize the 128-bit types in the dump.
   1.555 +        // Since this is PowerPC, by definition, the values are big-endian.
   1.556 +        for (unsigned int vr_index = 0;
   1.557 +             vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
   1.558 +             ++vr_index) {
   1.559 +          Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
   1.560 +        }
   1.561 +
   1.562 +        if (minidump_->swap()) {
   1.563 +          // context_ppc->context_flags was already swapped.
   1.564 +          Swap(&context_ppc->srr0);
   1.565 +          Swap(&context_ppc->srr1);
   1.566 +          for (unsigned int gpr_index = 0;
   1.567 +               gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
   1.568 +               ++gpr_index) {
   1.569 +            Swap(&context_ppc->gpr[gpr_index]);
   1.570 +          }
   1.571 +          Swap(&context_ppc->cr);
   1.572 +          Swap(&context_ppc->xer);
   1.573 +          Swap(&context_ppc->lr);
   1.574 +          Swap(&context_ppc->ctr);
   1.575 +          Swap(&context_ppc->mq);
   1.576 +          Swap(&context_ppc->vrsave);
   1.577 +          for (unsigned int fpr_index = 0;
   1.578 +               fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
   1.579 +               ++fpr_index) {
   1.580 +            Swap(&context_ppc->float_save.fpregs[fpr_index]);
   1.581 +          }
   1.582 +          // Don't swap context_ppc->float_save.fpscr_pad because it is only
   1.583 +          // used for padding.
   1.584 +          Swap(&context_ppc->float_save.fpscr);
   1.585 +          for (unsigned int vr_index = 0;
   1.586 +               vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
   1.587 +               ++vr_index) {
   1.588 +            Swap(&context_ppc->vector_save.save_vr[vr_index]);
   1.589 +          }
   1.590 +          Swap(&context_ppc->vector_save.save_vscr);
   1.591 +          // Don't swap the padding fields in vector_save.
   1.592 +          Swap(&context_ppc->vector_save.save_vrvalid);
   1.593 +        }
   1.594 +
   1.595 +        context_.ppc = context_ppc.release();
   1.596 +
   1.597 +        break;
   1.598 +      }
   1.599 +
   1.600 +      case MD_CONTEXT_SPARC: {
   1.601 +        if (expected_size != sizeof(MDRawContextSPARC)) {
   1.602 +          BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
   1.603 +            expected_size << " != " << sizeof(MDRawContextSPARC);
   1.604 +          return false;
   1.605 +        }
   1.606 +
   1.607 +        scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
   1.608 +
   1.609 +        // Set the context_flags member, which has already been read, and
   1.610 +        // read the rest of the structure beginning with the first member
   1.611 +        // after context_flags.
   1.612 +        context_sparc->context_flags = context_flags;
   1.613 +
   1.614 +        size_t flags_size = sizeof(context_sparc->context_flags);
   1.615 +        uint8_t* context_after_flags =
   1.616 +            reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
   1.617 +        if (!minidump_->ReadBytes(context_after_flags,
   1.618 +                                  sizeof(MDRawContextSPARC) - flags_size)) {
   1.619 +          BPLOG(ERROR) << "MinidumpContext could not read sparc context";
   1.620 +          return false;
   1.621 +        }
   1.622 +
   1.623 +        // Do this after reading the entire MDRawContext structure because
   1.624 +        // GetSystemInfo may seek minidump to a new position.
   1.625 +        if (!CheckAgainstSystemInfo(cpu_type)) {
   1.626 +          BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
   1.627 +          return false;
   1.628 +        }
   1.629 +
   1.630 +        if (minidump_->swap()) {
   1.631 +          // context_sparc->context_flags was already swapped.
   1.632 +          for (unsigned int gpr_index = 0;
   1.633 +               gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
   1.634 +               ++gpr_index) {
   1.635 +            Swap(&context_sparc->g_r[gpr_index]);
   1.636 +          }
   1.637 +          Swap(&context_sparc->ccr);
   1.638 +          Swap(&context_sparc->pc);
   1.639 +          Swap(&context_sparc->npc);
   1.640 +          Swap(&context_sparc->y);
   1.641 +          Swap(&context_sparc->asi);
   1.642 +          Swap(&context_sparc->fprs);
   1.643 +          for (unsigned int fpr_index = 0;
   1.644 +               fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
   1.645 +               ++fpr_index) {
   1.646 +            Swap(&context_sparc->float_save.regs[fpr_index]);
   1.647 +          }
   1.648 +          Swap(&context_sparc->float_save.filler);
   1.649 +          Swap(&context_sparc->float_save.fsr);
   1.650 +        }
   1.651 +        context_.ctx_sparc = context_sparc.release();
   1.652 +
   1.653 +        break;
   1.654 +      }
   1.655 +
   1.656 +      case MD_CONTEXT_ARM: {
   1.657 +        if (expected_size != sizeof(MDRawContextARM)) {
   1.658 +          BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
   1.659 +            expected_size << " != " << sizeof(MDRawContextARM);
   1.660 +          return false;
   1.661 +        }
   1.662 +
   1.663 +        scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
   1.664 +
   1.665 +        // Set the context_flags member, which has already been read, and
   1.666 +        // read the rest of the structure beginning with the first member
   1.667 +        // after context_flags.
   1.668 +        context_arm->context_flags = context_flags;
   1.669 +
   1.670 +        size_t flags_size = sizeof(context_arm->context_flags);
   1.671 +        uint8_t* context_after_flags =
   1.672 +            reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
   1.673 +        if (!minidump_->ReadBytes(context_after_flags,
   1.674 +                                  sizeof(MDRawContextARM) - flags_size)) {
   1.675 +          BPLOG(ERROR) << "MinidumpContext could not read arm context";
   1.676 +          return false;
   1.677 +        }
   1.678 +
   1.679 +        // Do this after reading the entire MDRawContext structure because
   1.680 +        // GetSystemInfo may seek minidump to a new position.
   1.681 +        if (!CheckAgainstSystemInfo(cpu_type)) {
   1.682 +          BPLOG(ERROR) << "MinidumpContext arm does not match system info";
   1.683 +          return false;
   1.684 +        }
   1.685 +
   1.686 +        if (minidump_->swap()) {
   1.687 +          // context_arm->context_flags was already swapped.
   1.688 +          for (unsigned int ireg_index = 0;
   1.689 +               ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
   1.690 +               ++ireg_index) {
   1.691 +            Swap(&context_arm->iregs[ireg_index]);
   1.692 +          }
   1.693 +          Swap(&context_arm->cpsr);
   1.694 +          Swap(&context_arm->float_save.fpscr);
   1.695 +          for (unsigned int fpr_index = 0;
   1.696 +               fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
   1.697 +               ++fpr_index) {
   1.698 +            Swap(&context_arm->float_save.regs[fpr_index]);
   1.699 +          }
   1.700 +          for (unsigned int fpe_index = 0;
   1.701 +               fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
   1.702 +               ++fpe_index) {
   1.703 +            Swap(&context_arm->float_save.extra[fpe_index]);
   1.704 +          }
   1.705 +        }
   1.706 +        context_.arm = context_arm.release();
   1.707 +
   1.708 +        break;
   1.709 +      }
   1.710 +
   1.711 +      default: {
   1.712 +        // Unknown context type - Don't log as an error yet. Let the
   1.713 +        // caller work that out.
   1.714 +        BPLOG(INFO) << "MinidumpContext unknown context type " <<
   1.715 +          HexString(cpu_type);
   1.716 +        return false;
   1.717 +        break;
   1.718 +      }
   1.719 +    }
   1.720 +    context_flags_ = context_flags;
   1.721 +  }
   1.722 +
   1.723 +  valid_ = true;
   1.724 +  return true;
   1.725 +}
   1.726 +
   1.727 +
   1.728 +uint32_t MinidumpContext::GetContextCPU() const {
   1.729 +  if (!valid_) {
   1.730 +    // Don't log a message, GetContextCPU can be legitimately called with
   1.731 +    // valid_ false by FreeContext, which is called by Read.
   1.732 +    return 0;
   1.733 +  }
   1.734 +
   1.735 +  return context_flags_ & MD_CONTEXT_CPU_MASK;
   1.736 +}
   1.737 +
   1.738 +bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const {
   1.739 +  BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer "
   1.740 +                          "requires |ip|";
   1.741 +  assert(ip);
   1.742 +  *ip = 0;
   1.743 +
   1.744 +  if (!valid_) {
   1.745 +    BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer";
   1.746 +    return false;
   1.747 +  }
   1.748 +
   1.749 +  switch (context_flags_ & MD_CONTEXT_CPU_MASK) {
   1.750 +  case MD_CONTEXT_AMD64:
   1.751 +    *ip = context_.amd64->rip;
   1.752 +    break;
   1.753 +  case MD_CONTEXT_ARM:
   1.754 +    *ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC];
   1.755 +    break;
   1.756 +  case MD_CONTEXT_PPC:
   1.757 +    *ip = context_.ppc->srr0;
   1.758 +    break;
   1.759 +  case MD_CONTEXT_SPARC:
   1.760 +    *ip = context_.ctx_sparc->pc;
   1.761 +    break;
   1.762 +  case MD_CONTEXT_X86:
   1.763 +    *ip = context_.x86->eip;
   1.764 +    break;
   1.765 +  default:
   1.766 +    // This should never happen.
   1.767 +    BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
   1.768 +    return false;
   1.769 +  }
   1.770 +  return true;
   1.771 +}
   1.772 +
   1.773 +
   1.774 +const MDRawContextX86* MinidumpContext::GetContextX86() const {
   1.775 +  if (GetContextCPU() != MD_CONTEXT_X86) {
   1.776 +    BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
   1.777 +    return NULL;
   1.778 +  }
   1.779 +
   1.780 +  return context_.x86;
   1.781 +}
   1.782 +
   1.783 +
   1.784 +const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
   1.785 +  if (GetContextCPU() != MD_CONTEXT_PPC) {
   1.786 +    BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
   1.787 +    return NULL;
   1.788 +  }
   1.789 +
   1.790 +  return context_.ppc;
   1.791 +}
   1.792 +
   1.793 +const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
   1.794 +  if (GetContextCPU() != MD_CONTEXT_AMD64) {
   1.795 +    BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
   1.796 +    return NULL;
   1.797 +  }
   1.798 +
   1.799 +  return context_.amd64;
   1.800 +}
   1.801 +
   1.802 +const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
   1.803 +  if (GetContextCPU() != MD_CONTEXT_SPARC) {
   1.804 +    BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
   1.805 +    return NULL;
   1.806 +  }
   1.807 +
   1.808 +  return context_.ctx_sparc;
   1.809 +}
   1.810 +
   1.811 +const MDRawContextARM* MinidumpContext::GetContextARM() const {
   1.812 +  if (GetContextCPU() != MD_CONTEXT_ARM) {
   1.813 +    BPLOG(ERROR) << "MinidumpContext cannot get arm context";
   1.814 +    return NULL;
   1.815 +  }
   1.816 +
   1.817 +  return context_.arm;
   1.818 +}
   1.819 +
   1.820 +void MinidumpContext::FreeContext() {
   1.821 +  switch (GetContextCPU()) {
   1.822 +    case MD_CONTEXT_X86:
   1.823 +      delete context_.x86;
   1.824 +      break;
   1.825 +
   1.826 +    case MD_CONTEXT_PPC:
   1.827 +      delete context_.ppc;
   1.828 +      break;
   1.829 +
   1.830 +    case MD_CONTEXT_AMD64:
   1.831 +      delete context_.amd64;
   1.832 +      break;
   1.833 +
   1.834 +    case MD_CONTEXT_SPARC:
   1.835 +      delete context_.ctx_sparc;
   1.836 +      break;
   1.837 +
   1.838 +    case MD_CONTEXT_ARM:
   1.839 +      delete context_.arm;
   1.840 +      break;
   1.841 +
   1.842 +    default:
   1.843 +      // There is no context record (valid_ is false) or there's a
   1.844 +      // context record for an unknown CPU (shouldn't happen, only known
   1.845 +      // records are stored by Read).
   1.846 +      break;
   1.847 +  }
   1.848 +
   1.849 +  context_flags_ = 0;
   1.850 +  context_.base = NULL;
   1.851 +}
   1.852 +
   1.853 +
   1.854 +bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
   1.855 +  // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
   1.856 +  // as this function just implements a sanity check.
   1.857 +  MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
   1.858 +  if (!system_info) {
   1.859 +    BPLOG(INFO) << "MinidumpContext could not be compared against "
   1.860 +                   "MinidumpSystemInfo";
   1.861 +    return true;
   1.862 +  }
   1.863 +
   1.864 +  // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
   1.865 +  const MDRawSystemInfo* raw_system_info = system_info->system_info();
   1.866 +  if (!raw_system_info) {
   1.867 +    BPLOG(INFO) << "MinidumpContext could not be compared against "
   1.868 +                   "MDRawSystemInfo";
   1.869 +    return false;
   1.870 +  }
   1.871 +
   1.872 +  MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
   1.873 +      raw_system_info->processor_architecture);
   1.874 +
   1.875 +  // Compare the CPU type of the context record to the CPU type in the
   1.876 +  // minidump's system info stream.
   1.877 +  bool return_value = false;
   1.878 +  switch (context_cpu_type) {
   1.879 +    case MD_CONTEXT_X86:
   1.880 +      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
   1.881 +          system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
   1.882 +          system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
   1.883 +        return_value = true;
   1.884 +      }
   1.885 +      break;
   1.886 +
   1.887 +    case MD_CONTEXT_PPC:
   1.888 +      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
   1.889 +        return_value = true;
   1.890 +      break;
   1.891 +
   1.892 +    case MD_CONTEXT_AMD64:
   1.893 +      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
   1.894 +        return_value = true;
   1.895 +      break;
   1.896 +
   1.897 +    case MD_CONTEXT_SPARC:
   1.898 +      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
   1.899 +        return_value = true;
   1.900 +      break;
   1.901 +
   1.902 +    case MD_CONTEXT_ARM:
   1.903 +      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
   1.904 +        return_value = true;
   1.905 +      break;
   1.906 +  }
   1.907 +
   1.908 +  BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
   1.909 +                                    HexString(context_cpu_type) <<
   1.910 +                                    " wrong for MinidumpSystemInfo CPU " <<
   1.911 +                                    HexString(system_info_cpu_type);
   1.912 +
   1.913 +  return return_value;
   1.914 +}
   1.915 +
   1.916 +
   1.917 +void MinidumpContext::Print() {
   1.918 +  if (!valid_) {
   1.919 +    BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
   1.920 +    return;
   1.921 +  }
   1.922 +
   1.923 +  switch (GetContextCPU()) {
   1.924 +    case MD_CONTEXT_X86: {
   1.925 +      const MDRawContextX86* context_x86 = GetContextX86();
   1.926 +      printf("MDRawContextX86\n");
   1.927 +      printf("  context_flags                = 0x%x\n",
   1.928 +             context_x86->context_flags);
   1.929 +      printf("  dr0                          = 0x%x\n", context_x86->dr0);
   1.930 +      printf("  dr1                          = 0x%x\n", context_x86->dr1);
   1.931 +      printf("  dr2                          = 0x%x\n", context_x86->dr2);
   1.932 +      printf("  dr3                          = 0x%x\n", context_x86->dr3);
   1.933 +      printf("  dr6                          = 0x%x\n", context_x86->dr6);
   1.934 +      printf("  dr7                          = 0x%x\n", context_x86->dr7);
   1.935 +      printf("  float_save.control_word      = 0x%x\n",
   1.936 +             context_x86->float_save.control_word);
   1.937 +      printf("  float_save.status_word       = 0x%x\n",
   1.938 +             context_x86->float_save.status_word);
   1.939 +      printf("  float_save.tag_word          = 0x%x\n",
   1.940 +             context_x86->float_save.tag_word);
   1.941 +      printf("  float_save.error_offset      = 0x%x\n",
   1.942 +             context_x86->float_save.error_offset);
   1.943 +      printf("  float_save.error_selector    = 0x%x\n",
   1.944 +             context_x86->float_save.error_selector);
   1.945 +      printf("  float_save.data_offset       = 0x%x\n",
   1.946 +             context_x86->float_save.data_offset);
   1.947 +      printf("  float_save.data_selector     = 0x%x\n",
   1.948 +             context_x86->float_save.data_selector);
   1.949 +      printf("  float_save.register_area[%2d] = 0x",
   1.950 +             MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
   1.951 +      for (unsigned int register_index = 0;
   1.952 +           register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
   1.953 +           ++register_index) {
   1.954 +        printf("%02x", context_x86->float_save.register_area[register_index]);
   1.955 +      }
   1.956 +      printf("\n");
   1.957 +      printf("  float_save.cr0_npx_state     = 0x%x\n",
   1.958 +             context_x86->float_save.cr0_npx_state);
   1.959 +      printf("  gs                           = 0x%x\n", context_x86->gs);
   1.960 +      printf("  fs                           = 0x%x\n", context_x86->fs);
   1.961 +      printf("  es                           = 0x%x\n", context_x86->es);
   1.962 +      printf("  ds                           = 0x%x\n", context_x86->ds);
   1.963 +      printf("  edi                          = 0x%x\n", context_x86->edi);
   1.964 +      printf("  esi                          = 0x%x\n", context_x86->esi);
   1.965 +      printf("  ebx                          = 0x%x\n", context_x86->ebx);
   1.966 +      printf("  edx                          = 0x%x\n", context_x86->edx);
   1.967 +      printf("  ecx                          = 0x%x\n", context_x86->ecx);
   1.968 +      printf("  eax                          = 0x%x\n", context_x86->eax);
   1.969 +      printf("  ebp                          = 0x%x\n", context_x86->ebp);
   1.970 +      printf("  eip                          = 0x%x\n", context_x86->eip);
   1.971 +      printf("  cs                           = 0x%x\n", context_x86->cs);
   1.972 +      printf("  eflags                       = 0x%x\n", context_x86->eflags);
   1.973 +      printf("  esp                          = 0x%x\n", context_x86->esp);
   1.974 +      printf("  ss                           = 0x%x\n", context_x86->ss);
   1.975 +      printf("  extended_registers[%3d]      = 0x",
   1.976 +             MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
   1.977 +      for (unsigned int register_index = 0;
   1.978 +           register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
   1.979 +           ++register_index) {
   1.980 +        printf("%02x", context_x86->extended_registers[register_index]);
   1.981 +      }
   1.982 +      printf("\n\n");
   1.983 +
   1.984 +      break;
   1.985 +    }
   1.986 +
   1.987 +    case MD_CONTEXT_PPC: {
   1.988 +      const MDRawContextPPC* context_ppc = GetContextPPC();
   1.989 +      printf("MDRawContextPPC\n");
   1.990 +      printf("  context_flags            = 0x%x\n",
   1.991 +             context_ppc->context_flags);
   1.992 +      printf("  srr0                     = 0x%x\n", context_ppc->srr0);
   1.993 +      printf("  srr1                     = 0x%x\n", context_ppc->srr1);
   1.994 +      for (unsigned int gpr_index = 0;
   1.995 +           gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
   1.996 +           ++gpr_index) {
   1.997 +        printf("  gpr[%2d]                  = 0x%x\n",
   1.998 +               gpr_index, context_ppc->gpr[gpr_index]);
   1.999 +      }
  1.1000 +      printf("  cr                       = 0x%x\n", context_ppc->cr);
  1.1001 +      printf("  xer                      = 0x%x\n", context_ppc->xer);
  1.1002 +      printf("  lr                       = 0x%x\n", context_ppc->lr);
  1.1003 +      printf("  ctr                      = 0x%x\n", context_ppc->ctr);
  1.1004 +      printf("  mq                       = 0x%x\n", context_ppc->mq);
  1.1005 +      printf("  vrsave                   = 0x%x\n", context_ppc->vrsave);
  1.1006 +      for (unsigned int fpr_index = 0;
  1.1007 +           fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
  1.1008 +           ++fpr_index) {
  1.1009 +        printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
  1.1010 +               fpr_index, context_ppc->float_save.fpregs[fpr_index]);
  1.1011 +      }
  1.1012 +      printf("  float_save.fpscr         = 0x%x\n",
  1.1013 +             context_ppc->float_save.fpscr);
  1.1014 +      // TODO(mmentovai): print the 128-bit quantities in
  1.1015 +      // context_ppc->vector_save.  This isn't done yet because printf
  1.1016 +      // doesn't support 128-bit quantities, and printing them using
  1.1017 +      // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
  1.1018 +      // byte ordering.
  1.1019 +      printf("  vector_save.save_vrvalid = 0x%x\n",
  1.1020 +             context_ppc->vector_save.save_vrvalid);
  1.1021 +      printf("\n");
  1.1022 +
  1.1023 +      break;
  1.1024 +    }
  1.1025 +
  1.1026 +    case MD_CONTEXT_AMD64: {
  1.1027 +      const MDRawContextAMD64* context_amd64 = GetContextAMD64();
  1.1028 +      printf("MDRawContextAMD64\n");
  1.1029 +      printf("  p1_home       = 0x%" PRIx64 "\n",
  1.1030 +             context_amd64->p1_home);
  1.1031 +      printf("  p2_home       = 0x%" PRIx64 "\n",
  1.1032 +             context_amd64->p2_home);
  1.1033 +      printf("  p3_home       = 0x%" PRIx64 "\n",
  1.1034 +             context_amd64->p3_home);
  1.1035 +      printf("  p4_home       = 0x%" PRIx64 "\n",
  1.1036 +             context_amd64->p4_home);
  1.1037 +      printf("  p5_home       = 0x%" PRIx64 "\n",
  1.1038 +             context_amd64->p5_home);
  1.1039 +      printf("  p6_home       = 0x%" PRIx64 "\n",
  1.1040 +             context_amd64->p6_home);
  1.1041 +      printf("  context_flags = 0x%x\n",
  1.1042 +             context_amd64->context_flags);
  1.1043 +      printf("  mx_csr        = 0x%x\n",
  1.1044 +             context_amd64->mx_csr);
  1.1045 +      printf("  cs            = 0x%x\n", context_amd64->cs);
  1.1046 +      printf("  ds            = 0x%x\n", context_amd64->ds);
  1.1047 +      printf("  es            = 0x%x\n", context_amd64->es);
  1.1048 +      printf("  fs            = 0x%x\n", context_amd64->fs);
  1.1049 +      printf("  gs            = 0x%x\n", context_amd64->gs);
  1.1050 +      printf("  ss            = 0x%x\n", context_amd64->ss);
  1.1051 +      printf("  eflags        = 0x%x\n", context_amd64->eflags);
  1.1052 +      printf("  dr0           = 0x%" PRIx64 "\n", context_amd64->dr0);
  1.1053 +      printf("  dr1           = 0x%" PRIx64 "\n", context_amd64->dr1);
  1.1054 +      printf("  dr2           = 0x%" PRIx64 "\n", context_amd64->dr2);
  1.1055 +      printf("  dr3           = 0x%" PRIx64 "\n", context_amd64->dr3);
  1.1056 +      printf("  dr6           = 0x%" PRIx64 "\n", context_amd64->dr6);
  1.1057 +      printf("  dr7           = 0x%" PRIx64 "\n", context_amd64->dr7);
  1.1058 +      printf("  rax           = 0x%" PRIx64 "\n", context_amd64->rax);
  1.1059 +      printf("  rcx           = 0x%" PRIx64 "\n", context_amd64->rcx);
  1.1060 +      printf("  rdx           = 0x%" PRIx64 "\n", context_amd64->rdx);
  1.1061 +      printf("  rbx           = 0x%" PRIx64 "\n", context_amd64->rbx);
  1.1062 +      printf("  rsp           = 0x%" PRIx64 "\n", context_amd64->rsp);
  1.1063 +      printf("  rbp           = 0x%" PRIx64 "\n", context_amd64->rbp);
  1.1064 +      printf("  rsi           = 0x%" PRIx64 "\n", context_amd64->rsi);
  1.1065 +      printf("  rdi           = 0x%" PRIx64 "\n", context_amd64->rdi);
  1.1066 +      printf("  r8            = 0x%" PRIx64 "\n", context_amd64->r8);
  1.1067 +      printf("  r9            = 0x%" PRIx64 "\n", context_amd64->r9);
  1.1068 +      printf("  r10           = 0x%" PRIx64 "\n", context_amd64->r10);
  1.1069 +      printf("  r11           = 0x%" PRIx64 "\n", context_amd64->r11);
  1.1070 +      printf("  r12           = 0x%" PRIx64 "\n", context_amd64->r12);
  1.1071 +      printf("  r13           = 0x%" PRIx64 "\n", context_amd64->r13);
  1.1072 +      printf("  r14           = 0x%" PRIx64 "\n", context_amd64->r14);
  1.1073 +      printf("  r15           = 0x%" PRIx64 "\n", context_amd64->r15);
  1.1074 +      printf("  rip           = 0x%" PRIx64 "\n", context_amd64->rip);
  1.1075 +      //TODO: print xmm, vector, debug registers
  1.1076 +      printf("\n");
  1.1077 +      break;
  1.1078 +    }
  1.1079 +
  1.1080 +    case MD_CONTEXT_SPARC: {
  1.1081 +      const MDRawContextSPARC* context_sparc = GetContextSPARC();
  1.1082 +      printf("MDRawContextSPARC\n");
  1.1083 +      printf("  context_flags       = 0x%x\n",
  1.1084 +             context_sparc->context_flags);
  1.1085 +      for (unsigned int g_r_index = 0;
  1.1086 +           g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
  1.1087 +           ++g_r_index) {
  1.1088 +        printf("  g_r[%2d]             = 0x%" PRIx64 "\n",
  1.1089 +               g_r_index, context_sparc->g_r[g_r_index]);
  1.1090 +      }
  1.1091 +      printf("  ccr                 = 0x%" PRIx64 "\n", context_sparc->ccr);
  1.1092 +      printf("  pc                  = 0x%" PRIx64 "\n", context_sparc->pc);
  1.1093 +      printf("  npc                 = 0x%" PRIx64 "\n", context_sparc->npc);
  1.1094 +      printf("  y                   = 0x%" PRIx64 "\n", context_sparc->y);
  1.1095 +      printf("  asi                 = 0x%" PRIx64 "\n", context_sparc->asi);
  1.1096 +      printf("  fprs                = 0x%" PRIx64 "\n", context_sparc->fprs);
  1.1097 +
  1.1098 +      for (unsigned int fpr_index = 0;
  1.1099 +           fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
  1.1100 +           ++fpr_index) {
  1.1101 +        printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
  1.1102 +               fpr_index, context_sparc->float_save.regs[fpr_index]);
  1.1103 +      }
  1.1104 +      printf("  float_save.filler   = 0x%" PRIx64 "\n",
  1.1105 +             context_sparc->float_save.filler);
  1.1106 +      printf("  float_save.fsr      = 0x%" PRIx64 "\n",
  1.1107 +             context_sparc->float_save.fsr);
  1.1108 +      break;
  1.1109 +    }
  1.1110 +
  1.1111 +    case MD_CONTEXT_ARM: {
  1.1112 +      const MDRawContextARM* context_arm = GetContextARM();
  1.1113 +      printf("MDRawContextARM\n");
  1.1114 +      printf("  context_flags       = 0x%x\n",
  1.1115 +             context_arm->context_flags);
  1.1116 +      for (unsigned int ireg_index = 0;
  1.1117 +           ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
  1.1118 +           ++ireg_index) {
  1.1119 +        printf("  iregs[%2d]            = 0x%x\n",
  1.1120 +               ireg_index, context_arm->iregs[ireg_index]);
  1.1121 +      }
  1.1122 +      printf("  cpsr                = 0x%x\n", context_arm->cpsr);
  1.1123 +      printf("  float_save.fpscr     = 0x%" PRIx64 "\n",
  1.1124 +             context_arm->float_save.fpscr);
  1.1125 +      for (unsigned int fpr_index = 0;
  1.1126 +           fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
  1.1127 +           ++fpr_index) {
  1.1128 +        printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
  1.1129 +               fpr_index, context_arm->float_save.regs[fpr_index]);
  1.1130 +      }
  1.1131 +      for (unsigned int fpe_index = 0;
  1.1132 +           fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
  1.1133 +           ++fpe_index) {
  1.1134 +        printf("  float_save.extra[%2d] = 0x%" PRIx32 "\n",
  1.1135 +               fpe_index, context_arm->float_save.extra[fpe_index]);
  1.1136 +      }
  1.1137 +
  1.1138 +      break;
  1.1139 +    }
  1.1140 +
  1.1141 +    default: {
  1.1142 +      break;
  1.1143 +    }
  1.1144 +  }
  1.1145 +}
  1.1146 +
  1.1147 +
  1.1148 +//
  1.1149 +// MinidumpMemoryRegion
  1.1150 +//
  1.1151 +
  1.1152 +
  1.1153 +uint32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024;  // 1MB
  1.1154 +
  1.1155 +
  1.1156 +MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
  1.1157 +    : MinidumpObject(minidump),
  1.1158 +      descriptor_(NULL),
  1.1159 +      memory_(NULL) {
  1.1160 +}
  1.1161 +
  1.1162 +
  1.1163 +MinidumpMemoryRegion::~MinidumpMemoryRegion() {
  1.1164 +  delete memory_;
  1.1165 +}
  1.1166 +
  1.1167 +
  1.1168 +void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
  1.1169 +  descriptor_ = descriptor;
  1.1170 +  valid_ = descriptor &&
  1.1171 +           descriptor_->memory.data_size <=
  1.1172 +               numeric_limits<uint64_t>::max() -
  1.1173 +               descriptor_->start_of_memory_range;
  1.1174 +}
  1.1175 +
  1.1176 +
  1.1177 +const uint8_t* MinidumpMemoryRegion::GetMemory() const {
  1.1178 +  if (!valid_) {
  1.1179 +    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
  1.1180 +    return NULL;
  1.1181 +  }
  1.1182 +
  1.1183 +  if (!memory_) {
  1.1184 +    if (descriptor_->memory.data_size == 0) {
  1.1185 +      BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
  1.1186 +      return NULL;
  1.1187 +    }
  1.1188 +
  1.1189 +    if (!minidump_->SeekSet(descriptor_->memory.rva)) {
  1.1190 +      BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
  1.1191 +      return NULL;
  1.1192 +    }
  1.1193 +
  1.1194 +    if (descriptor_->memory.data_size > max_bytes_) {
  1.1195 +      BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
  1.1196 +                      descriptor_->memory.data_size << " exceeds maximum " <<
  1.1197 +                      max_bytes_;
  1.1198 +      return NULL;
  1.1199 +    }
  1.1200 +
  1.1201 +    scoped_ptr< vector<uint8_t> > memory(
  1.1202 +        new vector<uint8_t>(descriptor_->memory.data_size));
  1.1203 +
  1.1204 +    if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
  1.1205 +      BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
  1.1206 +      return NULL;
  1.1207 +    }
  1.1208 +
  1.1209 +    memory_ = memory.release();
  1.1210 +  }
  1.1211 +
  1.1212 +  return &(*memory_)[0];
  1.1213 +}
  1.1214 +
  1.1215 +
  1.1216 +uint64_t MinidumpMemoryRegion::GetBase() const {
  1.1217 +  if (!valid_) {
  1.1218 +    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
  1.1219 +    return static_cast<uint64_t>(-1);
  1.1220 +  }
  1.1221 +
  1.1222 +  return descriptor_->start_of_memory_range;
  1.1223 +}
  1.1224 +
  1.1225 +
  1.1226 +uint32_t MinidumpMemoryRegion::GetSize() const {
  1.1227 +  if (!valid_) {
  1.1228 +    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
  1.1229 +    return 0;
  1.1230 +  }
  1.1231 +
  1.1232 +  return descriptor_->memory.data_size;
  1.1233 +}
  1.1234 +
  1.1235 +
  1.1236 +void MinidumpMemoryRegion::FreeMemory() {
  1.1237 +  delete memory_;
  1.1238 +  memory_ = NULL;
  1.1239 +}
  1.1240 +
  1.1241 +
  1.1242 +template<typename T>
  1.1243 +bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
  1.1244 +                                                      T*        value) const {
  1.1245 +  BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
  1.1246 +                             "requires |value|";
  1.1247 +  assert(value);
  1.1248 +  *value = 0;
  1.1249 +
  1.1250 +  if (!valid_) {
  1.1251 +    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
  1.1252 +                    "GetMemoryAtAddressInternal";
  1.1253 +    return false;
  1.1254 +  }
  1.1255 +
  1.1256 +  // Common failure case
  1.1257 +  if (address < descriptor_->start_of_memory_range ||
  1.1258 +      sizeof(T) > numeric_limits<uint64_t>::max() - address ||
  1.1259 +      address + sizeof(T) > descriptor_->start_of_memory_range +
  1.1260 +                            descriptor_->memory.data_size) {
  1.1261 +    BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
  1.1262 +                    HexString(address) << "+" << sizeof(T) << "/" <<
  1.1263 +                    HexString(descriptor_->start_of_memory_range) << "+" <<
  1.1264 +                    HexString(descriptor_->memory.data_size);
  1.1265 +    return false;
  1.1266 +  }
  1.1267 +
  1.1268 +  const uint8_t* memory = GetMemory();
  1.1269 +  if (!memory) {
  1.1270 +    // GetMemory already logged a perfectly good message.
  1.1271 +    return false;
  1.1272 +  }
  1.1273 +
  1.1274 +  // If the CPU requires memory accesses to be aligned, this can crash.
  1.1275 +  // x86 and ppc are able to cope, though.
  1.1276 +  *value = *reinterpret_cast<const T*>(
  1.1277 +      &memory[address - descriptor_->start_of_memory_range]);
  1.1278 +
  1.1279 +  if (minidump_->swap())
  1.1280 +    Swap(value);
  1.1281 +
  1.1282 +  return true;
  1.1283 +}
  1.1284 +
  1.1285 +
  1.1286 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1.1287 +                                              uint8_t*  value) const {
  1.1288 +  return GetMemoryAtAddressInternal(address, value);
  1.1289 +}
  1.1290 +
  1.1291 +
  1.1292 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1.1293 +                                              uint16_t* value) const {
  1.1294 +  return GetMemoryAtAddressInternal(address, value);
  1.1295 +}
  1.1296 +
  1.1297 +
  1.1298 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1.1299 +                                              uint32_t* value) const {
  1.1300 +  return GetMemoryAtAddressInternal(address, value);
  1.1301 +}
  1.1302 +
  1.1303 +
  1.1304 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1.1305 +                                              uint64_t* value) const {
  1.1306 +  return GetMemoryAtAddressInternal(address, value);
  1.1307 +}
  1.1308 +
  1.1309 +
  1.1310 +void MinidumpMemoryRegion::Print() {
  1.1311 +  if (!valid_) {
  1.1312 +    BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
  1.1313 +    return;
  1.1314 +  }
  1.1315 +
  1.1316 +  const uint8_t* memory = GetMemory();
  1.1317 +  if (memory) {
  1.1318 +    printf("0x");
  1.1319 +    for (unsigned int byte_index = 0;
  1.1320 +         byte_index < descriptor_->memory.data_size;
  1.1321 +         byte_index++) {
  1.1322 +      printf("%02x", memory[byte_index]);
  1.1323 +    }
  1.1324 +    printf("\n");
  1.1325 +  } else {
  1.1326 +    printf("No memory\n");
  1.1327 +  }
  1.1328 +}
  1.1329 +
  1.1330 +
  1.1331 +//
  1.1332 +// MinidumpThread
  1.1333 +//
  1.1334 +
  1.1335 +
  1.1336 +MinidumpThread::MinidumpThread(Minidump* minidump)
  1.1337 +    : MinidumpObject(minidump),
  1.1338 +      thread_(),
  1.1339 +      memory_(NULL),
  1.1340 +      context_(NULL) {
  1.1341 +}
  1.1342 +
  1.1343 +
  1.1344 +MinidumpThread::~MinidumpThread() {
  1.1345 +  delete memory_;
  1.1346 +  delete context_;
  1.1347 +}
  1.1348 +
  1.1349 +
  1.1350 +bool MinidumpThread::Read() {
  1.1351 +  // Invalidate cached data.
  1.1352 +  delete memory_;
  1.1353 +  memory_ = NULL;
  1.1354 +  delete context_;
  1.1355 +  context_ = NULL;
  1.1356 +
  1.1357 +  valid_ = false;
  1.1358 +
  1.1359 +  if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
  1.1360 +    BPLOG(ERROR) << "MinidumpThread cannot read thread";
  1.1361 +    return false;
  1.1362 +  }
  1.1363 +
  1.1364 +  if (minidump_->swap()) {
  1.1365 +    Swap(&thread_.thread_id);
  1.1366 +    Swap(&thread_.suspend_count);
  1.1367 +    Swap(&thread_.priority_class);
  1.1368 +    Swap(&thread_.priority);
  1.1369 +    Swap(&thread_.teb);
  1.1370 +    Swap(&thread_.stack);
  1.1371 +    Swap(&thread_.thread_context);
  1.1372 +  }
  1.1373 +
  1.1374 +  // Check for base + size overflow or undersize.
  1.1375 +  if (thread_.stack.memory.data_size == 0 ||
  1.1376 +      thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
  1.1377 +                                       thread_.stack.start_of_memory_range) {
  1.1378 +    // This is ok, but log an error anyway.
  1.1379 +    BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
  1.1380 +                    HexString(thread_.stack.start_of_memory_range) << "+" <<
  1.1381 +                    HexString(thread_.stack.memory.data_size);
  1.1382 +  } else {
  1.1383 +    memory_ = new MinidumpMemoryRegion(minidump_);
  1.1384 +    memory_->SetDescriptor(&thread_.stack);
  1.1385 +  }
  1.1386 +
  1.1387 +  valid_ = true;
  1.1388 +  return true;
  1.1389 +}
  1.1390 +
  1.1391 +
  1.1392 +MinidumpMemoryRegion* MinidumpThread::GetMemory() {
  1.1393 +  if (!valid_) {
  1.1394 +    BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
  1.1395 +    return NULL;
  1.1396 +  }
  1.1397 +
  1.1398 +  return memory_;
  1.1399 +}
  1.1400 +
  1.1401 +
  1.1402 +MinidumpContext* MinidumpThread::GetContext() {
  1.1403 +  if (!valid_) {
  1.1404 +    BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
  1.1405 +    return NULL;
  1.1406 +  }
  1.1407 +
  1.1408 +  if (!context_) {
  1.1409 +    if (!minidump_->SeekSet(thread_.thread_context.rva)) {
  1.1410 +      BPLOG(ERROR) << "MinidumpThread cannot seek to context";
  1.1411 +      return NULL;
  1.1412 +    }
  1.1413 +
  1.1414 +    scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
  1.1415 +
  1.1416 +    if (!context->Read(thread_.thread_context.data_size)) {
  1.1417 +      BPLOG(ERROR) << "MinidumpThread cannot read context";
  1.1418 +      return NULL;
  1.1419 +    }
  1.1420 +
  1.1421 +    context_ = context.release();
  1.1422 +  }
  1.1423 +
  1.1424 +  return context_;
  1.1425 +}
  1.1426 +
  1.1427 +
  1.1428 +bool MinidumpThread::GetThreadID(uint32_t *thread_id) const {
  1.1429 +  BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
  1.1430 +                                 "|thread_id|";
  1.1431 +  assert(thread_id);
  1.1432 +  *thread_id = 0;
  1.1433 +
  1.1434 +  if (!valid_) {
  1.1435 +    BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
  1.1436 +    return false;
  1.1437 +  }
  1.1438 +
  1.1439 +  *thread_id = thread_.thread_id;
  1.1440 +  return true;
  1.1441 +}
  1.1442 +
  1.1443 +
  1.1444 +void MinidumpThread::Print() {
  1.1445 +  if (!valid_) {
  1.1446 +    BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
  1.1447 +    return;
  1.1448 +  }
  1.1449 +
  1.1450 +  printf("MDRawThread\n");
  1.1451 +  printf("  thread_id                   = 0x%x\n",   thread_.thread_id);
  1.1452 +  printf("  suspend_count               = %d\n",     thread_.suspend_count);
  1.1453 +  printf("  priority_class              = 0x%x\n",   thread_.priority_class);
  1.1454 +  printf("  priority                    = 0x%x\n",   thread_.priority);
  1.1455 +  printf("  teb                         = 0x%" PRIx64 "\n", thread_.teb);
  1.1456 +  printf("  stack.start_of_memory_range = 0x%" PRIx64 "\n",
  1.1457 +         thread_.stack.start_of_memory_range);
  1.1458 +  printf("  stack.memory.data_size      = 0x%x\n",
  1.1459 +         thread_.stack.memory.data_size);
  1.1460 +  printf("  stack.memory.rva            = 0x%x\n",   thread_.stack.memory.rva);
  1.1461 +  printf("  thread_context.data_size    = 0x%x\n",
  1.1462 +         thread_.thread_context.data_size);
  1.1463 +  printf("  thread_context.rva          = 0x%x\n",
  1.1464 +         thread_.thread_context.rva);
  1.1465 +
  1.1466 +  MinidumpContext* context = GetContext();
  1.1467 +  if (context) {
  1.1468 +    printf("\n");
  1.1469 +    context->Print();
  1.1470 +  } else {
  1.1471 +    printf("  (no context)\n");
  1.1472 +    printf("\n");
  1.1473 +  }
  1.1474 +
  1.1475 +  MinidumpMemoryRegion* memory = GetMemory();
  1.1476 +  if (memory) {
  1.1477 +    printf("Stack\n");
  1.1478 +    memory->Print();
  1.1479 +  } else {
  1.1480 +    printf("No stack\n");
  1.1481 +  }
  1.1482 +  printf("\n");
  1.1483 +}
  1.1484 +
  1.1485 +
  1.1486 +//
  1.1487 +// MinidumpThreadList
  1.1488 +//
  1.1489 +
  1.1490 +
  1.1491 +uint32_t MinidumpThreadList::max_threads_ = 4096;
  1.1492 +
  1.1493 +
  1.1494 +MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
  1.1495 +    : MinidumpStream(minidump),
  1.1496 +      id_to_thread_map_(),
  1.1497 +      threads_(NULL),
  1.1498 +      thread_count_(0) {
  1.1499 +}
  1.1500 +
  1.1501 +
  1.1502 +MinidumpThreadList::~MinidumpThreadList() {
  1.1503 +  delete threads_;
  1.1504 +}
  1.1505 +
  1.1506 +
  1.1507 +bool MinidumpThreadList::Read(uint32_t expected_size) {
  1.1508 +  // Invalidate cached data.
  1.1509 +  id_to_thread_map_.clear();
  1.1510 +  delete threads_;
  1.1511 +  threads_ = NULL;
  1.1512 +  thread_count_ = 0;
  1.1513 +
  1.1514 +  valid_ = false;
  1.1515 +
  1.1516 +  uint32_t thread_count;
  1.1517 +  if (expected_size < sizeof(thread_count)) {
  1.1518 +    BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
  1.1519 +                    expected_size << " < " << sizeof(thread_count);
  1.1520 +    return false;
  1.1521 +  }
  1.1522 +  if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
  1.1523 +    BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
  1.1524 +    return false;
  1.1525 +  }
  1.1526 +
  1.1527 +  if (minidump_->swap())
  1.1528 +    Swap(&thread_count);
  1.1529 +
  1.1530 +  if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
  1.1531 +    BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
  1.1532 +                    " would cause multiplication overflow";
  1.1533 +    return false;
  1.1534 +  }
  1.1535 +
  1.1536 +  if (expected_size != sizeof(thread_count) +
  1.1537 +                       thread_count * sizeof(MDRawThread)) {
  1.1538 +    // may be padded with 4 bytes on 64bit ABIs for alignment
  1.1539 +    if (expected_size == sizeof(thread_count) + 4 +
  1.1540 +                         thread_count * sizeof(MDRawThread)) {
  1.1541 +      uint32_t useless;
  1.1542 +      if (!minidump_->ReadBytes(&useless, 4)) {
  1.1543 +        BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes";
  1.1544 +        return false;
  1.1545 +      }
  1.1546 +    } else {
  1.1547 +      BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
  1.1548 +                    " != " << sizeof(thread_count) +
  1.1549 +                    thread_count * sizeof(MDRawThread);
  1.1550 +      return false;
  1.1551 +    }
  1.1552 +  }
  1.1553 +
  1.1554 +
  1.1555 +  if (thread_count > max_threads_) {
  1.1556 +    BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
  1.1557 +                    " exceeds maximum " << max_threads_;
  1.1558 +    return false;
  1.1559 +  }
  1.1560 +
  1.1561 +  if (thread_count != 0) {
  1.1562 +    scoped_ptr<MinidumpThreads> threads(
  1.1563 +        new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
  1.1564 +
  1.1565 +    for (unsigned int thread_index = 0;
  1.1566 +         thread_index < thread_count;
  1.1567 +         ++thread_index) {
  1.1568 +      MinidumpThread* thread = &(*threads)[thread_index];
  1.1569 +
  1.1570 +      // Assume that the file offset is correct after the last read.
  1.1571 +      if (!thread->Read()) {
  1.1572 +        BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
  1.1573 +                        thread_index << "/" << thread_count;
  1.1574 +        return false;
  1.1575 +      }
  1.1576 +
  1.1577 +      uint32_t thread_id;
  1.1578 +      if (!thread->GetThreadID(&thread_id)) {
  1.1579 +        BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
  1.1580 +                        thread_index << "/" << thread_count;
  1.1581 +        return false;
  1.1582 +      }
  1.1583 +
  1.1584 +      if (GetThreadByID(thread_id)) {
  1.1585 +        // Another thread with this ID is already in the list.  Data error.
  1.1586 +        BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
  1.1587 +                        HexString(thread_id) << " at thread " <<
  1.1588 +                        thread_index << "/" << thread_count;
  1.1589 +        return false;
  1.1590 +      }
  1.1591 +      id_to_thread_map_[thread_id] = thread;
  1.1592 +    }
  1.1593 +
  1.1594 +    threads_ = threads.release();
  1.1595 +  }
  1.1596 +
  1.1597 +  thread_count_ = thread_count;
  1.1598 +
  1.1599 +  valid_ = true;
  1.1600 +  return true;
  1.1601 +}
  1.1602 +
  1.1603 +
  1.1604 +MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
  1.1605 +    const {
  1.1606 +  if (!valid_) {
  1.1607 +    BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
  1.1608 +    return NULL;
  1.1609 +  }
  1.1610 +
  1.1611 +  if (index >= thread_count_) {
  1.1612 +    BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
  1.1613 +                    index << "/" << thread_count_;
  1.1614 +    return NULL;
  1.1615 +  }
  1.1616 +
  1.1617 +  return &(*threads_)[index];
  1.1618 +}
  1.1619 +
  1.1620 +
  1.1621 +MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
  1.1622 +  // Don't check valid_.  Read calls this method before everything is
  1.1623 +  // validated.  It is safe to not check valid_ here.
  1.1624 +  return id_to_thread_map_[thread_id];
  1.1625 +}
  1.1626 +
  1.1627 +
  1.1628 +void MinidumpThreadList::Print() {
  1.1629 +  if (!valid_) {
  1.1630 +    BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
  1.1631 +    return;
  1.1632 +  }
  1.1633 +
  1.1634 +  printf("MinidumpThreadList\n");
  1.1635 +  printf("  thread_count = %d\n", thread_count_);
  1.1636 +  printf("\n");
  1.1637 +
  1.1638 +  for (unsigned int thread_index = 0;
  1.1639 +       thread_index < thread_count_;
  1.1640 +       ++thread_index) {
  1.1641 +    printf("thread[%d]\n", thread_index);
  1.1642 +
  1.1643 +    (*threads_)[thread_index].Print();
  1.1644 +  }
  1.1645 +}
  1.1646 +
  1.1647 +
  1.1648 +//
  1.1649 +// MinidumpModule
  1.1650 +//
  1.1651 +
  1.1652 +
  1.1653 +uint32_t MinidumpModule::max_cv_bytes_ = 32768;
  1.1654 +uint32_t MinidumpModule::max_misc_bytes_ = 32768;
  1.1655 +
  1.1656 +
  1.1657 +MinidumpModule::MinidumpModule(Minidump* minidump)
  1.1658 +    : MinidumpObject(minidump),
  1.1659 +      module_valid_(false),
  1.1660 +      has_debug_info_(false),
  1.1661 +      module_(),
  1.1662 +      name_(NULL),
  1.1663 +      cv_record_(NULL),
  1.1664 +      cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
  1.1665 +      misc_record_(NULL) {
  1.1666 +}
  1.1667 +
  1.1668 +
  1.1669 +MinidumpModule::~MinidumpModule() {
  1.1670 +  delete name_;
  1.1671 +  delete cv_record_;
  1.1672 +  delete misc_record_;
  1.1673 +}
  1.1674 +
  1.1675 +
  1.1676 +bool MinidumpModule::Read() {
  1.1677 +  // Invalidate cached data.
  1.1678 +  delete name_;
  1.1679 +  name_ = NULL;
  1.1680 +  delete cv_record_;
  1.1681 +  cv_record_ = NULL;
  1.1682 +  cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
  1.1683 +  delete misc_record_;
  1.1684 +  misc_record_ = NULL;
  1.1685 +
  1.1686 +  module_valid_ = false;
  1.1687 +  has_debug_info_ = false;
  1.1688 +  valid_ = false;
  1.1689 +
  1.1690 +  if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
  1.1691 +    BPLOG(ERROR) << "MinidumpModule cannot read module";
  1.1692 +    return false;
  1.1693 +  }
  1.1694 +
  1.1695 +  if (minidump_->swap()) {
  1.1696 +    Swap(&module_.base_of_image);
  1.1697 +    Swap(&module_.size_of_image);
  1.1698 +    Swap(&module_.checksum);
  1.1699 +    Swap(&module_.time_date_stamp);
  1.1700 +    Swap(&module_.module_name_rva);
  1.1701 +    Swap(&module_.version_info.signature);
  1.1702 +    Swap(&module_.version_info.struct_version);
  1.1703 +    Swap(&module_.version_info.file_version_hi);
  1.1704 +    Swap(&module_.version_info.file_version_lo);
  1.1705 +    Swap(&module_.version_info.product_version_hi);
  1.1706 +    Swap(&module_.version_info.product_version_lo);
  1.1707 +    Swap(&module_.version_info.file_flags_mask);
  1.1708 +    Swap(&module_.version_info.file_flags);
  1.1709 +    Swap(&module_.version_info.file_os);
  1.1710 +    Swap(&module_.version_info.file_type);
  1.1711 +    Swap(&module_.version_info.file_subtype);
  1.1712 +    Swap(&module_.version_info.file_date_hi);
  1.1713 +    Swap(&module_.version_info.file_date_lo);
  1.1714 +    Swap(&module_.cv_record);
  1.1715 +    Swap(&module_.misc_record);
  1.1716 +    // Don't swap reserved fields because their contents are unknown (as
  1.1717 +    // are their proper widths).
  1.1718 +  }
  1.1719 +
  1.1720 +  // Check for base + size overflow or undersize.
  1.1721 +  if (module_.size_of_image == 0 ||
  1.1722 +      module_.size_of_image >
  1.1723 +          numeric_limits<uint64_t>::max() - module_.base_of_image) {
  1.1724 +    BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
  1.1725 +                    HexString(module_.base_of_image) << "+" <<
  1.1726 +                    HexString(module_.size_of_image);
  1.1727 +    return false;
  1.1728 +  }
  1.1729 +
  1.1730 +  module_valid_ = true;
  1.1731 +  return true;
  1.1732 +}
  1.1733 +
  1.1734 +
  1.1735 +bool MinidumpModule::ReadAuxiliaryData() {
  1.1736 +  if (!module_valid_) {
  1.1737 +    BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
  1.1738 +    return false;
  1.1739 +  }
  1.1740 +
  1.1741 +  // Each module must have a name.
  1.1742 +  name_ = minidump_->ReadString(module_.module_name_rva);
  1.1743 +  if (!name_) {
  1.1744 +    BPLOG(ERROR) << "MinidumpModule could not read name";
  1.1745 +    return false;
  1.1746 +  }
  1.1747 +
  1.1748 +  // At this point, we have enough info for the module to be valid.
  1.1749 +  valid_ = true;
  1.1750 +
  1.1751 +  // CodeView and miscellaneous debug records are only required if the
  1.1752 +  // module indicates that they exist.
  1.1753 +  if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
  1.1754 +    BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
  1.1755 +                    "but one was expected";
  1.1756 +    return false;
  1.1757 +  }
  1.1758 +
  1.1759 +  if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
  1.1760 +    BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
  1.1761 +                    "but one was expected";
  1.1762 +    return false;
  1.1763 +  }
  1.1764 +
  1.1765 +  has_debug_info_ = true;
  1.1766 +  return true;
  1.1767 +}
  1.1768 +
  1.1769 +
  1.1770 +string MinidumpModule::code_file() const {
  1.1771 +  if (!valid_) {
  1.1772 +    BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
  1.1773 +    return "";
  1.1774 +  }
  1.1775 +
  1.1776 +  return *name_;
  1.1777 +}
  1.1778 +
  1.1779 +
  1.1780 +string MinidumpModule::code_identifier() const {
  1.1781 +  if (!valid_) {
  1.1782 +    BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
  1.1783 +    return "";
  1.1784 +  }
  1.1785 +
  1.1786 +  if (!has_debug_info_)
  1.1787 +    return "";
  1.1788 +
  1.1789 +  MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
  1.1790 +  if (!minidump_system_info) {
  1.1791 +    BPLOG(ERROR) << "MinidumpModule code_identifier requires "
  1.1792 +                    "MinidumpSystemInfo";
  1.1793 +    return "";
  1.1794 +  }
  1.1795 +
  1.1796 +  const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
  1.1797 +  if (!raw_system_info) {
  1.1798 +    BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
  1.1799 +    return "";
  1.1800 +  }
  1.1801 +
  1.1802 +  string identifier;
  1.1803 +
  1.1804 +  switch (raw_system_info->platform_id) {
  1.1805 +    case MD_OS_WIN32_NT:
  1.1806 +    case MD_OS_WIN32_WINDOWS: {
  1.1807 +      // Use the same format that the MS symbol server uses in filesystem
  1.1808 +      // hierarchies.
  1.1809 +      char identifier_string[17];
  1.1810 +      snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
  1.1811 +               module_.time_date_stamp, module_.size_of_image);
  1.1812 +      identifier = identifier_string;
  1.1813 +      break;
  1.1814 +    }
  1.1815 +
  1.1816 +    case MD_OS_MAC_OS_X:
  1.1817 +    case MD_OS_IOS:
  1.1818 +    case MD_OS_SOLARIS:
  1.1819 +    case MD_OS_ANDROID:
  1.1820 +    case MD_OS_LINUX: {
  1.1821 +      // TODO(mmentovai): support uuid extension if present, otherwise fall
  1.1822 +      // back to version (from LC_ID_DYLIB?), otherwise fall back to something
  1.1823 +      // else.
  1.1824 +      identifier = "id";
  1.1825 +      break;
  1.1826 +    }
  1.1827 +
  1.1828 +    default: {
  1.1829 +      // Without knowing what OS generated the dump, we can't generate a good
  1.1830 +      // identifier.  Return an empty string, signalling failure.
  1.1831 +      BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
  1.1832 +                      "found " << HexString(raw_system_info->platform_id);
  1.1833 +      break;
  1.1834 +    }
  1.1835 +  }
  1.1836 +
  1.1837 +  return identifier;
  1.1838 +}
  1.1839 +
  1.1840 +
  1.1841 +string MinidumpModule::debug_file() const {
  1.1842 +  if (!valid_) {
  1.1843 +    BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
  1.1844 +    return "";
  1.1845 +  }
  1.1846 +
  1.1847 +  if (!has_debug_info_)
  1.1848 +    return "";
  1.1849 +
  1.1850 +  string file;
  1.1851 +  // Prefer the CodeView record if present.
  1.1852 +  if (cv_record_) {
  1.1853 +    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  1.1854 +      // It's actually an MDCVInfoPDB70 structure.
  1.1855 +      const MDCVInfoPDB70* cv_record_70 =
  1.1856 +          reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
  1.1857 +      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  1.1858 +
  1.1859 +      // GetCVRecord guarantees pdb_file_name is null-terminated.
  1.1860 +      file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
  1.1861 +    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  1.1862 +      // It's actually an MDCVInfoPDB20 structure.
  1.1863 +      const MDCVInfoPDB20* cv_record_20 =
  1.1864 +          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
  1.1865 +      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  1.1866 +
  1.1867 +      // GetCVRecord guarantees pdb_file_name is null-terminated.
  1.1868 +      file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
  1.1869 +    }
  1.1870 +
  1.1871 +    // If there's a CodeView record but it doesn't match a known signature,
  1.1872 +    // try the miscellaneous record.
  1.1873 +  }
  1.1874 +
  1.1875 +  if (file.empty()) {
  1.1876 +    // No usable CodeView record.  Try the miscellaneous debug record.
  1.1877 +    if (misc_record_) {
  1.1878 +      const MDImageDebugMisc* misc_record =
  1.1879 +          reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
  1.1880 +      if (!misc_record->unicode) {
  1.1881 +        // If it's not Unicode, just stuff it into the string.  It's unclear
  1.1882 +        // if misc_record->data is 0-terminated, so use an explicit size.
  1.1883 +        file = string(
  1.1884 +            reinterpret_cast<const char*>(misc_record->data),
  1.1885 +            module_.misc_record.data_size - MDImageDebugMisc_minsize);
  1.1886 +      } else {
  1.1887 +        // There's a misc_record but it encodes the debug filename in UTF-16.
  1.1888 +        // (Actually, because miscellaneous records are so old, it's probably
  1.1889 +        // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
  1.1890 +        // that this method (and all other methods in the Minidump family)
  1.1891 +        // return.
  1.1892 +
  1.1893 +        unsigned int bytes =
  1.1894 +            module_.misc_record.data_size - MDImageDebugMisc_minsize;
  1.1895 +        if (bytes % 2 == 0) {
  1.1896 +          unsigned int utf16_words = bytes / 2;
  1.1897 +
  1.1898 +          // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
  1.1899 +          // and copy the UTF-16 data into it.
  1.1900 +          vector<uint16_t> string_utf16(utf16_words);
  1.1901 +          if (utf16_words)
  1.1902 +            memcpy(&string_utf16[0], &misc_record->data, bytes);
  1.1903 +
  1.1904 +          // GetMiscRecord already byte-swapped the data[] field if it contains
  1.1905 +          // UTF-16, so pass false as the swap argument.
  1.1906 +          scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
  1.1907 +          file = *new_file;
  1.1908 +        }
  1.1909 +      }
  1.1910 +    }
  1.1911 +  }
  1.1912 +
  1.1913 +  // Relatively common case
  1.1914 +  BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
  1.1915 +                                  "debug_file for " << *name_;
  1.1916 +
  1.1917 +  return file;
  1.1918 +}
  1.1919 +
  1.1920 +
  1.1921 +string MinidumpModule::debug_identifier() const {
  1.1922 +  if (!valid_) {
  1.1923 +    BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
  1.1924 +    return "";
  1.1925 +  }
  1.1926 +
  1.1927 +  if (!has_debug_info_)
  1.1928 +    return "";
  1.1929 +
  1.1930 +  string identifier;
  1.1931 +
  1.1932 +  // Use the CodeView record if present.
  1.1933 +  if (cv_record_) {
  1.1934 +    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  1.1935 +      // It's actually an MDCVInfoPDB70 structure.
  1.1936 +      const MDCVInfoPDB70* cv_record_70 =
  1.1937 +          reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
  1.1938 +      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  1.1939 +
  1.1940 +      // Use the same format that the MS symbol server uses in filesystem
  1.1941 +      // hierarchies.
  1.1942 +      char identifier_string[41];
  1.1943 +      snprintf(identifier_string, sizeof(identifier_string),
  1.1944 +               "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
  1.1945 +               cv_record_70->signature.data1,
  1.1946 +               cv_record_70->signature.data2,
  1.1947 +               cv_record_70->signature.data3,
  1.1948 +               cv_record_70->signature.data4[0],
  1.1949 +               cv_record_70->signature.data4[1],
  1.1950 +               cv_record_70->signature.data4[2],
  1.1951 +               cv_record_70->signature.data4[3],
  1.1952 +               cv_record_70->signature.data4[4],
  1.1953 +               cv_record_70->signature.data4[5],
  1.1954 +               cv_record_70->signature.data4[6],
  1.1955 +               cv_record_70->signature.data4[7],
  1.1956 +               cv_record_70->age);
  1.1957 +      identifier = identifier_string;
  1.1958 +    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  1.1959 +      // It's actually an MDCVInfoPDB20 structure.
  1.1960 +      const MDCVInfoPDB20* cv_record_20 =
  1.1961 +          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
  1.1962 +      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  1.1963 +
  1.1964 +      // Use the same format that the MS symbol server uses in filesystem
  1.1965 +      // hierarchies.
  1.1966 +      char identifier_string[17];
  1.1967 +      snprintf(identifier_string, sizeof(identifier_string),
  1.1968 +               "%08X%x", cv_record_20->signature, cv_record_20->age);
  1.1969 +      identifier = identifier_string;
  1.1970 +    }
  1.1971 +  }
  1.1972 +
  1.1973 +  // TODO(mmentovai): if there's no usable CodeView record, there might be a
  1.1974 +  // miscellaneous debug record.  It only carries a filename, though, and no
  1.1975 +  // identifier.  I'm not sure what the right thing to do for the identifier
  1.1976 +  // is in that case, but I don't expect to find many modules without a
  1.1977 +  // CodeView record (or some other Breakpad extension structure in place of
  1.1978 +  // a CodeView record).  Treat it as an error (empty identifier) for now.
  1.1979 +
  1.1980 +  // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
  1.1981 +
  1.1982 +  // Relatively common case
  1.1983 +  BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
  1.1984 +                                        "debug_identifier for " << *name_;
  1.1985 +
  1.1986 +  return identifier;
  1.1987 +}
  1.1988 +
  1.1989 +
  1.1990 +string MinidumpModule::version() const {
  1.1991 +  if (!valid_) {
  1.1992 +    BPLOG(ERROR) << "Invalid MinidumpModule for version";
  1.1993 +    return "";
  1.1994 +  }
  1.1995 +
  1.1996 +  string version;
  1.1997 +
  1.1998 +  if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
  1.1999 +      module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
  1.2000 +    char version_string[24];
  1.2001 +    snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
  1.2002 +             module_.version_info.file_version_hi >> 16,
  1.2003 +             module_.version_info.file_version_hi & 0xffff,
  1.2004 +             module_.version_info.file_version_lo >> 16,
  1.2005 +             module_.version_info.file_version_lo & 0xffff);
  1.2006 +    version = version_string;
  1.2007 +  }
  1.2008 +
  1.2009 +  // TODO(mmentovai): possibly support other struct types in place of
  1.2010 +  // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
  1.2011 +  // a different structure that better represents versioning facilities on
  1.2012 +  // Mac OS X and Linux, instead of forcing them to adhere to the dotted
  1.2013 +  // quad of 16-bit ints that Windows uses.
  1.2014 +
  1.2015 +  BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
  1.2016 +                                     "version for " << *name_;
  1.2017 +
  1.2018 +  return version;
  1.2019 +}
  1.2020 +
  1.2021 +
  1.2022 +const CodeModule* MinidumpModule::Copy() const {
  1.2023 +  return new BasicCodeModule(this);
  1.2024 +}
  1.2025 +
  1.2026 +
  1.2027 +const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
  1.2028 +  if (!module_valid_) {
  1.2029 +    BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
  1.2030 +    return NULL;
  1.2031 +  }
  1.2032 +
  1.2033 +  if (!cv_record_) {
  1.2034 +    // This just guards against 0-sized CodeView records; more specific checks
  1.2035 +    // are used when the signature is checked against various structure types.
  1.2036 +    if (module_.cv_record.data_size == 0) {
  1.2037 +      return NULL;
  1.2038 +    }
  1.2039 +
  1.2040 +    if (!minidump_->SeekSet(module_.cv_record.rva)) {
  1.2041 +      BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
  1.2042 +      return NULL;
  1.2043 +    }
  1.2044 +
  1.2045 +    if (module_.cv_record.data_size > max_cv_bytes_) {
  1.2046 +      BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
  1.2047 +                      module_.cv_record.data_size << " exceeds maximum " <<
  1.2048 +                      max_cv_bytes_;
  1.2049 +      return NULL;
  1.2050 +    }
  1.2051 +
  1.2052 +    // Allocating something that will be accessed as MDCVInfoPDB70 or
  1.2053 +    // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
  1.2054 +    // problems.  x86 and ppc are able to cope, though.  This allocation
  1.2055 +    // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
  1.2056 +    // variable-sized due to their pdb_file_name fields; these structures
  1.2057 +    // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
  1.2058 +    // them as such would result in incomplete structures or overruns.
  1.2059 +    scoped_ptr< vector<uint8_t> > cv_record(
  1.2060 +        new vector<uint8_t>(module_.cv_record.data_size));
  1.2061 +
  1.2062 +    if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
  1.2063 +      BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
  1.2064 +      return NULL;
  1.2065 +    }
  1.2066 +
  1.2067 +    uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
  1.2068 +    if (module_.cv_record.data_size > sizeof(signature)) {
  1.2069 +      MDCVInfoPDB70* cv_record_signature =
  1.2070 +          reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
  1.2071 +      signature = cv_record_signature->cv_signature;
  1.2072 +      if (minidump_->swap())
  1.2073 +        Swap(&signature);
  1.2074 +    }
  1.2075 +
  1.2076 +    if (signature == MD_CVINFOPDB70_SIGNATURE) {
  1.2077 +      // Now that the structure type is known, recheck the size.
  1.2078 +      if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
  1.2079 +        BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
  1.2080 +                        MDCVInfoPDB70_minsize << " > " <<
  1.2081 +                        module_.cv_record.data_size;
  1.2082 +        return NULL;
  1.2083 +      }
  1.2084 +
  1.2085 +      if (minidump_->swap()) {
  1.2086 +        MDCVInfoPDB70* cv_record_70 =
  1.2087 +            reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
  1.2088 +        Swap(&cv_record_70->cv_signature);
  1.2089 +        Swap(&cv_record_70->signature);
  1.2090 +        Swap(&cv_record_70->age);
  1.2091 +        // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
  1.2092 +        // quantities.  (It's a path, is it UTF-8?)
  1.2093 +      }
  1.2094 +
  1.2095 +      // The last field of either structure is null-terminated 8-bit character
  1.2096 +      // data.  Ensure that it's null-terminated.
  1.2097 +      if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
  1.2098 +        BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
  1.2099 +                        "0-terminated";
  1.2100 +        return NULL;
  1.2101 +      }
  1.2102 +    } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
  1.2103 +      // Now that the structure type is known, recheck the size.
  1.2104 +      if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
  1.2105 +        BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
  1.2106 +                        MDCVInfoPDB20_minsize << " > " <<
  1.2107 +                        module_.cv_record.data_size;
  1.2108 +        return NULL;
  1.2109 +      }
  1.2110 +      if (minidump_->swap()) {
  1.2111 +        MDCVInfoPDB20* cv_record_20 =
  1.2112 +            reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
  1.2113 +        Swap(&cv_record_20->cv_header.signature);
  1.2114 +        Swap(&cv_record_20->cv_header.offset);
  1.2115 +        Swap(&cv_record_20->signature);
  1.2116 +        Swap(&cv_record_20->age);
  1.2117 +        // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
  1.2118 +        // quantities.  (It's a path, is it UTF-8?)
  1.2119 +      }
  1.2120 +
  1.2121 +      // The last field of either structure is null-terminated 8-bit character
  1.2122 +      // data.  Ensure that it's null-terminated.
  1.2123 +      if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
  1.2124 +        BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
  1.2125 +                        "0-terminated";
  1.2126 +        return NULL;
  1.2127 +      }
  1.2128 +    }
  1.2129 +
  1.2130 +    // If the signature doesn't match something above, it's not something
  1.2131 +    // that Breakpad can presently handle directly.  Because some modules in
  1.2132 +    // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
  1.2133 +    // don't bail out here - allow the data to be returned to the user,
  1.2134 +    // although byte-swapping can't be done.
  1.2135 +
  1.2136 +    // Store the vector type because that's how storage was allocated, but
  1.2137 +    // return it casted to uint8_t*.
  1.2138 +    cv_record_ = cv_record.release();
  1.2139 +    cv_record_signature_ = signature;
  1.2140 +  }
  1.2141 +
  1.2142 +  if (size)
  1.2143 +    *size = module_.cv_record.data_size;
  1.2144 +
  1.2145 +  return &(*cv_record_)[0];
  1.2146 +}
  1.2147 +
  1.2148 +
  1.2149 +const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
  1.2150 +  if (!module_valid_) {
  1.2151 +    BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
  1.2152 +    return NULL;
  1.2153 +  }
  1.2154 +
  1.2155 +  if (!misc_record_) {
  1.2156 +    if (module_.misc_record.data_size == 0) {
  1.2157 +      return NULL;
  1.2158 +    }
  1.2159 +
  1.2160 +    if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
  1.2161 +      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
  1.2162 +                      "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
  1.2163 +                      module_.misc_record.data_size;
  1.2164 +      return NULL;
  1.2165 +    }
  1.2166 +
  1.2167 +    if (!minidump_->SeekSet(module_.misc_record.rva)) {
  1.2168 +      BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
  1.2169 +                      "debugging record";
  1.2170 +      return NULL;
  1.2171 +    }
  1.2172 +
  1.2173 +    if (module_.misc_record.data_size > max_misc_bytes_) {
  1.2174 +      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
  1.2175 +                      module_.misc_record.data_size << " exceeds maximum " <<
  1.2176 +                      max_misc_bytes_;
  1.2177 +      return NULL;
  1.2178 +    }
  1.2179 +
  1.2180 +    // Allocating something that will be accessed as MDImageDebugMisc but
  1.2181 +    // is allocated as uint8_t[] can cause alignment problems.  x86 and
  1.2182 +    // ppc are able to cope, though.  This allocation style is needed
  1.2183 +    // because the MDImageDebugMisc is variable-sized due to its data field;
  1.2184 +    // this structure is not MDImageDebugMisc_minsize and treating it as such
  1.2185 +    // would result in an incomplete structure or an overrun.
  1.2186 +    scoped_ptr< vector<uint8_t> > misc_record_mem(
  1.2187 +        new vector<uint8_t>(module_.misc_record.data_size));
  1.2188 +    MDImageDebugMisc* misc_record =
  1.2189 +        reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
  1.2190 +
  1.2191 +    if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
  1.2192 +      BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
  1.2193 +                      "record";
  1.2194 +      return NULL;
  1.2195 +    }
  1.2196 +
  1.2197 +    if (minidump_->swap()) {
  1.2198 +      Swap(&misc_record->data_type);
  1.2199 +      Swap(&misc_record->length);
  1.2200 +      // Don't swap misc_record.unicode because it's an 8-bit quantity.
  1.2201 +      // Don't swap the reserved fields for the same reason, and because
  1.2202 +      // they don't contain any valid data.
  1.2203 +      if (misc_record->unicode) {
  1.2204 +        // There is a potential alignment problem, but shouldn't be a problem
  1.2205 +        // in practice due to the layout of MDImageDebugMisc.
  1.2206 +        uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
  1.2207 +        unsigned int dataBytes = module_.misc_record.data_size -
  1.2208 +                                 MDImageDebugMisc_minsize;
  1.2209 +        unsigned int dataLength = dataBytes / 2;
  1.2210 +        for (unsigned int characterIndex = 0;
  1.2211 +             characterIndex < dataLength;
  1.2212 +             ++characterIndex) {
  1.2213 +          Swap(&data16[characterIndex]);
  1.2214 +        }
  1.2215 +      }
  1.2216 +    }
  1.2217 +
  1.2218 +    if (module_.misc_record.data_size != misc_record->length) {
  1.2219 +      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
  1.2220 +                      "size mismatch, " << module_.misc_record.data_size <<
  1.2221 +                      " != " << misc_record->length;
  1.2222 +      return NULL;
  1.2223 +    }
  1.2224 +
  1.2225 +    // Store the vector type because that's how storage was allocated, but
  1.2226 +    // return it casted to MDImageDebugMisc*.
  1.2227 +    misc_record_ = misc_record_mem.release();
  1.2228 +  }
  1.2229 +
  1.2230 +  if (size)
  1.2231 +    *size = module_.misc_record.data_size;
  1.2232 +
  1.2233 +  return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
  1.2234 +}
  1.2235 +
  1.2236 +
  1.2237 +void MinidumpModule::Print() {
  1.2238 +  if (!valid_) {
  1.2239 +    BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
  1.2240 +    return;
  1.2241 +  }
  1.2242 +
  1.2243 +  printf("MDRawModule\n");
  1.2244 +  printf("  base_of_image                   = 0x%" PRIx64 "\n",
  1.2245 +         module_.base_of_image);
  1.2246 +  printf("  size_of_image                   = 0x%x\n",
  1.2247 +         module_.size_of_image);
  1.2248 +  printf("  checksum                        = 0x%x\n",
  1.2249 +         module_.checksum);
  1.2250 +  printf("  time_date_stamp                 = 0x%x\n",
  1.2251 +         module_.time_date_stamp);
  1.2252 +  printf("  module_name_rva                 = 0x%x\n",
  1.2253 +         module_.module_name_rva);
  1.2254 +  printf("  version_info.signature          = 0x%x\n",
  1.2255 +         module_.version_info.signature);
  1.2256 +  printf("  version_info.struct_version     = 0x%x\n",
  1.2257 +         module_.version_info.struct_version);
  1.2258 +  printf("  version_info.file_version       = 0x%x:0x%x\n",
  1.2259 +         module_.version_info.file_version_hi,
  1.2260 +         module_.version_info.file_version_lo);
  1.2261 +  printf("  version_info.product_version    = 0x%x:0x%x\n",
  1.2262 +         module_.version_info.product_version_hi,
  1.2263 +         module_.version_info.product_version_lo);
  1.2264 +  printf("  version_info.file_flags_mask    = 0x%x\n",
  1.2265 +         module_.version_info.file_flags_mask);
  1.2266 +  printf("  version_info.file_flags         = 0x%x\n",
  1.2267 +         module_.version_info.file_flags);
  1.2268 +  printf("  version_info.file_os            = 0x%x\n",
  1.2269 +         module_.version_info.file_os);
  1.2270 +  printf("  version_info.file_type          = 0x%x\n",
  1.2271 +         module_.version_info.file_type);
  1.2272 +  printf("  version_info.file_subtype       = 0x%x\n",
  1.2273 +         module_.version_info.file_subtype);
  1.2274 +  printf("  version_info.file_date          = 0x%x:0x%x\n",
  1.2275 +         module_.version_info.file_date_hi,
  1.2276 +         module_.version_info.file_date_lo);
  1.2277 +  printf("  cv_record.data_size             = %d\n",
  1.2278 +         module_.cv_record.data_size);
  1.2279 +  printf("  cv_record.rva                   = 0x%x\n",
  1.2280 +         module_.cv_record.rva);
  1.2281 +  printf("  misc_record.data_size           = %d\n",
  1.2282 +         module_.misc_record.data_size);
  1.2283 +  printf("  misc_record.rva                 = 0x%x\n",
  1.2284 +         module_.misc_record.rva);
  1.2285 +
  1.2286 +  printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
  1.2287 +  printf("  (code_identifier)               = \"%s\"\n",
  1.2288 +         code_identifier().c_str());
  1.2289 +
  1.2290 +  uint32_t cv_record_size;
  1.2291 +  const uint8_t *cv_record = GetCVRecord(&cv_record_size);
  1.2292 +  if (cv_record) {
  1.2293 +    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  1.2294 +      const MDCVInfoPDB70* cv_record_70 =
  1.2295 +          reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
  1.2296 +      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  1.2297 +
  1.2298 +      printf("  (cv_record).cv_signature        = 0x%x\n",
  1.2299 +             cv_record_70->cv_signature);
  1.2300 +      printf("  (cv_record).signature           = %08x-%04x-%04x-%02x%02x-",
  1.2301 +             cv_record_70->signature.data1,
  1.2302 +             cv_record_70->signature.data2,
  1.2303 +             cv_record_70->signature.data3,
  1.2304 +             cv_record_70->signature.data4[0],
  1.2305 +             cv_record_70->signature.data4[1]);
  1.2306 +      for (unsigned int guidIndex = 2;
  1.2307 +           guidIndex < 8;
  1.2308 +           ++guidIndex) {
  1.2309 +        printf("%02x", cv_record_70->signature.data4[guidIndex]);
  1.2310 +      }
  1.2311 +      printf("\n");
  1.2312 +      printf("  (cv_record).age                 = %d\n",
  1.2313 +             cv_record_70->age);
  1.2314 +      printf("  (cv_record).pdb_file_name       = \"%s\"\n",
  1.2315 +             cv_record_70->pdb_file_name);
  1.2316 +    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  1.2317 +      const MDCVInfoPDB20* cv_record_20 =
  1.2318 +          reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
  1.2319 +      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  1.2320 +
  1.2321 +      printf("  (cv_record).cv_header.signature = 0x%x\n",
  1.2322 +             cv_record_20->cv_header.signature);
  1.2323 +      printf("  (cv_record).cv_header.offset    = 0x%x\n",
  1.2324 +             cv_record_20->cv_header.offset);
  1.2325 +      printf("  (cv_record).signature           = 0x%x\n",
  1.2326 +             cv_record_20->signature);
  1.2327 +      printf("  (cv_record).age                 = %d\n",
  1.2328 +             cv_record_20->age);
  1.2329 +      printf("  (cv_record).pdb_file_name       = \"%s\"\n",
  1.2330 +             cv_record_20->pdb_file_name);
  1.2331 +    } else {
  1.2332 +      printf("  (cv_record)                     = ");
  1.2333 +      for (unsigned int cv_byte_index = 0;
  1.2334 +           cv_byte_index < cv_record_size;
  1.2335 +           ++cv_byte_index) {
  1.2336 +        printf("%02x", cv_record[cv_byte_index]);
  1.2337 +      }
  1.2338 +      printf("\n");
  1.2339 +    }
  1.2340 +  } else {
  1.2341 +    printf("  (cv_record)                     = (null)\n");
  1.2342 +  }
  1.2343 +
  1.2344 +  const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
  1.2345 +  if (misc_record) {
  1.2346 +    printf("  (misc_record).data_type         = 0x%x\n",
  1.2347 +           misc_record->data_type);
  1.2348 +    printf("  (misc_record).length            = 0x%x\n",
  1.2349 +           misc_record->length);
  1.2350 +    printf("  (misc_record).unicode           = %d\n",
  1.2351 +           misc_record->unicode);
  1.2352 +    // Don't bother printing the UTF-16, we don't really even expect to ever
  1.2353 +    // see this misc_record anyway.
  1.2354 +    if (misc_record->unicode)
  1.2355 +      printf("  (misc_record).data              = \"%s\"\n",
  1.2356 +             misc_record->data);
  1.2357 +    else
  1.2358 +      printf("  (misc_record).data              = (UTF-16)\n");
  1.2359 +  } else {
  1.2360 +    printf("  (misc_record)                   = (null)\n");
  1.2361 +  }
  1.2362 +
  1.2363 +  printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
  1.2364 +  printf("  (debug_identifier)              = \"%s\"\n",
  1.2365 +         debug_identifier().c_str());
  1.2366 +  printf("  (version)                       = \"%s\"\n", version().c_str());
  1.2367 +  printf("\n");
  1.2368 +}
  1.2369 +
  1.2370 +
  1.2371 +//
  1.2372 +// MinidumpModuleList
  1.2373 +//
  1.2374 +
  1.2375 +
  1.2376 +uint32_t MinidumpModuleList::max_modules_ = 1024;
  1.2377 +
  1.2378 +
  1.2379 +MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
  1.2380 +    : MinidumpStream(minidump),
  1.2381 +      range_map_(new RangeMap<uint64_t, unsigned int>()),
  1.2382 +      modules_(NULL),
  1.2383 +      module_count_(0) {
  1.2384 +}
  1.2385 +
  1.2386 +
  1.2387 +MinidumpModuleList::~MinidumpModuleList() {
  1.2388 +  delete range_map_;
  1.2389 +  delete modules_;
  1.2390 +}
  1.2391 +
  1.2392 +
  1.2393 +bool MinidumpModuleList::Read(uint32_t expected_size) {
  1.2394 +  // Invalidate cached data.
  1.2395 +  range_map_->Clear();
  1.2396 +  delete modules_;
  1.2397 +  modules_ = NULL;
  1.2398 +  module_count_ = 0;
  1.2399 +
  1.2400 +  valid_ = false;
  1.2401 +
  1.2402 +  uint32_t module_count;
  1.2403 +  if (expected_size < sizeof(module_count)) {
  1.2404 +    BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
  1.2405 +                    expected_size << " < " << sizeof(module_count);
  1.2406 +    return false;
  1.2407 +  }
  1.2408 +  if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
  1.2409 +    BPLOG(ERROR) << "MinidumpModuleList could not read module count";
  1.2410 +    return false;
  1.2411 +  }
  1.2412 +
  1.2413 +  if (minidump_->swap())
  1.2414 +    Swap(&module_count);
  1.2415 +
  1.2416 +  if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
  1.2417 +    BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
  1.2418 +                    " would cause multiplication overflow";
  1.2419 +    return false;
  1.2420 +  }
  1.2421 +
  1.2422 +  if (expected_size != sizeof(module_count) +
  1.2423 +                       module_count * MD_MODULE_SIZE) {
  1.2424 +    // may be padded with 4 bytes on 64bit ABIs for alignment
  1.2425 +    if (expected_size == sizeof(module_count) + 4 +
  1.2426 +                         module_count * MD_MODULE_SIZE) {
  1.2427 +      uint32_t useless;
  1.2428 +      if (!minidump_->ReadBytes(&useless, 4)) {
  1.2429 +        BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes";
  1.2430 +        return false;
  1.2431 +      }
  1.2432 +    } else {
  1.2433 +      BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
  1.2434 +                      " != " << sizeof(module_count) +
  1.2435 +                      module_count * MD_MODULE_SIZE;
  1.2436 +      return false;
  1.2437 +    }
  1.2438 +  }
  1.2439 +
  1.2440 +  if (module_count > max_modules_) {
  1.2441 +    BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
  1.2442 +                    " exceeds maximum " << max_modules_;
  1.2443 +    return false;
  1.2444 +  }
  1.2445 +
  1.2446 +  if (module_count != 0) {
  1.2447 +    scoped_ptr<MinidumpModules> modules(
  1.2448 +        new MinidumpModules(module_count, MinidumpModule(minidump_)));
  1.2449 +
  1.2450 +    for (unsigned int module_index = 0;
  1.2451 +         module_index < module_count;
  1.2452 +         ++module_index) {
  1.2453 +      MinidumpModule* module = &(*modules)[module_index];
  1.2454 +
  1.2455 +      // Assume that the file offset is correct after the last read.
  1.2456 +      if (!module->Read()) {
  1.2457 +        BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
  1.2458 +                        module_index << "/" << module_count;
  1.2459 +        return false;
  1.2460 +      }
  1.2461 +    }
  1.2462 +
  1.2463 +    // Loop through the module list once more to read additional data and
  1.2464 +    // build the range map.  This is done in a second pass because
  1.2465 +    // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
  1.2466 +    // included in the loop above, additional seeks would be needed where
  1.2467 +    // none are now to read contiguous data.
  1.2468 +    for (unsigned int module_index = 0;
  1.2469 +         module_index < module_count;
  1.2470 +         ++module_index) {
  1.2471 +      MinidumpModule* module = &(*modules)[module_index];
  1.2472 +
  1.2473 +      // ReadAuxiliaryData fails if any data that the module indicates should
  1.2474 +      // exist is missing, but we treat some such cases as valid anyway.  See
  1.2475 +      // issue #222: if a debugging record is of a format that's too large to
  1.2476 +      // handle, it shouldn't render the entire dump invalid.  Check module
  1.2477 +      // validity before giving up.
  1.2478 +      if (!module->ReadAuxiliaryData() && !module->valid()) {
  1.2479 +        BPLOG(ERROR) << "MinidumpModuleList could not read required module "
  1.2480 +                        "auxiliary data for module " <<
  1.2481 +                        module_index << "/" << module_count;
  1.2482 +        return false;
  1.2483 +      }
  1.2484 +
  1.2485 +      // It is safe to use module->code_file() after successfully calling
  1.2486 +      // module->ReadAuxiliaryData or noting that the module is valid.
  1.2487 +
  1.2488 +      uint64_t base_address = module->base_address();
  1.2489 +      uint64_t module_size = module->size();
  1.2490 +      if (base_address == static_cast<uint64_t>(-1)) {
  1.2491 +        BPLOG(ERROR) << "MinidumpModuleList found bad base address "
  1.2492 +                        "for module " << module_index << "/" << module_count <<
  1.2493 +                        ", " << module->code_file();
  1.2494 +        return false;
  1.2495 +      }
  1.2496 +
  1.2497 +      if (!range_map_->StoreRange(base_address, module_size, module_index)) {
  1.2498 +        BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
  1.2499 +                        module_index << "/" << module_count << ", " <<
  1.2500 +                        module->code_file() << ", " <<
  1.2501 +                        HexString(base_address) << "+" <<
  1.2502 +                        HexString(module_size);
  1.2503 +        return false;
  1.2504 +      }
  1.2505 +    }
  1.2506 +
  1.2507 +    modules_ = modules.release();
  1.2508 +  }
  1.2509 +
  1.2510 +  module_count_ = module_count;
  1.2511 +
  1.2512 +  valid_ = true;
  1.2513 +  return true;
  1.2514 +}
  1.2515 +
  1.2516 +
  1.2517 +const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
  1.2518 +    uint64_t address) const {
  1.2519 +  if (!valid_) {
  1.2520 +    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
  1.2521 +    return NULL;
  1.2522 +  }
  1.2523 +
  1.2524 +  unsigned int module_index;
  1.2525 +  if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) {
  1.2526 +    BPLOG(INFO) << "MinidumpModuleList has no module at " <<
  1.2527 +                   HexString(address);
  1.2528 +    return NULL;
  1.2529 +  }
  1.2530 +
  1.2531 +  return GetModuleAtIndex(module_index);
  1.2532 +}
  1.2533 +
  1.2534 +
  1.2535 +const MinidumpModule* MinidumpModuleList::GetMainModule() const {
  1.2536 +  if (!valid_) {
  1.2537 +    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
  1.2538 +    return NULL;
  1.2539 +  }
  1.2540 +
  1.2541 +  // The main code module is the first one present in a minidump file's
  1.2542 +  // MDRawModuleList.
  1.2543 +  return GetModuleAtIndex(0);
  1.2544 +}
  1.2545 +
  1.2546 +
  1.2547 +const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
  1.2548 +    unsigned int sequence) const {
  1.2549 +  if (!valid_) {
  1.2550 +    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
  1.2551 +    return NULL;
  1.2552 +  }
  1.2553 +
  1.2554 +  if (sequence >= module_count_) {
  1.2555 +    BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
  1.2556 +                    sequence << "/" << module_count_;
  1.2557 +    return NULL;
  1.2558 +  }
  1.2559 +
  1.2560 +  unsigned int module_index;
  1.2561 +  if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) {
  1.2562 +    BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
  1.2563 +    return NULL;
  1.2564 +  }
  1.2565 +
  1.2566 +  return GetModuleAtIndex(module_index);
  1.2567 +}
  1.2568 +
  1.2569 +
  1.2570 +const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
  1.2571 +    unsigned int index) const {
  1.2572 +  if (!valid_) {
  1.2573 +    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
  1.2574 +    return NULL;
  1.2575 +  }
  1.2576 +
  1.2577 +  if (index >= module_count_) {
  1.2578 +    BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
  1.2579 +                    index << "/" << module_count_;
  1.2580 +    return NULL;
  1.2581 +  }
  1.2582 +
  1.2583 +  return &(*modules_)[index];
  1.2584 +}
  1.2585 +
  1.2586 +
  1.2587 +const CodeModules* MinidumpModuleList::Copy() const {
  1.2588 +  return new BasicCodeModules(this);
  1.2589 +}
  1.2590 +
  1.2591 +
  1.2592 +void MinidumpModuleList::Print() {
  1.2593 +  if (!valid_) {
  1.2594 +    BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
  1.2595 +    return;
  1.2596 +  }
  1.2597 +
  1.2598 +  printf("MinidumpModuleList\n");
  1.2599 +  printf("  module_count = %d\n", module_count_);
  1.2600 +  printf("\n");
  1.2601 +
  1.2602 +  for (unsigned int module_index = 0;
  1.2603 +       module_index < module_count_;
  1.2604 +       ++module_index) {
  1.2605 +    printf("module[%d]\n", module_index);
  1.2606 +
  1.2607 +    (*modules_)[module_index].Print();
  1.2608 +  }
  1.2609 +}
  1.2610 +
  1.2611 +
  1.2612 +//
  1.2613 +// MinidumpMemoryList
  1.2614 +//
  1.2615 +
  1.2616 +
  1.2617 +uint32_t MinidumpMemoryList::max_regions_ = 4096;
  1.2618 +
  1.2619 +
  1.2620 +MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
  1.2621 +    : MinidumpStream(minidump),
  1.2622 +      range_map_(new RangeMap<uint64_t, unsigned int>()),
  1.2623 +      descriptors_(NULL),
  1.2624 +      regions_(NULL),
  1.2625 +      region_count_(0) {
  1.2626 +}
  1.2627 +
  1.2628 +
  1.2629 +MinidumpMemoryList::~MinidumpMemoryList() {
  1.2630 +  delete range_map_;
  1.2631 +  delete descriptors_;
  1.2632 +  delete regions_;
  1.2633 +}
  1.2634 +
  1.2635 +
  1.2636 +bool MinidumpMemoryList::Read(uint32_t expected_size) {
  1.2637 +  // Invalidate cached data.
  1.2638 +  delete descriptors_;
  1.2639 +  descriptors_ = NULL;
  1.2640 +  delete regions_;
  1.2641 +  regions_ = NULL;
  1.2642 +  range_map_->Clear();
  1.2643 +  region_count_ = 0;
  1.2644 +
  1.2645 +  valid_ = false;
  1.2646 +
  1.2647 +  uint32_t region_count;
  1.2648 +  if (expected_size < sizeof(region_count)) {
  1.2649 +    BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
  1.2650 +                    expected_size << " < " << sizeof(region_count);
  1.2651 +    return false;
  1.2652 +  }
  1.2653 +  if (!minidump_->ReadBytes(&region_count, sizeof(region_count))) {
  1.2654 +    BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
  1.2655 +    return false;
  1.2656 +  }
  1.2657 +
  1.2658 +  if (minidump_->swap())
  1.2659 +    Swap(&region_count);
  1.2660 +
  1.2661 +  if (region_count >
  1.2662 +          numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
  1.2663 +    BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
  1.2664 +                    " would cause multiplication overflow";
  1.2665 +    return false;
  1.2666 +  }
  1.2667 +
  1.2668 +  if (expected_size != sizeof(region_count) +
  1.2669 +                       region_count * sizeof(MDMemoryDescriptor)) {
  1.2670 +    // may be padded with 4 bytes on 64bit ABIs for alignment
  1.2671 +    if (expected_size == sizeof(region_count) + 4 +
  1.2672 +                         region_count * sizeof(MDMemoryDescriptor)) {
  1.2673 +      uint32_t useless;
  1.2674 +      if (!minidump_->ReadBytes(&useless, 4)) {
  1.2675 +        BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes";
  1.2676 +        return false;
  1.2677 +      }
  1.2678 +    } else {
  1.2679 +      BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
  1.2680 +                      " != " << sizeof(region_count) + 
  1.2681 +                      region_count * sizeof(MDMemoryDescriptor);
  1.2682 +      return false;
  1.2683 +    }
  1.2684 +  }
  1.2685 +
  1.2686 +  if (region_count > max_regions_) {
  1.2687 +    BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
  1.2688 +                    " exceeds maximum " << max_regions_;
  1.2689 +    return false;
  1.2690 +  }
  1.2691 +
  1.2692 +  if (region_count != 0) {
  1.2693 +    scoped_ptr<MemoryDescriptors> descriptors(
  1.2694 +        new MemoryDescriptors(region_count));
  1.2695 +
  1.2696 +    // Read the entire array in one fell swoop, instead of reading one entry
  1.2697 +    // at a time in the loop.
  1.2698 +    if (!minidump_->ReadBytes(&(*descriptors)[0],
  1.2699 +                              sizeof(MDMemoryDescriptor) * region_count)) {
  1.2700 +      BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
  1.2701 +      return false;
  1.2702 +    }
  1.2703 +
  1.2704 +    scoped_ptr<MemoryRegions> regions(
  1.2705 +        new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
  1.2706 +
  1.2707 +    for (unsigned int region_index = 0;
  1.2708 +         region_index < region_count;
  1.2709 +         ++region_index) {
  1.2710 +      MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
  1.2711 +
  1.2712 +      if (minidump_->swap())
  1.2713 +        Swap(descriptor);
  1.2714 +
  1.2715 +      uint64_t base_address = descriptor->start_of_memory_range;
  1.2716 +      uint32_t region_size = descriptor->memory.data_size;
  1.2717 +
  1.2718 +      // Check for base + size overflow or undersize.
  1.2719 +      if (region_size == 0 ||
  1.2720 +          region_size > numeric_limits<uint64_t>::max() - base_address) {
  1.2721 +        BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
  1.2722 +                        " region " << region_index << "/" << region_count <<
  1.2723 +                        ", " << HexString(base_address) << "+" <<
  1.2724 +                        HexString(region_size);
  1.2725 +        return false;
  1.2726 +      }
  1.2727 +
  1.2728 +      if (!range_map_->StoreRange(base_address, region_size, region_index)) {
  1.2729 +        BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
  1.2730 +                        region_index << "/" << region_count << ", " <<
  1.2731 +                        HexString(base_address) << "+" <<
  1.2732 +                        HexString(region_size);
  1.2733 +        return false;
  1.2734 +      }
  1.2735 +
  1.2736 +      (*regions)[region_index].SetDescriptor(descriptor);
  1.2737 +    }
  1.2738 +
  1.2739 +    descriptors_ = descriptors.release();
  1.2740 +    regions_ = regions.release();
  1.2741 +  }
  1.2742 +
  1.2743 +  region_count_ = region_count;
  1.2744 +
  1.2745 +  valid_ = true;
  1.2746 +  return true;
  1.2747 +}
  1.2748 +
  1.2749 +
  1.2750 +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
  1.2751 +      unsigned int index) {
  1.2752 +  if (!valid_) {
  1.2753 +    BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
  1.2754 +    return NULL;
  1.2755 +  }
  1.2756 +
  1.2757 +  if (index >= region_count_) {
  1.2758 +    BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
  1.2759 +                    index << "/" << region_count_;
  1.2760 +    return NULL;
  1.2761 +  }
  1.2762 +
  1.2763 +  return &(*regions_)[index];
  1.2764 +}
  1.2765 +
  1.2766 +
  1.2767 +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
  1.2768 +    uint64_t address) {
  1.2769 +  if (!valid_) {
  1.2770 +    BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
  1.2771 +    return NULL;
  1.2772 +  }
  1.2773 +
  1.2774 +  unsigned int region_index;
  1.2775 +  if (!range_map_->RetrieveRange(address, &region_index, NULL, NULL)) {
  1.2776 +    BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
  1.2777 +                   HexString(address);
  1.2778 +    return NULL;
  1.2779 +  }
  1.2780 +
  1.2781 +  return GetMemoryRegionAtIndex(region_index);
  1.2782 +}
  1.2783 +
  1.2784 +
  1.2785 +void MinidumpMemoryList::Print() {
  1.2786 +  if (!valid_) {
  1.2787 +    BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
  1.2788 +    return;
  1.2789 +  }
  1.2790 +
  1.2791 +  printf("MinidumpMemoryList\n");
  1.2792 +  printf("  region_count = %d\n", region_count_);
  1.2793 +  printf("\n");
  1.2794 +
  1.2795 +  for (unsigned int region_index = 0;
  1.2796 +       region_index < region_count_;
  1.2797 +       ++region_index) {
  1.2798 +    MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
  1.2799 +    printf("region[%d]\n", region_index);
  1.2800 +    printf("MDMemoryDescriptor\n");
  1.2801 +    printf("  start_of_memory_range = 0x%" PRIx64 "\n",
  1.2802 +           descriptor->start_of_memory_range);
  1.2803 +    printf("  memory.data_size      = 0x%x\n", descriptor->memory.data_size);
  1.2804 +    printf("  memory.rva            = 0x%x\n", descriptor->memory.rva);
  1.2805 +    MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
  1.2806 +    if (region) {
  1.2807 +      printf("Memory\n");
  1.2808 +      region->Print();
  1.2809 +    } else {
  1.2810 +      printf("No memory\n");
  1.2811 +    }
  1.2812 +    printf("\n");
  1.2813 +  }
  1.2814 +}
  1.2815 +
  1.2816 +
  1.2817 +//
  1.2818 +// MinidumpException
  1.2819 +//
  1.2820 +
  1.2821 +
  1.2822 +MinidumpException::MinidumpException(Minidump* minidump)
  1.2823 +    : MinidumpStream(minidump),
  1.2824 +      exception_(),
  1.2825 +      context_(NULL) {
  1.2826 +}
  1.2827 +
  1.2828 +
  1.2829 +MinidumpException::~MinidumpException() {
  1.2830 +  delete context_;
  1.2831 +}
  1.2832 +
  1.2833 +
  1.2834 +bool MinidumpException::Read(uint32_t expected_size) {
  1.2835 +  // Invalidate cached data.
  1.2836 +  delete context_;
  1.2837 +  context_ = NULL;
  1.2838 +
  1.2839 +  valid_ = false;
  1.2840 +
  1.2841 +  if (expected_size != sizeof(exception_)) {
  1.2842 +    BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
  1.2843 +                    " != " << sizeof(exception_);
  1.2844 +    return false;
  1.2845 +  }
  1.2846 +
  1.2847 +  if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
  1.2848 +    BPLOG(ERROR) << "MinidumpException cannot read exception";
  1.2849 +    return false;
  1.2850 +  }
  1.2851 +
  1.2852 +  if (minidump_->swap()) {
  1.2853 +    Swap(&exception_.thread_id);
  1.2854 +    // exception_.__align is for alignment only and does not need to be
  1.2855 +    // swapped.
  1.2856 +    Swap(&exception_.exception_record.exception_code);
  1.2857 +    Swap(&exception_.exception_record.exception_flags);
  1.2858 +    Swap(&exception_.exception_record.exception_record);
  1.2859 +    Swap(&exception_.exception_record.exception_address);
  1.2860 +    Swap(&exception_.exception_record.number_parameters);
  1.2861 +    // exception_.exception_record.__align is for alignment only and does not
  1.2862 +    // need to be swapped.
  1.2863 +    for (unsigned int parameter_index = 0;
  1.2864 +         parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
  1.2865 +         ++parameter_index) {
  1.2866 +      Swap(&exception_.exception_record.exception_information[parameter_index]);
  1.2867 +    }
  1.2868 +    Swap(&exception_.thread_context);
  1.2869 +  }
  1.2870 +
  1.2871 +  valid_ = true;
  1.2872 +  return true;
  1.2873 +}
  1.2874 +
  1.2875 +
  1.2876 +bool MinidumpException::GetThreadID(uint32_t *thread_id) const {
  1.2877 +  BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
  1.2878 +                                 "|thread_id|";
  1.2879 +  assert(thread_id);
  1.2880 +  *thread_id = 0;
  1.2881 +
  1.2882 +  if (!valid_) {
  1.2883 +    BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
  1.2884 +    return false;
  1.2885 +  }
  1.2886 +
  1.2887 +  *thread_id = exception_.thread_id;
  1.2888 +  return true;
  1.2889 +}
  1.2890 +
  1.2891 +
  1.2892 +MinidumpContext* MinidumpException::GetContext() {
  1.2893 +  if (!valid_) {
  1.2894 +    BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
  1.2895 +    return NULL;
  1.2896 +  }
  1.2897 +
  1.2898 +  if (!context_) {
  1.2899 +    if (!minidump_->SeekSet(exception_.thread_context.rva)) {
  1.2900 +      BPLOG(ERROR) << "MinidumpException cannot seek to context";
  1.2901 +      return NULL;
  1.2902 +    }
  1.2903 +
  1.2904 +    scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
  1.2905 +
  1.2906 +    // Don't log as an error if we can still fall back on the thread's context
  1.2907 +    // (which must be possible if we got this far.)
  1.2908 +    if (!context->Read(exception_.thread_context.data_size)) {
  1.2909 +      BPLOG(INFO) << "MinidumpException cannot read context";
  1.2910 +      return NULL;
  1.2911 +    }
  1.2912 +
  1.2913 +    context_ = context.release();
  1.2914 +  }
  1.2915 +
  1.2916 +  return context_;
  1.2917 +}
  1.2918 +
  1.2919 +
  1.2920 +void MinidumpException::Print() {
  1.2921 +  if (!valid_) {
  1.2922 +    BPLOG(ERROR) << "MinidumpException cannot print invalid data";
  1.2923 +    return;
  1.2924 +  }
  1.2925 +
  1.2926 +  printf("MDException\n");
  1.2927 +  printf("  thread_id                                  = 0x%x\n",
  1.2928 +         exception_.thread_id);
  1.2929 +  printf("  exception_record.exception_code            = 0x%x\n",
  1.2930 +         exception_.exception_record.exception_code);
  1.2931 +  printf("  exception_record.exception_flags           = 0x%x\n",
  1.2932 +         exception_.exception_record.exception_flags);
  1.2933 +  printf("  exception_record.exception_record          = 0x%" PRIx64 "\n",
  1.2934 +         exception_.exception_record.exception_record);
  1.2935 +  printf("  exception_record.exception_address         = 0x%" PRIx64 "\n",
  1.2936 +         exception_.exception_record.exception_address);
  1.2937 +  printf("  exception_record.number_parameters         = %d\n",
  1.2938 +         exception_.exception_record.number_parameters);
  1.2939 +  for (unsigned int parameterIndex = 0;
  1.2940 +       parameterIndex < exception_.exception_record.number_parameters;
  1.2941 +       ++parameterIndex) {
  1.2942 +    printf("  exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
  1.2943 +           parameterIndex,
  1.2944 +           exception_.exception_record.exception_information[parameterIndex]);
  1.2945 +  }
  1.2946 +  printf("  thread_context.data_size                   = %d\n",
  1.2947 +         exception_.thread_context.data_size);
  1.2948 +  printf("  thread_context.rva                         = 0x%x\n",
  1.2949 +         exception_.thread_context.rva);
  1.2950 +  MinidumpContext* context = GetContext();
  1.2951 +  if (context) {
  1.2952 +    printf("\n");
  1.2953 +    context->Print();
  1.2954 +  } else {
  1.2955 +    printf("  (no context)\n");
  1.2956 +    printf("\n");
  1.2957 +  }
  1.2958 +}
  1.2959 +
  1.2960 +//
  1.2961 +// MinidumpAssertion
  1.2962 +//
  1.2963 +
  1.2964 +
  1.2965 +MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
  1.2966 +    : MinidumpStream(minidump),
  1.2967 +      assertion_(),
  1.2968 +      expression_(),
  1.2969 +      function_(),
  1.2970 +      file_() {
  1.2971 +}
  1.2972 +
  1.2973 +
  1.2974 +MinidumpAssertion::~MinidumpAssertion() {
  1.2975 +}
  1.2976 +
  1.2977 +
  1.2978 +bool MinidumpAssertion::Read(uint32_t expected_size) {
  1.2979 +  // Invalidate cached data.
  1.2980 +  valid_ = false;
  1.2981 +
  1.2982 +  if (expected_size != sizeof(assertion_)) {
  1.2983 +    BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
  1.2984 +                    " != " << sizeof(assertion_);
  1.2985 +    return false;
  1.2986 +  }
  1.2987 +
  1.2988 +  if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
  1.2989 +    BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
  1.2990 +    return false;
  1.2991 +  }
  1.2992 +
  1.2993 +  // Each of {expression, function, file} is a UTF-16 string,
  1.2994 +  // we'll convert them to UTF-8 for ease of use.
  1.2995 +  // expression
  1.2996 +  // Since we don't have an explicit byte length for each string,
  1.2997 +  // we use UTF16codeunits to calculate word length, then derive byte
  1.2998 +  // length from that.
  1.2999 +  uint32_t word_length = UTF16codeunits(assertion_.expression,
  1.3000 +                                         sizeof(assertion_.expression));
  1.3001 +  if (word_length > 0) {
  1.3002 +    uint32_t byte_length = word_length * 2;
  1.3003 +    vector<uint16_t> expression_utf16(word_length);
  1.3004 +    memcpy(&expression_utf16[0], &assertion_.expression[0], byte_length);
  1.3005 +
  1.3006 +    scoped_ptr<string> new_expression(UTF16ToUTF8(expression_utf16,
  1.3007 +                                                  minidump_->swap()));
  1.3008 +    if (new_expression.get())
  1.3009 +      expression_ = *new_expression;
  1.3010 +  }
  1.3011 +  
  1.3012 +  // assertion
  1.3013 +  word_length = UTF16codeunits(assertion_.function,
  1.3014 +                               sizeof(assertion_.function));
  1.3015 +  if (word_length) {
  1.3016 +    uint32_t byte_length = word_length * 2;
  1.3017 +    vector<uint16_t> function_utf16(word_length);
  1.3018 +    memcpy(&function_utf16[0], &assertion_.function[0], byte_length);
  1.3019 +    scoped_ptr<string> new_function(UTF16ToUTF8(function_utf16,
  1.3020 +                                                minidump_->swap()));
  1.3021 +    if (new_function.get())
  1.3022 +      function_ = *new_function;
  1.3023 +  }
  1.3024 +
  1.3025 +  // file
  1.3026 +  word_length = UTF16codeunits(assertion_.file,
  1.3027 +                               sizeof(assertion_.file));
  1.3028 +  if (word_length > 0) {
  1.3029 +    uint32_t byte_length = word_length * 2;
  1.3030 +    vector<uint16_t> file_utf16(word_length);
  1.3031 +    memcpy(&file_utf16[0], &assertion_.file[0], byte_length);
  1.3032 +    scoped_ptr<string> new_file(UTF16ToUTF8(file_utf16,
  1.3033 +                                            minidump_->swap()));
  1.3034 +    if (new_file.get())
  1.3035 +      file_ = *new_file;
  1.3036 +  }
  1.3037 +
  1.3038 +  if (minidump_->swap()) {
  1.3039 +    Swap(&assertion_.line);
  1.3040 +    Swap(&assertion_.type);
  1.3041 +  }
  1.3042 +
  1.3043 +  valid_ = true;
  1.3044 +  return true;
  1.3045 +}
  1.3046 +
  1.3047 +void MinidumpAssertion::Print() {
  1.3048 +  if (!valid_) {
  1.3049 +    BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
  1.3050 +    return;
  1.3051 +  }
  1.3052 +
  1.3053 +  printf("MDAssertion\n");
  1.3054 +  printf("  expression                                 = %s\n",
  1.3055 +         expression_.c_str());
  1.3056 +  printf("  function                                   = %s\n",
  1.3057 +         function_.c_str());
  1.3058 +  printf("  file                                       = %s\n",
  1.3059 +         file_.c_str());
  1.3060 +  printf("  line                                       = %u\n",
  1.3061 +         assertion_.line);
  1.3062 +  printf("  type                                       = %u\n",
  1.3063 +         assertion_.type);
  1.3064 +  printf("\n");
  1.3065 +}
  1.3066 +
  1.3067 +//
  1.3068 +// MinidumpSystemInfo
  1.3069 +//
  1.3070 +
  1.3071 +
  1.3072 +MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
  1.3073 +    : MinidumpStream(minidump),
  1.3074 +      system_info_(),
  1.3075 +      csd_version_(NULL),
  1.3076 +      cpu_vendor_(NULL) {
  1.3077 +}
  1.3078 +
  1.3079 +
  1.3080 +MinidumpSystemInfo::~MinidumpSystemInfo() {
  1.3081 +  delete csd_version_;
  1.3082 +  delete cpu_vendor_;
  1.3083 +}
  1.3084 +
  1.3085 +
  1.3086 +bool MinidumpSystemInfo::Read(uint32_t expected_size) {
  1.3087 +  // Invalidate cached data.
  1.3088 +  delete csd_version_;
  1.3089 +  csd_version_ = NULL;
  1.3090 +  delete cpu_vendor_;
  1.3091 +  cpu_vendor_ = NULL;
  1.3092 +
  1.3093 +  valid_ = false;
  1.3094 +
  1.3095 +  if (expected_size != sizeof(system_info_)) {
  1.3096 +    BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
  1.3097 +                    " != " << sizeof(system_info_);
  1.3098 +    return false;
  1.3099 +  }
  1.3100 +
  1.3101 +  if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
  1.3102 +    BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
  1.3103 +    return false;
  1.3104 +  }
  1.3105 +
  1.3106 +  if (minidump_->swap()) {
  1.3107 +    Swap(&system_info_.processor_architecture);
  1.3108 +    Swap(&system_info_.processor_level);
  1.3109 +    Swap(&system_info_.processor_revision);
  1.3110 +    // number_of_processors and product_type are 8-bit quantities and need no
  1.3111 +    // swapping.
  1.3112 +    Swap(&system_info_.major_version);
  1.3113 +    Swap(&system_info_.minor_version);
  1.3114 +    Swap(&system_info_.build_number);
  1.3115 +    Swap(&system_info_.platform_id);
  1.3116 +    Swap(&system_info_.csd_version_rva);
  1.3117 +    Swap(&system_info_.suite_mask);
  1.3118 +    // Don't swap the reserved2 field because its contents are unknown.
  1.3119 +
  1.3120 +    if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
  1.3121 +        system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
  1.3122 +      for (unsigned int i = 0; i < 3; ++i)
  1.3123 +        Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
  1.3124 +      Swap(&system_info_.cpu.x86_cpu_info.version_information);
  1.3125 +      Swap(&system_info_.cpu.x86_cpu_info.feature_information);
  1.3126 +      Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
  1.3127 +    } else {
  1.3128 +      for (unsigned int i = 0; i < 2; ++i)
  1.3129 +        Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
  1.3130 +    }
  1.3131 +  }
  1.3132 +
  1.3133 +  valid_ = true;
  1.3134 +  return true;
  1.3135 +}
  1.3136 +
  1.3137 +
  1.3138 +string MinidumpSystemInfo::GetOS() {
  1.3139 +  string os;
  1.3140 +
  1.3141 +  if (!valid_) {
  1.3142 +    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
  1.3143 +    return os;
  1.3144 +  }
  1.3145 +
  1.3146 +  switch (system_info_.platform_id) {
  1.3147 +    case MD_OS_WIN32_NT:
  1.3148 +    case MD_OS_WIN32_WINDOWS:
  1.3149 +      os = "windows";
  1.3150 +      break;
  1.3151 +
  1.3152 +    case MD_OS_MAC_OS_X:
  1.3153 +      os = "mac";
  1.3154 +      break;
  1.3155 +
  1.3156 +    case MD_OS_IOS:
  1.3157 +      os = "ios";
  1.3158 +      break;
  1.3159 +
  1.3160 +    case MD_OS_LINUX:
  1.3161 +      os = "linux";
  1.3162 +      break;
  1.3163 +
  1.3164 +    case MD_OS_SOLARIS:
  1.3165 +      os = "solaris";
  1.3166 +      break;
  1.3167 +
  1.3168 +    case MD_OS_ANDROID:
  1.3169 +      os = "android";
  1.3170 +      break;
  1.3171 +
  1.3172 +    default:
  1.3173 +      BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
  1.3174 +                      HexString(system_info_.platform_id);
  1.3175 +      break;
  1.3176 +  }
  1.3177 +
  1.3178 +  return os;
  1.3179 +}
  1.3180 +
  1.3181 +
  1.3182 +string MinidumpSystemInfo::GetCPU() {
  1.3183 +  if (!valid_) {
  1.3184 +    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
  1.3185 +    return "";
  1.3186 +  }
  1.3187 +
  1.3188 +  string cpu;
  1.3189 +
  1.3190 +  switch (system_info_.processor_architecture) {
  1.3191 +    case MD_CPU_ARCHITECTURE_X86:
  1.3192 +    case MD_CPU_ARCHITECTURE_X86_WIN64:
  1.3193 +      cpu = "x86";
  1.3194 +      break;
  1.3195 +
  1.3196 +    case MD_CPU_ARCHITECTURE_AMD64:
  1.3197 +      cpu = "x86-64";
  1.3198 +      break;
  1.3199 +
  1.3200 +    case MD_CPU_ARCHITECTURE_PPC:
  1.3201 +      cpu = "ppc";
  1.3202 +      break;
  1.3203 +
  1.3204 +    case MD_CPU_ARCHITECTURE_SPARC:
  1.3205 +      cpu = "sparc";
  1.3206 +      break;
  1.3207 +
  1.3208 +    case MD_CPU_ARCHITECTURE_ARM:
  1.3209 +      cpu = "arm";
  1.3210 +      break;
  1.3211 +
  1.3212 +    default:
  1.3213 +      BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
  1.3214 +                      HexString(system_info_.processor_architecture);
  1.3215 +      break;
  1.3216 +  }
  1.3217 +
  1.3218 +  return cpu;
  1.3219 +}
  1.3220 +
  1.3221 +
  1.3222 +const string* MinidumpSystemInfo::GetCSDVersion() {
  1.3223 +  if (!valid_) {
  1.3224 +    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
  1.3225 +    return NULL;
  1.3226 +  }
  1.3227 +
  1.3228 +  if (!csd_version_)
  1.3229 +    csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
  1.3230 +
  1.3231 +  BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
  1.3232 +                                    "CSD version";
  1.3233 +
  1.3234 +  return csd_version_;
  1.3235 +}
  1.3236 +
  1.3237 +
  1.3238 +const string* MinidumpSystemInfo::GetCPUVendor() {
  1.3239 +  if (!valid_) {
  1.3240 +    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
  1.3241 +    return NULL;
  1.3242 +  }
  1.3243 +
  1.3244 +  // CPU vendor information can only be determined from x86 minidumps.
  1.3245 +  if (!cpu_vendor_ &&
  1.3246 +      (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
  1.3247 +       system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
  1.3248 +    char cpu_vendor_string[13];
  1.3249 +    snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
  1.3250 +             "%c%c%c%c%c%c%c%c%c%c%c%c",
  1.3251 +              system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
  1.3252 +             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
  1.3253 +             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
  1.3254 +             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
  1.3255 +              system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
  1.3256 +             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
  1.3257 +             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
  1.3258 +             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
  1.3259 +              system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
  1.3260 +             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
  1.3261 +             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
  1.3262 +             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
  1.3263 +    cpu_vendor_ = new string(cpu_vendor_string);
  1.3264 +  }
  1.3265 +
  1.3266 +  return cpu_vendor_;
  1.3267 +}
  1.3268 +
  1.3269 +
  1.3270 +void MinidumpSystemInfo::Print() {
  1.3271 +  if (!valid_) {
  1.3272 +    BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
  1.3273 +    return;
  1.3274 +  }
  1.3275 +
  1.3276 +  printf("MDRawSystemInfo\n");
  1.3277 +  printf("  processor_architecture                     = %d\n",
  1.3278 +         system_info_.processor_architecture);
  1.3279 +  printf("  processor_level                            = %d\n",
  1.3280 +         system_info_.processor_level);
  1.3281 +  printf("  processor_revision                         = 0x%x\n",
  1.3282 +         system_info_.processor_revision);
  1.3283 +  printf("  number_of_processors                       = %d\n",
  1.3284 +         system_info_.number_of_processors);
  1.3285 +  printf("  product_type                               = %d\n",
  1.3286 +         system_info_.product_type);
  1.3287 +  printf("  major_version                              = %d\n",
  1.3288 +         system_info_.major_version);
  1.3289 +  printf("  minor_version                              = %d\n",
  1.3290 +         system_info_.minor_version);
  1.3291 +  printf("  build_number                               = %d\n",
  1.3292 +         system_info_.build_number);
  1.3293 +  printf("  platform_id                                = %d\n",
  1.3294 +         system_info_.platform_id);
  1.3295 +  printf("  csd_version_rva                            = 0x%x\n",
  1.3296 +         system_info_.csd_version_rva);
  1.3297 +  printf("  suite_mask                                 = 0x%x\n",
  1.3298 +         system_info_.suite_mask);
  1.3299 +  for (unsigned int i = 0; i < 3; ++i) {
  1.3300 +    printf("  cpu.x86_cpu_info.vendor_id[%d]              = 0x%x\n",
  1.3301 +           i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
  1.3302 +  }
  1.3303 +  printf("  cpu.x86_cpu_info.version_information       = 0x%x\n",
  1.3304 +         system_info_.cpu.x86_cpu_info.version_information);
  1.3305 +  printf("  cpu.x86_cpu_info.feature_information       = 0x%x\n",
  1.3306 +         system_info_.cpu.x86_cpu_info.feature_information);
  1.3307 +  printf("  cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
  1.3308 +         system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
  1.3309 +  const string* csd_version = GetCSDVersion();
  1.3310 +  if (csd_version) {
  1.3311 +    printf("  (csd_version)                              = \"%s\"\n",
  1.3312 +           csd_version->c_str());
  1.3313 +  } else {
  1.3314 +    printf("  (csd_version)                              = (null)\n");
  1.3315 +  }
  1.3316 +  const string* cpu_vendor = GetCPUVendor();
  1.3317 +  if (cpu_vendor) {
  1.3318 +    printf("  (cpu_vendor)                               = \"%s\"\n",
  1.3319 +           cpu_vendor->c_str());
  1.3320 +  } else {
  1.3321 +    printf("  (cpu_vendor)                               = (null)\n");
  1.3322 +  }
  1.3323 +  printf("\n");
  1.3324 +}
  1.3325 +
  1.3326 +
  1.3327 +//
  1.3328 +// MinidumpMiscInfo
  1.3329 +//
  1.3330 +
  1.3331 +
  1.3332 +MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
  1.3333 +    : MinidumpStream(minidump),
  1.3334 +      misc_info_() {
  1.3335 +}
  1.3336 +
  1.3337 +
  1.3338 +bool MinidumpMiscInfo::Read(uint32_t expected_size) {
  1.3339 +  valid_ = false;
  1.3340 +
  1.3341 +  if (expected_size != MD_MISCINFO_SIZE &&
  1.3342 +      expected_size != MD_MISCINFO2_SIZE) {
  1.3343 +    BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size <<
  1.3344 +                    " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE <<
  1.3345 +                    ")";
  1.3346 +    return false;
  1.3347 +  }
  1.3348 +
  1.3349 +  if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
  1.3350 +    BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
  1.3351 +    return false;
  1.3352 +  }
  1.3353 +
  1.3354 +  if (minidump_->swap()) {
  1.3355 +    Swap(&misc_info_.size_of_info);
  1.3356 +    Swap(&misc_info_.flags1);
  1.3357 +    Swap(&misc_info_.process_id);
  1.3358 +    Swap(&misc_info_.process_create_time);
  1.3359 +    Swap(&misc_info_.process_user_time);
  1.3360 +    Swap(&misc_info_.process_kernel_time);
  1.3361 +    if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
  1.3362 +      Swap(&misc_info_.processor_max_mhz);
  1.3363 +      Swap(&misc_info_.processor_current_mhz);
  1.3364 +      Swap(&misc_info_.processor_mhz_limit);
  1.3365 +      Swap(&misc_info_.processor_max_idle_state);
  1.3366 +      Swap(&misc_info_.processor_current_idle_state);
  1.3367 +    }
  1.3368 +  }
  1.3369 +
  1.3370 +  if (expected_size != misc_info_.size_of_info) {
  1.3371 +    BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
  1.3372 +                    expected_size << " != " << misc_info_.size_of_info;
  1.3373 +    return false;
  1.3374 +  }
  1.3375 +
  1.3376 +  valid_ = true;
  1.3377 +  return true;
  1.3378 +}
  1.3379 +
  1.3380 +
  1.3381 +void MinidumpMiscInfo::Print() {
  1.3382 +  if (!valid_) {
  1.3383 +    BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
  1.3384 +    return;
  1.3385 +  }
  1.3386 +
  1.3387 +  printf("MDRawMiscInfo\n");
  1.3388 +  printf("  size_of_info                 = %d\n",   misc_info_.size_of_info);
  1.3389 +  printf("  flags1                       = 0x%x\n", misc_info_.flags1);
  1.3390 +  printf("  process_id                   = 0x%x\n", misc_info_.process_id);
  1.3391 +  printf("  process_create_time          = 0x%x\n",
  1.3392 +         misc_info_.process_create_time);
  1.3393 +  printf("  process_user_time            = 0x%x\n",
  1.3394 +         misc_info_.process_user_time);
  1.3395 +  printf("  process_kernel_time          = 0x%x\n",
  1.3396 +         misc_info_.process_kernel_time);
  1.3397 +  if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
  1.3398 +    printf("  processor_max_mhz            = %d\n",
  1.3399 +           misc_info_.processor_max_mhz);
  1.3400 +    printf("  processor_current_mhz        = %d\n",
  1.3401 +           misc_info_.processor_current_mhz);
  1.3402 +    printf("  processor_mhz_limit          = %d\n",
  1.3403 +           misc_info_.processor_mhz_limit);
  1.3404 +    printf("  processor_max_idle_state     = 0x%x\n",
  1.3405 +           misc_info_.processor_max_idle_state);
  1.3406 +    printf("  processor_current_idle_state = 0x%x\n",
  1.3407 +           misc_info_.processor_current_idle_state);
  1.3408 +  }
  1.3409 +  printf("\n");
  1.3410 +}
  1.3411 +
  1.3412 +
  1.3413 +//
  1.3414 +// MinidumpBreakpadInfo
  1.3415 +//
  1.3416 +
  1.3417 +
  1.3418 +MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
  1.3419 +    : MinidumpStream(minidump),
  1.3420 +      breakpad_info_() {
  1.3421 +}
  1.3422 +
  1.3423 +
  1.3424 +bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
  1.3425 +  valid_ = false;
  1.3426 +
  1.3427 +  if (expected_size != sizeof(breakpad_info_)) {
  1.3428 +    BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
  1.3429 +                    " != " << sizeof(breakpad_info_);
  1.3430 +    return false;
  1.3431 +  }
  1.3432 +
  1.3433 +  if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
  1.3434 +    BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
  1.3435 +    return false;
  1.3436 +  }
  1.3437 +
  1.3438 +  if (minidump_->swap()) {
  1.3439 +    Swap(&breakpad_info_.validity);
  1.3440 +    Swap(&breakpad_info_.dump_thread_id);
  1.3441 +    Swap(&breakpad_info_.requesting_thread_id);
  1.3442 +  }
  1.3443 +
  1.3444 +  valid_ = true;
  1.3445 +  return true;
  1.3446 +}
  1.3447 +
  1.3448 +
  1.3449 +bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
  1.3450 +  BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
  1.3451 +                                 "requires |thread_id|";
  1.3452 +  assert(thread_id);
  1.3453 +  *thread_id = 0;
  1.3454 +
  1.3455 +  if (!valid_) {
  1.3456 +    BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
  1.3457 +    return false;
  1.3458 +  }
  1.3459 +
  1.3460 +  if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
  1.3461 +    BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
  1.3462 +    return false;
  1.3463 +  }
  1.3464 +
  1.3465 +  *thread_id = breakpad_info_.dump_thread_id;
  1.3466 +  return true;
  1.3467 +}
  1.3468 +
  1.3469 +
  1.3470 +bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id)
  1.3471 +    const {
  1.3472 +  BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
  1.3473 +                                 "requires |thread_id|";
  1.3474 +  assert(thread_id);
  1.3475 +  *thread_id = 0;
  1.3476 +
  1.3477 +  if (!thread_id || !valid_) {
  1.3478 +    BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
  1.3479 +    return false;
  1.3480 +  }
  1.3481 +
  1.3482 +  if (!(breakpad_info_.validity &
  1.3483 +            MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
  1.3484 +    BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
  1.3485 +    return false;
  1.3486 +  }
  1.3487 +
  1.3488 +  *thread_id = breakpad_info_.requesting_thread_id;
  1.3489 +  return true;
  1.3490 +}
  1.3491 +
  1.3492 +
  1.3493 +void MinidumpBreakpadInfo::Print() {
  1.3494 +  if (!valid_) {
  1.3495 +    BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
  1.3496 +    return;
  1.3497 +  }
  1.3498 +
  1.3499 +  printf("MDRawBreakpadInfo\n");
  1.3500 +  printf("  validity             = 0x%x\n", breakpad_info_.validity);
  1.3501 +
  1.3502 +  if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
  1.3503 +    printf("  dump_thread_id       = 0x%x\n", breakpad_info_.dump_thread_id);
  1.3504 +  } else {
  1.3505 +    printf("  dump_thread_id       = (invalid)\n");
  1.3506 +  }
  1.3507 +
  1.3508 +  if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
  1.3509 +    printf("  requesting_thread_id = 0x%x\n",
  1.3510 +           breakpad_info_.requesting_thread_id);
  1.3511 +  } else {
  1.3512 +    printf("  requesting_thread_id = (invalid)\n");
  1.3513 +  }
  1.3514 +
  1.3515 +  printf("\n");
  1.3516 +}
  1.3517 +
  1.3518 +
  1.3519 +//
  1.3520 +// MinidumpMemoryInfo
  1.3521 +//
  1.3522 +
  1.3523 +
  1.3524 +MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
  1.3525 +    : MinidumpObject(minidump),
  1.3526 +      memory_info_() {
  1.3527 +}
  1.3528 +
  1.3529 +
  1.3530 +bool MinidumpMemoryInfo::IsExecutable() const {
  1.3531 +  uint32_t protection =
  1.3532 +      memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
  1.3533 +  return protection == MD_MEMORY_PROTECT_EXECUTE ||
  1.3534 +      protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
  1.3535 +      protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
  1.3536 +}
  1.3537 +
  1.3538 +
  1.3539 +bool MinidumpMemoryInfo::IsWritable() const {
  1.3540 +  uint32_t protection =
  1.3541 +      memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
  1.3542 +  return protection == MD_MEMORY_PROTECT_READWRITE ||
  1.3543 +    protection == MD_MEMORY_PROTECT_WRITECOPY ||
  1.3544 +    protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
  1.3545 +    protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
  1.3546 +}
  1.3547 +
  1.3548 +
  1.3549 +bool MinidumpMemoryInfo::Read() {
  1.3550 +  valid_ = false;
  1.3551 +
  1.3552 +  if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
  1.3553 +    BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
  1.3554 +    return false;
  1.3555 +  }
  1.3556 +
  1.3557 +  if (minidump_->swap()) {
  1.3558 +    Swap(&memory_info_.base_address);
  1.3559 +    Swap(&memory_info_.allocation_base);
  1.3560 +    Swap(&memory_info_.allocation_protection);
  1.3561 +    Swap(&memory_info_.region_size);
  1.3562 +    Swap(&memory_info_.state);
  1.3563 +    Swap(&memory_info_.protection);
  1.3564 +    Swap(&memory_info_.type);
  1.3565 +  }
  1.3566 +
  1.3567 +  // Check for base + size overflow or undersize.
  1.3568 +  if (memory_info_.region_size == 0 ||
  1.3569 +      memory_info_.region_size > numeric_limits<uint64_t>::max() -
  1.3570 +                                     memory_info_.base_address) {
  1.3571 +    BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
  1.3572 +                    HexString(memory_info_.base_address) << "+" <<
  1.3573 +                    HexString(memory_info_.region_size);
  1.3574 +    return false;
  1.3575 +  }
  1.3576 +
  1.3577 +  valid_ = true;
  1.3578 +  return true;
  1.3579 +}
  1.3580 +
  1.3581 +
  1.3582 +void MinidumpMemoryInfo::Print() {
  1.3583 +  if (!valid_) {
  1.3584 +    BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
  1.3585 +    return;
  1.3586 +  }
  1.3587 +
  1.3588 +  printf("MDRawMemoryInfo\n");
  1.3589 +  printf("  base_address          = 0x%" PRIx64 "\n",
  1.3590 +         memory_info_.base_address);
  1.3591 +  printf("  allocation_base       = 0x%" PRIx64 "\n",
  1.3592 +         memory_info_.allocation_base);
  1.3593 +  printf("  allocation_protection = 0x%x\n",
  1.3594 +         memory_info_.allocation_protection);
  1.3595 +  printf("  region_size           = 0x%" PRIx64 "\n", memory_info_.region_size);
  1.3596 +  printf("  state                 = 0x%x\n", memory_info_.state);
  1.3597 +  printf("  protection            = 0x%x\n", memory_info_.protection);
  1.3598 +  printf("  type                  = 0x%x\n", memory_info_.type);
  1.3599 +}
  1.3600 +
  1.3601 +
  1.3602 +//
  1.3603 +// MinidumpMemoryInfoList
  1.3604 +//
  1.3605 +
  1.3606 +
  1.3607 +MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
  1.3608 +    : MinidumpStream(minidump),
  1.3609 +      range_map_(new RangeMap<uint64_t, unsigned int>()),
  1.3610 +      infos_(NULL),
  1.3611 +      info_count_(0) {
  1.3612 +}
  1.3613 +
  1.3614 +
  1.3615 +MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
  1.3616 +  delete range_map_;
  1.3617 +  delete infos_;
  1.3618 +}
  1.3619 +
  1.3620 +
  1.3621 +bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
  1.3622 +  // Invalidate cached data.
  1.3623 +  delete infos_;
  1.3624 +  infos_ = NULL;
  1.3625 +  range_map_->Clear();
  1.3626 +  info_count_ = 0;
  1.3627 +
  1.3628 +  valid_ = false;
  1.3629 +
  1.3630 +  MDRawMemoryInfoList header;
  1.3631 +  if (expected_size < sizeof(MDRawMemoryInfoList)) {
  1.3632 +    BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
  1.3633 +                    expected_size << " < " << sizeof(MDRawMemoryInfoList);
  1.3634 +    return false;
  1.3635 +  }
  1.3636 +  if (!minidump_->ReadBytes(&header, sizeof(header))) {
  1.3637 +    BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
  1.3638 +    return false;
  1.3639 +  }
  1.3640 +
  1.3641 +  if (minidump_->swap()) {
  1.3642 +    Swap(&header.size_of_header);
  1.3643 +    Swap(&header.size_of_entry);
  1.3644 +    Swap(&header.number_of_entries);
  1.3645 +  }
  1.3646 +
  1.3647 +  // Sanity check that the header is the expected size.
  1.3648 +  //TODO(ted): could possibly handle this more gracefully, assuming
  1.3649 +  // that future versions of the structs would be backwards-compatible.
  1.3650 +  if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
  1.3651 +    BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
  1.3652 +                    header.size_of_header << " != " <<
  1.3653 +                    sizeof(MDRawMemoryInfoList);
  1.3654 +    return false;
  1.3655 +  }
  1.3656 +
  1.3657 +  // Sanity check that the entries are the expected size.
  1.3658 +  if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
  1.3659 +    BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
  1.3660 +                    header.size_of_entry << " != " <<
  1.3661 +                    sizeof(MDRawMemoryInfo);
  1.3662 +    return false;
  1.3663 +  }
  1.3664 +
  1.3665 +  if (header.number_of_entries >
  1.3666 +          numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
  1.3667 +    BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
  1.3668 +                    header.number_of_entries <<
  1.3669 +                    " would cause multiplication overflow";
  1.3670 +    return false;
  1.3671 +  }
  1.3672 +
  1.3673 +  if (expected_size != sizeof(MDRawMemoryInfoList) +
  1.3674 +                        header.number_of_entries * sizeof(MDRawMemoryInfo)) {
  1.3675 +    BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
  1.3676 +                    " != " << sizeof(MDRawMemoryInfoList) +
  1.3677 +                        header.number_of_entries * sizeof(MDRawMemoryInfo);
  1.3678 +    return false;
  1.3679 +  }
  1.3680 +
  1.3681 +  if (header.number_of_entries != 0) {
  1.3682 +    scoped_ptr<MinidumpMemoryInfos> infos(
  1.3683 +        new MinidumpMemoryInfos(header.number_of_entries,
  1.3684 +                                MinidumpMemoryInfo(minidump_)));
  1.3685 +
  1.3686 +    for (unsigned int index = 0;
  1.3687 +         index < header.number_of_entries;
  1.3688 +         ++index) {
  1.3689 +      MinidumpMemoryInfo* info = &(*infos)[index];
  1.3690 +
  1.3691 +      // Assume that the file offset is correct after the last read.
  1.3692 +      if (!info->Read()) {
  1.3693 +        BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
  1.3694 +                        index << "/" << header.number_of_entries;
  1.3695 +        return false;
  1.3696 +      }
  1.3697 +
  1.3698 +      uint64_t base_address = info->GetBase();
  1.3699 +      uint32_t region_size = info->GetSize();
  1.3700 +
  1.3701 +      if (!range_map_->StoreRange(base_address, region_size, index)) {
  1.3702 +        BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
  1.3703 +                        " memory region " <<
  1.3704 +                        index << "/" << header.number_of_entries << ", " <<
  1.3705 +                        HexString(base_address) << "+" <<
  1.3706 +                        HexString(region_size);
  1.3707 +        return false;
  1.3708 +      }
  1.3709 +    }
  1.3710 +
  1.3711 +    infos_ = infos.release();
  1.3712 +  }
  1.3713 +
  1.3714 +  info_count_ = header.number_of_entries;
  1.3715 +
  1.3716 +  valid_ = true;
  1.3717 +  return true;
  1.3718 +}
  1.3719 +
  1.3720 +
  1.3721 +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
  1.3722 +      unsigned int index) const {
  1.3723 +  if (!valid_) {
  1.3724 +    BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
  1.3725 +    return NULL;
  1.3726 +  }
  1.3727 +
  1.3728 +  if (index >= info_count_) {
  1.3729 +    BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
  1.3730 +                    index << "/" << info_count_;
  1.3731 +    return NULL;
  1.3732 +  }
  1.3733 +
  1.3734 +  return &(*infos_)[index];
  1.3735 +}
  1.3736 +
  1.3737 +
  1.3738 +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
  1.3739 +    uint64_t address) const {
  1.3740 +  if (!valid_) {
  1.3741 +    BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
  1.3742 +                    " GetMemoryInfoForAddress";
  1.3743 +    return NULL;
  1.3744 +  }
  1.3745 +
  1.3746 +  unsigned int info_index;
  1.3747 +  if (!range_map_->RetrieveRange(address, &info_index, NULL, NULL)) {
  1.3748 +    BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
  1.3749 +                   HexString(address);
  1.3750 +    return NULL;
  1.3751 +  }
  1.3752 +
  1.3753 +  return GetMemoryInfoAtIndex(info_index);
  1.3754 +}
  1.3755 +
  1.3756 +
  1.3757 +void MinidumpMemoryInfoList::Print() {
  1.3758 +  if (!valid_) {
  1.3759 +    BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
  1.3760 +    return;
  1.3761 +  }
  1.3762 +
  1.3763 +  printf("MinidumpMemoryInfoList\n");
  1.3764 +  printf("  info_count = %d\n", info_count_);
  1.3765 +  printf("\n");
  1.3766 +
  1.3767 +  for (unsigned int info_index = 0;
  1.3768 +       info_index < info_count_;
  1.3769 +       ++info_index) {
  1.3770 +    printf("info[%d]\n", info_index);
  1.3771 +    (*infos_)[info_index].Print();
  1.3772 +    printf("\n");
  1.3773 +  }
  1.3774 +}
  1.3775 +
  1.3776 +
  1.3777 +//
  1.3778 +// Minidump
  1.3779 +//
  1.3780 +
  1.3781 +
  1.3782 +uint32_t Minidump::max_streams_ = 128;
  1.3783 +unsigned int Minidump::max_string_length_ = 1024;
  1.3784 +
  1.3785 +
  1.3786 +Minidump::Minidump(const string& path)
  1.3787 +    : header_(),
  1.3788 +      directory_(NULL),
  1.3789 +      stream_map_(new MinidumpStreamMap()),
  1.3790 +      path_(path),
  1.3791 +      stream_(NULL),
  1.3792 +      swap_(false),
  1.3793 +      valid_(false) {
  1.3794 +}
  1.3795 +
  1.3796 +Minidump::Minidump(istream& stream)
  1.3797 +    : header_(),
  1.3798 +      directory_(NULL),
  1.3799 +      stream_map_(new MinidumpStreamMap()),
  1.3800 +      path_(),
  1.3801 +      stream_(&stream),
  1.3802 +      swap_(false),
  1.3803 +      valid_(false) {
  1.3804 +}
  1.3805 +
  1.3806 +Minidump::~Minidump() {
  1.3807 +  if (stream_) {
  1.3808 +    BPLOG(INFO) << "Minidump closing minidump";
  1.3809 +  }
  1.3810 +  if (!path_.empty()) {
  1.3811 +    delete stream_;
  1.3812 +  }
  1.3813 +  delete directory_;
  1.3814 +  delete stream_map_;
  1.3815 +}
  1.3816 +
  1.3817 +
  1.3818 +bool Minidump::Open() {
  1.3819 +  if (stream_ != NULL) {
  1.3820 +    BPLOG(INFO) << "Minidump reopening minidump " << path_;
  1.3821 +
  1.3822 +    // The file is already open.  Seek to the beginning, which is the position
  1.3823 +    // the file would be at if it were opened anew.
  1.3824 +    return SeekSet(0);
  1.3825 +  }
  1.3826 +
  1.3827 +  stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
  1.3828 +  if (!stream_ || !stream_->good()) {
  1.3829 +    string error_string;
  1.3830 +    int error_code = ErrnoString(&error_string);
  1.3831 +    BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
  1.3832 +                    ", error " << error_code << ": " << error_string;
  1.3833 +    return false;
  1.3834 +  }
  1.3835 +
  1.3836 +  BPLOG(INFO) << "Minidump opened minidump " << path_;
  1.3837 +  return true;
  1.3838 +}
  1.3839 +
  1.3840 +bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
  1.3841 +  // Initialize output parameters
  1.3842 +  *context_cpu_flags = 0;
  1.3843 +
  1.3844 +  // Save the current stream position
  1.3845 +  off_t saved_position = Tell();
  1.3846 +  if (saved_position == -1) {
  1.3847 +    // Failed to save the current stream position.
  1.3848 +    // Returns true because the current position of the stream is preserved.
  1.3849 +    return true;
  1.3850 +  }
  1.3851 +
  1.3852 +  const MDRawSystemInfo* system_info =
  1.3853 +    GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
  1.3854 +
  1.3855 +  if (system_info != NULL) {
  1.3856 +    switch (system_info->processor_architecture) {
  1.3857 +      case MD_CPU_ARCHITECTURE_X86:
  1.3858 +        *context_cpu_flags = MD_CONTEXT_X86;
  1.3859 +        break;
  1.3860 +      case MD_CPU_ARCHITECTURE_MIPS:
  1.3861 +        *context_cpu_flags = MD_CONTEXT_MIPS;
  1.3862 +        break;
  1.3863 +      case MD_CPU_ARCHITECTURE_ALPHA:
  1.3864 +        *context_cpu_flags = MD_CONTEXT_ALPHA;
  1.3865 +        break;
  1.3866 +      case MD_CPU_ARCHITECTURE_PPC:
  1.3867 +        *context_cpu_flags = MD_CONTEXT_PPC;
  1.3868 +        break;
  1.3869 +      case MD_CPU_ARCHITECTURE_SHX:
  1.3870 +        *context_cpu_flags = MD_CONTEXT_SHX;
  1.3871 +        break;
  1.3872 +      case MD_CPU_ARCHITECTURE_ARM:
  1.3873 +        *context_cpu_flags = MD_CONTEXT_ARM;
  1.3874 +        break;
  1.3875 +      case MD_CPU_ARCHITECTURE_IA64:
  1.3876 +        *context_cpu_flags = MD_CONTEXT_IA64;
  1.3877 +        break;
  1.3878 +      case MD_CPU_ARCHITECTURE_ALPHA64:
  1.3879 +        *context_cpu_flags = 0;
  1.3880 +        break;
  1.3881 +      case MD_CPU_ARCHITECTURE_MSIL:
  1.3882 +        *context_cpu_flags = 0;
  1.3883 +        break;
  1.3884 +      case MD_CPU_ARCHITECTURE_AMD64:
  1.3885 +        *context_cpu_flags = MD_CONTEXT_AMD64;
  1.3886 +        break;
  1.3887 +      case MD_CPU_ARCHITECTURE_X86_WIN64:
  1.3888 +        *context_cpu_flags = 0;
  1.3889 +        break;
  1.3890 +      case MD_CPU_ARCHITECTURE_SPARC:
  1.3891 +        *context_cpu_flags = MD_CONTEXT_SPARC;
  1.3892 +        break;
  1.3893 +      case MD_CPU_ARCHITECTURE_UNKNOWN:
  1.3894 +        *context_cpu_flags = 0;
  1.3895 +        break;
  1.3896 +      default:
  1.3897 +        *context_cpu_flags = 0;
  1.3898 +        break;
  1.3899 +    }
  1.3900 +  }
  1.3901 +
  1.3902 +  // Restore position and return
  1.3903 +  return SeekSet(saved_position);
  1.3904 +}
  1.3905 +
  1.3906 +
  1.3907 +bool Minidump::Read() {
  1.3908 +  // Invalidate cached data.
  1.3909 +  delete directory_;
  1.3910 +  directory_ = NULL;
  1.3911 +  stream_map_->clear();
  1.3912 +
  1.3913 +  valid_ = false;
  1.3914 +
  1.3915 +  if (!Open()) {
  1.3916 +    BPLOG(ERROR) << "Minidump cannot open minidump";
  1.3917 +    return false;
  1.3918 +  }
  1.3919 +
  1.3920 +  if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
  1.3921 +    BPLOG(ERROR) << "Minidump cannot read header";
  1.3922 +    return false;
  1.3923 +  }
  1.3924 +
  1.3925 +  if (header_.signature != MD_HEADER_SIGNATURE) {
  1.3926 +    // The file may be byte-swapped.  Under the present architecture, these
  1.3927 +    // classes don't know or need to know what CPU (or endianness) the
  1.3928 +    // minidump was produced on in order to parse it.  Use the signature as
  1.3929 +    // a byte order marker.
  1.3930 +    uint32_t signature_swapped = header_.signature;
  1.3931 +    Swap(&signature_swapped);
  1.3932 +    if (signature_swapped != MD_HEADER_SIGNATURE) {
  1.3933 +      // This isn't a minidump or a byte-swapped minidump.
  1.3934 +      BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
  1.3935 +                      HexString(header_.signature) << ", " <<
  1.3936 +                      HexString(signature_swapped) << ") != " <<
  1.3937 +                      HexString(MD_HEADER_SIGNATURE);
  1.3938 +      return false;
  1.3939 +    }
  1.3940 +    swap_ = true;
  1.3941 +  } else {
  1.3942 +    // The file is not byte-swapped.  Set swap_ false (it may have been true
  1.3943 +    // if the object is being reused?)
  1.3944 +    swap_ = false;
  1.3945 +  }
  1.3946 +
  1.3947 +  BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
  1.3948 +                 "byte-swapping minidump";
  1.3949 +
  1.3950 +  if (swap_) {
  1.3951 +    Swap(&header_.signature);
  1.3952 +    Swap(&header_.version);
  1.3953 +    Swap(&header_.stream_count);
  1.3954 +    Swap(&header_.stream_directory_rva);
  1.3955 +    Swap(&header_.checksum);
  1.3956 +    Swap(&header_.time_date_stamp);
  1.3957 +    Swap(&header_.flags);
  1.3958 +  }
  1.3959 +
  1.3960 +  // Version check.  The high 16 bits of header_.version contain something
  1.3961 +  // else "implementation specific."
  1.3962 +  if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
  1.3963 +    BPLOG(ERROR) << "Minidump version mismatch: " <<
  1.3964 +                    HexString(header_.version & 0x0000ffff) << " != " <<
  1.3965 +                    HexString(MD_HEADER_VERSION);
  1.3966 +    return false;
  1.3967 +  }
  1.3968 +
  1.3969 +  if (!SeekSet(header_.stream_directory_rva)) {
  1.3970 +    BPLOG(ERROR) << "Minidump cannot seek to stream directory";
  1.3971 +    return false;
  1.3972 +  }
  1.3973 +
  1.3974 +  if (header_.stream_count > max_streams_) {
  1.3975 +    BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
  1.3976 +                    " exceeds maximum " << max_streams_;
  1.3977 +    return false;
  1.3978 +  }
  1.3979 +
  1.3980 +  if (header_.stream_count != 0) {
  1.3981 +    scoped_ptr<MinidumpDirectoryEntries> directory(
  1.3982 +        new MinidumpDirectoryEntries(header_.stream_count));
  1.3983 +
  1.3984 +    // Read the entire array in one fell swoop, instead of reading one entry
  1.3985 +    // at a time in the loop.
  1.3986 +    if (!ReadBytes(&(*directory)[0],
  1.3987 +                   sizeof(MDRawDirectory) * header_.stream_count)) {
  1.3988 +      BPLOG(ERROR) << "Minidump cannot read stream directory";
  1.3989 +      return false;
  1.3990 +    }
  1.3991 +
  1.3992 +    for (unsigned int stream_index = 0;
  1.3993 +         stream_index < header_.stream_count;
  1.3994 +         ++stream_index) {
  1.3995 +      MDRawDirectory* directory_entry = &(*directory)[stream_index];
  1.3996 +
  1.3997 +      if (swap_) {
  1.3998 +        Swap(&directory_entry->stream_type);
  1.3999 +        Swap(&directory_entry->location);
  1.4000 +      }
  1.4001 +
  1.4002 +      // Initialize the stream_map_ map, which speeds locating a stream by
  1.4003 +      // type.
  1.4004 +      unsigned int stream_type = directory_entry->stream_type;
  1.4005 +      switch (stream_type) {
  1.4006 +        case MD_THREAD_LIST_STREAM:
  1.4007 +        case MD_MODULE_LIST_STREAM:
  1.4008 +        case MD_MEMORY_LIST_STREAM:
  1.4009 +        case MD_EXCEPTION_STREAM:
  1.4010 +        case MD_SYSTEM_INFO_STREAM:
  1.4011 +        case MD_MISC_INFO_STREAM:
  1.4012 +        case MD_BREAKPAD_INFO_STREAM: {
  1.4013 +          if (stream_map_->find(stream_type) != stream_map_->end()) {
  1.4014 +            // Another stream with this type was already found.  A minidump
  1.4015 +            // file should contain at most one of each of these stream types.
  1.4016 +            BPLOG(ERROR) << "Minidump found multiple streams of type " <<
  1.4017 +                            stream_type << ", but can only deal with one";
  1.4018 +            return false;
  1.4019 +          }
  1.4020 +          // Fall through to default
  1.4021 +        }
  1.4022 +
  1.4023 +        default: {
  1.4024 +          // Overwrites for stream types other than those above, but it's
  1.4025 +          // expected to be the user's burden in that case.
  1.4026 +          (*stream_map_)[stream_type].stream_index = stream_index;
  1.4027 +        }
  1.4028 +      }
  1.4029 +    }
  1.4030 +
  1.4031 +    directory_ = directory.release();
  1.4032 +  }
  1.4033 +
  1.4034 +  valid_ = true;
  1.4035 +  return true;
  1.4036 +}
  1.4037 +
  1.4038 +
  1.4039 +MinidumpThreadList* Minidump::GetThreadList() {
  1.4040 +  MinidumpThreadList* thread_list;
  1.4041 +  return GetStream(&thread_list);
  1.4042 +}
  1.4043 +
  1.4044 +
  1.4045 +MinidumpModuleList* Minidump::GetModuleList() {
  1.4046 +  MinidumpModuleList* module_list;
  1.4047 +  return GetStream(&module_list);
  1.4048 +}
  1.4049 +
  1.4050 +
  1.4051 +MinidumpMemoryList* Minidump::GetMemoryList() {
  1.4052 +  MinidumpMemoryList* memory_list;
  1.4053 +  return GetStream(&memory_list);
  1.4054 +}
  1.4055 +
  1.4056 +
  1.4057 +MinidumpException* Minidump::GetException() {
  1.4058 +  MinidumpException* exception;
  1.4059 +  return GetStream(&exception);
  1.4060 +}
  1.4061 +
  1.4062 +MinidumpAssertion* Minidump::GetAssertion() {
  1.4063 +  MinidumpAssertion* assertion;
  1.4064 +  return GetStream(&assertion);
  1.4065 +}
  1.4066 +
  1.4067 +
  1.4068 +MinidumpSystemInfo* Minidump::GetSystemInfo() {
  1.4069 +  MinidumpSystemInfo* system_info;
  1.4070 +  return GetStream(&system_info);
  1.4071 +}
  1.4072 +
  1.4073 +
  1.4074 +MinidumpMiscInfo* Minidump::GetMiscInfo() {
  1.4075 +  MinidumpMiscInfo* misc_info;
  1.4076 +  return GetStream(&misc_info);
  1.4077 +}
  1.4078 +
  1.4079 +
  1.4080 +MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
  1.4081 +  MinidumpBreakpadInfo* breakpad_info;
  1.4082 +  return GetStream(&breakpad_info);
  1.4083 +}
  1.4084 +
  1.4085 +MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
  1.4086 +  MinidumpMemoryInfoList* memory_info_list;
  1.4087 +  return GetStream(&memory_info_list);
  1.4088 +}
  1.4089 +
  1.4090 +
  1.4091 +void Minidump::Print() {
  1.4092 +  if (!valid_) {
  1.4093 +    BPLOG(ERROR) << "Minidump cannot print invalid data";
  1.4094 +    return;
  1.4095 +  }
  1.4096 +
  1.4097 +  printf("MDRawHeader\n");
  1.4098 +  printf("  signature            = 0x%x\n",    header_.signature);
  1.4099 +  printf("  version              = 0x%x\n",    header_.version);
  1.4100 +  printf("  stream_count         = %d\n",      header_.stream_count);
  1.4101 +  printf("  stream_directory_rva = 0x%x\n",    header_.stream_directory_rva);
  1.4102 +  printf("  checksum             = 0x%x\n",    header_.checksum);
  1.4103 +  struct tm timestruct;
  1.4104 +#ifdef _WIN32
  1.4105 +  gmtime_s(&timestruct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
  1.4106 +#else
  1.4107 +  gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), &timestruct);
  1.4108 +#endif
  1.4109 +  char timestr[20];
  1.4110 +  strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
  1.4111 +  printf("  time_date_stamp      = 0x%x %s\n", header_.time_date_stamp,
  1.4112 +                                               timestr);
  1.4113 +  printf("  flags                = 0x%" PRIx64 "\n",  header_.flags);
  1.4114 +  printf("\n");
  1.4115 +
  1.4116 +  for (unsigned int stream_index = 0;
  1.4117 +       stream_index < header_.stream_count;
  1.4118 +       ++stream_index) {
  1.4119 +    MDRawDirectory* directory_entry = &(*directory_)[stream_index];
  1.4120 +
  1.4121 +    printf("mDirectory[%d]\n", stream_index);
  1.4122 +    printf("MDRawDirectory\n");
  1.4123 +    printf("  stream_type        = %d\n",   directory_entry->stream_type);
  1.4124 +    printf("  location.data_size = %d\n",
  1.4125 +           directory_entry->location.data_size);
  1.4126 +    printf("  location.rva       = 0x%x\n", directory_entry->location.rva);
  1.4127 +    printf("\n");
  1.4128 +  }
  1.4129 +
  1.4130 +  printf("Streams:\n");
  1.4131 +  for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
  1.4132 +       iterator != stream_map_->end();
  1.4133 +       ++iterator) {
  1.4134 +    uint32_t stream_type = iterator->first;
  1.4135 +    MinidumpStreamInfo info = iterator->second;
  1.4136 +    printf("  stream type 0x%x at index %d\n", stream_type, info.stream_index);
  1.4137 +  }
  1.4138 +  printf("\n");
  1.4139 +}
  1.4140 +
  1.4141 +
  1.4142 +const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
  1.4143 +      const {
  1.4144 +  if (!valid_) {
  1.4145 +    BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
  1.4146 +    return NULL;
  1.4147 +  }
  1.4148 +
  1.4149 +  if (index >= header_.stream_count) {
  1.4150 +    BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
  1.4151 +                    index << "/" << header_.stream_count;
  1.4152 +    return NULL;
  1.4153 +  }
  1.4154 +
  1.4155 +  return &(*directory_)[index];
  1.4156 +}
  1.4157 +
  1.4158 +
  1.4159 +bool Minidump::ReadBytes(void* bytes, size_t count) {
  1.4160 +  // Can't check valid_ because Read needs to call this method before
  1.4161 +  // validity can be determined.
  1.4162 +  if (!stream_) {
  1.4163 +    return false;
  1.4164 +  }
  1.4165 +  stream_->read(static_cast<char*>(bytes), count);
  1.4166 +  size_t bytes_read = stream_->gcount();
  1.4167 +  if (bytes_read != count) {
  1.4168 +    if (bytes_read == size_t(-1)) {
  1.4169 +      string error_string;
  1.4170 +      int error_code = ErrnoString(&error_string);
  1.4171 +      BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
  1.4172 +    } else {
  1.4173 +      BPLOG(ERROR) << "ReadBytes: read " << bytes_read << "/" << count;
  1.4174 +    }
  1.4175 +    return false;
  1.4176 +  }
  1.4177 +  return true;
  1.4178 +}
  1.4179 +
  1.4180 +
  1.4181 +bool Minidump::SeekSet(off_t offset) {
  1.4182 +  // Can't check valid_ because Read needs to call this method before
  1.4183 +  // validity can be determined.
  1.4184 +  if (!stream_) {
  1.4185 +    return false;
  1.4186 +  }
  1.4187 +  stream_->seekg(offset, std::ios_base::beg);
  1.4188 +  if (!stream_->good()) {
  1.4189 +    string error_string;
  1.4190 +    int error_code = ErrnoString(&error_string);
  1.4191 +    BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
  1.4192 +    return false;
  1.4193 +  }
  1.4194 +  return true;
  1.4195 +}
  1.4196 +
  1.4197 +off_t Minidump::Tell() {
  1.4198 +  if (!valid_ || !stream_) {
  1.4199 +    return (off_t)-1;
  1.4200 +  }
  1.4201 +
  1.4202 +  return stream_->tellg();
  1.4203 +}
  1.4204 +
  1.4205 +
  1.4206 +string* Minidump::ReadString(off_t offset) {
  1.4207 +  if (!valid_) {
  1.4208 +    BPLOG(ERROR) << "Invalid Minidump for ReadString";
  1.4209 +    return NULL;
  1.4210 +  }
  1.4211 +  if (!SeekSet(offset)) {
  1.4212 +    BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
  1.4213 +    return NULL;
  1.4214 +  }
  1.4215 +
  1.4216 +  uint32_t bytes;
  1.4217 +  if (!ReadBytes(&bytes, sizeof(bytes))) {
  1.4218 +    BPLOG(ERROR) << "ReadString could not read string size at offset " <<
  1.4219 +                    offset;
  1.4220 +    return NULL;
  1.4221 +  }
  1.4222 +  if (swap_)
  1.4223 +    Swap(&bytes);
  1.4224 +
  1.4225 +  if (bytes % 2 != 0) {
  1.4226 +    BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
  1.4227 +                    "-byte string at offset " << offset;
  1.4228 +    return NULL;
  1.4229 +  }
  1.4230 +  unsigned int utf16_words = bytes / 2;
  1.4231 +
  1.4232 +  if (utf16_words > max_string_length_) {
  1.4233 +    BPLOG(ERROR) << "ReadString string length " << utf16_words <<
  1.4234 +                    " exceeds maximum " << max_string_length_ <<
  1.4235 +                    " at offset " << offset;
  1.4236 +    return NULL;
  1.4237 +  }
  1.4238 +
  1.4239 +  vector<uint16_t> string_utf16(utf16_words);
  1.4240 +
  1.4241 +  if (utf16_words) {
  1.4242 +    if (!ReadBytes(&string_utf16[0], bytes)) {
  1.4243 +      BPLOG(ERROR) << "ReadString could not read " << bytes <<
  1.4244 +                      "-byte string at offset " << offset;
  1.4245 +      return NULL;
  1.4246 +    }
  1.4247 +  }
  1.4248 +
  1.4249 +  return UTF16ToUTF8(string_utf16, swap_);
  1.4250 +}
  1.4251 +
  1.4252 +
  1.4253 +bool Minidump::SeekToStreamType(uint32_t  stream_type,
  1.4254 +                                uint32_t* stream_length) {
  1.4255 +  BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
  1.4256 +                                     "|stream_length|";
  1.4257 +  assert(stream_length);
  1.4258 +  *stream_length = 0;
  1.4259 +
  1.4260 +  if (!valid_) {
  1.4261 +    BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
  1.4262 +    return false;
  1.4263 +  }
  1.4264 +
  1.4265 +  MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
  1.4266 +  if (iterator == stream_map_->end()) {
  1.4267 +    // This stream type didn't exist in the directory.
  1.4268 +    BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
  1.4269 +    return false;
  1.4270 +  }
  1.4271 +
  1.4272 +  MinidumpStreamInfo info = iterator->second;
  1.4273 +  if (info.stream_index >= header_.stream_count) {
  1.4274 +    BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
  1.4275 +                    " out of range: " <<
  1.4276 +                    info.stream_index << "/" << header_.stream_count;
  1.4277 +    return false;
  1.4278 +  }
  1.4279 +
  1.4280 +  MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
  1.4281 +  if (!SeekSet(directory_entry->location.rva)) {
  1.4282 +    BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
  1.4283 +                    stream_type;
  1.4284 +    return false;
  1.4285 +  }
  1.4286 +
  1.4287 +  *stream_length = directory_entry->location.data_size;
  1.4288 +
  1.4289 +  return true;
  1.4290 +}
  1.4291 +
  1.4292 +
  1.4293 +template<typename T>
  1.4294 +T* Minidump::GetStream(T** stream) {
  1.4295 +  // stream is a garbage parameter that's present only to account for C++'s
  1.4296 +  // inability to overload a method based solely on its return type.
  1.4297 +
  1.4298 +  const uint32_t stream_type = T::kStreamType;
  1.4299 +
  1.4300 +  BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
  1.4301 +                              " requires |stream|";
  1.4302 +  assert(stream);
  1.4303 +  *stream = NULL;
  1.4304 +
  1.4305 +  if (!valid_) {
  1.4306 +    BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
  1.4307 +    return NULL;
  1.4308 +  }
  1.4309 +
  1.4310 +  MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
  1.4311 +  if (iterator == stream_map_->end()) {
  1.4312 +    // This stream type didn't exist in the directory.
  1.4313 +    BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
  1.4314 +    return NULL;
  1.4315 +  }
  1.4316 +
  1.4317 +  // Get a pointer so that the stored stream field can be altered.
  1.4318 +  MinidumpStreamInfo* info = &iterator->second;
  1.4319 +
  1.4320 +  if (info->stream) {
  1.4321 +    // This cast is safe because info.stream is only populated by this
  1.4322 +    // method, and there is a direct correlation between T and stream_type.
  1.4323 +    *stream = static_cast<T*>(info->stream);
  1.4324 +    return *stream;
  1.4325 +  }
  1.4326 +
  1.4327 +  uint32_t stream_length;
  1.4328 +  if (!SeekToStreamType(stream_type, &stream_length)) {
  1.4329 +    BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
  1.4330 +    return NULL;
  1.4331 +  }
  1.4332 +
  1.4333 +  scoped_ptr<T> new_stream(new T(this));
  1.4334 +
  1.4335 +  if (!new_stream->Read(stream_length)) {
  1.4336 +    BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
  1.4337 +    return NULL;
  1.4338 +  }
  1.4339 +
  1.4340 +  *stream = new_stream.release();
  1.4341 +  info->stream = *stream;
  1.4342 +  return *stream;
  1.4343 +}
  1.4344 +
  1.4345 +
  1.4346 +}  // namespace google_breakpad

mercurial