/ src / processor / minidump.cc
minidump.cc
   1  // Copyright 2010 Google LLC
   2  //
   3  // Redistribution and use in source and binary forms, with or without
   4  // modification, are permitted provided that the following conditions are
   5  // met:
   6  //
   7  //     * Redistributions of source code must retain the above copyright
   8  // notice, this list of conditions and the following disclaimer.
   9  //     * Redistributions in binary form must reproduce the above
  10  // copyright notice, this list of conditions and the following disclaimer
  11  // in the documentation and/or other materials provided with the
  12  // distribution.
  13  //     * Neither the name of Google LLC nor the names of its
  14  // contributors may be used to endorse or promote products derived from
  15  // this software without specific prior written permission.
  16  //
  17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  21  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  22  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  23  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28  
  29  // minidump.cc: A minidump reader.
  30  //
  31  // See minidump.h for documentation.
  32  //
  33  // Author: Mark Mentovai
  34  
  35  #ifdef HAVE_CONFIG_H
  36  #include <config.h>  // Must come first
  37  #endif
  38  
  39  #include "google_breakpad/processor/minidump.h"
  40  
  41  #include <assert.h>
  42  #include <fcntl.h>
  43  #include <inttypes.h>
  44  #include <stddef.h>
  45  #include <string.h>
  46  #include <time.h>
  47  
  48  #ifdef _WIN32
  49  #include <io.h>
  50  #else  // _WIN32
  51  #include <unistd.h>
  52  #endif  // _WIN32
  53  
  54  #include <algorithm>
  55  #include <fstream>
  56  #include <limits>
  57  #include <utility>
  58  
  59  #include "processor/range_map-inl.h"
  60  
  61  #include "common/macros.h"
  62  #include "common/scoped_ptr.h"
  63  #include "common/stdio_wrapper.h"
  64  #include "google_breakpad/processor/dump_context.h"
  65  #include "processor/basic_code_module.h"
  66  #include "processor/basic_code_modules.h"
  67  #include "processor/convert_old_arm64_context.h"
  68  #include "processor/logging.h"
  69  
  70  namespace google_breakpad {
  71  
  72  using std::istream;
  73  using std::ifstream;
  74  using std::numeric_limits;
  75  using std::vector;
  76  
  77  namespace {
  78  
  79  // Limit arrived at by adding up possible states in Intel Ch. 13.5 X-SAVE
  80  // MANAGED STATE
  81  // (~ 3680 bytes) plus some extra for the future.
  82  const uint32_t kMaxXSaveAreaSize = 16384;
  83  
  84  // Returns true iff |context_size| matches exactly one of the sizes of the
  85  // various MDRawContext* types.
  86  // TODO(blundell): This function can be removed once
  87  // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 is fixed.
  88  bool IsContextSizeUnique(uint32_t context_size) {
  89    int num_matching_contexts = 0;
  90    if (context_size == sizeof(MDRawContextX86))
  91      num_matching_contexts++;
  92    if (context_size == sizeof(MDRawContextPPC))
  93      num_matching_contexts++;
  94    if (context_size == sizeof(MDRawContextPPC64))
  95      num_matching_contexts++;
  96    if (context_size == sizeof(MDRawContextAMD64))
  97      num_matching_contexts++;
  98    if (context_size == sizeof(MDRawContextSPARC))
  99      num_matching_contexts++;
 100    if (context_size == sizeof(MDRawContextARM))
 101      num_matching_contexts++;
 102    if (context_size == sizeof(MDRawContextARM64))
 103      num_matching_contexts++;
 104    if (context_size == sizeof(MDRawContextARM64_Old))
 105      num_matching_contexts++;
 106    if (context_size == sizeof(MDRawContextMIPS))
 107      num_matching_contexts++;
 108    if (context_size == sizeof(MDRawContextRISCV))
 109      num_matching_contexts++;
 110    if (context_size == sizeof(MDRawContextRISCV64))
 111      num_matching_contexts++;
 112    return num_matching_contexts == 1;
 113  }
 114  
 115  //
 116  // Swapping routines
 117  //
 118  // Inlining these doesn't increase code size significantly, and it saves
 119  // a whole lot of unnecessary jumping back and forth.
 120  //
 121  
 122  
 123  // Swapping an 8-bit quantity is a no-op.  This function is only provided
 124  // to account for certain templatized operations that require swapping for
 125  // wider types but handle uint8_t too
 126  // (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
 127  inline void Swap(uint8_t* value) {}
 128  
 129  // Optimization: don't need to AND the furthest right shift, because we're
 130  // shifting an unsigned quantity.  The standard requires zero-filling in this
 131  // case.  If the quantities were signed, a bitmask whould be needed for this
 132  // right shift to avoid an arithmetic shift (which retains the sign bit).
 133  // The furthest left shift never needs to be ANDed bitmask.
 134  
 135  inline void Swap(uint16_t* value) {
 136    *value = (*value >> 8) | (*value << 8);
 137  }
 138  
 139  inline void Swap(uint32_t* value) {
 140    *value =  (*value >> 24) |
 141             ((*value >> 8)  & 0x0000ff00) |
 142             ((*value << 8)  & 0x00ff0000) |
 143              (*value << 24);
 144  }
 145  
 146  inline void Swap(uint64_t* value) {
 147    uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
 148    Swap(&value32[0]);
 149    Swap(&value32[1]);
 150    uint32_t temp = value32[0];
 151    value32[0] = value32[1];
 152    value32[1] = temp;
 153  }
 154  
 155  
 156  // Given a pointer to a 128-bit int in the minidump data, set the "low"
 157  // and "high" fields appropriately.
 158  void Normalize128(uint128_struct* value, bool is_big_endian) {
 159    // The struct format is [high, low], so if the format is big-endian,
 160    // the most significant bytes will already be in the high field.
 161    if (!is_big_endian) {
 162      uint64_t temp = value->low;
 163      value->low = value->high;
 164      value->high = temp;
 165    }
 166  }
 167  
 168  // This just swaps each int64 half of the 128-bit value.
 169  // The value should also be normalized by calling Normalize128().
 170  void Swap(uint128_struct* value) {
 171    Swap(&value->low);
 172    Swap(&value->high);
 173  }
 174  
 175  // Swapping signed integers
 176  inline void Swap(int32_t* value) {
 177    Swap(reinterpret_cast<uint32_t*>(value));
 178  }
 179  
 180  inline void Swap(MDLocationDescriptor* location_descriptor) {
 181    Swap(&location_descriptor->data_size);
 182    Swap(&location_descriptor->rva);
 183  }
 184  
 185  inline void Swap(MDMemoryDescriptor* memory_descriptor) {
 186    Swap(&memory_descriptor->start_of_memory_range);
 187    Swap(&memory_descriptor->memory);
 188  }
 189  
 190  inline void Swap(MDGUID* guid) {
 191    Swap(&guid->data1);
 192    Swap(&guid->data2);
 193    Swap(&guid->data3);
 194    // Don't swap guid->data4[] because it contains 8-bit quantities.
 195  }
 196  
 197  inline void Swap(MDSystemTime* system_time) {
 198    Swap(&system_time->year);
 199    Swap(&system_time->month);
 200    Swap(&system_time->day_of_week);
 201    Swap(&system_time->day);
 202    Swap(&system_time->hour);
 203    Swap(&system_time->minute);
 204    Swap(&system_time->second);
 205    Swap(&system_time->milliseconds);
 206  }
 207  
 208  inline void Swap(MDXStateFeature* xstate_feature) {
 209    Swap(&xstate_feature->offset);
 210    Swap(&xstate_feature->size);
 211  }
 212  
 213  inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
 214    Swap(&xstate_feature_info->size_of_info);
 215    Swap(&xstate_feature_info->context_size);
 216    Swap(&xstate_feature_info->enabled_features);
 217  
 218    for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) {
 219      Swap(&xstate_feature_info->features[i]);
 220    }
 221  }
 222  
 223  inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
 224    Swap(&entry->key);
 225    Swap(&entry->value);
 226  }
 227  
 228  inline void Swap(MDRawCrashpadAnnotation* annotation) {
 229    Swap(&annotation->name);
 230    Swap(&annotation->type);
 231    Swap(&annotation->value);
 232  }
 233  
 234  inline void Swap(uint16_t* data, size_t size_in_bytes) {
 235    size_t data_length = size_in_bytes / sizeof(data[0]);
 236    for (size_t i = 0; i < data_length; i++) {
 237      Swap(&data[i]);
 238    }
 239  }
 240  
 241  //
 242  // Character conversion routines
 243  //
 244  
 245  
 246  // Standard wide-character conversion routines depend on the system's own
 247  // idea of what width a wide character should be: some use 16 bits, and
 248  // some use 32 bits.  For the purposes of a minidump, wide strings are
 249  // always represented with 16-bit UTF-16 chracters.  iconv isn't available
 250  // everywhere, and its interface varies where it is available.  iconv also
 251  // deals purely with char* pointers, so in addition to considering the swap
 252  // parameter, a converter that uses iconv would also need to take the host
 253  // CPU's endianness into consideration.  It doesn't seems worth the trouble
 254  // of making it a dependency when we don't care about anything but UTF-16.
 255  string* UTF16ToUTF8(const vector<uint16_t>& in, bool swap) {
 256    scoped_ptr<string> out(new string());
 257  
 258    // Set the string's initial capacity to the number of UTF-16 characters,
 259    // because the UTF-8 representation will always be at least this long.
 260    // If the UTF-8 representation is longer, the string will grow dynamically.
 261    out->reserve(in.size());
 262  
 263    for (vector<uint16_t>::const_iterator iterator = in.begin();
 264         iterator != in.end();
 265         ++iterator) {
 266      // Get a 16-bit value from the input
 267      uint16_t in_word = *iterator;
 268      if (swap)
 269        Swap(&in_word);
 270  
 271      // Convert the input value (in_word) into a Unicode code point (unichar).
 272      uint32_t unichar;
 273      if (in_word >= 0xdc00 && in_word <= 0xdcff) {
 274        BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
 275                        HexString(in_word) << " without high";
 276        return NULL;
 277      } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
 278        // High surrogate.
 279        unichar = (in_word - 0xd7c0) << 10;
 280        if (++iterator == in.end()) {
 281          BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
 282                          HexString(in_word) << " at end of string";
 283          return NULL;
 284        }
 285        uint32_t high_word = in_word;
 286        in_word = *iterator;
 287        if (in_word < 0xdc00 || in_word > 0xdcff) {
 288          BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
 289                          HexString(high_word) << " without low " <<
 290                          HexString(in_word);
 291          return NULL;
 292        }
 293        unichar |= in_word & 0x03ff;
 294      } else {
 295        // The ordinary case, a single non-surrogate Unicode character encoded
 296        // as a single 16-bit value.
 297        unichar = in_word;
 298      }
 299  
 300      // Convert the Unicode code point (unichar) into its UTF-8 representation,
 301      // appending it to the out string.
 302      if (unichar < 0x80) {
 303        (*out) += static_cast<char>(unichar);
 304      } else if (unichar < 0x800) {
 305        (*out) += 0xc0 | static_cast<char>(unichar >> 6);
 306        (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
 307      } else if (unichar < 0x10000) {
 308        (*out) += 0xe0 | static_cast<char>(unichar >> 12);
 309        (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
 310        (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
 311      } else if (unichar < 0x200000) {
 312        (*out) += 0xf0 | static_cast<char>(unichar >> 18);
 313        (*out) += 0x80 | static_cast<char>((unichar >> 12) & 0x3f);
 314        (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
 315        (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
 316      } else {
 317        BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
 318                        HexString(unichar) << " in UTF-8";
 319        return NULL;
 320      }
 321    }
 322  
 323    return out.release();
 324  }
 325  
 326  // Return the smaller of the number of code units in the UTF-16 string,
 327  // not including the terminating null word, or maxlen.
 328  size_t UTF16codeunits(const uint16_t* string, size_t maxlen) {
 329    size_t count = 0;
 330    while (count < maxlen && string[count] != 0)
 331      count++;
 332    return count;
 333  }
 334  
 335  inline void Swap(MDTimeZoneInformation* time_zone) {
 336    Swap(&time_zone->bias);
 337    // Skip time_zone->standard_name.  No need to swap UTF-16 fields.
 338    // The swap will be done as part of the conversion to UTF-8.
 339    Swap(&time_zone->standard_date);
 340    Swap(&time_zone->standard_bias);
 341    // Skip time_zone->daylight_name.  No need to swap UTF-16 fields.
 342    // The swap will be done as part of the conversion to UTF-8.
 343    Swap(&time_zone->daylight_date);
 344    Swap(&time_zone->daylight_bias);
 345  }
 346  
 347  void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data,
 348                                      size_t max_length_in_bytes,
 349                                      string* utf8_result,
 350                                      bool swap) {
 351    // Since there is no explicit byte length for each string, use
 352    // UTF16codeunits to calculate word length, then derive byte
 353    // length from that.
 354    size_t max_word_length = max_length_in_bytes / sizeof(utf16_data[0]);
 355    size_t word_length = UTF16codeunits(utf16_data, max_word_length);
 356    if (word_length > 0) {
 357      size_t byte_length = word_length * sizeof(utf16_data[0]);
 358      vector<uint16_t> utf16_vector(word_length);
 359      memcpy(&utf16_vector[0], &utf16_data[0], byte_length);
 360      scoped_ptr<string> temp(UTF16ToUTF8(utf16_vector, swap));
 361      if (temp.get()) {
 362        utf8_result->assign(*temp);
 363      }
 364    } else {
 365      utf8_result->clear();
 366    }
 367  }
 368  
 369  
 370  // For fields that may or may not be valid, PrintValueOrInvalid will print the
 371  // string "(invalid)" if the field is not valid, and will print the value if
 372  // the field is valid. The value is printed as hexadecimal or decimal.
 373  
 374  enum NumberFormat {
 375    kNumberFormatDecimal,
 376    kNumberFormatHexadecimal,
 377  };
 378  
 379  void PrintValueOrInvalid(bool valid,
 380                           NumberFormat number_format,
 381                           uint32_t value) {
 382    if (!valid) {
 383      printf("(invalid)\n");
 384    } else if (number_format == kNumberFormatDecimal) {
 385      printf("%d\n", value);
 386    } else {
 387      printf("0x%x\n", value);
 388    }
 389  }
 390  
 391  // Converts a time_t to a string showing the time in UTC.
 392  string TimeTToUTCString(time_t tt) {
 393    struct tm timestruct;
 394  #ifdef _WIN32
 395    gmtime_s(&timestruct, &tt);
 396  #else
 397    gmtime_r(&tt, &timestruct);
 398  #endif
 399  
 400    char timestr[20];
 401    size_t rv = strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
 402    if (rv == 0) {
 403      return string();
 404    }
 405  
 406    return string(timestr);
 407  }
 408  
 409  string MDGUIDToString(const MDGUID& uuid) {
 410    char buf[37];
 411    snprintf(buf, sizeof(buf), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
 412             uuid.data1,
 413             uuid.data2,
 414             uuid.data3,
 415             uuid.data4[0],
 416             uuid.data4[1],
 417             uuid.data4[2],
 418             uuid.data4[3],
 419             uuid.data4[4],
 420             uuid.data4[5],
 421             uuid.data4[6],
 422             uuid.data4[7]);
 423    return std::string(buf);
 424  }
 425  
 426  bool IsDevAshmem(const string& filename) {
 427    const string kDevAshmem("/dev/ashmem/");
 428    return filename.compare(0, kDevAshmem.length(), kDevAshmem) == 0;
 429  }
 430  
 431  }  // namespace
 432  
 433  //
 434  // MinidumpObject
 435  //
 436  
 437  
 438  MinidumpObject::MinidumpObject(Minidump* minidump)
 439      : DumpObject(),
 440        minidump_(minidump) {
 441  }
 442  
 443  
 444  //
 445  // MinidumpStream
 446  //
 447  
 448  
 449  MinidumpStream::MinidumpStream(Minidump* minidump)
 450      : MinidumpObject(minidump) {
 451  }
 452  
 453  
 454  //
 455  // MinidumpContext
 456  //
 457  
 458  
 459  MinidumpContext::MinidumpContext(Minidump* minidump)
 460      : DumpContext(),
 461        minidump_(minidump) {
 462  }
 463  
 464  MinidumpContext::~MinidumpContext() {
 465  }
 466  
 467  bool MinidumpContext::Read(uint32_t expected_size) {
 468    valid_ = false;
 469  
 470    // Certain raw context types are currently assumed to have unique sizes.
 471    if (!IsContextSizeUnique(sizeof(MDRawContextAMD64))) {
 472      BPLOG(ERROR) << "sizeof(MDRawContextAMD64) cannot match the size of any "
 473                   << "other raw context";
 474      return false;
 475    }
 476    if (!IsContextSizeUnique(sizeof(MDRawContextPPC64))) {
 477      BPLOG(ERROR) << "sizeof(MDRawContextPPC64) cannot match the size of any "
 478                   << "other raw context";
 479      return false;
 480    }
 481    if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) {
 482      BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any "
 483                   << "other raw context";
 484      return false;
 485    }
 486  
 487    FreeContext();
 488  
 489    // First, figure out what type of CPU this context structure is for.
 490    // For some reason, the AMD64 Context doesn't have context_flags
 491    // at the beginning of the structure, so special case it here.
 492  
 493    uint32_t sysinfo_cpu_type = 0;
 494    if (!minidump_->GetContextCPUFlagsFromSystemInfo(&sysinfo_cpu_type)) {
 495      BPLOG(ERROR) << "Failed to preserve the current stream position";
 496      return false;
 497    }
 498  
 499    if (expected_size == sizeof(MDRawContextAMD64) ||
 500        (sysinfo_cpu_type == MD_CONTEXT_AMD64 &&
 501         expected_size >= sizeof(MDRawContextAMD64))) {
 502      BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
 503  
 504      scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
 505      if (!minidump_->ReadBytes(context_amd64.get(),
 506                                sizeof(MDRawContextAMD64))) {
 507        BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
 508        return false;
 509      }
 510  
 511      // Context may include xsave registers and so be larger than
 512      // sizeof(MDRawContextAMD64). For now we skip this extended data.
 513      if (expected_size > sizeof(MDRawContextAMD64)) {
 514        size_t bytes_left = expected_size - sizeof(MDRawContextAMD64);
 515        if (bytes_left > kMaxXSaveAreaSize) {
 516          BPLOG(ERROR) << "MinidumpContext oversized xstate area";
 517          return false;
 518        }
 519        std::vector<uint8_t> xstate(bytes_left);
 520        if (!minidump_->ReadBytes(xstate.data(),
 521                                  bytes_left)) {
 522          BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate";
 523          return false;
 524        }
 525      }
 526  
 527      if (minidump_->swap())
 528        Swap(&context_amd64->context_flags);
 529  
 530      uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
 531      if (cpu_type == 0) {
 532        context_amd64->context_flags |= sysinfo_cpu_type;
 533      }
 534  
 535      if (cpu_type != MD_CONTEXT_AMD64) {
 536        // TODO: Fall through to switch below.
 537        // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
 538        BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
 539        return false;
 540      }
 541  
 542      // Do this after reading the entire MDRawContext structure because
 543      // GetSystemInfo may seek minidump to a new position.
 544      if (!CheckAgainstSystemInfo(cpu_type)) {
 545        BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
 546        return false;
 547      }
 548  
 549      // Normalize the 128-bit types in the dump.
 550      // Since this is AMD64, by definition, the values are little-endian.
 551      for (unsigned int vr_index = 0;
 552           vr_index < MD_CONTEXT_AMD64_VR_COUNT;
 553           ++vr_index)
 554        Normalize128(&context_amd64->vector_register[vr_index], false);
 555  
 556      if (minidump_->swap()) {
 557        Swap(&context_amd64->p1_home);
 558        Swap(&context_amd64->p2_home);
 559        Swap(&context_amd64->p3_home);
 560        Swap(&context_amd64->p4_home);
 561        Swap(&context_amd64->p5_home);
 562        Swap(&context_amd64->p6_home);
 563        // context_flags is already swapped
 564        Swap(&context_amd64->mx_csr);
 565        Swap(&context_amd64->cs);
 566        Swap(&context_amd64->ds);
 567        Swap(&context_amd64->es);
 568        Swap(&context_amd64->fs);
 569        Swap(&context_amd64->ss);
 570        Swap(&context_amd64->eflags);
 571        Swap(&context_amd64->dr0);
 572        Swap(&context_amd64->dr1);
 573        Swap(&context_amd64->dr2);
 574        Swap(&context_amd64->dr3);
 575        Swap(&context_amd64->dr6);
 576        Swap(&context_amd64->dr7);
 577        Swap(&context_amd64->rax);
 578        Swap(&context_amd64->rcx);
 579        Swap(&context_amd64->rdx);
 580        Swap(&context_amd64->rbx);
 581        Swap(&context_amd64->rsp);
 582        Swap(&context_amd64->rbp);
 583        Swap(&context_amd64->rsi);
 584        Swap(&context_amd64->rdi);
 585        Swap(&context_amd64->r8);
 586        Swap(&context_amd64->r9);
 587        Swap(&context_amd64->r10);
 588        Swap(&context_amd64->r11);
 589        Swap(&context_amd64->r12);
 590        Swap(&context_amd64->r13);
 591        Swap(&context_amd64->r14);
 592        Swap(&context_amd64->r15);
 593        Swap(&context_amd64->rip);
 594        // FIXME: I'm not sure what actually determines
 595        // which member of the union {flt_save, sse_registers}
 596        // is valid.  We're not currently using either,
 597        // but it would be good to have them swapped properly.
 598  
 599        for (unsigned int vr_index = 0;
 600             vr_index < MD_CONTEXT_AMD64_VR_COUNT;
 601             ++vr_index)
 602          Swap(&context_amd64->vector_register[vr_index]);
 603        Swap(&context_amd64->vector_control);
 604        Swap(&context_amd64->debug_control);
 605        Swap(&context_amd64->last_branch_to_rip);
 606        Swap(&context_amd64->last_branch_from_rip);
 607        Swap(&context_amd64->last_exception_to_rip);
 608        Swap(&context_amd64->last_exception_from_rip);
 609      }
 610  
 611      SetContextFlags(context_amd64->context_flags);
 612  
 613      SetContextAMD64(context_amd64.release());
 614    } else if (expected_size == sizeof(MDRawContextPPC64)) {
 615      // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext
 616      // in the else case have 32 bits |context_flags|, so special case it here.
 617      uint64_t context_flags;
 618      if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
 619        BPLOG(ERROR) << "MinidumpContext could not read context flags";
 620        return false;
 621      }
 622      if (minidump_->swap())
 623        Swap(&context_flags);
 624  
 625      uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
 626      scoped_ptr<MDRawContextPPC64> context_ppc64(new MDRawContextPPC64());
 627  
 628      if (cpu_type == 0) {
 629        if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
 630          context_ppc64->context_flags |= cpu_type;
 631        } else {
 632          BPLOG(ERROR) << "Failed to preserve the current stream position";
 633          return false;
 634        }
 635      }
 636  
 637      if (cpu_type != MD_CONTEXT_PPC64) {
 638        // TODO: Fall through to switch below.
 639        // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
 640        BPLOG(ERROR) << "MinidumpContext not actually ppc64 context";
 641        return false;
 642      }
 643  
 644      // Set the context_flags member, which has already been read, and
 645      // read the rest of the structure beginning with the first member
 646      // after context_flags.
 647      context_ppc64->context_flags = context_flags;
 648  
 649      size_t flags_size = sizeof(context_ppc64->context_flags);
 650      uint8_t* context_after_flags =
 651            reinterpret_cast<uint8_t*>(context_ppc64.get()) + flags_size;
 652      if (!minidump_->ReadBytes(context_after_flags,
 653                                sizeof(MDRawContextPPC64) - flags_size)) {
 654        BPLOG(ERROR) << "MinidumpContext could not read ppc64 context";
 655        return false;
 656      }
 657  
 658      // Do this after reading the entire MDRawContext structure because
 659      // GetSystemInfo may seek minidump to a new position.
 660      if (!CheckAgainstSystemInfo(cpu_type)) {
 661        BPLOG(ERROR) << "MinidumpContext ppc64 does not match system info";
 662        return false;
 663      }
 664      if (minidump_->swap()) {
 665        // context_ppc64->context_flags was already swapped.
 666        Swap(&context_ppc64->srr0);
 667        Swap(&context_ppc64->srr1);
 668        for (unsigned int gpr_index = 0;
 669             gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
 670             ++gpr_index) {
 671          Swap(&context_ppc64->gpr[gpr_index]);
 672        }
 673        Swap(&context_ppc64->cr);
 674        Swap(&context_ppc64->xer);
 675        Swap(&context_ppc64->lr);
 676        Swap(&context_ppc64->ctr);
 677        Swap(&context_ppc64->vrsave);
 678        for (unsigned int fpr_index = 0;
 679             fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
 680             ++fpr_index) {
 681          Swap(&context_ppc64->float_save.fpregs[fpr_index]);
 682        }
 683        // Don't swap context_ppc64->float_save.fpscr_pad because it is only
 684        // used for padding.
 685        Swap(&context_ppc64->float_save.fpscr);
 686        for (unsigned int vr_index = 0;
 687             vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
 688             ++vr_index) {
 689          Normalize128(&context_ppc64->vector_save.save_vr[vr_index], true);
 690          Swap(&context_ppc64->vector_save.save_vr[vr_index]);
 691        }
 692        Swap(&context_ppc64->vector_save.save_vscr);
 693        // Don't swap the padding fields in vector_save.
 694        Swap(&context_ppc64->vector_save.save_vrvalid);
 695      }
 696  
 697      SetContextFlags(static_cast<uint32_t>(context_ppc64->context_flags));
 698  
 699      // Check for data loss when converting context flags from uint64_t into
 700      // uint32_t
 701      if (static_cast<uint64_t>(GetContextFlags()) !=
 702          context_ppc64->context_flags) {
 703        BPLOG(ERROR) << "Data loss detected when converting PPC64 context_flags";
 704        return false;
 705      }
 706  
 707      SetContextPPC64(context_ppc64.release());
 708    } else if (expected_size == sizeof(MDRawContextARM64_Old)) {
 709      // |context_flags| of MDRawContextARM64_Old is 64 bits, but other MDRawContext
 710      // in the else case have 32 bits |context_flags|, so special case it here.
 711      uint64_t context_flags;
 712  
 713      BPLOG(INFO) << "MinidumpContext: looks like ARM64 context";
 714  
 715      if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
 716        BPLOG(ERROR) << "MinidumpContext could not read context flags";
 717        return false;
 718      }
 719      if (minidump_->swap())
 720        Swap(&context_flags);
 721  
 722      scoped_ptr<MDRawContextARM64_Old> context_arm64(new MDRawContextARM64_Old());
 723  
 724      uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
 725      if (cpu_type == 0) {
 726        if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
 727          context_arm64->context_flags |= cpu_type;
 728        } else {
 729          BPLOG(ERROR) << "Failed to preserve the current stream position";
 730          return false;
 731        }
 732      }
 733  
 734      if (cpu_type != MD_CONTEXT_ARM64_OLD) {
 735        // TODO: Fall through to switch below.
 736        // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
 737        BPLOG(ERROR) << "MinidumpContext not actually arm64 context";
 738        return false;
 739      }
 740  
 741      // Set the context_flags member, which has already been read, and
 742      // read the rest of the structure beginning with the first member
 743      // after context_flags.
 744      context_arm64->context_flags = context_flags;
 745  
 746      size_t flags_size = sizeof(context_arm64->context_flags);
 747      uint8_t* context_after_flags =
 748          reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
 749      if (!minidump_->ReadBytes(context_after_flags,
 750                                sizeof(MDRawContextARM64_Old) - flags_size)) {
 751        BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
 752        return false;
 753      }
 754  
 755      // Do this after reading the entire MDRawContext structure because
 756      // GetSystemInfo may seek minidump to a new position.
 757      if (!CheckAgainstSystemInfo(cpu_type)) {
 758        BPLOG(ERROR) << "MinidumpContext arm64 does not match system info";
 759        return false;
 760      }
 761  
 762      if (minidump_->swap()) {
 763        // context_arm64->context_flags was already swapped.
 764        for (unsigned int ireg_index = 0;
 765             ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
 766             ++ireg_index) {
 767          Swap(&context_arm64->iregs[ireg_index]);
 768        }
 769        Swap(&context_arm64->cpsr);
 770        Swap(&context_arm64->float_save.fpsr);
 771        Swap(&context_arm64->float_save.fpcr);
 772        for (unsigned int fpr_index = 0;
 773             fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
 774             ++fpr_index) {
 775          Normalize128(&context_arm64->float_save.regs[fpr_index],
 776                       minidump_->is_big_endian());
 777          Swap(&context_arm64->float_save.regs[fpr_index]);
 778        }
 779      }
 780  
 781      scoped_ptr<MDRawContextARM64> new_context(new MDRawContextARM64());
 782      ConvertOldARM64Context(*context_arm64.get(), new_context.get());
 783      SetContextFlags(new_context->context_flags);
 784      SetContextARM64(new_context.release());
 785    } else {
 786      uint32_t context_flags;
 787      if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
 788        BPLOG(ERROR) << "MinidumpContext could not read context flags";
 789        return false;
 790      }
 791      if (minidump_->swap())
 792        Swap(&context_flags);
 793  
 794      uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
 795      if (cpu_type == 0) {
 796        // Unfortunately the flag for MD_CONTEXT_ARM that was taken
 797        // from a Windows CE SDK header conflicts in practice with
 798        // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
 799        // but handle dumps with the legacy value gracefully here.
 800        if (context_flags & MD_CONTEXT_ARM_OLD) {
 801          context_flags |= MD_CONTEXT_ARM;
 802          context_flags &= ~MD_CONTEXT_ARM_OLD;
 803          cpu_type = MD_CONTEXT_ARM;
 804        }
 805      }
 806  
 807      // Fixup if we were not provided a cpu type.
 808      if (cpu_type == 0) {
 809        cpu_type = sysinfo_cpu_type;
 810        context_flags |= cpu_type;
 811      }
 812  
 813      // Allocate the context structure for the correct CPU and fill it.  The
 814      // casts are slightly unorthodox, but it seems better to do that than to
 815      // maintain a separate pointer for each type of CPU context structure
 816      // when only one of them will be used.
 817      switch (cpu_type) {
 818        case MD_CONTEXT_X86: {
 819          if (expected_size != sizeof(MDRawContextX86)) {
 820            BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
 821              expected_size << " != " << sizeof(MDRawContextX86);
 822            return false;
 823          }
 824  
 825          scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
 826  
 827          // Set the context_flags member, which has already been read, and
 828          // read the rest of the structure beginning with the first member
 829          // after context_flags.
 830          context_x86->context_flags = context_flags;
 831  
 832          size_t flags_size = sizeof(context_x86->context_flags);
 833          uint8_t* context_after_flags =
 834            reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
 835          if (!minidump_->ReadBytes(context_after_flags,
 836                                    sizeof(MDRawContextX86) - flags_size)) {
 837            BPLOG(ERROR) << "MinidumpContext could not read x86 context";
 838            return false;
 839          }
 840  
 841          // Do this after reading the entire MDRawContext structure because
 842          // GetSystemInfo may seek minidump to a new position.
 843          if (!CheckAgainstSystemInfo(cpu_type)) {
 844            BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
 845            return false;
 846          }
 847  
 848          if (minidump_->swap()) {
 849            // context_x86->context_flags was already swapped.
 850            Swap(&context_x86->dr0);
 851            Swap(&context_x86->dr1);
 852            Swap(&context_x86->dr2);
 853            Swap(&context_x86->dr3);
 854            Swap(&context_x86->dr6);
 855            Swap(&context_x86->dr7);
 856            Swap(&context_x86->float_save.control_word);
 857            Swap(&context_x86->float_save.status_word);
 858            Swap(&context_x86->float_save.tag_word);
 859            Swap(&context_x86->float_save.error_offset);
 860            Swap(&context_x86->float_save.error_selector);
 861            Swap(&context_x86->float_save.data_offset);
 862            Swap(&context_x86->float_save.data_selector);
 863            // context_x86->float_save.register_area[] contains 8-bit quantities
 864            // and does not need to be swapped.
 865            Swap(&context_x86->float_save.cr0_npx_state);
 866            Swap(&context_x86->gs);
 867            Swap(&context_x86->fs);
 868            Swap(&context_x86->es);
 869            Swap(&context_x86->ds);
 870            Swap(&context_x86->edi);
 871            Swap(&context_x86->esi);
 872            Swap(&context_x86->ebx);
 873            Swap(&context_x86->edx);
 874            Swap(&context_x86->ecx);
 875            Swap(&context_x86->eax);
 876            Swap(&context_x86->ebp);
 877            Swap(&context_x86->eip);
 878            Swap(&context_x86->cs);
 879            Swap(&context_x86->eflags);
 880            Swap(&context_x86->esp);
 881            Swap(&context_x86->ss);
 882            // context_x86->extended_registers[] contains 8-bit quantities and
 883            // does not need to be swapped.
 884          }
 885  
 886          SetContextX86(context_x86.release());
 887  
 888          break;
 889        }
 890  
 891        case MD_CONTEXT_PPC: {
 892          if (expected_size != sizeof(MDRawContextPPC)) {
 893            BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
 894              expected_size << " != " << sizeof(MDRawContextPPC);
 895            return false;
 896          }
 897  
 898          scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
 899  
 900          // Set the context_flags member, which has already been read, and
 901          // read the rest of the structure beginning with the first member
 902          // after context_flags.
 903          context_ppc->context_flags = context_flags;
 904  
 905          size_t flags_size = sizeof(context_ppc->context_flags);
 906          uint8_t* context_after_flags =
 907            reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
 908          if (!minidump_->ReadBytes(context_after_flags,
 909                                    sizeof(MDRawContextPPC) - flags_size)) {
 910            BPLOG(ERROR) << "MinidumpContext could not read ppc context";
 911            return false;
 912          }
 913  
 914          // Do this after reading the entire MDRawContext structure because
 915          // GetSystemInfo may seek minidump to a new position.
 916          if (!CheckAgainstSystemInfo(cpu_type)) {
 917            BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
 918            return false;
 919          }
 920  
 921          // Normalize the 128-bit types in the dump.
 922          // Since this is PowerPC, by definition, the values are big-endian.
 923          for (unsigned int vr_index = 0;
 924               vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
 925               ++vr_index) {
 926            Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
 927          }
 928  
 929          if (minidump_->swap()) {
 930            // context_ppc->context_flags was already swapped.
 931            Swap(&context_ppc->srr0);
 932            Swap(&context_ppc->srr1);
 933            for (unsigned int gpr_index = 0;
 934                 gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
 935                 ++gpr_index) {
 936              Swap(&context_ppc->gpr[gpr_index]);
 937            }
 938            Swap(&context_ppc->cr);
 939            Swap(&context_ppc->xer);
 940            Swap(&context_ppc->lr);
 941            Swap(&context_ppc->ctr);
 942            Swap(&context_ppc->mq);
 943            Swap(&context_ppc->vrsave);
 944            for (unsigned int fpr_index = 0;
 945                 fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
 946                 ++fpr_index) {
 947              Swap(&context_ppc->float_save.fpregs[fpr_index]);
 948            }
 949            // Don't swap context_ppc->float_save.fpscr_pad because it is only
 950            // used for padding.
 951            Swap(&context_ppc->float_save.fpscr);
 952            for (unsigned int vr_index = 0;
 953                 vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
 954                 ++vr_index) {
 955              Swap(&context_ppc->vector_save.save_vr[vr_index]);
 956            }
 957            Swap(&context_ppc->vector_save.save_vscr);
 958            // Don't swap the padding fields in vector_save.
 959            Swap(&context_ppc->vector_save.save_vrvalid);
 960          }
 961  
 962          SetContextPPC(context_ppc.release());
 963  
 964          break;
 965        }
 966  
 967        case MD_CONTEXT_SPARC: {
 968          if (expected_size != sizeof(MDRawContextSPARC)) {
 969            BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
 970              expected_size << " != " << sizeof(MDRawContextSPARC);
 971            return false;
 972          }
 973  
 974          scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
 975  
 976          // Set the context_flags member, which has already been read, and
 977          // read the rest of the structure beginning with the first member
 978          // after context_flags.
 979          context_sparc->context_flags = context_flags;
 980  
 981          size_t flags_size = sizeof(context_sparc->context_flags);
 982          uint8_t* context_after_flags =
 983              reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
 984          if (!minidump_->ReadBytes(context_after_flags,
 985                                    sizeof(MDRawContextSPARC) - flags_size)) {
 986            BPLOG(ERROR) << "MinidumpContext could not read sparc context";
 987            return false;
 988          }
 989  
 990          // Do this after reading the entire MDRawContext structure because
 991          // GetSystemInfo may seek minidump to a new position.
 992          if (!CheckAgainstSystemInfo(cpu_type)) {
 993            BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
 994            return false;
 995          }
 996  
 997          if (minidump_->swap()) {
 998            // context_sparc->context_flags was already swapped.
 999            for (unsigned int gpr_index = 0;
1000                 gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
1001                 ++gpr_index) {
1002              Swap(&context_sparc->g_r[gpr_index]);
1003            }
1004            Swap(&context_sparc->ccr);
1005            Swap(&context_sparc->pc);
1006            Swap(&context_sparc->npc);
1007            Swap(&context_sparc->y);
1008            Swap(&context_sparc->asi);
1009            Swap(&context_sparc->fprs);
1010            for (unsigned int fpr_index = 0;
1011                 fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
1012                 ++fpr_index) {
1013              Swap(&context_sparc->float_save.regs[fpr_index]);
1014            }
1015            Swap(&context_sparc->float_save.filler);
1016            Swap(&context_sparc->float_save.fsr);
1017          }
1018          SetContextSPARC(context_sparc.release());
1019  
1020          break;
1021        }
1022  
1023        case MD_CONTEXT_ARM: {
1024          if (expected_size != sizeof(MDRawContextARM)) {
1025            BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
1026              expected_size << " != " << sizeof(MDRawContextARM);
1027            return false;
1028          }
1029  
1030          scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
1031  
1032          // Set the context_flags member, which has already been read, and
1033          // read the rest of the structure beginning with the first member
1034          // after context_flags.
1035          context_arm->context_flags = context_flags;
1036  
1037          size_t flags_size = sizeof(context_arm->context_flags);
1038          uint8_t* context_after_flags =
1039              reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
1040          if (!minidump_->ReadBytes(context_after_flags,
1041                                    sizeof(MDRawContextARM) - flags_size)) {
1042            BPLOG(ERROR) << "MinidumpContext could not read arm context";
1043            return false;
1044          }
1045  
1046          // Do this after reading the entire MDRawContext structure because
1047          // GetSystemInfo may seek minidump to a new position.
1048          if (!CheckAgainstSystemInfo(cpu_type)) {
1049            BPLOG(ERROR) << "MinidumpContext arm does not match system info";
1050            return false;
1051          }
1052  
1053          if (minidump_->swap()) {
1054            // context_arm->context_flags was already swapped.
1055            for (unsigned int ireg_index = 0;
1056                 ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
1057                 ++ireg_index) {
1058              Swap(&context_arm->iregs[ireg_index]);
1059            }
1060            Swap(&context_arm->cpsr);
1061            Swap(&context_arm->float_save.fpscr);
1062            for (unsigned int fpr_index = 0;
1063                 fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
1064                 ++fpr_index) {
1065              Swap(&context_arm->float_save.regs[fpr_index]);
1066            }
1067            for (unsigned int fpe_index = 0;
1068                 fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
1069                 ++fpe_index) {
1070              Swap(&context_arm->float_save.extra[fpe_index]);
1071            }
1072          }
1073          SetContextARM(context_arm.release());
1074  
1075          break;
1076        }
1077  
1078        case MD_CONTEXT_ARM64: {
1079          if (expected_size != sizeof(MDRawContextARM64)) {
1080            BPLOG(ERROR) << "MinidumpContext arm64 size mismatch, " <<
1081                         expected_size << " != " << sizeof(MDRawContextARM64);
1082            return false;
1083          }
1084  
1085          scoped_ptr<MDRawContextARM64> context_arm64(new MDRawContextARM64());
1086  
1087          // Set the context_flags member, which has already been read, and
1088          // read the rest of the structure beginning with the first member
1089          // after context_flags.
1090          context_arm64->context_flags = context_flags;
1091  
1092          size_t flags_size = sizeof(context_arm64->context_flags);
1093          uint8_t* context_after_flags =
1094              reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
1095          if (!minidump_->ReadBytes(context_after_flags,
1096                                    sizeof(*context_arm64) - flags_size)) {
1097            BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
1098            return false;
1099          }
1100  
1101          // Do this after reading the entire MDRawContext structure because
1102          // GetSystemInfo may seek minidump to a new position.
1103          if (!CheckAgainstSystemInfo(cpu_type)) {
1104            BPLOG(ERROR) << "MinidumpContext arm does not match system info";
1105            return false;
1106          }
1107  
1108          if (minidump_->swap()) {
1109            // context_arm64->context_flags was already swapped.
1110            for (unsigned int ireg_index = 0;
1111                 ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
1112                 ++ireg_index) {
1113              Swap(&context_arm64->iregs[ireg_index]);
1114            }
1115            Swap(&context_arm64->cpsr);
1116            Swap(&context_arm64->float_save.fpsr);
1117            Swap(&context_arm64->float_save.fpcr);
1118            for (unsigned int fpr_index = 0;
1119                 fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
1120                 ++fpr_index) {
1121              Normalize128(&context_arm64->float_save.regs[fpr_index],
1122                           minidump_->is_big_endian());
1123              Swap(&context_arm64->float_save.regs[fpr_index]);
1124            }
1125          }
1126          SetContextARM64(context_arm64.release());
1127          break;
1128        }
1129  
1130        case MD_CONTEXT_MIPS:
1131        case MD_CONTEXT_MIPS64: {
1132          if (expected_size != sizeof(MDRawContextMIPS)) {
1133            BPLOG(ERROR) << "MinidumpContext MIPS size mismatch, "
1134                         << expected_size
1135                         << " != "
1136                         << sizeof(MDRawContextMIPS);
1137            return false;
1138          }
1139  
1140          scoped_ptr<MDRawContextMIPS> context_mips(new MDRawContextMIPS());
1141  
1142          // Set the context_flags member, which has already been read, and
1143          // read the rest of the structure beginning with the first member
1144          // after context_flags.
1145          context_mips->context_flags = context_flags;
1146  
1147          size_t flags_size = sizeof(context_mips->context_flags);
1148          uint8_t* context_after_flags =
1149              reinterpret_cast<uint8_t*>(context_mips.get()) + flags_size;
1150          if (!minidump_->ReadBytes(context_after_flags,
1151                                    sizeof(MDRawContextMIPS) - flags_size)) {
1152            BPLOG(ERROR) << "MinidumpContext could not read MIPS context";
1153            return false;
1154          }
1155  
1156          // Do this after reading the entire MDRawContext structure because
1157          // GetSystemInfo may seek minidump to a new position.
1158          if (!CheckAgainstSystemInfo(cpu_type)) {
1159            BPLOG(ERROR) << "MinidumpContext MIPS does not match system info";
1160            return false;
1161          }
1162  
1163          if (minidump_->swap()) {
1164            // context_mips->context_flags was already swapped.
1165            for (int ireg_index = 0;
1166                 ireg_index < MD_CONTEXT_MIPS_GPR_COUNT;
1167                 ++ireg_index) {
1168              Swap(&context_mips->iregs[ireg_index]);
1169            }
1170  	  Swap(&context_mips->mdhi);
1171  	  Swap(&context_mips->mdlo);
1172            for (int dsp_index = 0;
1173                 dsp_index < MD_CONTEXT_MIPS_DSP_COUNT;
1174                 ++dsp_index) {
1175              Swap(&context_mips->hi[dsp_index]);
1176              Swap(&context_mips->lo[dsp_index]);
1177            }
1178  	  Swap(&context_mips->dsp_control);
1179            Swap(&context_mips->epc);
1180            Swap(&context_mips->badvaddr);
1181            Swap(&context_mips->status);
1182            Swap(&context_mips->cause);
1183            for (int fpr_index = 0;
1184                 fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT;
1185                 ++fpr_index) {
1186              Swap(&context_mips->float_save.regs[fpr_index]);
1187            }
1188            Swap(&context_mips->float_save.fpcsr);
1189            Swap(&context_mips->float_save.fir);
1190          }
1191          SetContextMIPS(context_mips.release());
1192  
1193          break;
1194        }
1195  
1196        case MD_CONTEXT_RISCV: {
1197          if (expected_size != sizeof(MDRawContextRISCV)) {
1198            BPLOG(ERROR) << "MinidumpContext RISCV size mismatch, "
1199                         << expected_size
1200                         << " != "
1201                         << sizeof(MDRawContextRISCV);
1202            return false;
1203          }
1204  
1205          scoped_ptr<MDRawContextRISCV> context_riscv(new MDRawContextRISCV());
1206  
1207          // Set the context_flags member, which has already been read, and
1208          // read the rest of the structure beginning with the first member
1209          // after context_flags.
1210          context_riscv->context_flags = context_flags;
1211  
1212          size_t flags_size = sizeof(context_riscv->context_flags);
1213          uint8_t* context_after_flags =
1214              reinterpret_cast<uint8_t*>(context_riscv.get()) + flags_size;
1215          if (!minidump_->ReadBytes(context_after_flags,
1216                                    sizeof(MDRawContextRISCV) - flags_size)) {
1217            BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
1218            return false;
1219          }
1220  
1221          // Do this after reading the entire MDRawContext structure because
1222          // GetSystemInfo may seek minidump to a new position.
1223          if (!CheckAgainstSystemInfo(cpu_type)) {
1224            BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
1225            return false;
1226          }
1227  
1228          if (minidump_->swap()) {
1229            Swap(&context_riscv->pc);
1230            Swap(&context_riscv->ra);
1231            Swap(&context_riscv->sp);
1232            Swap(&context_riscv->gp);
1233            Swap(&context_riscv->tp);
1234            Swap(&context_riscv->t0);
1235            Swap(&context_riscv->t1);
1236            Swap(&context_riscv->t2);
1237            Swap(&context_riscv->s0);
1238            Swap(&context_riscv->s1);
1239            Swap(&context_riscv->a0);
1240            Swap(&context_riscv->a1);
1241            Swap(&context_riscv->a2);
1242            Swap(&context_riscv->a3);
1243            Swap(&context_riscv->a4);
1244            Swap(&context_riscv->a5);
1245            Swap(&context_riscv->a6);
1246            Swap(&context_riscv->a7);
1247            Swap(&context_riscv->s2);
1248            Swap(&context_riscv->s3);
1249            Swap(&context_riscv->s4);
1250            Swap(&context_riscv->s5);
1251            Swap(&context_riscv->s6);
1252            Swap(&context_riscv->s7);
1253            Swap(&context_riscv->s8);
1254            Swap(&context_riscv->s9);
1255            Swap(&context_riscv->s10);
1256            Swap(&context_riscv->s11);
1257            Swap(&context_riscv->t3);
1258            Swap(&context_riscv->t4);
1259            Swap(&context_riscv->t5);
1260            Swap(&context_riscv->t6);
1261  
1262            for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT;
1263                 ++fpr_index) {
1264              Swap(&context_riscv->fpregs[fpr_index]);
1265            }
1266            Swap(&context_riscv->fcsr);
1267          }
1268          SetContextRISCV(context_riscv.release());
1269  
1270          break;
1271        }
1272  
1273        case MD_CONTEXT_RISCV64: {
1274          if (expected_size != sizeof(MDRawContextRISCV64)) {
1275            BPLOG(ERROR) << "MinidumpContext RISCV64 size mismatch, "
1276                         << expected_size
1277                         << " != "
1278                         << sizeof(MDRawContextRISCV64);
1279            return false;
1280          }
1281  
1282          scoped_ptr<MDRawContextRISCV64> context_riscv64(
1283              new MDRawContextRISCV64());
1284  
1285          // Set the context_flags member, which has already been read, and
1286          // read the rest of the structure beginning with the first member
1287          // after context_flags.
1288          context_riscv64->context_flags = context_flags;
1289  
1290          size_t flags_size = sizeof(context_riscv64->context_flags);
1291          uint8_t* context_after_flags =
1292              reinterpret_cast<uint8_t*>(context_riscv64.get()) + flags_size;
1293          if (!minidump_->ReadBytes(context_after_flags,
1294                                    sizeof(MDRawContextRISCV64) - flags_size)) {
1295            BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
1296            return false;
1297          }
1298  
1299          // Do this after reading the entire MDRawContext structure because
1300          // GetSystemInfo may seek minidump to a new position.
1301          if (!CheckAgainstSystemInfo(cpu_type)) {
1302            BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
1303            return false;
1304          }
1305  
1306          if (minidump_->swap()) {
1307            Swap(&context_riscv64->pc);
1308            Swap(&context_riscv64->ra);
1309            Swap(&context_riscv64->sp);
1310            Swap(&context_riscv64->gp);
1311            Swap(&context_riscv64->tp);
1312            Swap(&context_riscv64->t0);
1313            Swap(&context_riscv64->t1);
1314            Swap(&context_riscv64->t2);
1315            Swap(&context_riscv64->s0);
1316            Swap(&context_riscv64->s1);
1317            Swap(&context_riscv64->a0);
1318            Swap(&context_riscv64->a1);
1319            Swap(&context_riscv64->a2);
1320            Swap(&context_riscv64->a3);
1321            Swap(&context_riscv64->a4);
1322            Swap(&context_riscv64->a5);
1323            Swap(&context_riscv64->a6);
1324            Swap(&context_riscv64->a7);
1325            Swap(&context_riscv64->s2);
1326            Swap(&context_riscv64->s3);
1327            Swap(&context_riscv64->s4);
1328            Swap(&context_riscv64->s5);
1329            Swap(&context_riscv64->s6);
1330            Swap(&context_riscv64->s7);
1331            Swap(&context_riscv64->s8);
1332            Swap(&context_riscv64->s9);
1333            Swap(&context_riscv64->s10);
1334            Swap(&context_riscv64->s11);
1335            Swap(&context_riscv64->t3);
1336            Swap(&context_riscv64->t4);
1337            Swap(&context_riscv64->t5);
1338            Swap(&context_riscv64->t6);
1339  
1340            for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT;
1341                 ++fpr_index) {
1342              Swap(&context_riscv64->fpregs[fpr_index]);
1343            }
1344            Swap(&context_riscv64->fcsr);
1345          }
1346          SetContextRISCV64(context_riscv64.release());
1347  
1348          break;
1349        }
1350  
1351        default: {
1352          // Unknown context type - Don't log as an error yet. Let the
1353          // caller work that out.
1354          BPLOG(INFO) << "MinidumpContext unknown context type " <<
1355            HexString(cpu_type);
1356          return false;
1357        }
1358      }
1359      SetContextFlags(context_flags);
1360    }
1361  
1362    valid_ = true;
1363    return true;
1364  }
1365  
1366  bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
1367    // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
1368    // as this function just implements a sanity check.
1369    MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
1370    if (!system_info) {
1371      BPLOG(INFO) << "MinidumpContext could not be compared against "
1372                     "MinidumpSystemInfo";
1373      return true;
1374    }
1375  
1376    // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
1377    const MDRawSystemInfo* raw_system_info = system_info->system_info();
1378    if (!raw_system_info) {
1379      BPLOG(INFO) << "MinidumpContext could not be compared against "
1380                     "MDRawSystemInfo";
1381      return false;
1382    }
1383  
1384    MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
1385        raw_system_info->processor_architecture);
1386  
1387    // Compare the CPU type of the context record to the CPU type in the
1388    // minidump's system info stream.
1389    bool return_value = false;
1390    switch (context_cpu_type) {
1391      case MD_CONTEXT_X86:
1392        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
1393            system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
1394            system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
1395          return_value = true;
1396        }
1397        break;
1398  
1399      case MD_CONTEXT_PPC:
1400        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
1401          return_value = true;
1402        break;
1403  
1404      case MD_CONTEXT_PPC64:
1405        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC64)
1406          return_value = true;
1407        break;
1408  
1409      case MD_CONTEXT_AMD64:
1410        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
1411          return_value = true;
1412        break;
1413  
1414      case MD_CONTEXT_SPARC:
1415        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
1416          return_value = true;
1417        break;
1418  
1419      case MD_CONTEXT_ARM:
1420        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
1421          return_value = true;
1422        break;
1423  
1424      case MD_CONTEXT_ARM64:
1425        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64)
1426          return_value = true;
1427        break;
1428  
1429      case MD_CONTEXT_ARM64_OLD:
1430        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64_OLD)
1431          return_value = true;
1432        break;
1433  
1434      case MD_CONTEXT_MIPS:
1435        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS)
1436          return_value = true;
1437        break;
1438  
1439      case MD_CONTEXT_MIPS64:
1440        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS64)
1441          return_value = true;
1442        break;
1443  
1444      case MD_CONTEXT_RISCV:
1445        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV)
1446         return_value = true;
1447        break;
1448  
1449      case MD_CONTEXT_RISCV64:
1450        if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV64)
1451          return_value = true;
1452        break;
1453    }
1454  
1455    BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
1456                                      HexString(context_cpu_type) <<
1457                                      " wrong for MinidumpSystemInfo CPU " <<
1458                                      HexString(system_info_cpu_type);
1459  
1460    return return_value;
1461  }
1462  
1463  
1464  //
1465  // MinidumpMemoryRegion
1466  //
1467  
1468  
1469  uint32_t MinidumpMemoryRegion::max_bytes_ = 64 * 1024 * 1024;  // 64MB
1470  
1471  
1472  MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
1473      : MinidumpObject(minidump),
1474        descriptor_(NULL),
1475        memory_(NULL) {
1476    hexdump_width_ = minidump_ ? minidump_->HexdumpMode() : 0;
1477    hexdump_ = hexdump_width_ != 0;
1478  }
1479  
1480  
1481  MinidumpMemoryRegion::~MinidumpMemoryRegion() {
1482    delete memory_;
1483  }
1484  
1485  
1486  void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
1487    descriptor_ = descriptor;
1488    valid_ = descriptor &&
1489             descriptor_->memory.data_size <=
1490                 numeric_limits<uint64_t>::max() -
1491                 descriptor_->start_of_memory_range;
1492  }
1493  
1494  
1495  const uint8_t* MinidumpMemoryRegion::GetMemory() const {
1496    if (!valid_) {
1497      BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
1498      return NULL;
1499    }
1500  
1501    if (!memory_) {
1502      if (descriptor_->memory.data_size == 0) {
1503        BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
1504        return NULL;
1505      }
1506  
1507      if (!minidump_->SeekSet(descriptor_->memory.rva)) {
1508        BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
1509        return NULL;
1510      }
1511  
1512      if (descriptor_->memory.data_size > max_bytes_) {
1513        BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
1514                        descriptor_->memory.data_size << " exceeds maximum " <<
1515                        max_bytes_;
1516        return NULL;
1517      }
1518  
1519      scoped_ptr< vector<uint8_t> > memory(
1520          new vector<uint8_t>(descriptor_->memory.data_size));
1521  
1522      if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
1523        BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
1524        return NULL;
1525      }
1526  
1527      memory_ = memory.release();
1528    }
1529  
1530    return &(*memory_)[0];
1531  }
1532  
1533  
1534  uint64_t MinidumpMemoryRegion::GetBase() const {
1535    if (!valid_) {
1536      BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
1537      return static_cast<uint64_t>(-1);
1538    }
1539  
1540    return descriptor_->start_of_memory_range;
1541  }
1542  
1543  
1544  uint32_t MinidumpMemoryRegion::GetSize() const {
1545    if (!valid_) {
1546      BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
1547      return 0;
1548    }
1549  
1550    return descriptor_->memory.data_size;
1551  }
1552  
1553  
1554  void MinidumpMemoryRegion::FreeMemory() {
1555    delete memory_;
1556    memory_ = NULL;
1557  }
1558  
1559  
1560  template<typename T>
1561  bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
1562                                                        T*        value) const {
1563    BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
1564                               "requires |value|";
1565    assert(value);
1566    *value = 0;
1567  
1568    if (!valid_) {
1569      BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
1570                      "GetMemoryAtAddressInternal";
1571      return false;
1572    }
1573  
1574    // Common failure case
1575    if (address < descriptor_->start_of_memory_range ||
1576        sizeof(T) > numeric_limits<uint64_t>::max() - address ||
1577        address + sizeof(T) > descriptor_->start_of_memory_range +
1578                              descriptor_->memory.data_size) {
1579      BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
1580                      HexString(address) << "+" << sizeof(T) << "/" <<
1581                      HexString(descriptor_->start_of_memory_range) << "+" <<
1582                      HexString(descriptor_->memory.data_size);
1583      return false;
1584    }
1585  
1586    const uint8_t* memory = GetMemory();
1587    if (!memory) {
1588      // GetMemory already logged a perfectly good message.
1589      return false;
1590    }
1591  
1592    // If the CPU requires memory accesses to be aligned, this can crash.
1593    // x86 and ppc are able to cope, though.
1594    *value = *reinterpret_cast<const T*>(
1595        &memory[address - descriptor_->start_of_memory_range]);
1596  
1597    if (minidump_->swap())
1598      Swap(value);
1599  
1600    return true;
1601  }
1602  
1603  
1604  bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1605                                                uint8_t*  value) const {
1606    return GetMemoryAtAddressInternal(address, value);
1607  }
1608  
1609  
1610  bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1611                                                uint16_t* value) const {
1612    return GetMemoryAtAddressInternal(address, value);
1613  }
1614  
1615  
1616  bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1617                                                uint32_t* value) const {
1618    return GetMemoryAtAddressInternal(address, value);
1619  }
1620  
1621  
1622  bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1623                                                uint64_t* value) const {
1624    return GetMemoryAtAddressInternal(address, value);
1625  }
1626  
1627  
1628  void MinidumpMemoryRegion::Print() const {
1629    if (!valid_) {
1630      BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
1631      return;
1632    }
1633  
1634    const uint8_t* memory = GetMemory();
1635    if (memory) {
1636      if (hexdump_) {
1637        // Pretty hexdump view.
1638        for (unsigned int byte_index = 0;
1639             byte_index < descriptor_->memory.data_size;
1640             byte_index += hexdump_width_) {
1641          // In case the memory won't fill a whole line.
1642          unsigned int num_bytes = std::min(
1643              descriptor_->memory.data_size - byte_index, hexdump_width_);
1644  
1645          // Display the leading address.
1646          printf("%08x  ", byte_index);
1647  
1648          // Show the bytes in hex.
1649          for (unsigned int i = 0; i < hexdump_width_; ++i) {
1650            if (i < num_bytes) {
1651              // Show the single byte of memory in hex.
1652              printf("%02x ", memory[byte_index + i]);
1653            } else {
1654              // If this line doesn't fill up, pad it out.
1655              printf("   ");
1656            }
1657  
1658            // Insert a space every 8 bytes to make it more readable.
1659            if (((i + 1) % 8) == 0) {
1660              printf(" ");
1661            }
1662          }
1663  
1664          // Decode the line as ASCII.
1665          printf("|");
1666          for (unsigned int i = 0; i < hexdump_width_; ++i) {
1667            if (i < num_bytes) {
1668              uint8_t byte = memory[byte_index + i];
1669              printf("%c", isprint(byte) ? byte : '.');
1670            } else {
1671              // If this line doesn't fill up, pad it out.
1672              printf(" ");
1673            }
1674          }
1675          printf("|\n");
1676        }
1677      } else {
1678        // Ugly raw string view.
1679        printf("0x");
1680        for (unsigned int i = 0;
1681             i < descriptor_->memory.data_size;
1682             i++) {
1683          printf("%02x", memory[i]);
1684        }
1685        printf("\n");
1686      }
1687    } else {
1688      printf("No memory\n");
1689    }
1690  }
1691  
1692  
1693  void MinidumpMemoryRegion::SetPrintMode(bool hexdump,
1694                                          unsigned int hexdump_width) {
1695    // Require the width to be a multiple of 8 bytes.
1696    if (hexdump_width == 0 || (hexdump_width % 8) != 0) {
1697      BPLOG(ERROR) << "MinidumpMemoryRegion print hexdump_width must be "
1698                      "multiple of 8, not " << hexdump_width;
1699      return;
1700    }
1701  
1702    hexdump_ = hexdump;
1703    hexdump_width_ = hexdump_width;
1704  }
1705  
1706  
1707  //
1708  // MinidumpThread
1709  //
1710  
1711  
1712  MinidumpThread::MinidumpThread(Minidump* minidump)
1713      : MinidumpObject(minidump),
1714        thread_(),
1715        memory_(NULL),
1716        context_(NULL) {
1717  }
1718  
1719  
1720  MinidumpThread::~MinidumpThread() {
1721    delete memory_;
1722    delete context_;
1723  }
1724  
1725  
1726  bool MinidumpThread::Read() {
1727    // Invalidate cached data.
1728    delete memory_;
1729    memory_ = NULL;
1730    delete context_;
1731    context_ = NULL;
1732  
1733    valid_ = false;
1734  
1735    if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
1736      BPLOG(ERROR) << "MinidumpThread cannot read thread";
1737      return false;
1738    }
1739  
1740    if (minidump_->swap()) {
1741      Swap(&thread_.thread_id);
1742      Swap(&thread_.suspend_count);
1743      Swap(&thread_.priority_class);
1744      Swap(&thread_.priority);
1745      Swap(&thread_.teb);
1746      Swap(&thread_.stack);
1747      Swap(&thread_.thread_context);
1748    }
1749  
1750    // Check for base + size overflow or undersize.
1751    if (thread_.stack.memory.rva == 0 ||
1752        thread_.stack.memory.data_size == 0 ||
1753        thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
1754                                         thread_.stack.start_of_memory_range) {
1755      // This is ok, but log an error anyway.
1756      BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
1757                      HexString(thread_.stack.start_of_memory_range) << "+" <<
1758                      HexString(thread_.stack.memory.data_size) <<
1759                      ", RVA 0x" << HexString(thread_.stack.memory.rva);
1760    } else {
1761      memory_ = new MinidumpMemoryRegion(minidump_);
1762      memory_->SetDescriptor(&thread_.stack);
1763    }
1764  
1765    valid_ = true;
1766    return true;
1767  }
1768  
1769  uint64_t MinidumpThread::GetStartOfStackMemoryRange() const {
1770    if (!valid_) {
1771      BPLOG(ERROR) << "GetStartOfStackMemoryRange: Invalid MinidumpThread";
1772      return 0;
1773    }
1774  
1775    return thread_.stack.start_of_memory_range;
1776  }
1777  
1778  MinidumpMemoryRegion* MinidumpThread::GetMemory() {
1779    if (!valid_) {
1780      BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
1781      return NULL;
1782    }
1783  
1784    return memory_;
1785  }
1786  
1787  
1788  MinidumpContext* MinidumpThread::GetContext() {
1789    if (!valid_) {
1790      BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
1791      return NULL;
1792    }
1793  
1794    if (!context_) {
1795      if (!minidump_->SeekSet(thread_.thread_context.rva)) {
1796        BPLOG(ERROR) << "MinidumpThread cannot seek to context";
1797        return NULL;
1798      }
1799  
1800      scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
1801  
1802      if (!context->Read(thread_.thread_context.data_size)) {
1803        BPLOG(ERROR) << "MinidumpThread cannot read context";
1804        return NULL;
1805      }
1806  
1807      context_ = context.release();
1808    }
1809  
1810    return context_;
1811  }
1812  
1813  
1814  bool MinidumpThread::GetThreadID(uint32_t* thread_id) const {
1815    BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
1816                                   "|thread_id|";
1817    assert(thread_id);
1818    *thread_id = 0;
1819  
1820    if (!valid_) {
1821      BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
1822      return false;
1823    }
1824  
1825    *thread_id = thread_.thread_id;
1826    return true;
1827  }
1828  
1829  
1830  void MinidumpThread::Print() {
1831    if (!valid_) {
1832      BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
1833      return;
1834    }
1835  
1836    printf("MDRawThread\n");
1837    printf("  thread_id                   = 0x%x\n",   thread_.thread_id);
1838    printf("  suspend_count               = %d\n",     thread_.suspend_count);
1839    printf("  priority_class              = 0x%x\n",   thread_.priority_class);
1840    printf("  priority                    = 0x%x\n",   thread_.priority);
1841    printf("  teb                         = 0x%" PRIx64 "\n", thread_.teb);
1842    printf("  stack.start_of_memory_range = 0x%" PRIx64 "\n",
1843           thread_.stack.start_of_memory_range);
1844    printf("  stack.memory.data_size      = 0x%x\n",
1845           thread_.stack.memory.data_size);
1846    printf("  stack.memory.rva            = 0x%x\n",   thread_.stack.memory.rva);
1847    printf("  thread_context.data_size    = 0x%x\n",
1848           thread_.thread_context.data_size);
1849    printf("  thread_context.rva          = 0x%x\n",
1850           thread_.thread_context.rva);
1851  
1852    MinidumpContext* context = GetContext();
1853    if (context) {
1854      printf("\n");
1855      context->Print();
1856    } else {
1857      printf("  (no context)\n");
1858      printf("\n");
1859    }
1860  
1861    MinidumpMemoryRegion* memory = GetMemory();
1862    if (memory) {
1863      printf("Stack\n");
1864      memory->Print();
1865    } else {
1866      printf("No stack\n");
1867    }
1868    printf("\n");
1869  }
1870  
1871  
1872  //
1873  // MinidumpThreadList
1874  //
1875  
1876  
1877  uint32_t MinidumpThreadList::max_threads_ = 4096;
1878  
1879  
1880  MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
1881      : MinidumpStream(minidump),
1882        id_to_thread_map_(),
1883        threads_(NULL),
1884        thread_count_(0) {
1885  }
1886  
1887  
1888  MinidumpThreadList::~MinidumpThreadList() {
1889    delete threads_;
1890  }
1891  
1892  
1893  bool MinidumpThreadList::Read(uint32_t expected_size) {
1894    // Invalidate cached data.
1895    id_to_thread_map_.clear();
1896    delete threads_;
1897    threads_ = NULL;
1898    thread_count_ = 0;
1899  
1900    valid_ = false;
1901  
1902    uint32_t thread_count;
1903    if (expected_size < sizeof(thread_count)) {
1904      BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
1905                      expected_size << " < " << sizeof(thread_count);
1906      return false;
1907    }
1908    if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
1909      BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
1910      return false;
1911    }
1912  
1913    if (minidump_->swap())
1914      Swap(&thread_count);
1915  
1916    if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
1917      BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
1918                      " would cause multiplication overflow";
1919      return false;
1920    }
1921  
1922    if (expected_size != sizeof(thread_count) +
1923                         thread_count * sizeof(MDRawThread)) {
1924      // may be padded with 4 bytes on 64bit ABIs for alignment
1925      if (expected_size == sizeof(thread_count) + 4 +
1926                           thread_count * sizeof(MDRawThread)) {
1927        uint32_t useless;
1928        if (!minidump_->ReadBytes(&useless, 4)) {
1929          BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded "
1930                          "bytes";
1931          return false;
1932        }
1933      } else {
1934        BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
1935                      " != " << sizeof(thread_count) +
1936                      thread_count * sizeof(MDRawThread);
1937        return false;
1938      }
1939    }
1940  
1941  
1942    if (thread_count > max_threads_) {
1943      BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
1944                      " exceeds maximum " << max_threads_;
1945      return false;
1946    }
1947  
1948    if (thread_count != 0) {
1949      scoped_ptr<MinidumpThreads> threads(
1950          new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
1951  
1952      for (unsigned int thread_index = 0;
1953           thread_index < thread_count;
1954           ++thread_index) {
1955        MinidumpThread* thread = &(*threads)[thread_index];
1956  
1957        // Assume that the file offset is correct after the last read.
1958        if (!thread->Read()) {
1959          BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
1960                          thread_index << "/" << thread_count;
1961          return false;
1962        }
1963  
1964        uint32_t thread_id;
1965        if (!thread->GetThreadID(&thread_id)) {
1966          BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
1967                          thread_index << "/" << thread_count;
1968          return false;
1969        }
1970  
1971        if (GetThreadByID(thread_id)) {
1972          // Another thread with this ID is already in the list.  Data error.
1973          BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
1974                          HexString(thread_id) << " at thread " <<
1975                          thread_index << "/" << thread_count;
1976          return false;
1977        }
1978        id_to_thread_map_[thread_id] = thread;
1979      }
1980  
1981      threads_ = threads.release();
1982    }
1983  
1984    thread_count_ = thread_count;
1985  
1986    valid_ = true;
1987    return true;
1988  }
1989  
1990  
1991  MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
1992      const {
1993    if (!valid_) {
1994      BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
1995      return NULL;
1996    }
1997  
1998    if (index >= thread_count_) {
1999      BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
2000                      index << "/" << thread_count_;
2001      return NULL;
2002    }
2003  
2004    return &(*threads_)[index];
2005  }
2006  
2007  
2008  MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
2009    // Don't check valid_.  Read calls this method before everything is
2010    // validated.  It is safe to not check valid_ here.
2011    return id_to_thread_map_[thread_id];
2012  }
2013  
2014  
2015  void MinidumpThreadList::Print() {
2016    if (!valid_) {
2017      BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
2018      return;
2019    }
2020  
2021    printf("MinidumpThreadList\n");
2022    printf("  thread_count = %d\n", thread_count_);
2023    printf("\n");
2024  
2025    for (unsigned int thread_index = 0;
2026         thread_index < thread_count_;
2027         ++thread_index) {
2028      printf("thread[%d]\n", thread_index);
2029  
2030      (*threads_)[thread_index].Print();
2031    }
2032  }
2033  
2034  //
2035  // MinidumpThreadName
2036  //
2037  
2038  MinidumpThreadName::MinidumpThreadName(Minidump* minidump)
2039      : MinidumpObject(minidump),
2040        thread_name_valid_(false),
2041        thread_name_(),
2042        name_(NULL) {}
2043  
2044  MinidumpThreadName::~MinidumpThreadName() {
2045    delete name_;
2046  }
2047  
2048  bool MinidumpThreadName::Read() {
2049    // Invalidate cached data.
2050    delete name_;
2051    name_ = NULL;
2052  
2053    valid_ = false;
2054  
2055    if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) {
2056      BPLOG(ERROR) << "MinidumpThreadName cannot read thread name";
2057      return false;
2058    }
2059  
2060    if (minidump_->swap()) {
2061      Swap(&thread_name_.thread_id);
2062      Swap(&thread_name_.thread_name_rva);
2063    }
2064  
2065    thread_name_valid_ = true;
2066    return true;
2067  }
2068  
2069  bool MinidumpThreadName::ReadAuxiliaryData() {
2070    if (!thread_name_valid_) {
2071      BPLOG(ERROR) << "Invalid MinidumpThreadName for ReadAuxiliaryData";
2072      return false;
2073    }
2074  
2075    // On 32-bit systems, check that the RVA64 is within range (off_t is 32 bits).
2076    if (thread_name_.thread_name_rva > numeric_limits<off_t>::max()) {
2077      BPLOG(ERROR) << "MinidumpThreadName RVA64 out of range";
2078      return false;
2079    }
2080  
2081    // Read the thread name.
2082    const off_t thread_name_rva_offset =
2083        static_cast<off_t>(thread_name_.thread_name_rva);
2084    name_ = minidump_->ReadString(thread_name_rva_offset);
2085    if (!name_) {
2086      BPLOG(ERROR) << "MinidumpThreadName could not read name";
2087      return false;
2088    }
2089  
2090    // At this point, we have enough info for the thread name to be valid.
2091    valid_ = true;
2092    return true;
2093  }
2094  
2095  bool MinidumpThreadName::GetThreadID(uint32_t* thread_id) const {
2096    BPLOG_IF(ERROR, !thread_id) << "MinidumpThreadName::GetThreadID requires "
2097                                   "|thread_id|";
2098    assert(thread_id);
2099    *thread_id = 0;
2100  
2101    if (!valid_) {
2102      BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadID";
2103      return false;
2104    }
2105  
2106    *thread_id = thread_name_.thread_id;
2107    return true;
2108  }
2109  
2110  string MinidumpThreadName::GetThreadName() const {
2111    if (!valid_) {
2112      BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadName";
2113      return "";
2114    }
2115  
2116    return *name_;
2117  }
2118  
2119  void MinidumpThreadName::Print() {
2120    if (!valid_) {
2121      BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data";
2122      return;
2123    }
2124  
2125    printf("MDRawThreadName\n");
2126    printf("  thread_id                   = 0x%x\n", thread_name_.thread_id);
2127    printf("  thread_name_rva             = 0x%" PRIx64 "\n",
2128           thread_name_.thread_name_rva);
2129    printf("  thread_name                 = \"%s\"\n", GetThreadName().c_str());
2130    printf("\n");
2131  }
2132  
2133  //
2134  // MinidumpThreadNameList
2135  //
2136  
2137  MinidumpThreadNameList::MinidumpThreadNameList(Minidump* minidump)
2138      : MinidumpStream(minidump), thread_names_(NULL), thread_name_count_(0) {}
2139  
2140  MinidumpThreadNameList::~MinidumpThreadNameList() {
2141    delete thread_names_;
2142  }
2143  
2144  bool MinidumpThreadNameList::Read(uint32_t expected_size) {
2145    // Invalidate cached data.
2146    delete thread_names_;
2147    thread_names_ = NULL;
2148    thread_name_count_ = 0;
2149  
2150    valid_ = false;
2151  
2152    uint32_t thread_name_count;
2153    if (expected_size < sizeof(thread_name_count)) {
2154      BPLOG(ERROR) << "MinidumpThreadNameList count size mismatch, "
2155                   << expected_size << " < " << sizeof(thread_name_count);
2156      return false;
2157    }
2158    if (!minidump_->ReadBytes(&thread_name_count, sizeof(thread_name_count))) {
2159      BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name count";
2160      return false;
2161    }
2162  
2163    if (minidump_->swap())
2164      Swap(&thread_name_count);
2165  
2166    if (thread_name_count >
2167        numeric_limits<uint32_t>::max() / sizeof(MDRawThreadName)) {
2168      BPLOG(ERROR) << "MinidumpThreadNameList thread name count "
2169                   << thread_name_count << " would cause multiplication overflow";
2170      return false;
2171    }
2172  
2173    if (expected_size !=
2174        sizeof(thread_name_count) + thread_name_count * sizeof(MDRawThreadName)) {
2175      BPLOG(ERROR) << "MinidumpThreadNameList size mismatch, " << expected_size
2176                   << " != "
2177                   << sizeof(thread_name_count) +
2178                          thread_name_count * sizeof(MDRawThreadName);
2179      return false;
2180    }
2181  
2182    if (thread_name_count > MinidumpThreadList::max_threads()) {
2183      BPLOG(ERROR) << "MinidumpThreadNameList count " << thread_name_count
2184                   << " exceeds maximum " << MinidumpThreadList::max_threads();
2185      return false;
2186    }
2187  
2188    if (thread_name_count != 0) {
2189      scoped_ptr<MinidumpThreadNames> thread_names(new MinidumpThreadNames(
2190          thread_name_count, MinidumpThreadName(minidump_)));
2191  
2192      for (unsigned int thread_name_index = 0;
2193           thread_name_index < thread_name_count; ++thread_name_index) {
2194        MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
2195  
2196        // Assume that the file offset is correct after the last read.
2197        if (!thread_name->Read()) {
2198          BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
2199                       << thread_name_index << "/" << thread_name_count;
2200          return false;
2201        }
2202      }
2203  
2204      for (unsigned int thread_name_index = 0;
2205           thread_name_index < thread_name_count; ++thread_name_index) {
2206        MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
2207  
2208        if (!thread_name->ReadAuxiliaryData() && !thread_name->valid()) {
2209          BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
2210                       << thread_name_index << "/" << thread_name_count;
2211          return false;
2212        }
2213      }
2214  
2215      thread_names_ = thread_names.release();
2216    }
2217  
2218    thread_name_count_ = thread_name_count;
2219  
2220    valid_ = true;
2221    return true;
2222  }
2223  
2224  MinidumpThreadName* MinidumpThreadNameList::GetThreadNameAtIndex(
2225      unsigned int index) const {
2226    if (!valid_) {
2227      BPLOG(ERROR) << "Invalid MinidumpThreadNameList for GetThreadNameAtIndex";
2228      return NULL;
2229    }
2230  
2231    if (index >= thread_name_count_) {
2232      BPLOG(ERROR) << "MinidumpThreadNameList index out of range: " << index
2233                   << "/" << thread_name_count_;
2234      return NULL;
2235    }
2236  
2237    return &(*thread_names_)[index];
2238  }
2239  
2240  void MinidumpThreadNameList::Print() {
2241    if (!valid_) {
2242      BPLOG(ERROR) << "MinidumpThreadNameList cannot print invalid data";
2243      return;
2244    }
2245  
2246    printf("MinidumpThreadNameList\n");
2247    printf("  thread_name_count = %d\n", thread_name_count_);
2248    printf("\n");
2249  
2250    for (unsigned int thread_name_index = 0;
2251         thread_name_index < thread_name_count_; ++thread_name_index) {
2252      printf("thread_name[%d]\n", thread_name_index);
2253  
2254      (*thread_names_)[thread_name_index].Print();
2255    }
2256  }
2257  
2258  //
2259  // MinidumpModule
2260  //
2261  
2262  
2263  uint32_t MinidumpModule::max_cv_bytes_ = 32768;
2264  uint32_t MinidumpModule::max_misc_bytes_ = 32768;
2265  
2266  
2267  MinidumpModule::MinidumpModule(Minidump* minidump)
2268      : MinidumpObject(minidump),
2269        module_valid_(false),
2270        has_debug_info_(false),
2271        module_(),
2272        name_(NULL),
2273        cv_record_(NULL),
2274        cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
2275        misc_record_(NULL) {
2276  }
2277  
2278  
2279  MinidumpModule::~MinidumpModule() {
2280    delete name_;
2281    delete cv_record_;
2282    delete misc_record_;
2283  }
2284  
2285  
2286  bool MinidumpModule::Read() {
2287    // Invalidate cached data.
2288    delete name_;
2289    name_ = NULL;
2290    delete cv_record_;
2291    cv_record_ = NULL;
2292    cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
2293    delete misc_record_;
2294    misc_record_ = NULL;
2295  
2296    module_valid_ = false;
2297    has_debug_info_ = false;
2298    valid_ = false;
2299  
2300    if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
2301      BPLOG(ERROR) << "MinidumpModule cannot read module";
2302      return false;
2303    }
2304  
2305    if (minidump_->swap()) {
2306      Swap(&module_.base_of_image);
2307      Swap(&module_.size_of_image);
2308      Swap(&module_.checksum);
2309      Swap(&module_.time_date_stamp);
2310      Swap(&module_.module_name_rva);
2311      Swap(&module_.version_info.signature);
2312      Swap(&module_.version_info.struct_version);
2313      Swap(&module_.version_info.file_version_hi);
2314      Swap(&module_.version_info.file_version_lo);
2315      Swap(&module_.version_info.product_version_hi);
2316      Swap(&module_.version_info.product_version_lo);
2317      Swap(&module_.version_info.file_flags_mask);
2318      Swap(&module_.version_info.file_flags);
2319      Swap(&module_.version_info.file_os);
2320      Swap(&module_.version_info.file_type);
2321      Swap(&module_.version_info.file_subtype);
2322      Swap(&module_.version_info.file_date_hi);
2323      Swap(&module_.version_info.file_date_lo);
2324      Swap(&module_.cv_record);
2325      Swap(&module_.misc_record);
2326      // Don't swap reserved fields because their contents are unknown (as
2327      // are their proper widths).
2328    }
2329  
2330    // Check for base + size overflow or undersize.
2331    if (module_.size_of_image == 0 ||
2332        module_.size_of_image >
2333            numeric_limits<uint64_t>::max() - module_.base_of_image) {
2334      BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
2335                      HexString(module_.base_of_image) << "+" <<
2336                      HexString(module_.size_of_image);
2337      return false;
2338    }
2339  
2340    module_valid_ = true;
2341    return true;
2342  }
2343  
2344  
2345  bool MinidumpModule::ReadAuxiliaryData() {
2346    if (!module_valid_) {
2347      BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
2348      return false;
2349    }
2350  
2351    // Each module must have a name.
2352    name_ = minidump_->ReadString(module_.module_name_rva);
2353    if (!name_) {
2354      BPLOG(ERROR) << "MinidumpModule could not read name";
2355      return false;
2356    }
2357  
2358    // At this point, we have enough info for the module to be valid.
2359    valid_ = true;
2360  
2361    // CodeView and miscellaneous debug records are only required if the
2362    // module indicates that they exist.
2363    if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
2364      BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
2365                      "but one was expected";
2366      return false;
2367    }
2368  
2369    if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
2370      BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
2371                      "but one was expected";
2372      return false;
2373    }
2374  
2375    has_debug_info_ = true;
2376    return true;
2377  }
2378  
2379  
2380  string MinidumpModule::code_file() const {
2381    if (!valid_) {
2382      BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
2383      return "";
2384    }
2385  
2386    return *name_;
2387  }
2388  
2389  
2390  string MinidumpModule::code_identifier() const {
2391    if (!valid_) {
2392      BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
2393      return "";
2394    }
2395  
2396    if (!has_debug_info_)
2397      return "";
2398  
2399    MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
2400    if (!minidump_system_info) {
2401      BPLOG(ERROR) << "MinidumpModule code_identifier requires "
2402                      "MinidumpSystemInfo";
2403      return "";
2404    }
2405  
2406    const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
2407    if (!raw_system_info) {
2408      BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
2409      return "";
2410    }
2411  
2412    string identifier;
2413  
2414    switch (raw_system_info->platform_id) {
2415      case MD_OS_WIN32_NT:
2416      case MD_OS_WIN32_WINDOWS: {
2417        // Use the same format that the MS symbol server uses in filesystem
2418        // hierarchies.
2419        char identifier_string[17];
2420        snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
2421                 module_.time_date_stamp, module_.size_of_image);
2422        identifier = identifier_string;
2423        break;
2424      }
2425  
2426      case MD_OS_ANDROID:
2427      case MD_OS_FUCHSIA:
2428      case MD_OS_LINUX: {
2429        // If ELF CodeView data is present, return the debug id.
2430        if (cv_record_ && cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2431          const MDCVInfoELF* cv_record_elf =
2432              reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
2433          assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
2434  
2435          for (unsigned int build_id_index = 0;
2436               build_id_index < (cv_record_->size() - MDCVInfoELF_minsize);
2437               ++build_id_index) {
2438            char hexbyte[3];
2439            snprintf(hexbyte, sizeof(hexbyte), "%02x",
2440                     cv_record_elf->build_id[build_id_index]);
2441            identifier += hexbyte;
2442          }
2443          break;
2444        }
2445        // Otherwise fall through to the case below.
2446        BP_FALLTHROUGH;
2447      }
2448  
2449      case MD_OS_MAC_OS_X:
2450      case MD_OS_IOS:
2451      case MD_OS_SOLARIS:
2452      case MD_OS_NACL:
2453      case MD_OS_PS3: {
2454        // TODO(mmentovai): support uuid extension if present, otherwise fall
2455        // back to version (from LC_ID_DYLIB?), otherwise fall back to something
2456        // else.
2457        identifier = "id";
2458        break;
2459      }
2460  
2461      default: {
2462        // Without knowing what OS generated the dump, we can't generate a good
2463        // identifier.  Return an empty string, signalling failure.
2464        BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
2465                        "found " << HexString(raw_system_info->platform_id);
2466        break;
2467      }
2468    }
2469  
2470    return identifier;
2471  }
2472  
2473  
2474  string MinidumpModule::debug_file() const {
2475    if (!valid_) {
2476      BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
2477      return "";
2478    }
2479  
2480    if (!has_debug_info_)
2481      return "";
2482  
2483    string file;
2484    // Prefer the CodeView record if present.
2485    if (cv_record_) {
2486      if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2487        // It's actually an MDCVInfoPDB70 structure.
2488        const MDCVInfoPDB70* cv_record_70 =
2489            reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2490        assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2491  
2492        // GetCVRecord guarantees pdb_file_name is null-terminated.
2493        file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
2494      } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2495        // It's actually an MDCVInfoPDB20 structure.
2496        const MDCVInfoPDB20* cv_record_20 =
2497            reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2498        assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2499  
2500        // GetCVRecord guarantees pdb_file_name is null-terminated.
2501        file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
2502      } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2503        // It's actually an MDCVInfoELF structure.
2504        assert(reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0])->
2505            cv_signature == MD_CVINFOELF_SIGNATURE);
2506  
2507        // For MDCVInfoELF, the debug file is the code file.
2508        file = *name_;
2509      }
2510  
2511      // If there's a CodeView record but it doesn't match a known signature,
2512      // try the miscellaneous record.
2513    }
2514  
2515    if (file.empty()) {
2516      // No usable CodeView record.  Try the miscellaneous debug record.
2517      if (misc_record_) {
2518        const MDImageDebugMisc* misc_record =
2519            reinterpret_cast<const MDImageDebugMisc*>(&(*misc_record_)[0]);
2520        if (!misc_record->unicode) {
2521          // If it's not Unicode, just stuff it into the string.  It's unclear
2522          // if misc_record->data is 0-terminated, so use an explicit size.
2523          file = string(
2524              reinterpret_cast<const char*>(misc_record->data),
2525              module_.misc_record.data_size - MDImageDebugMisc_minsize);
2526        } else {
2527          // There's a misc_record but it encodes the debug filename in UTF-16.
2528          // (Actually, because miscellaneous records are so old, it's probably
2529          // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
2530          // that this method (and all other methods in the Minidump family)
2531          // return.
2532  
2533          size_t bytes =
2534              module_.misc_record.data_size - MDImageDebugMisc_minsize;
2535          if (bytes % 2 == 0) {
2536            size_t utf16_words = bytes / 2;
2537  
2538            // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
2539            // and copy the UTF-16 data into it.
2540            vector<uint16_t> string_utf16(utf16_words);
2541            if (utf16_words)
2542              memcpy(&string_utf16[0], &misc_record->data, bytes);
2543  
2544            // GetMiscRecord already byte-swapped the data[] field if it contains
2545            // UTF-16, so pass false as the swap argument.
2546            scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
2547            if (new_file.get() != nullptr) {
2548              file = *new_file;
2549            }
2550          }
2551        }
2552      }
2553    }
2554  
2555    // Relatively common case
2556    BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
2557                                    "debug_file for " << *name_;
2558  
2559    return file;
2560  }
2561  
2562  static string guid_and_age_to_debug_id(const MDGUID& guid,
2563                                         uint32_t age) {
2564    char identifier_string[41];
2565    snprintf(identifier_string, sizeof(identifier_string),
2566             "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
2567             guid.data1,
2568             guid.data2,
2569             guid.data3,
2570             guid.data4[0],
2571             guid.data4[1],
2572             guid.data4[2],
2573             guid.data4[3],
2574             guid.data4[4],
2575             guid.data4[5],
2576             guid.data4[6],
2577             guid.data4[7],
2578             age);
2579    return identifier_string;
2580  }
2581  
2582  string MinidumpModule::debug_identifier() const {
2583    if (!valid_) {
2584      BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
2585      return "";
2586    }
2587  
2588    if (!has_debug_info_)
2589      return "";
2590  
2591    string identifier;
2592  
2593    // Use the CodeView record if present.
2594    if (cv_record_) {
2595      if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2596        // It's actually an MDCVInfoPDB70 structure.
2597        const MDCVInfoPDB70* cv_record_70 =
2598            reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2599        assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2600  
2601        // Use the same format that the MS symbol server uses in filesystem
2602        // hierarchies.
2603        identifier = guid_and_age_to_debug_id(cv_record_70->signature,
2604                                              cv_record_70->age);
2605      } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2606        // It's actually an MDCVInfoPDB20 structure.
2607        const MDCVInfoPDB20* cv_record_20 =
2608            reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2609        assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2610  
2611        // Use the same format that the MS symbol server uses in filesystem
2612        // hierarchies.
2613        char identifier_string[17];
2614        snprintf(identifier_string, sizeof(identifier_string),
2615                 "%08X%x", cv_record_20->signature, cv_record_20->age);
2616        identifier = identifier_string;
2617      } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2618        // It's actually an MDCVInfoELF structure.
2619        const MDCVInfoELF* cv_record_elf =
2620            reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
2621        assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
2622  
2623        // For backwards-compatibility, stuff as many bytes as will fit into
2624        // a MDGUID and use the MS symbol server format as MDCVInfoPDB70 does
2625        // with age = 0. Historically Breakpad would do this during dump
2626        // writing to fit the build id data into a MDCVInfoPDB70 struct.
2627        // The full build id is available by calling code_identifier.
2628        MDGUID guid = {0};
2629        memcpy(&guid, &cv_record_elf->build_id,
2630               std::min(cv_record_->size() - MDCVInfoELF_minsize,
2631                        sizeof(MDGUID)));
2632        identifier = guid_and_age_to_debug_id(guid, 0);
2633      }
2634    }
2635  
2636    // TODO(mmentovai): if there's no usable CodeView record, there might be a
2637    // miscellaneous debug record.  It only carries a filename, though, and no
2638    // identifier.  I'm not sure what the right thing to do for the identifier
2639    // is in that case, but I don't expect to find many modules without a
2640    // CodeView record (or some other Breakpad extension structure in place of
2641    // a CodeView record).  Treat it as an error (empty identifier) for now.
2642  
2643    // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
2644  
2645    // Relatively common case
2646    BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
2647                                          "debug_identifier for " << *name_;
2648  
2649    return identifier;
2650  }
2651  
2652  
2653  string MinidumpModule::version() const {
2654    if (!valid_) {
2655      BPLOG(ERROR) << "Invalid MinidumpModule for version";
2656      return "";
2657    }
2658  
2659    string version;
2660  
2661    if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
2662        module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
2663      char version_string[24];
2664      snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
2665               module_.version_info.file_version_hi >> 16,
2666               module_.version_info.file_version_hi & 0xffff,
2667               module_.version_info.file_version_lo >> 16,
2668               module_.version_info.file_version_lo & 0xffff);
2669      version = version_string;
2670    }
2671  
2672    // TODO(mmentovai): possibly support other struct types in place of
2673    // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
2674    // a different structure that better represents versioning facilities on
2675    // Mac OS X and Linux, instead of forcing them to adhere to the dotted
2676    // quad of 16-bit ints that Windows uses.
2677  
2678    BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
2679                                       "version for " << *name_;
2680  
2681    return version;
2682  }
2683  
2684  
2685  CodeModule* MinidumpModule::Copy() const {
2686    return new BasicCodeModule(this);
2687  }
2688  
2689  
2690  uint64_t MinidumpModule::shrink_down_delta() const {
2691    return 0;
2692  }
2693  
2694  void MinidumpModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
2695    // Not implemented
2696    assert(false);
2697  }
2698  
2699  
2700  const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
2701    if (!module_valid_) {
2702      BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
2703      return NULL;
2704    }
2705  
2706    if (!cv_record_) {
2707      // This just guards against 0-sized CodeView records; more specific checks
2708      // are used when the signature is checked against various structure types.
2709      if (module_.cv_record.data_size == 0) {
2710        return NULL;
2711      }
2712  
2713      if (!minidump_->SeekSet(module_.cv_record.rva)) {
2714        BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
2715        return NULL;
2716      }
2717  
2718      if (module_.cv_record.data_size > max_cv_bytes_) {
2719        BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
2720                        module_.cv_record.data_size << " exceeds maximum " <<
2721                        max_cv_bytes_;
2722        return NULL;
2723      }
2724  
2725      // Allocating something that will be accessed as MDCVInfoPDB70 or
2726      // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
2727      // problems.  x86 and ppc are able to cope, though.  This allocation
2728      // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
2729      // variable-sized due to their pdb_file_name fields; these structures
2730      // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
2731      // them as such would result in incomplete structures or overruns.
2732      scoped_ptr< vector<uint8_t> > cv_record(
2733          new vector<uint8_t>(module_.cv_record.data_size));
2734  
2735      if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
2736        BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
2737        return NULL;
2738      }
2739  
2740      uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
2741      if (module_.cv_record.data_size > sizeof(signature)) {
2742        MDCVInfoPDB70* cv_record_signature =
2743            reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2744        signature = cv_record_signature->cv_signature;
2745        if (minidump_->swap())
2746          Swap(&signature);
2747      }
2748  
2749      if (signature == MD_CVINFOPDB70_SIGNATURE) {
2750        // Now that the structure type is known, recheck the size,
2751        // ensuring at least one byte for the null terminator.
2752        if (MDCVInfoPDB70_minsize + 1 > module_.cv_record.data_size) {
2753          BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
2754                          MDCVInfoPDB70_minsize << " > " <<
2755                          module_.cv_record.data_size;
2756          return NULL;
2757        }
2758  
2759        if (minidump_->swap()) {
2760          MDCVInfoPDB70* cv_record_70 =
2761              reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2762          Swap(&cv_record_70->cv_signature);
2763          Swap(&cv_record_70->signature);
2764          Swap(&cv_record_70->age);
2765          // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
2766          // quantities.  (It's a path, is it UTF-8?)
2767        }
2768  
2769        // The last field of either structure is null-terminated 8-bit character
2770        // data.  Ensure that it's null-terminated.
2771        if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2772          BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
2773                          "0-terminated";
2774          return NULL;
2775        }
2776      } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
2777        // Now that the structure type is known, recheck the size,
2778        // ensuring at least one byte for the null terminator.
2779        if (MDCVInfoPDB20_minsize + 1 > module_.cv_record.data_size) {
2780          BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
2781                          MDCVInfoPDB20_minsize << " > " <<
2782                          module_.cv_record.data_size;
2783          return NULL;
2784        }
2785        if (minidump_->swap()) {
2786          MDCVInfoPDB20* cv_record_20 =
2787              reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
2788          Swap(&cv_record_20->cv_header.signature);
2789          Swap(&cv_record_20->cv_header.offset);
2790          Swap(&cv_record_20->signature);
2791          Swap(&cv_record_20->age);
2792          // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
2793          // quantities.  (It's a path, is it UTF-8?)
2794        }
2795  
2796        // The last field of either structure is null-terminated 8-bit character
2797        // data.  Ensure that it's null-terminated.
2798        if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2799          BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
2800                          "0-terminated";
2801          return NULL;
2802        }
2803      } else if (signature == MD_CVINFOELF_SIGNATURE) {
2804        // Now that the structure type is known, recheck the size.
2805        if (MDCVInfoELF_minsize > module_.cv_record.data_size) {
2806          BPLOG(ERROR) << "MinidumpModule CodeViewELF record size mismatch, " <<
2807                          MDCVInfoELF_minsize << " > " <<
2808                          module_.cv_record.data_size;
2809          return NULL;
2810        }
2811        if (minidump_->swap()) {
2812          MDCVInfoELF* cv_record_elf =
2813              reinterpret_cast<MDCVInfoELF*>(&(*cv_record)[0]);
2814          Swap(&cv_record_elf->cv_signature);
2815        }
2816      }
2817  
2818      // If the signature doesn't match something above, it's not something
2819      // that Breakpad can presently handle directly.  Because some modules in
2820      // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
2821      // don't bail out here - allow the data to be returned to the user,
2822      // although byte-swapping can't be done.
2823  
2824      // Store the vector type because that's how storage was allocated, but
2825      // return it casted to uint8_t*.
2826      cv_record_ = cv_record.release();
2827      cv_record_signature_ = signature;
2828    }
2829  
2830    if (size)
2831      *size = module_.cv_record.data_size;
2832  
2833    return &(*cv_record_)[0];
2834  }
2835  
2836  
2837  const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
2838    if (!module_valid_) {
2839      BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
2840      return NULL;
2841    }
2842  
2843    if (!misc_record_) {
2844      if (module_.misc_record.data_size == 0) {
2845        return NULL;
2846      }
2847  
2848      if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
2849        BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
2850                        "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
2851                        module_.misc_record.data_size;
2852        return NULL;
2853      }
2854  
2855      if (!minidump_->SeekSet(module_.misc_record.rva)) {
2856        BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
2857                        "debugging record";
2858        return NULL;
2859      }
2860  
2861      if (module_.misc_record.data_size > max_misc_bytes_) {
2862        BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
2863                        module_.misc_record.data_size << " exceeds maximum " <<
2864                        max_misc_bytes_;
2865        return NULL;
2866      }
2867  
2868      // Allocating something that will be accessed as MDImageDebugMisc but
2869      // is allocated as uint8_t[] can cause alignment problems.  x86 and
2870      // ppc are able to cope, though.  This allocation style is needed
2871      // because the MDImageDebugMisc is variable-sized due to its data field;
2872      // this structure is not MDImageDebugMisc_minsize and treating it as such
2873      // would result in an incomplete structure or an overrun.
2874      scoped_ptr< vector<uint8_t> > misc_record_mem(
2875          new vector<uint8_t>(module_.misc_record.data_size));
2876      MDImageDebugMisc* misc_record =
2877          reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
2878  
2879      if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
2880        BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
2881                        "record";
2882        return NULL;
2883      }
2884  
2885      if (minidump_->swap()) {
2886        Swap(&misc_record->data_type);
2887        Swap(&misc_record->length);
2888        // Don't swap misc_record.unicode because it's an 8-bit quantity.
2889        // Don't swap the reserved fields for the same reason, and because
2890        // they don't contain any valid data.
2891        if (misc_record->unicode) {
2892          // There is a potential alignment problem, but shouldn't be a problem
2893          // in practice due to the layout of MDImageDebugMisc.
2894          uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
2895          size_t dataBytes = module_.misc_record.data_size -
2896                             MDImageDebugMisc_minsize;
2897          Swap(data16, dataBytes);
2898        }
2899      }
2900  
2901      if (module_.misc_record.data_size != misc_record->length) {
2902        BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
2903                        "size mismatch, " << module_.misc_record.data_size <<
2904                        " != " << misc_record->length;
2905        return NULL;
2906      }
2907  
2908      // Store the vector type because that's how storage was allocated, but
2909      // return it casted to MDImageDebugMisc*.
2910      misc_record_ = misc_record_mem.release();
2911    }
2912  
2913    if (size)
2914      *size = module_.misc_record.data_size;
2915  
2916    return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
2917  }
2918  
2919  
2920  void MinidumpModule::Print() {
2921    if (!valid_) {
2922      BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
2923      return;
2924    }
2925  
2926    printf("MDRawModule\n");
2927    printf("  base_of_image                   = 0x%" PRIx64 "\n",
2928           module_.base_of_image);
2929    printf("  size_of_image                   = 0x%x\n",
2930           module_.size_of_image);
2931    printf("  checksum                        = 0x%x\n",
2932           module_.checksum);
2933    printf("  time_date_stamp                 = 0x%x %s\n",
2934           module_.time_date_stamp,
2935           TimeTToUTCString(module_.time_date_stamp).c_str());
2936    printf("  module_name_rva                 = 0x%x\n",
2937           module_.module_name_rva);
2938    printf("  version_info.signature          = 0x%x\n",
2939           module_.version_info.signature);
2940    printf("  version_info.struct_version     = 0x%x\n",
2941           module_.version_info.struct_version);
2942    printf("  version_info.file_version       = 0x%x:0x%x\n",
2943           module_.version_info.file_version_hi,
2944           module_.version_info.file_version_lo);
2945    printf("  version_info.product_version    = 0x%x:0x%x\n",
2946           module_.version_info.product_version_hi,
2947           module_.version_info.product_version_lo);
2948    printf("  version_info.file_flags_mask    = 0x%x\n",
2949           module_.version_info.file_flags_mask);
2950    printf("  version_info.file_flags         = 0x%x\n",
2951           module_.version_info.file_flags);
2952    printf("  version_info.file_os            = 0x%x\n",
2953           module_.version_info.file_os);
2954    printf("  version_info.file_type          = 0x%x\n",
2955           module_.version_info.file_type);
2956    printf("  version_info.file_subtype       = 0x%x\n",
2957           module_.version_info.file_subtype);
2958    printf("  version_info.file_date          = 0x%x:0x%x\n",
2959           module_.version_info.file_date_hi,
2960           module_.version_info.file_date_lo);
2961    printf("  cv_record.data_size             = %d\n",
2962           module_.cv_record.data_size);
2963    printf("  cv_record.rva                   = 0x%x\n",
2964           module_.cv_record.rva);
2965    printf("  misc_record.data_size           = %d\n",
2966           module_.misc_record.data_size);
2967    printf("  misc_record.rva                 = 0x%x\n",
2968           module_.misc_record.rva);
2969  
2970    printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
2971    printf("  (code_identifier)               = \"%s\"\n",
2972           code_identifier().c_str());
2973  
2974    uint32_t cv_record_size;
2975    const uint8_t* cv_record = GetCVRecord(&cv_record_size);
2976    if (cv_record) {
2977      if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2978        const MDCVInfoPDB70* cv_record_70 =
2979            reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
2980        assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2981  
2982        printf("  (cv_record).cv_signature        = 0x%x\n",
2983               cv_record_70->cv_signature);
2984        printf("  (cv_record).signature           = %s\n",
2985               MDGUIDToString(cv_record_70->signature).c_str());
2986        printf("  (cv_record).age                 = %d\n",
2987               cv_record_70->age);
2988        printf("  (cv_record).pdb_file_name       = \"%s\"\n",
2989               cv_record_70->pdb_file_name);
2990      } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2991        const MDCVInfoPDB20* cv_record_20 =
2992            reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
2993        assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2994  
2995        printf("  (cv_record).cv_header.signature = 0x%x\n",
2996               cv_record_20->cv_header.signature);
2997        printf("  (cv_record).cv_header.offset    = 0x%x\n",
2998               cv_record_20->cv_header.offset);
2999        printf("  (cv_record).signature           = 0x%x %s\n",
3000               cv_record_20->signature,
3001               TimeTToUTCString(cv_record_20->signature).c_str());
3002        printf("  (cv_record).age                 = %d\n",
3003               cv_record_20->age);
3004        printf("  (cv_record).pdb_file_name       = \"%s\"\n",
3005               cv_record_20->pdb_file_name);
3006      } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
3007        const MDCVInfoELF* cv_record_elf =
3008            reinterpret_cast<const MDCVInfoELF*>(cv_record);
3009        assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
3010  
3011        printf("  (cv_record).cv_signature        = 0x%x\n",
3012               cv_record_elf->cv_signature);
3013        printf("  (cv_record).build_id            = ");
3014        for (unsigned int build_id_index = 0;
3015             build_id_index < (cv_record_size - MDCVInfoELF_minsize);
3016             ++build_id_index) {
3017          printf("%02x", cv_record_elf->build_id[build_id_index]);
3018        }
3019        printf("\n");
3020      } else {
3021        printf("  (cv_record)                     = ");
3022        for (unsigned int cv_byte_index = 0;
3023             cv_byte_index < cv_record_size;
3024             ++cv_byte_index) {
3025          printf("%02x", cv_record[cv_byte_index]);
3026        }
3027        printf("\n");
3028      }
3029    } else {
3030      printf("  (cv_record)                     = (null)\n");
3031    }
3032  
3033    const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
3034    if (misc_record) {
3035      printf("  (misc_record).data_type         = 0x%x\n",
3036             misc_record->data_type);
3037      printf("  (misc_record).length            = 0x%x\n",
3038             misc_record->length);
3039      printf("  (misc_record).unicode           = %d\n",
3040             misc_record->unicode);
3041      if (misc_record->unicode) {
3042        string misc_record_data_utf8;
3043        ConvertUTF16BufferToUTF8String(
3044            reinterpret_cast<const uint16_t*>(misc_record->data),
3045            misc_record->length - offsetof(MDImageDebugMisc, data),
3046            &misc_record_data_utf8,
3047            false);  // already swapped
3048        printf("  (misc_record).data              = \"%s\"\n",
3049               misc_record_data_utf8.c_str());
3050      } else {
3051        printf("  (misc_record).data              = \"%s\"\n",
3052               misc_record->data);
3053      }
3054    } else {
3055      printf("  (misc_record)                   = (null)\n");
3056    }
3057  
3058    printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
3059    printf("  (debug_identifier)              = \"%s\"\n",
3060           debug_identifier().c_str());
3061    printf("  (version)                       = \"%s\"\n", version().c_str());
3062    printf("\n");
3063  }
3064  
3065  
3066  //
3067  // MinidumpModuleList
3068  //
3069  
3070  
3071  uint32_t MinidumpModuleList::max_modules_ = 2048;
3072  
3073  
3074  MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
3075      : MinidumpStream(minidump),
3076        range_map_(new RangeMap<uint64_t, unsigned int>()),
3077        modules_(NULL),
3078        module_count_(0) {
3079    MDOSPlatform platform;
3080    if (minidump_->GetPlatform(&platform) &&
3081        (platform == MD_OS_ANDROID || platform == MD_OS_LINUX)) {
3082      range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
3083    }
3084  }
3085  
3086  
3087  MinidumpModuleList::~MinidumpModuleList() {
3088    delete range_map_;
3089    delete modules_;
3090  }
3091  
3092  
3093  bool MinidumpModuleList::Read(uint32_t expected_size) {
3094    // Invalidate cached data.
3095    range_map_->Clear();
3096    delete modules_;
3097    modules_ = NULL;
3098    module_count_ = 0;
3099  
3100    valid_ = false;
3101  
3102    uint32_t module_count;
3103    if (expected_size < sizeof(module_count)) {
3104      BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
3105                      expected_size << " < " << sizeof(module_count);
3106      return false;
3107    }
3108    if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
3109      BPLOG(ERROR) << "MinidumpModuleList could not read module count";
3110      return false;
3111    }
3112  
3113    if (minidump_->swap())
3114      Swap(&module_count);
3115  
3116    if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
3117      BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
3118                      " would cause multiplication overflow";
3119      return false;
3120    }
3121  
3122    if (expected_size != sizeof(module_count) +
3123                         module_count * MD_MODULE_SIZE) {
3124      // may be padded with 4 bytes on 64bit ABIs for alignment
3125      if (expected_size == sizeof(module_count) + 4 +
3126                           module_count * MD_MODULE_SIZE) {
3127        uint32_t useless;
3128        if (!minidump_->ReadBytes(&useless, 4)) {
3129          BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded "
3130                          "bytes";
3131          return false;
3132        }
3133      } else {
3134        BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
3135                        " != " << sizeof(module_count) +
3136                        module_count * MD_MODULE_SIZE;
3137        return false;
3138      }
3139    }
3140  
3141    if (module_count > max_modules_) {
3142      BPLOG(ERROR) << "MinidumpModuleList count " << module_count <<
3143                      " exceeds maximum " << max_modules_;
3144      return false;
3145    }
3146  
3147    if (module_count != 0) {
3148      scoped_ptr<MinidumpModules> modules(
3149          new MinidumpModules(module_count, MinidumpModule(minidump_)));
3150  
3151      for (uint32_t module_index = 0; module_index < module_count;
3152           ++module_index) {
3153        MinidumpModule* module = &(*modules)[module_index];
3154  
3155        // Assume that the file offset is correct after the last read.
3156        if (!module->Read()) {
3157          BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
3158                          module_index << "/" << module_count;
3159          return false;
3160        }
3161      }
3162  
3163      // Loop through the module list once more to read additional data and
3164      // build the range map.  This is done in a second pass because
3165      // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
3166      // included in the loop above, additional seeks would be needed where
3167      // none are now to read contiguous data.
3168      uint64_t last_end_address = 0;
3169      for (uint32_t module_index = 0; module_index < module_count;
3170           ++module_index) {
3171        MinidumpModule& module = (*modules)[module_index];
3172  
3173        // ReadAuxiliaryData fails if any data that the module indicates should
3174        // exist is missing, but we treat some such cases as valid anyway.  See
3175        // issue #222: if a debugging record is of a format that's too large to
3176        // handle, it shouldn't render the entire dump invalid.  Check module
3177        // validity before giving up.
3178        if (!module.ReadAuxiliaryData() && !module.valid()) {
3179          BPLOG(ERROR) << "MinidumpModuleList could not read required module "
3180                          "auxiliary data for module " <<
3181                          module_index << "/" << module_count;
3182          return false;
3183        }
3184  
3185        // It is safe to use module->code_file() after successfully calling
3186        // module->ReadAuxiliaryData or noting that the module is valid.
3187  
3188        uint64_t base_address = module.base_address();
3189        uint64_t module_size = module.size();
3190        if (base_address == static_cast<uint64_t>(-1)) {
3191          BPLOG(ERROR) << "MinidumpModuleList found bad base address for module "
3192                       << module_index << "/" << module_count << ", "
3193                       << module.code_file();
3194          return false;
3195        }
3196  
3197        // Some minidumps have additional modules in the list that are duplicates.
3198        // Ignore them. See https://crbug.com/838322
3199        uint32_t existing_module_index;
3200        if (range_map_->RetrieveRange(base_address, &existing_module_index,
3201                                      nullptr, nullptr, nullptr) &&
3202            existing_module_index < module_count) {
3203          const MinidumpModule& existing_module =
3204              (*modules)[existing_module_index];
3205          if (existing_module.base_address() == module.base_address() &&
3206              existing_module.size() == module.size() &&
3207              existing_module.code_file() == module.code_file() &&
3208              existing_module.code_identifier() == module.code_identifier()) {
3209            continue;
3210          }
3211        }
3212  
3213        const bool is_android = minidump_->IsAndroid();
3214        if (!StoreRange(module, base_address, module_index, module_count,
3215                        is_android)) {
3216          if (!is_android || base_address >= last_end_address) {
3217            BPLOG(ERROR) << "MinidumpModuleList could not store module "
3218                         << module_index << "/" << module_count << ", "
3219                         << module.code_file() << ", " << HexString(base_address)
3220                         << "+" << HexString(module_size);
3221            return false;
3222          }
3223  
3224          // If failed due to apparent range overlap the cause may be the client
3225          // correction applied for Android packed relocations.  If this is the
3226          // case, back out the client correction and retry.
3227          assert(is_android);
3228          module_size -= last_end_address - base_address;
3229          base_address = last_end_address;
3230          if (!range_map_->StoreRange(base_address, module_size, module_index)) {
3231            BPLOG(ERROR) << "MinidumpModuleList could not store module "
3232                         << module_index << "/" << module_count << ", "
3233                         << module.code_file() << ", " << HexString(base_address)
3234                         << "+" << HexString(module_size) << ", after adjusting";
3235            return false;
3236          }
3237        }
3238        last_end_address = base_address + module_size;
3239      }
3240  
3241      modules_ = modules.release();
3242    }
3243  
3244    module_count_ = module_count;
3245  
3246    valid_ = true;
3247    return true;
3248  }
3249  
3250  bool MinidumpModuleList::StoreRange(const MinidumpModule& module,
3251                                      uint64_t base_address,
3252                                      uint32_t module_index,
3253                                      uint32_t module_count,
3254                                      bool is_android) {
3255    if (range_map_->StoreRange(base_address, module.size(), module_index))
3256      return true;
3257  
3258    // Android's shared memory implementation /dev/ashmem can contain duplicate
3259    // entries for JITted code, so ignore these.
3260    // TODO(wfh): Remove this code when Android is fixed.
3261    // See https://crbug.com/439531
3262    if (is_android && IsDevAshmem(module.code_file())) {
3263      BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module "
3264                  << module_index << "/" << module_count << ", "
3265                  << module.code_file() << ", " << HexString(base_address) << "+"
3266                  << HexString(module.size());
3267      return true;
3268    }
3269  
3270    return false;
3271  }
3272  
3273  const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
3274      uint64_t address) const {
3275    if (!valid_) {
3276      BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
3277      return NULL;
3278    }
3279  
3280    unsigned int module_index;
3281    if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */,
3282                                   NULL /* delta */, NULL /* size */)) {
3283      BPLOG(INFO) << "MinidumpModuleList has no module at " <<
3284                     HexString(address);
3285      return NULL;
3286    }
3287  
3288    return GetModuleAtIndex(module_index);
3289  }
3290  
3291  
3292  const MinidumpModule* MinidumpModuleList::GetMainModule() const {
3293    if (!valid_) {
3294      BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
3295      return NULL;
3296    }
3297  
3298    // The main code module is the first one present in a minidump file's
3299    // MDRawModuleList.
3300    return GetModuleAtIndex(0);
3301  }
3302  
3303  
3304  const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
3305      unsigned int sequence) const {
3306    if (!valid_) {
3307      BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
3308      return NULL;
3309    }
3310  
3311    if (sequence >= module_count_) {
3312      BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
3313                      sequence << "/" << module_count_;
3314      return NULL;
3315    }
3316  
3317    unsigned int module_index;
3318    if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
3319                                          NULL /* base */, NULL /* delta */,
3320                                          NULL /* size */)) {
3321      BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
3322      return NULL;
3323    }
3324  
3325    return GetModuleAtIndex(module_index);
3326  }
3327  
3328  
3329  const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
3330      unsigned int index) const {
3331    if (!valid_) {
3332      BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
3333      return NULL;
3334    }
3335  
3336    if (index >= module_count_) {
3337      BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
3338                      index << "/" << module_count_;
3339      return NULL;
3340    }
3341  
3342    return &(*modules_)[index];
3343  }
3344  
3345  
3346  const CodeModules* MinidumpModuleList::Copy() const {
3347    return new BasicCodeModules(this, range_map_->GetMergeStrategy());
3348  }
3349  
3350  vector<linked_ptr<const CodeModule> >
3351  MinidumpModuleList::GetShrunkRangeModules() const {
3352    return vector<linked_ptr<const CodeModule> >();
3353  }
3354  
3355  void MinidumpModuleList::Print() {
3356    if (!valid_) {
3357      BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
3358      return;
3359    }
3360  
3361    printf("MinidumpModuleList\n");
3362    printf("  module_count = %d\n", module_count_);
3363    printf("\n");
3364  
3365    for (unsigned int module_index = 0;
3366         module_index < module_count_;
3367         ++module_index) {
3368      printf("module[%d]\n", module_index);
3369  
3370      (*modules_)[module_index].Print();
3371    }
3372  }
3373  
3374  
3375  //
3376  // MinidumpMemoryList
3377  //
3378  
3379  
3380  uint32_t MinidumpMemoryList::max_regions_ = 4096;
3381  
3382  
3383  MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
3384      : MinidumpStream(minidump),
3385        range_map_(new RangeMap<uint64_t, unsigned int>()),
3386        descriptors_(NULL),
3387        regions_(NULL),
3388        region_count_(0) {
3389  }
3390  
3391  
3392  MinidumpMemoryList::~MinidumpMemoryList() {
3393    delete range_map_;
3394    delete descriptors_;
3395    delete regions_;
3396  }
3397  
3398  
3399  bool MinidumpMemoryList::Read(uint32_t expected_size) {
3400    // Invalidate cached data.
3401    delete descriptors_;
3402    descriptors_ = NULL;
3403    delete regions_;
3404    regions_ = NULL;
3405    range_map_->Clear();
3406    region_count_ = 0;
3407  
3408    valid_ = false;
3409  
3410    uint32_t region_count;
3411    if (expected_size < sizeof(region_count)) {
3412      BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
3413                      expected_size << " < " << sizeof(region_count);
3414      return false;
3415    }
3416    if (!minidump_->ReadBytes(&region_count, sizeof(region_count))) {
3417      BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
3418      return false;
3419    }
3420  
3421    if (minidump_->swap())
3422      Swap(&region_count);
3423  
3424    if (region_count >
3425            numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
3426      BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
3427                      " would cause multiplication overflow";
3428      return false;
3429    }
3430  
3431    if (expected_size != sizeof(region_count) +
3432                         region_count * sizeof(MDMemoryDescriptor)) {
3433      // may be padded with 4 bytes on 64bit ABIs for alignment
3434      if (expected_size == sizeof(region_count) + 4 +
3435                           region_count * sizeof(MDMemoryDescriptor)) {
3436        uint32_t useless;
3437        if (!minidump_->ReadBytes(&useless, 4)) {
3438          BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded "
3439                          "bytes";
3440          return false;
3441        }
3442      } else {
3443        BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
3444                        " != " << sizeof(region_count) +
3445                        region_count * sizeof(MDMemoryDescriptor);
3446        return false;
3447      }
3448    }
3449  
3450    if (region_count > max_regions_) {
3451      BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
3452                      " exceeds maximum " << max_regions_;
3453      return false;
3454    }
3455  
3456    if (region_count != 0) {
3457      scoped_ptr<MemoryDescriptors> descriptors(
3458          new MemoryDescriptors(region_count));
3459  
3460      // Read the entire array in one fell swoop, instead of reading one entry
3461      // at a time in the loop.
3462      if (!minidump_->ReadBytes(&(*descriptors)[0],
3463                                sizeof(MDMemoryDescriptor) * region_count)) {
3464        BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
3465        return false;
3466      }
3467  
3468      scoped_ptr<MemoryRegions> regions(
3469          new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
3470  
3471      for (unsigned int region_index = 0;
3472           region_index < region_count;
3473           ++region_index) {
3474        MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
3475  
3476        if (minidump_->swap())
3477          Swap(descriptor);
3478  
3479        uint64_t base_address = descriptor->start_of_memory_range;
3480        uint32_t region_size = descriptor->memory.data_size;
3481  
3482        // Check for base + size overflow or undersize.
3483        if (region_size == 0 ||
3484            region_size > numeric_limits<uint64_t>::max() - base_address) {
3485          BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
3486                          " region " << region_index << "/" << region_count <<
3487                          ", " << HexString(base_address) << "+" <<
3488                          HexString(region_size);
3489          return false;
3490        }
3491  
3492        if (!range_map_->StoreRange(base_address, region_size, region_index)) {
3493          BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
3494                          region_index << "/" << region_count << ", " <<
3495                          HexString(base_address) << "+" <<
3496                          HexString(region_size);
3497          return false;
3498        }
3499  
3500        (*regions)[region_index].SetDescriptor(descriptor);
3501      }
3502  
3503      descriptors_ = descriptors.release();
3504      regions_ = regions.release();
3505    }
3506  
3507    region_count_ = region_count;
3508  
3509    valid_ = true;
3510    return true;
3511  }
3512  
3513  
3514  MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
3515        unsigned int index) {
3516    if (!valid_) {
3517      BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
3518      return NULL;
3519    }
3520  
3521    if (index >= region_count_) {
3522      BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
3523                      index << "/" << region_count_;
3524      return NULL;
3525    }
3526  
3527    return &(*regions_)[index];
3528  }
3529  
3530  
3531  MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
3532      uint64_t address) {
3533    if (!valid_) {
3534      BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
3535      return NULL;
3536    }
3537  
3538    unsigned int region_index;
3539    if (!range_map_->RetrieveRange(address, &region_index, NULL /* base */,
3540                                   NULL /* delta */, NULL /* size */)) {
3541      BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
3542                     HexString(address);
3543      return NULL;
3544    }
3545  
3546    return GetMemoryRegionAtIndex(region_index);
3547  }
3548  
3549  
3550  void MinidumpMemoryList::Print() {
3551    if (!valid_) {
3552      BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
3553      return;
3554    }
3555  
3556    printf("MinidumpMemoryList\n");
3557    printf("  region_count = %d\n", region_count_);
3558    printf("\n");
3559  
3560    for (unsigned int region_index = 0;
3561         region_index < region_count_;
3562         ++region_index) {
3563      MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
3564      printf("region[%d]\n", region_index);
3565      printf("MDMemoryDescriptor\n");
3566      printf("  start_of_memory_range = 0x%" PRIx64 "\n",
3567             descriptor->start_of_memory_range);
3568      printf("  memory.data_size      = 0x%x\n", descriptor->memory.data_size);
3569      printf("  memory.rva            = 0x%x\n", descriptor->memory.rva);
3570      MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
3571      if (region) {
3572        printf("Memory\n");
3573        region->Print();
3574      } else {
3575        printf("No memory\n");
3576      }
3577      printf("\n");
3578    }
3579  }
3580  
3581  
3582  //
3583  // MinidumpException
3584  //
3585  
3586  
3587  MinidumpException::MinidumpException(Minidump* minidump)
3588      : MinidumpStream(minidump),
3589        exception_(),
3590        context_(NULL) {
3591  }
3592  
3593  
3594  MinidumpException::~MinidumpException() {
3595    delete context_;
3596  }
3597  
3598  
3599  bool MinidumpException::Read(uint32_t expected_size) {
3600    // Invalidate cached data.
3601    delete context_;
3602    context_ = NULL;
3603  
3604    valid_ = false;
3605  
3606    if (expected_size != sizeof(exception_)) {
3607      BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
3608                      " != " << sizeof(exception_);
3609      return false;
3610    }
3611  
3612    if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
3613      BPLOG(ERROR) << "MinidumpException cannot read exception";
3614      return false;
3615    }
3616  
3617    if (minidump_->swap()) {
3618      Swap(&exception_.thread_id);
3619      // exception_.__align is for alignment only and does not need to be
3620      // swapped.
3621      Swap(&exception_.exception_record.exception_code);
3622      Swap(&exception_.exception_record.exception_flags);
3623      Swap(&exception_.exception_record.exception_record);
3624      Swap(&exception_.exception_record.exception_address);
3625      Swap(&exception_.exception_record.number_parameters);
3626      // exception_.exception_record.__align is for alignment only and does not
3627      // need to be swapped.
3628      for (unsigned int parameter_index = 0;
3629           parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
3630           ++parameter_index) {
3631        Swap(&exception_.exception_record.exception_information[parameter_index]);
3632      }
3633      Swap(&exception_.thread_context);
3634    }
3635  
3636    valid_ = true;
3637    return true;
3638  }
3639  
3640  
3641  bool MinidumpException::GetThreadID(uint32_t* thread_id) const {
3642    BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
3643                                   "|thread_id|";
3644    assert(thread_id);
3645    *thread_id = 0;
3646  
3647    if (!valid_) {
3648      BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
3649      return false;
3650    }
3651  
3652    *thread_id = exception_.thread_id;
3653    return true;
3654  }
3655  
3656  
3657  MinidumpContext* MinidumpException::GetContext() {
3658    if (!valid_) {
3659      BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
3660      return NULL;
3661    }
3662  
3663    if (!context_) {
3664      if (!minidump_->SeekSet(exception_.thread_context.rva)) {
3665        BPLOG(ERROR) << "MinidumpException cannot seek to context";
3666        return NULL;
3667      }
3668  
3669      scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
3670  
3671      // Don't log as an error if we can still fall back on the thread's context
3672      // (which must be possible if we got this far.)
3673      if (!context->Read(exception_.thread_context.data_size)) {
3674        BPLOG(INFO) << "MinidumpException cannot read context";
3675        return NULL;
3676      }
3677  
3678      context_ = context.release();
3679    }
3680  
3681    return context_;
3682  }
3683  
3684  
3685  void MinidumpException::Print() {
3686    if (!valid_) {
3687      BPLOG(ERROR) << "MinidumpException cannot print invalid data";
3688      return;
3689    }
3690  
3691    printf("MDException\n");
3692    printf("  thread_id                                  = 0x%x\n",
3693           exception_.thread_id);
3694    printf("  exception_record.exception_code            = 0x%x\n",
3695           exception_.exception_record.exception_code);
3696    printf("  exception_record.exception_flags           = 0x%x\n",
3697           exception_.exception_record.exception_flags);
3698    printf("  exception_record.exception_record          = 0x%" PRIx64 "\n",
3699           exception_.exception_record.exception_record);
3700    printf("  exception_record.exception_address         = 0x%" PRIx64 "\n",
3701           exception_.exception_record.exception_address);
3702    printf("  exception_record.number_parameters         = %d\n",
3703           exception_.exception_record.number_parameters);
3704    for (unsigned int parameterIndex = 0;
3705         parameterIndex < exception_.exception_record.number_parameters;
3706         ++parameterIndex) {
3707      printf("  exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
3708             parameterIndex,
3709             exception_.exception_record.exception_information[parameterIndex]);
3710    }
3711    printf("  thread_context.data_size                   = %d\n",
3712           exception_.thread_context.data_size);
3713    printf("  thread_context.rva                         = 0x%x\n",
3714           exception_.thread_context.rva);
3715    MinidumpContext* context = GetContext();
3716    if (context) {
3717      printf("\n");
3718      context->Print();
3719    } else {
3720      printf("  (no context)\n");
3721      printf("\n");
3722    }
3723  }
3724  
3725  //
3726  // MinidumpAssertion
3727  //
3728  
3729  
3730  MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
3731      : MinidumpStream(minidump),
3732        assertion_(),
3733        expression_(),
3734        function_(),
3735        file_() {
3736  }
3737  
3738  
3739  MinidumpAssertion::~MinidumpAssertion() {
3740  }
3741  
3742  
3743  bool MinidumpAssertion::Read(uint32_t expected_size) {
3744    // Invalidate cached data.
3745    valid_ = false;
3746  
3747    if (expected_size != sizeof(assertion_)) {
3748      BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
3749                      " != " << sizeof(assertion_);
3750      return false;
3751    }
3752  
3753    if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
3754      BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
3755      return false;
3756    }
3757  
3758    // Each of {expression, function, file} is a UTF-16 string,
3759    // we'll convert them to UTF-8 for ease of use.
3760    ConvertUTF16BufferToUTF8String(assertion_.expression,
3761                                   sizeof(assertion_.expression), &expression_,
3762                                   minidump_->swap());
3763    ConvertUTF16BufferToUTF8String(assertion_.function,
3764                                   sizeof(assertion_.function), &function_,
3765                                   minidump_->swap());
3766    ConvertUTF16BufferToUTF8String(assertion_.file, sizeof(assertion_.file),
3767                                   &file_, minidump_->swap());
3768  
3769    if (minidump_->swap()) {
3770      Swap(&assertion_.line);
3771      Swap(&assertion_.type);
3772    }
3773  
3774    valid_ = true;
3775    return true;
3776  }
3777  
3778  void MinidumpAssertion::Print() {
3779    if (!valid_) {
3780      BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
3781      return;
3782    }
3783  
3784    printf("MDAssertion\n");
3785    printf("  expression                                 = %s\n",
3786           expression_.c_str());
3787    printf("  function                                   = %s\n",
3788           function_.c_str());
3789    printf("  file                                       = %s\n",
3790           file_.c_str());
3791    printf("  line                                       = %u\n",
3792           assertion_.line);
3793    printf("  type                                       = %u\n",
3794           assertion_.type);
3795    printf("\n");
3796  }
3797  
3798  //
3799  // MinidumpSystemInfo
3800  //
3801  
3802  
3803  MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
3804      : MinidumpStream(minidump),
3805        system_info_(),
3806        csd_version_(NULL),
3807        cpu_vendor_(NULL) {
3808  }
3809  
3810  
3811  MinidumpSystemInfo::~MinidumpSystemInfo() {
3812    delete csd_version_;
3813    delete cpu_vendor_;
3814  }
3815  
3816  
3817  bool MinidumpSystemInfo::Read(uint32_t expected_size) {
3818    // Invalidate cached data.
3819    delete csd_version_;
3820    csd_version_ = NULL;
3821    delete cpu_vendor_;
3822    cpu_vendor_ = NULL;
3823  
3824    valid_ = false;
3825  
3826    if (expected_size != sizeof(system_info_)) {
3827      BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
3828                      " != " << sizeof(system_info_);
3829      return false;
3830    }
3831  
3832    if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
3833      BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
3834      return false;
3835    }
3836  
3837    if (minidump_->swap()) {
3838      Swap(&system_info_.processor_architecture);
3839      Swap(&system_info_.processor_level);
3840      Swap(&system_info_.processor_revision);
3841      // number_of_processors and product_type are 8-bit quantities and need no
3842      // swapping.
3843      Swap(&system_info_.major_version);
3844      Swap(&system_info_.minor_version);
3845      Swap(&system_info_.build_number);
3846      Swap(&system_info_.platform_id);
3847      Swap(&system_info_.csd_version_rva);
3848      Swap(&system_info_.suite_mask);
3849      // Don't swap the reserved2 field because its contents are unknown.
3850  
3851      if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3852          system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
3853        for (unsigned int i = 0; i < 3; ++i)
3854          Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
3855        Swap(&system_info_.cpu.x86_cpu_info.version_information);
3856        Swap(&system_info_.cpu.x86_cpu_info.feature_information);
3857        Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3858      } else {
3859        for (unsigned int i = 0; i < 2; ++i)
3860          Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
3861      }
3862    }
3863  
3864    valid_ = true;
3865    return true;
3866  }
3867  
3868  
3869  string MinidumpSystemInfo::GetOS() {
3870    string os;
3871  
3872    if (!valid_) {
3873      BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
3874      return os;
3875    }
3876  
3877    switch (system_info_.platform_id) {
3878      case MD_OS_WIN32_NT:
3879      case MD_OS_WIN32_WINDOWS:
3880        os = "windows";
3881        break;
3882  
3883      case MD_OS_MAC_OS_X:
3884        os = "mac";
3885        break;
3886  
3887      case MD_OS_IOS:
3888        os = "ios";
3889        break;
3890  
3891      case MD_OS_LINUX:
3892        os = "linux";
3893        break;
3894  
3895      case MD_OS_SOLARIS:
3896        os = "solaris";
3897        break;
3898  
3899      case MD_OS_ANDROID:
3900        os = "android";
3901        break;
3902  
3903      case MD_OS_PS3:
3904        os = "ps3";
3905        break;
3906  
3907      case MD_OS_NACL:
3908        os = "nacl";
3909        break;
3910  
3911      case MD_OS_FUCHSIA:
3912        os = "fuchsia";
3913        break;
3914  
3915      default:
3916        BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
3917                        HexString(system_info_.platform_id);
3918        break;
3919    }
3920  
3921    return os;
3922  }
3923  
3924  
3925  string MinidumpSystemInfo::GetCPU() {
3926    if (!valid_) {
3927      BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
3928      return "";
3929    }
3930  
3931    string cpu;
3932  
3933    switch (system_info_.processor_architecture) {
3934      case MD_CPU_ARCHITECTURE_X86:
3935      case MD_CPU_ARCHITECTURE_X86_WIN64:
3936        cpu = "x86";
3937        break;
3938  
3939      case MD_CPU_ARCHITECTURE_AMD64:
3940        cpu = "x86-64";
3941        break;
3942  
3943      case MD_CPU_ARCHITECTURE_PPC:
3944        cpu = "ppc";
3945        break;
3946  
3947      case MD_CPU_ARCHITECTURE_PPC64:
3948        cpu = "ppc64";
3949        break;
3950  
3951      case MD_CPU_ARCHITECTURE_SPARC:
3952        cpu = "sparc";
3953        break;
3954  
3955      case MD_CPU_ARCHITECTURE_ARM:
3956        cpu = "arm";
3957        break;
3958  
3959      case MD_CPU_ARCHITECTURE_ARM64:
3960      case MD_CPU_ARCHITECTURE_ARM64_OLD:
3961        cpu = "arm64";
3962        break;
3963  
3964      case MD_CPU_ARCHITECTURE_RISCV:
3965        cpu = "riscv";
3966        break;
3967  
3968      case MD_CPU_ARCHITECTURE_RISCV64:
3969        cpu = "riscv64";
3970        break;
3971  
3972      default:
3973        BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
3974                        HexString(system_info_.processor_architecture);
3975        break;
3976    }
3977  
3978    return cpu;
3979  }
3980  
3981  
3982  const string* MinidumpSystemInfo::GetCSDVersion() {
3983    if (!valid_) {
3984      BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
3985      return NULL;
3986    }
3987  
3988    if (!csd_version_)
3989      csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
3990  
3991    BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
3992                                      "CSD version";
3993  
3994    return csd_version_;
3995  }
3996  
3997  
3998  const string* MinidumpSystemInfo::GetCPUVendor() {
3999    if (!valid_) {
4000      BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
4001      return NULL;
4002    }
4003  
4004    // CPU vendor information can only be determined from x86 minidumps.
4005    if (!cpu_vendor_ &&
4006        (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
4007         system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
4008      char cpu_vendor_string[13];
4009      snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
4010               "%c%c%c%c%c%c%c%c%c%c%c%c",
4011                system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
4012               (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
4013               (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
4014               (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
4015                system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
4016               (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
4017               (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
4018               (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
4019                system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
4020               (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
4021               (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
4022               (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
4023      cpu_vendor_ = new string(cpu_vendor_string);
4024    }
4025  
4026    return cpu_vendor_;
4027  }
4028  
4029  
4030  void MinidumpSystemInfo::Print() {
4031    if (!valid_) {
4032      BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
4033      return;
4034    }
4035  
4036    printf("MDRawSystemInfo\n");
4037    printf("  processor_architecture                     = 0x%x (%s)\n",
4038           system_info_.processor_architecture, GetCPU().c_str());
4039    printf("  processor_level                            = %d\n",
4040           system_info_.processor_level);
4041    printf("  processor_revision                         = 0x%x\n",
4042           system_info_.processor_revision);
4043    printf("  number_of_processors                       = %d\n",
4044           system_info_.number_of_processors);
4045    printf("  product_type                               = %d\n",
4046           system_info_.product_type);
4047    printf("  major_version                              = %d\n",
4048           system_info_.major_version);
4049    printf("  minor_version                              = %d\n",
4050           system_info_.minor_version);
4051    printf("  build_number                               = %d\n",
4052           system_info_.build_number);
4053    printf("  platform_id                                = 0x%x (%s)\n",
4054           system_info_.platform_id, GetOS().c_str());
4055    printf("  csd_version_rva                            = 0x%x\n",
4056           system_info_.csd_version_rva);
4057    printf("  suite_mask                                 = 0x%x\n",
4058           system_info_.suite_mask);
4059    if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
4060        system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
4061      printf("  cpu.x86_cpu_info (valid):\n");
4062    } else {
4063      printf("  cpu.x86_cpu_info (invalid):\n");
4064    }
4065    for (unsigned int i = 0; i < 3; ++i) {
4066      printf("  cpu.x86_cpu_info.vendor_id[%d]              = 0x%x\n",
4067             i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
4068    }
4069    printf("  cpu.x86_cpu_info.version_information       = 0x%x\n",
4070           system_info_.cpu.x86_cpu_info.version_information);
4071    printf("  cpu.x86_cpu_info.feature_information       = 0x%x\n",
4072           system_info_.cpu.x86_cpu_info.feature_information);
4073    printf("  cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
4074           system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
4075    if (system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86 &&
4076        system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86_WIN64) {
4077      printf("  cpu.other_cpu_info (valid):\n");
4078      for (unsigned int i = 0; i < 2; ++i) {
4079        printf("  cpu.other_cpu_info.processor_features[%d]   = 0x%" PRIx64 "\n",
4080               i, system_info_.cpu.other_cpu_info.processor_features[i]);
4081      }
4082    }
4083    const string* csd_version = GetCSDVersion();
4084    if (csd_version) {
4085      printf("  (csd_version)                              = \"%s\"\n",
4086             csd_version->c_str());
4087    } else {
4088      printf("  (csd_version)                              = (null)\n");
4089    }
4090    const string* cpu_vendor = GetCPUVendor();
4091    if (cpu_vendor) {
4092      printf("  (cpu_vendor)                               = \"%s\"\n",
4093             cpu_vendor->c_str());
4094    } else {
4095      printf("  (cpu_vendor)                               = (null)\n");
4096    }
4097    printf("\n");
4098  }
4099  
4100  
4101  //
4102  // MinidumpUnloadedModule
4103  //
4104  
4105  
4106  MinidumpUnloadedModule::MinidumpUnloadedModule(Minidump* minidump)
4107      : MinidumpObject(minidump),
4108        module_valid_(false),
4109        unloaded_module_(),
4110        name_(NULL) {
4111  
4112  }
4113  
4114  MinidumpUnloadedModule::~MinidumpUnloadedModule() {
4115    delete name_;
4116  }
4117  
4118  string MinidumpUnloadedModule::code_file() const {
4119    if (!valid_) {
4120      BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file";
4121      return "";
4122    }
4123  
4124    return *name_;
4125  }
4126  
4127  string MinidumpUnloadedModule::code_identifier() const {
4128    if (!valid_) {
4129      BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_identifier";
4130      return "";
4131    }
4132  
4133    MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
4134    if (!minidump_system_info) {
4135      BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
4136                      "MinidumpSystemInfo";
4137      return "";
4138    }
4139  
4140    const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
4141    if (!raw_system_info) {
4142      BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
4143                   << "MDRawSystemInfo";
4144      return "";
4145    }
4146  
4147    string identifier;
4148  
4149    switch (raw_system_info->platform_id) {
4150      case MD_OS_WIN32_NT:
4151      case MD_OS_WIN32_WINDOWS: {
4152        // Use the same format that the MS symbol server uses in filesystem
4153        // hierarchies.
4154        char identifier_string[17];
4155        snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
4156                 unloaded_module_.time_date_stamp,
4157                 unloaded_module_.size_of_image);
4158        identifier = identifier_string;
4159        break;
4160      }
4161  
4162      case MD_OS_ANDROID:
4163      case MD_OS_LINUX:
4164      case MD_OS_MAC_OS_X:
4165      case MD_OS_IOS:
4166      case MD_OS_SOLARIS:
4167      case MD_OS_NACL:
4168      case MD_OS_PS3: {
4169        // TODO(mmentovai): support uuid extension if present, otherwise fall
4170        // back to version (from LC_ID_DYLIB?), otherwise fall back to something
4171        // else.
4172        identifier = "id";
4173        break;
4174      }
4175  
4176      default: {
4177        // Without knowing what OS generated the dump, we can't generate a good
4178        // identifier.  Return an empty string, signalling failure.
4179        BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires known "
4180                     << "platform, found "
4181                     << HexString(raw_system_info->platform_id);
4182        break;
4183      }
4184    }
4185  
4186    return identifier;
4187  }
4188  
4189  string MinidumpUnloadedModule::debug_file() const {
4190    return "";  // No debug info provided with unloaded modules
4191  }
4192  
4193  string MinidumpUnloadedModule::debug_identifier() const {
4194    return "";  // No debug info provided with unloaded modules
4195  }
4196  
4197  string MinidumpUnloadedModule::version() const {
4198    return "";  // No version info provided with unloaded modules
4199  }
4200  
4201  CodeModule* MinidumpUnloadedModule::Copy() const {
4202    return new BasicCodeModule(this);
4203  }
4204  
4205  uint64_t MinidumpUnloadedModule::shrink_down_delta() const {
4206    return 0;
4207  }
4208  
4209  void MinidumpUnloadedModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
4210    // Not implemented
4211    assert(false);
4212  }
4213  
4214  bool MinidumpUnloadedModule::Read(uint32_t expected_size) {
4215  
4216    delete name_;
4217    valid_ = false;
4218  
4219    if (expected_size < sizeof(unloaded_module_)) {
4220      BPLOG(ERROR) << "MinidumpUnloadedModule expected size is less than size "
4221                   << "of struct " << expected_size << " < "
4222                   << sizeof(unloaded_module_);
4223      return false;
4224    }
4225  
4226    if (!minidump_->ReadBytes(&unloaded_module_, sizeof(unloaded_module_))) {
4227      BPLOG(ERROR) << "MinidumpUnloadedModule cannot read module";
4228      return false;
4229    }
4230  
4231    if (expected_size > sizeof(unloaded_module_)) {
4232      uint32_t module_bytes_remaining = expected_size - sizeof(unloaded_module_);
4233      off_t pos = minidump_->Tell();
4234      if (!minidump_->SeekSet(pos + module_bytes_remaining)) {
4235        BPLOG(ERROR) << "MinidumpUnloadedModule unable to seek to end of module";
4236        return false;
4237      }
4238    }
4239  
4240    if (minidump_->swap()) {
4241      Swap(&unloaded_module_.base_of_image);
4242      Swap(&unloaded_module_.size_of_image);
4243      Swap(&unloaded_module_.checksum);
4244      Swap(&unloaded_module_.time_date_stamp);
4245      Swap(&unloaded_module_.module_name_rva);
4246    }
4247  
4248    // Check for base + size overflow or undersize.
4249    if (unloaded_module_.size_of_image == 0 ||
4250        unloaded_module_.size_of_image >
4251            numeric_limits<uint64_t>::max() - unloaded_module_.base_of_image) {
4252      BPLOG(ERROR) << "MinidumpUnloadedModule has a module problem, " <<
4253                      HexString(unloaded_module_.base_of_image) << "+" <<
4254                      HexString(unloaded_module_.size_of_image);
4255      return false;
4256    }
4257  
4258  
4259    module_valid_ = true;
4260    return true;
4261  }
4262  
4263  bool MinidumpUnloadedModule::ReadAuxiliaryData() {
4264    if (!module_valid_) {
4265      BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for ReadAuxiliaryData";
4266      return false;
4267    }
4268  
4269    // Each module must have a name.
4270    name_ = minidump_->ReadString(unloaded_module_.module_name_rva);
4271    if (!name_) {
4272      BPLOG(ERROR) << "MinidumpUnloadedModule could not read name";
4273      return false;
4274    }
4275  
4276    // At this point, we have enough info for the module to be valid.
4277    valid_ = true;
4278    return true;
4279  }
4280  
4281  //
4282  // MinidumpUnloadedModuleList
4283  //
4284  
4285  
4286  uint32_t MinidumpUnloadedModuleList::max_modules_ = 2048;
4287  
4288  
4289  MinidumpUnloadedModuleList::MinidumpUnloadedModuleList(Minidump* minidump)
4290    : MinidumpStream(minidump),
4291      range_map_(new RangeMap<uint64_t, unsigned int>()),
4292      unloaded_modules_(NULL),
4293      module_count_(0) {
4294    range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
4295  }
4296  
4297  MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() {
4298    delete range_map_;
4299    delete unloaded_modules_;
4300  }
4301  
4302  
4303  bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) {
4304    range_map_->Clear();
4305    delete unloaded_modules_;
4306    unloaded_modules_ = NULL;
4307    module_count_ = 0;
4308  
4309    valid_ = false;
4310  
4311    uint32_t size_of_header;
4312    if (!minidump_->ReadBytes(&size_of_header, sizeof(size_of_header))) {
4313      BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header size";
4314      return false;
4315    }
4316  
4317    uint32_t size_of_entry;
4318    if (!minidump_->ReadBytes(&size_of_entry, sizeof(size_of_entry))) {
4319      BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read entry size";
4320      return false;
4321    }
4322  
4323    uint32_t number_of_entries;
4324    if (!minidump_->ReadBytes(&number_of_entries, sizeof(number_of_entries))) {
4325      BPLOG(ERROR) <<
4326                   "MinidumpUnloadedModuleList could not read number of entries";
4327      return false;
4328    }
4329  
4330    if (minidump_->swap()) {
4331      Swap(&size_of_header);
4332      Swap(&size_of_entry);
4333      Swap(&number_of_entries);
4334    }
4335  
4336    uint32_t header_bytes_remaining = size_of_header - sizeof(size_of_header) -
4337        sizeof(size_of_entry) - sizeof(number_of_entries);
4338    if (header_bytes_remaining) {
4339      off_t pos = minidump_->Tell();
4340      if (!minidump_->SeekSet(pos + header_bytes_remaining)) {
4341        BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header sized "
4342                     << size_of_header;
4343        return false;
4344      }
4345    }
4346  
4347    if (expected_size != size_of_header + (size_of_entry * number_of_entries)) {
4348      BPLOG(ERROR) << "MinidumpUnloadedModuleList expected_size mismatch " <<
4349                   expected_size << " != " << size_of_header << " + (" <<
4350                   size_of_entry << " * " << number_of_entries << ")";
4351      return false;
4352    }
4353  
4354    if (number_of_entries > max_modules_) {
4355      BPLOG(ERROR) << "MinidumpUnloadedModuleList count " <<
4356                   number_of_entries << " exceeds maximum " << max_modules_;
4357      return false;
4358    }
4359  
4360    if (number_of_entries != 0) {
4361      scoped_ptr<MinidumpUnloadedModules> modules(
4362          new MinidumpUnloadedModules(number_of_entries,
4363                                      MinidumpUnloadedModule(minidump_)));
4364  
4365      for (unsigned int module_index = 0;
4366           module_index < number_of_entries;
4367           ++module_index) {
4368        MinidumpUnloadedModule* module = &(*modules)[module_index];
4369  
4370        if (!module->Read(size_of_entry)) {
4371          BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read module " <<
4372                       module_index << "/" << number_of_entries;
4373          return false;
4374        }
4375      }
4376  
4377      for (unsigned int module_index = 0;
4378           module_index < number_of_entries;
4379           ++module_index) {
4380        MinidumpUnloadedModule* module = &(*modules)[module_index];
4381  
4382        if (!module->ReadAuxiliaryData()) {
4383          BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read required "
4384                       "module auxiliary data for module " <<
4385                       module_index << "/" << number_of_entries;
4386          return false;
4387        }
4388  
4389        uint64_t base_address = module->base_address();
4390        uint64_t module_size = module->size();
4391  
4392        // Ignore any failures for conflicting address ranges
4393        range_map_->StoreRange(base_address, module_size, module_index);
4394  
4395      }
4396      unloaded_modules_ = modules.release();
4397    }
4398  
4399    module_count_ = number_of_entries;
4400    valid_ = true;
4401    return true;
4402  }
4403  
4404  const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress(
4405      uint64_t address) const {
4406    if (!valid_) {
4407      BPLOG(ERROR)
4408          << "Invalid MinidumpUnloadedModuleList for GetModuleForAddress";
4409      return NULL;
4410    }
4411  
4412    unsigned int module_index;
4413    if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */,
4414                                   NULL /* delta */, NULL /* size */)) {
4415      BPLOG(INFO) << "MinidumpUnloadedModuleList has no module at "
4416                  << HexString(address);
4417      return NULL;
4418    }
4419  
4420    return GetModuleAtIndex(module_index);
4421  }
4422  
4423  const MinidumpUnloadedModule*
4424  MinidumpUnloadedModuleList::GetMainModule() const {
4425    return NULL;
4426  }
4427  
4428  const MinidumpUnloadedModule*
4429  MinidumpUnloadedModuleList::GetModuleAtSequence(unsigned int sequence) const {
4430    if (!valid_) {
4431      BPLOG(ERROR)
4432          << "Invalid MinidumpUnloadedModuleList for GetModuleAtSequence";
4433      return NULL;
4434    }
4435  
4436    if (sequence >= module_count_) {
4437      BPLOG(ERROR) << "MinidumpUnloadedModuleList sequence out of range: "
4438                   << sequence << "/" << module_count_;
4439      return NULL;
4440    }
4441  
4442    unsigned int module_index;
4443    if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
4444                                          NULL /* base */, NULL /* delta */,
4445                                          NULL /* size */)) {
4446      BPLOG(ERROR) << "MinidumpUnloadedModuleList has no module at sequence "
4447                   << sequence;
4448      return NULL;
4449    }
4450  
4451    return GetModuleAtIndex(module_index);
4452  }
4453  
4454  const MinidumpUnloadedModule*
4455  MinidumpUnloadedModuleList::GetModuleAtIndex(
4456      unsigned int index) const {
4457    if (!valid_) {
4458      BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtIndex";
4459      return NULL;
4460    }
4461  
4462    if (index >= module_count_) {
4463      BPLOG(ERROR) << "MinidumpUnloadedModuleList index out of range: "
4464                   << index << "/" << module_count_;
4465      return NULL;
4466    }
4467  
4468    return &(*unloaded_modules_)[index];
4469  }
4470  
4471  const CodeModules* MinidumpUnloadedModuleList::Copy() const {
4472    return new BasicCodeModules(this, range_map_->GetMergeStrategy());
4473  }
4474  
4475  vector<linked_ptr<const CodeModule>>
4476  MinidumpUnloadedModuleList::GetShrunkRangeModules() const {
4477    return vector<linked_ptr<const CodeModule> >();
4478  }
4479  
4480  
4481  //
4482  // MinidumpMiscInfo
4483  //
4484  
4485  
4486  MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
4487      : MinidumpStream(minidump),
4488        misc_info_() {
4489  }
4490  
4491  
4492  bool MinidumpMiscInfo::Read(uint32_t expected_size) {
4493    valid_ = false;
4494  
4495    size_t padding = 0;
4496    if (expected_size != MD_MISCINFO_SIZE &&
4497        expected_size != MD_MISCINFO2_SIZE &&
4498        expected_size != MD_MISCINFO3_SIZE &&
4499        expected_size != MD_MISCINFO4_SIZE &&
4500        expected_size != MD_MISCINFO5_SIZE) {
4501      if (expected_size > MD_MISCINFO5_SIZE) {
4502        // Only read the part of the misc info structure we know how to handle
4503        BPLOG(INFO) << "MinidumpMiscInfo size larger than expected "
4504                    << expected_size << ", skipping over the unknown part";
4505        padding = expected_size - MD_MISCINFO5_SIZE;
4506        expected_size = MD_MISCINFO5_SIZE;
4507      } else {
4508        BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size
4509                    << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE
4510                    << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE
4511                    << ", " << MD_MISCINFO5_SIZE << ")";
4512        return false;
4513      }
4514    }
4515  
4516    if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
4517      BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
4518      return false;
4519    }
4520  
4521    if (padding != 0) {
4522      off_t saved_position = minidump_->Tell();
4523      if (saved_position == -1) {
4524        BPLOG(ERROR) << "MinidumpMiscInfo could not tell the current position";
4525        return false;
4526      }
4527  
4528      if (!minidump_->SeekSet(saved_position + static_cast<off_t>(padding))) {
4529        BPLOG(ERROR) << "MinidumpMiscInfo could not seek past the miscellaneous "
4530                     << "info structure";
4531        return false;
4532      }
4533    }
4534  
4535    if (minidump_->swap()) {
4536      // Swap version 1 fields
4537      Swap(&misc_info_.size_of_info);
4538      Swap(&misc_info_.flags1);
4539      Swap(&misc_info_.process_id);
4540      Swap(&misc_info_.process_create_time);
4541      Swap(&misc_info_.process_user_time);
4542      Swap(&misc_info_.process_kernel_time);
4543      if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
4544        // Swap version 2 fields
4545        Swap(&misc_info_.processor_max_mhz);
4546        Swap(&misc_info_.processor_current_mhz);
4547        Swap(&misc_info_.processor_mhz_limit);
4548        Swap(&misc_info_.processor_max_idle_state);
4549        Swap(&misc_info_.processor_current_idle_state);
4550      }
4551      if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4552        // Swap version 3 fields
4553        Swap(&misc_info_.process_integrity_level);
4554        Swap(&misc_info_.process_execute_flags);
4555        Swap(&misc_info_.protected_process);
4556        Swap(&misc_info_.time_zone_id);
4557        Swap(&misc_info_.time_zone);
4558      }
4559      if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4560        // Swap version 4 fields.
4561        // Do not swap UTF-16 strings.  The swap is done as part of the
4562        // conversion to UTF-8 (code follows below).
4563      }
4564      if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) {
4565        // Swap version 5 fields
4566        Swap(&misc_info_.xstate_data);
4567        Swap(&misc_info_.process_cookie);
4568      }
4569    }
4570  
4571    if (expected_size + padding != misc_info_.size_of_info) {
4572      BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
4573                      expected_size << " != " << misc_info_.size_of_info;
4574      return false;
4575    }
4576  
4577    // Convert UTF-16 strings
4578    if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4579      // Convert UTF-16 strings in version 3 fields
4580      ConvertUTF16BufferToUTF8String(misc_info_.time_zone.standard_name,
4581                                     sizeof(misc_info_.time_zone.standard_name),
4582                                     &standard_name_, minidump_->swap());
4583      ConvertUTF16BufferToUTF8String(misc_info_.time_zone.daylight_name,
4584                                     sizeof(misc_info_.time_zone.daylight_name),
4585                                     &daylight_name_, minidump_->swap());
4586    }
4587    if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4588      // Convert UTF-16 strings in version 4 fields
4589      ConvertUTF16BufferToUTF8String(misc_info_.build_string,
4590                                     sizeof(misc_info_.build_string),
4591                                     &build_string_, minidump_->swap());
4592      ConvertUTF16BufferToUTF8String(misc_info_.dbg_bld_str,
4593                                     sizeof(misc_info_.dbg_bld_str),
4594                                     &dbg_bld_str_, minidump_->swap());
4595    }
4596  
4597    valid_ = true;
4598    return true;
4599  }
4600  
4601  
4602  void MinidumpMiscInfo::Print() {
4603    if (!valid_) {
4604      BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
4605      return;
4606    }
4607  
4608    printf("MDRawMiscInfo\n");
4609    // Print version 1 fields
4610    printf("  size_of_info                 = %d\n",   misc_info_.size_of_info);
4611    printf("  flags1                       = 0x%x\n", misc_info_.flags1);
4612    printf("  process_id                   = ");
4613    PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_ID,
4614                        kNumberFormatDecimal, misc_info_.process_id);
4615    if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES) {
4616      printf("  process_create_time          = 0x%x %s\n",
4617             misc_info_.process_create_time,
4618             TimeTToUTCString(misc_info_.process_create_time).c_str());
4619    } else {
4620      printf("  process_create_time          = (invalid)\n");
4621    }
4622    printf("  process_user_time            = ");
4623    PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES,
4624                        kNumberFormatDecimal, misc_info_.process_user_time);
4625    printf("  process_kernel_time          = ");
4626    PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES,
4627                        kNumberFormatDecimal, misc_info_.process_kernel_time);
4628    if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
4629      // Print version 2 fields
4630      printf("  processor_max_mhz            = ");
4631      PrintValueOrInvalid(misc_info_.flags1 &
4632                              MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4633                          kNumberFormatDecimal, misc_info_.processor_max_mhz);
4634      printf("  processor_current_mhz        = ");
4635      PrintValueOrInvalid(misc_info_.flags1 &
4636                              MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4637                          kNumberFormatDecimal, misc_info_.processor_current_mhz);
4638      printf("  processor_mhz_limit          = ");
4639      PrintValueOrInvalid(misc_info_.flags1 &
4640                              MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4641                          kNumberFormatDecimal, misc_info_.processor_mhz_limit);
4642      printf("  processor_max_idle_state     = ");
4643      PrintValueOrInvalid(misc_info_.flags1 &
4644                              MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4645                          kNumberFormatDecimal,
4646                          misc_info_.processor_max_idle_state);
4647      printf("  processor_current_idle_state = ");
4648      PrintValueOrInvalid(misc_info_.flags1 &
4649                              MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4650                          kNumberFormatDecimal,
4651                          misc_info_.processor_current_idle_state);
4652    }
4653    if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4654      // Print version 3 fields
4655      printf("  process_integrity_level      = ");
4656      PrintValueOrInvalid(misc_info_.flags1 &
4657                              MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY,
4658                          kNumberFormatHexadecimal,
4659                          misc_info_.process_integrity_level);
4660      printf("  process_execute_flags        = ");
4661      PrintValueOrInvalid(misc_info_.flags1 &
4662                              MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS,
4663                          kNumberFormatHexadecimal,
4664                          misc_info_.process_execute_flags);
4665      printf("  protected_process            = ");
4666      PrintValueOrInvalid(misc_info_.flags1 &
4667                              MD_MISCINFO_FLAGS1_PROTECTED_PROCESS,
4668                          kNumberFormatDecimal, misc_info_.protected_process);
4669      printf("  time_zone_id                 = ");
4670      PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE,
4671                          kNumberFormatDecimal, misc_info_.time_zone_id);
4672      if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE) {
4673        printf("  time_zone.bias               = %d\n",
4674               misc_info_.time_zone.bias);
4675        printf("  time_zone.standard_name      = %s\n", standard_name_.c_str());
4676        printf("  time_zone.standard_date      = "
4677                   "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n",
4678               misc_info_.time_zone.standard_date.year,
4679               misc_info_.time_zone.standard_date.month,
4680               misc_info_.time_zone.standard_date.day,
4681               misc_info_.time_zone.standard_date.day_of_week,
4682               misc_info_.time_zone.standard_date.hour,
4683               misc_info_.time_zone.standard_date.minute,
4684               misc_info_.time_zone.standard_date.second,
4685               misc_info_.time_zone.standard_date.milliseconds);
4686        printf("  time_zone.standard_bias      = %d\n",
4687               misc_info_.time_zone.standard_bias);
4688        printf("  time_zone.daylight_name      = %s\n", daylight_name_.c_str());
4689        printf("  time_zone.daylight_date      = "
4690                   "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n",
4691               misc_info_.time_zone.daylight_date.year,
4692               misc_info_.time_zone.daylight_date.month,
4693               misc_info_.time_zone.daylight_date.day,
4694               misc_info_.time_zone.daylight_date.day_of_week,
4695               misc_info_.time_zone.daylight_date.hour,
4696               misc_info_.time_zone.daylight_date.minute,
4697               misc_info_.time_zone.daylight_date.second,
4698               misc_info_.time_zone.daylight_date.milliseconds);
4699        printf("  time_zone.daylight_bias      = %d\n",
4700               misc_info_.time_zone.daylight_bias);
4701      } else {
4702        printf("  time_zone.bias               = (invalid)\n");
4703        printf("  time_zone.standard_name      = (invalid)\n");
4704        printf("  time_zone.standard_date      = (invalid)\n");
4705        printf("  time_zone.standard_bias      = (invalid)\n");
4706        printf("  time_zone.daylight_name      = (invalid)\n");
4707        printf("  time_zone.daylight_date      = (invalid)\n");
4708        printf("  time_zone.daylight_bias      = (invalid)\n");
4709      }
4710    }
4711    if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4712      // Print version 4 fields
4713      if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_BUILDSTRING) {
4714        printf("  build_string                 = %s\n", build_string_.c_str());
4715        printf("  dbg_bld_str                  = %s\n", dbg_bld_str_.c_str());
4716      } else {
4717        printf("  build_string                 = (invalid)\n");
4718        printf("  dbg_bld_str                  = (invalid)\n");
4719      }
4720    }
4721    if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) {
4722      // Print version 5 fields
4723      if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_COOKIE) {
4724        printf("  xstate_data.size_of_info     = %d\n",
4725               misc_info_.xstate_data.size_of_info);
4726        printf("  xstate_data.context_size     = %d\n",
4727               misc_info_.xstate_data.context_size);
4728        printf("  xstate_data.enabled_features = 0x%" PRIx64 "\n",
4729               misc_info_.xstate_data.enabled_features);
4730        for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) {
4731          if ((misc_info_.xstate_data.enabled_features >> i) & 1) {
4732            printf("  xstate_data.features[%02zu]     = { %d, %d }\n", i,
4733                   misc_info_.xstate_data.features[i].offset,
4734                   misc_info_.xstate_data.features[i].size);
4735          }
4736        }
4737        if (misc_info_.xstate_data.enabled_features == 0) {
4738          printf("  xstate_data.features[]       = (empty)\n");
4739        }
4740        printf("  process_cookie               = %d\n",
4741               misc_info_.process_cookie);
4742      } else {
4743        printf("  xstate_data.size_of_info     = (invalid)\n");
4744        printf("  xstate_data.context_size     = (invalid)\n");
4745        printf("  xstate_data.enabled_features = (invalid)\n");
4746        printf("  xstate_data.features[]       = (invalid)\n");
4747        printf("  process_cookie               = (invalid)\n");
4748      }
4749    }
4750    printf("\n");
4751  }
4752  
4753  
4754  //
4755  // MinidumpBreakpadInfo
4756  //
4757  
4758  
4759  MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
4760      : MinidumpStream(minidump),
4761        breakpad_info_() {
4762  }
4763  
4764  
4765  bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
4766    valid_ = false;
4767  
4768    if (expected_size != sizeof(breakpad_info_)) {
4769      BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
4770                      " != " << sizeof(breakpad_info_);
4771      return false;
4772    }
4773  
4774    if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
4775      BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
4776      return false;
4777    }
4778  
4779    if (minidump_->swap()) {
4780      Swap(&breakpad_info_.validity);
4781      Swap(&breakpad_info_.dump_thread_id);
4782      Swap(&breakpad_info_.requesting_thread_id);
4783    }
4784  
4785    valid_ = true;
4786    return true;
4787  }
4788  
4789  
4790  bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t* thread_id) const {
4791    BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
4792                                   "requires |thread_id|";
4793    assert(thread_id);
4794    *thread_id = 0;
4795  
4796    if (!valid_) {
4797      BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
4798      return false;
4799    }
4800  
4801    if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
4802      BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
4803      return false;
4804    }
4805  
4806    *thread_id = breakpad_info_.dump_thread_id;
4807    return true;
4808  }
4809  
4810  
4811  bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t* thread_id)
4812      const {
4813    BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
4814                                   "requires |thread_id|";
4815    assert(thread_id);
4816    *thread_id = 0;
4817  
4818    if (!thread_id || !valid_) {
4819      BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
4820      return false;
4821    }
4822  
4823    if (!(breakpad_info_.validity &
4824              MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
4825      BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
4826      return false;
4827    }
4828  
4829    *thread_id = breakpad_info_.requesting_thread_id;
4830    return true;
4831  }
4832  
4833  
4834  void MinidumpBreakpadInfo::Print() {
4835    if (!valid_) {
4836      BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
4837      return;
4838    }
4839  
4840    printf("MDRawBreakpadInfo\n");
4841    printf("  validity             = 0x%x\n", breakpad_info_.validity);
4842    printf("  dump_thread_id       = ");
4843    PrintValueOrInvalid(breakpad_info_.validity &
4844                            MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID,
4845                        kNumberFormatHexadecimal, breakpad_info_.dump_thread_id);
4846    printf("  requesting_thread_id = ");
4847    PrintValueOrInvalid(breakpad_info_.validity &
4848                            MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID,
4849                        kNumberFormatHexadecimal,
4850                        breakpad_info_.requesting_thread_id);
4851  
4852    printf("\n");
4853  }
4854  
4855  
4856  //
4857  // MinidumpMemoryInfo
4858  //
4859  
4860  
4861  MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
4862      : MinidumpObject(minidump),
4863        memory_info_() {
4864  }
4865  
4866  
4867  bool MinidumpMemoryInfo::IsExecutable() const {
4868    uint32_t protection =
4869        memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
4870    return protection == MD_MEMORY_PROTECT_EXECUTE ||
4871        protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
4872        protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
4873  }
4874  
4875  
4876  bool MinidumpMemoryInfo::IsWritable() const {
4877    uint32_t protection =
4878        memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
4879    return protection == MD_MEMORY_PROTECT_READWRITE ||
4880      protection == MD_MEMORY_PROTECT_WRITECOPY ||
4881      protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
4882      protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
4883  }
4884  
4885  
4886  bool MinidumpMemoryInfo::Read() {
4887    valid_ = false;
4888  
4889    if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
4890      BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
4891      return false;
4892    }
4893  
4894    if (minidump_->swap()) {
4895      Swap(&memory_info_.base_address);
4896      Swap(&memory_info_.allocation_base);
4897      Swap(&memory_info_.allocation_protection);
4898      Swap(&memory_info_.region_size);
4899      Swap(&memory_info_.state);
4900      Swap(&memory_info_.protection);
4901      Swap(&memory_info_.type);
4902    }
4903  
4904    // Check for base + size overflow or undersize.
4905    if (memory_info_.region_size == 0 ||
4906        memory_info_.region_size > numeric_limits<uint64_t>::max() -
4907                                       memory_info_.base_address) {
4908      BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
4909                      HexString(memory_info_.base_address) << "+" <<
4910                      HexString(memory_info_.region_size);
4911      return false;
4912    }
4913  
4914    valid_ = true;
4915    return true;
4916  }
4917  
4918  
4919  void MinidumpMemoryInfo::Print() {
4920    if (!valid_) {
4921      BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
4922      return;
4923    }
4924  
4925    printf("MDRawMemoryInfo\n");
4926    printf("  base_address          = 0x%" PRIx64 "\n",
4927           memory_info_.base_address);
4928    printf("  allocation_base       = 0x%" PRIx64 "\n",
4929           memory_info_.allocation_base);
4930    printf("  allocation_protection = 0x%x\n",
4931           memory_info_.allocation_protection);
4932    printf("  region_size           = 0x%" PRIx64 "\n", memory_info_.region_size);
4933    printf("  state                 = 0x%x\n", memory_info_.state);
4934    printf("  protection            = 0x%x\n", memory_info_.protection);
4935    printf("  type                  = 0x%x\n", memory_info_.type);
4936  }
4937  
4938  
4939  //
4940  // MinidumpMemoryInfoList
4941  //
4942  
4943  
4944  MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
4945      : MinidumpStream(minidump),
4946        range_map_(new RangeMap<uint64_t, unsigned int>()),
4947        infos_(NULL),
4948        info_count_(0) {
4949  }
4950  
4951  
4952  MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
4953    delete range_map_;
4954    delete infos_;
4955  }
4956  
4957  
4958  bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
4959    // Invalidate cached data.
4960    delete infos_;
4961    infos_ = NULL;
4962    range_map_->Clear();
4963    info_count_ = 0;
4964  
4965    valid_ = false;
4966  
4967    MDRawMemoryInfoList header;
4968    if (expected_size < sizeof(MDRawMemoryInfoList)) {
4969      BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
4970                      expected_size << " < " << sizeof(MDRawMemoryInfoList);
4971      return false;
4972    }
4973    if (!minidump_->ReadBytes(&header, sizeof(header))) {
4974      BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
4975      return false;
4976    }
4977  
4978    if (minidump_->swap()) {
4979      Swap(&header.size_of_header);
4980      Swap(&header.size_of_entry);
4981      Swap(&header.number_of_entries);
4982    }
4983  
4984    // Sanity check that the header is the expected size.
4985    // TODO(ted): could possibly handle this more gracefully, assuming
4986    // that future versions of the structs would be backwards-compatible.
4987    if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
4988      BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
4989                      header.size_of_header << " != " <<
4990                      sizeof(MDRawMemoryInfoList);
4991      return false;
4992    }
4993  
4994    // Sanity check that the entries are the expected size.
4995    if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
4996      BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
4997                      header.size_of_entry << " != " <<
4998                      sizeof(MDRawMemoryInfo);
4999      return false;
5000    }
5001  
5002    if (header.number_of_entries >
5003            numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
5004      BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
5005                      header.number_of_entries <<
5006                      " would cause multiplication overflow";
5007      return false;
5008    }
5009  
5010    if (expected_size != sizeof(MDRawMemoryInfoList) +
5011                          header.number_of_entries * sizeof(MDRawMemoryInfo)) {
5012      BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
5013                      " != " << sizeof(MDRawMemoryInfoList) +
5014                          header.number_of_entries * sizeof(MDRawMemoryInfo);
5015      return false;
5016    }
5017  
5018    // Check for data loss when converting header.number_of_entries from
5019    // uint64_t into MinidumpMemoryInfos::size_type (uint32_t)
5020    MinidumpMemoryInfos::size_type header_number_of_entries =
5021        static_cast<unsigned int>(header.number_of_entries);
5022    if (static_cast<uint64_t>(header_number_of_entries) !=
5023        header.number_of_entries) {
5024      BPLOG(ERROR) << "Data loss detected when converting "
5025                      "the header's number_of_entries";
5026      return false;
5027    }
5028  
5029    if (header.number_of_entries != 0) {
5030      scoped_ptr<MinidumpMemoryInfos> infos(
5031          new MinidumpMemoryInfos(header_number_of_entries,
5032                                  MinidumpMemoryInfo(minidump_)));
5033  
5034      for (unsigned int index = 0;
5035           index < header.number_of_entries;
5036           ++index) {
5037        MinidumpMemoryInfo* info = &(*infos)[index];
5038  
5039        // Assume that the file offset is correct after the last read.
5040        if (!info->Read()) {
5041          BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
5042                          index << "/" << header.number_of_entries;
5043          return false;
5044        }
5045  
5046        uint64_t base_address = info->GetBase();
5047        uint64_t region_size = info->GetSize();
5048  
5049        if (!range_map_->StoreRange(base_address, region_size, index)) {
5050          BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
5051                          " memory region " <<
5052                          index << "/" << header.number_of_entries << ", " <<
5053                          HexString(base_address) << "+" <<
5054                          HexString(region_size);
5055          return false;
5056        }
5057      }
5058  
5059      infos_ = infos.release();
5060    }
5061  
5062    info_count_ = static_cast<uint32_t>(header_number_of_entries);
5063  
5064    valid_ = true;
5065    return true;
5066  }
5067  
5068  
5069  const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
5070        unsigned int index) const {
5071    if (!valid_) {
5072      BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
5073      return NULL;
5074    }
5075  
5076    if (index >= info_count_) {
5077      BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
5078                      index << "/" << info_count_;
5079      return NULL;
5080    }
5081  
5082    return &(*infos_)[index];
5083  }
5084  
5085  
5086  const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
5087      uint64_t address) const {
5088    if (!valid_) {
5089      BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
5090                      " GetMemoryInfoForAddress";
5091      return NULL;
5092    }
5093  
5094    unsigned int info_index;
5095    if (!range_map_->RetrieveRange(address, &info_index, NULL /* base */,
5096                                   NULL /* delta */, NULL /* size */)) {
5097      BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
5098                     HexString(address);
5099      return NULL;
5100    }
5101  
5102    return GetMemoryInfoAtIndex(info_index);
5103  }
5104  
5105  
5106  void MinidumpMemoryInfoList::Print() {
5107    if (!valid_) {
5108      BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
5109      return;
5110    }
5111  
5112    printf("MinidumpMemoryInfoList\n");
5113    printf("  info_count = %d\n", info_count_);
5114    printf("\n");
5115  
5116    for (unsigned int info_index = 0;
5117         info_index < info_count_;
5118         ++info_index) {
5119      printf("info[%d]\n", info_index);
5120      (*infos_)[info_index].Print();
5121      printf("\n");
5122    }
5123  }
5124  
5125  //
5126  // MinidumpLinuxMaps
5127  //
5128  
5129  MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump* minidump)
5130      : MinidumpObject(minidump) {
5131  }
5132  
5133  void MinidumpLinuxMaps::Print() const {
5134    if (!valid_) {
5135      BPLOG(ERROR) << "MinidumpLinuxMaps cannot print invalid data";
5136      return;
5137    }
5138    std::cout << region_.line << std::endl;
5139  }
5140  
5141  //
5142  // MinidumpLinuxMapsList
5143  //
5144  
5145  MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump* minidump)
5146      : MinidumpStream(minidump),
5147        maps_(NULL),
5148        maps_count_(0) {
5149  }
5150  
5151  MinidumpLinuxMapsList::~MinidumpLinuxMapsList() {
5152    if (maps_) {
5153      for (unsigned int i = 0; i < maps_->size(); i++) {
5154        delete (*maps_)[i];
5155      }
5156      delete maps_;
5157    }
5158  }
5159  
5160  const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress(
5161      uint64_t address) const {
5162    if (!valid_ || (maps_ == NULL)) {
5163      BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress";
5164      return NULL;
5165    }
5166  
5167    // Search every memory mapping.
5168    for (unsigned int index = 0; index < maps_count_; index++) {
5169      // Check if address is within bounds of the current memory region.
5170      if ((*maps_)[index]->GetBase() <= address &&
5171          (*maps_)[index]->GetBase() + (*maps_)[index]->GetSize() > address) {
5172        return (*maps_)[index];
5173      }
5174    }
5175  
5176    // No mapping encloses the memory address.
5177    BPLOG(ERROR) << "MinidumpLinuxMapsList has no mapping at "
5178                 << HexString(address);
5179    return NULL;
5180  }
5181  
5182  const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsAtIndex(
5183      unsigned int index) const {
5184    if (!valid_ || (maps_ == NULL)) {
5185      BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex";
5186      return NULL;
5187    }
5188  
5189    // Index out of bounds.
5190    if (index >= maps_count_ || (maps_ == NULL)) {
5191      BPLOG(ERROR) << "MinidumpLinuxMapsList index of out range: "
5192                   << index
5193                   << "/"
5194                   << maps_count_;
5195      return NULL;
5196    }
5197    return (*maps_)[index];
5198  }
5199  
5200  bool MinidumpLinuxMapsList::Read(uint32_t expected_size) {
5201    // Invalidate cached data.
5202    if (maps_) {
5203      for (unsigned int i = 0; i < maps_->size(); i++) {
5204        delete (*maps_)[i];
5205      }
5206      delete maps_;
5207    }
5208    maps_ = NULL;
5209    maps_count_ = 0;
5210  
5211    valid_ = false;
5212  
5213    // Load and check expected stream length.
5214    uint32_t length = 0;
5215    if (!minidump_->SeekToStreamType(MD_LINUX_MAPS, &length)) {
5216      BPLOG(ERROR) << "MinidumpLinuxMapsList stream type not found";
5217      return false;
5218    }
5219    if (expected_size != length) {
5220      BPLOG(ERROR) << "MinidumpLinuxMapsList size mismatch: "
5221                   << expected_size
5222                   << " != "
5223                   << length;
5224      return false;
5225    }
5226  
5227    // Create a vector to read stream data. The vector needs to have
5228    // at least enough capacity to read all the data.
5229    vector<char> mapping_bytes(length);
5230    if (!minidump_->ReadBytes(&mapping_bytes[0], length)) {
5231      BPLOG(ERROR) << "MinidumpLinuxMapsList failed to read bytes";
5232      return false;
5233    }
5234    string map_string(mapping_bytes.begin(), mapping_bytes.end());
5235    vector<MappedMemoryRegion> all_regions;
5236  
5237    // Parse string into mapping data.
5238    if (!ParseProcMaps(map_string, &all_regions)) {
5239      return false;
5240    }
5241  
5242    scoped_ptr<MinidumpLinuxMappings> maps(new MinidumpLinuxMappings());
5243  
5244    // Push mapping data into wrapper classes.
5245    for (size_t i = 0; i < all_regions.size(); i++) {
5246      scoped_ptr<MinidumpLinuxMaps> ele(new MinidumpLinuxMaps(minidump_));
5247      ele->region_ = all_regions[i];
5248      ele->valid_ = true;
5249      maps->push_back(ele.release());
5250    }
5251  
5252    // Set instance variables.
5253    maps_ = maps.release();
5254    maps_count_ = static_cast<uint32_t>(maps_->size());
5255    valid_ = true;
5256    return true;
5257  }
5258  
5259  void MinidumpLinuxMapsList::Print() const {
5260    if (!valid_ || (maps_ == NULL)) {
5261      BPLOG(ERROR) << "MinidumpLinuxMapsList cannot print valid data";
5262      return;
5263    }
5264    for (size_t i = 0; i < maps_->size(); i++) {
5265      (*maps_)[i]->Print();
5266    }
5267  }
5268  
5269  //
5270  // MinidumpCrashpadInfo
5271  //
5272  
5273  
5274  MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
5275      : MinidumpStream(minidump),
5276        crashpad_info_(),
5277        module_crashpad_info_links_(),
5278        module_crashpad_info_(),
5279        module_crashpad_info_list_annotations_(),
5280        module_crashpad_info_simple_annotations_(),
5281        module_crashpad_info_annotation_objects_(),
5282        simple_annotations_() {
5283  }
5284  
5285  
5286  bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
5287    valid_ = false;
5288  
5289    // Support old minidumps that do not implement newer crashpad_info_
5290    // fields, currently limited to the address mask.
5291    static_assert(sizeof(crashpad_info_) == 64,
5292                  "Updated ::Read for new crashpad_info field.");
5293  
5294    constexpr size_t crashpad_info_min_size =
5295        offsetof(decltype(crashpad_info_), reserved);
5296    if (expected_size < crashpad_info_min_size) {
5297      BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size
5298                   << " < " << crashpad_info_min_size;
5299      return false;
5300    }
5301  
5302    if (!minidump_->ReadBytes(&crashpad_info_, crashpad_info_min_size)) {
5303      BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info";
5304      return false;
5305    }
5306    expected_size -= crashpad_info_min_size;
5307  
5308    // Read `reserved` if available.
5309    size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved);
5310    if (expected_size >= crashpad_reserved_size) {
5311      if (!minidump_->ReadBytes(
5312              &crashpad_info_.reserved,
5313              crashpad_reserved_size)) {
5314        BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read reserved";
5315        return false;
5316      }
5317      expected_size -= crashpad_reserved_size;
5318    } else {
5319      crashpad_info_.reserved = 0;
5320    }
5321  
5322    // Read `address_mask` if available.
5323    size_t crashpad_address_mask_size = sizeof(crashpad_info_.address_mask);
5324    if (expected_size >= crashpad_address_mask_size) {
5325      if (!minidump_->ReadBytes(
5326              &crashpad_info_.address_mask,
5327              crashpad_address_mask_size)) {
5328        BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read address mask";
5329        return false;
5330      }
5331      expected_size -= crashpad_address_mask_size;
5332    } else {
5333      crashpad_info_.address_mask = 0;
5334    }
5335  
5336    if (minidump_->swap()) {
5337      Swap(&crashpad_info_.version);
5338      Swap(&crashpad_info_.report_id);
5339      Swap(&crashpad_info_.client_id);
5340      Swap(&crashpad_info_.simple_annotations);
5341      Swap(&crashpad_info_.module_list);
5342      Swap(&crashpad_info_.reserved);
5343      Swap(&crashpad_info_.address_mask);
5344    }
5345  
5346    if (crashpad_info_.simple_annotations.data_size) {
5347      if (!minidump_->ReadSimpleStringDictionary(
5348          crashpad_info_.simple_annotations.rva,
5349          &simple_annotations_)) {
5350        BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read simple_annotations";
5351        return false;
5352      }
5353    }
5354  
5355    if (crashpad_info_.module_list.data_size) {
5356      if (!minidump_->SeekSet(crashpad_info_.module_list.rva)) {
5357        BPLOG(ERROR) << "MinidumpCrashpadInfo cannot seek to module_list";
5358        return false;
5359      }
5360  
5361      uint32_t count;
5362      if (!minidump_->ReadBytes(&count, sizeof(count))) {
5363        BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read module_list count";
5364        return false;
5365      }
5366  
5367      if (minidump_->swap()) {
5368        Swap(&count);
5369      }
5370  
5371      scoped_array<MDRawModuleCrashpadInfoLink> module_crashpad_info_links(
5372          new MDRawModuleCrashpadInfoLink[count]);
5373  
5374      // Read the entire array in one fell swoop, instead of reading one entry
5375      // at a time in the loop.
5376      if (!minidump_->ReadBytes(
5377              &module_crashpad_info_links[0],
5378              sizeof(MDRawModuleCrashpadInfoLink) * count)) {
5379        BPLOG(ERROR)
5380            << "MinidumpCrashpadInfo could not read Crashpad module links";
5381        return false;
5382      }
5383  
5384      for (uint32_t index = 0; index < count; ++index) {
5385        if (minidump_->swap()) {
5386          Swap(&module_crashpad_info_links[index].minidump_module_list_index);
5387          Swap(&module_crashpad_info_links[index].location);
5388        }
5389  
5390        if (!minidump_->SeekSet(module_crashpad_info_links[index].location.rva)) {
5391          BPLOG(ERROR)
5392              << "MinidumpCrashpadInfo cannot seek to Crashpad module info";
5393          return false;
5394        }
5395  
5396        MDRawModuleCrashpadInfo module_crashpad_info;
5397        if (!minidump_->ReadBytes(&module_crashpad_info,
5398                                  sizeof(module_crashpad_info))) {
5399          BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module info";
5400          return false;
5401        }
5402  
5403        if (minidump_->swap()) {
5404          Swap(&module_crashpad_info.version);
5405          Swap(&module_crashpad_info.list_annotations);
5406          Swap(&module_crashpad_info.simple_annotations);
5407          Swap(&module_crashpad_info.annotation_objects);
5408        }
5409  
5410        std::vector<std::string> list_annotations;
5411        if (module_crashpad_info.list_annotations.data_size) {
5412          if (!minidump_->ReadStringList(
5413                  module_crashpad_info.list_annotations.rva,
5414                  &list_annotations)) {
5415            BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
5416                "info list annotations";
5417            return false;
5418          }
5419        }
5420  
5421        std::map<std::string, std::string> simple_annotations;
5422        if (module_crashpad_info.simple_annotations.data_size) {
5423          if (!minidump_->ReadSimpleStringDictionary(
5424                  module_crashpad_info.simple_annotations.rva,
5425                  &simple_annotations)) {
5426            BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
5427                "info simple annotations";
5428            return false;
5429          }
5430        }
5431  
5432        std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects;
5433        if (module_crashpad_info.annotation_objects.data_size) {
5434          if (!minidump_->ReadCrashpadAnnotationsList(
5435                  module_crashpad_info.annotation_objects.rva,
5436                  &annotation_objects)) {
5437            BPLOG(ERROR)
5438                << "MinidumpCrashpadInfo cannot read Crashpad annotations list";
5439            return false;
5440          }
5441        }
5442  
5443        module_crashpad_info_links_.push_back(
5444            module_crashpad_info_links[index].minidump_module_list_index);
5445        module_crashpad_info_.push_back(module_crashpad_info);
5446        module_crashpad_info_list_annotations_.push_back(list_annotations);
5447        module_crashpad_info_simple_annotations_.push_back(simple_annotations);
5448        module_crashpad_info_annotation_objects_.push_back(annotation_objects);
5449      }
5450    }
5451  
5452    valid_ = true;
5453    return true;
5454  }
5455  
5456  
5457  void MinidumpCrashpadInfo::Print() {
5458    if (!valid_) {
5459      BPLOG(ERROR) << "MinidumpCrashpadInfo cannot print invalid data";
5460      return;
5461    }
5462  
5463    printf("MDRawCrashpadInfo\n");
5464    printf("  version = %d\n", crashpad_info_.version);
5465    printf("  report_id = %s\n",
5466           MDGUIDToString(crashpad_info_.report_id).c_str());
5467    printf("  client_id = %s\n",
5468           MDGUIDToString(crashpad_info_.client_id).c_str());
5469    for (const auto& annot : simple_annotations_) {
5470      printf("  simple_annotations[\"%s\"] = %s\n", annot.first.c_str(),
5471             annot.second.c_str());
5472    }
5473    for (uint32_t module_index = 0;
5474         module_index < module_crashpad_info_links_.size();
5475         ++module_index) {
5476      printf("  module_list[%d].minidump_module_list_index = %d\n",
5477             module_index, module_crashpad_info_links_[module_index]);
5478      printf("  module_list[%d].version = %d\n",
5479             module_index, module_crashpad_info_[module_index].version);
5480      const auto& list_annots =
5481          module_crashpad_info_list_annotations_[module_index];
5482      for (uint32_t annotation_index = 0; annotation_index < list_annots.size();
5483           ++annotation_index) {
5484        printf("  module_list[%d].list_annotations[%d] = %s\n", module_index,
5485               annotation_index, list_annots[annotation_index].c_str());
5486      }
5487      const auto& simple_annots =
5488          module_crashpad_info_simple_annotations_[module_index];
5489      for (const auto& annot : simple_annots) {
5490        printf("  module_list[%d].simple_annotations[\"%s\"] = %s\n",
5491               module_index, annot.first.c_str(), annot.second.c_str());
5492      }
5493      const auto& crashpad_annots =
5494          module_crashpad_info_annotation_objects_[module_index];
5495      for (const AnnotationObject& annot : crashpad_annots) {
5496        std::string str_value;
5497        if (annot.type == 1) {
5498          // Value represents a C-style string.
5499          for (const uint8_t& v : annot.value) {
5500            str_value.append(1, static_cast<char>(v));
5501          }
5502        } else {
5503          // Value represents something else.
5504          char buffer[3];
5505          for (const uint8_t& v : annot.value) {
5506            snprintf(buffer, sizeof(buffer), "%02X", v);
5507            str_value.append(buffer);
5508          }
5509        }
5510        printf(
5511            "  module_list[%d].crashpad_annotations[\"%s\"] (type = %u) = %s\n",
5512            module_index, annot.name.c_str(), annot.type, str_value.c_str());
5513      }
5514      printf("  address_mask = %" PRIu64 "\n", crashpad_info_.address_mask);
5515    }
5516  
5517    printf("\n");
5518  }
5519  
5520  
5521  //
5522  // Minidump
5523  //
5524  
5525  
5526  uint32_t Minidump::max_streams_ = 128;
5527  unsigned int Minidump::max_string_length_ = 1024;
5528  
5529  
5530  Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width)
5531      : header_(),
5532        directory_(NULL),
5533        stream_map_(new MinidumpStreamMap()),
5534        path_(path),
5535        stream_(NULL),
5536        swap_(false),
5537        is_big_endian_(false),
5538        valid_(false),
5539        hexdump_(hexdump),
5540        hexdump_width_(hexdump_width) {
5541  }
5542  
5543  Minidump::Minidump(istream& stream)
5544      : header_(),
5545        directory_(NULL),
5546        stream_map_(new MinidumpStreamMap()),
5547        path_(),
5548        stream_(&stream),
5549        swap_(false),
5550        is_big_endian_(false),
5551        valid_(false),
5552        hexdump_(false),
5553        hexdump_width_(0) {
5554  }
5555  
5556  Minidump::~Minidump() {
5557    if (stream_) {
5558      BPLOG(INFO) << "Minidump closing minidump";
5559    }
5560    if (!path_.empty()) {
5561      delete stream_;
5562    }
5563    delete directory_;
5564    delete stream_map_;
5565  }
5566  
5567  
5568  bool Minidump::Open() {
5569    if (stream_ != NULL) {
5570      BPLOG(INFO) << "Minidump reopening minidump " << path_;
5571  
5572      // The file is already open.  Seek to the beginning, which is the position
5573      // the file would be at if it were opened anew.
5574      return SeekSet(0);
5575    }
5576  
5577    stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
5578    if (!stream_ || !stream_->good()) {
5579      string error_string;
5580      int error_code = ErrnoString(&error_string);
5581      BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
5582                      ", error " << error_code << ": " << error_string;
5583      return false;
5584    }
5585  
5586    BPLOG(INFO) << "Minidump opened minidump " << path_;
5587    return true;
5588  }
5589  
5590  bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) {
5591    // Initialize output parameters
5592    *context_cpu_flags = 0;
5593  
5594    // Save the current stream position
5595    off_t saved_position = Tell();
5596    if (saved_position == -1) {
5597      // Failed to save the current stream position.
5598      // Returns true because the current position of the stream is preserved.
5599      return true;
5600    }
5601  
5602    const MDRawSystemInfo* system_info =
5603      GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
5604  
5605    if (system_info != NULL) {
5606      switch (system_info->processor_architecture) {
5607        case MD_CPU_ARCHITECTURE_X86:
5608          *context_cpu_flags = MD_CONTEXT_X86;
5609          break;
5610        case MD_CPU_ARCHITECTURE_MIPS:
5611          *context_cpu_flags = MD_CONTEXT_MIPS;
5612          break;
5613        case MD_CPU_ARCHITECTURE_MIPS64:
5614          *context_cpu_flags = MD_CONTEXT_MIPS64;
5615          break;
5616        case MD_CPU_ARCHITECTURE_ALPHA:
5617          *context_cpu_flags = MD_CONTEXT_ALPHA;
5618          break;
5619        case MD_CPU_ARCHITECTURE_PPC:
5620          *context_cpu_flags = MD_CONTEXT_PPC;
5621          break;
5622        case MD_CPU_ARCHITECTURE_PPC64:
5623          *context_cpu_flags = MD_CONTEXT_PPC64;
5624          break;
5625        case MD_CPU_ARCHITECTURE_SHX:
5626          *context_cpu_flags = MD_CONTEXT_SHX;
5627          break;
5628        case MD_CPU_ARCHITECTURE_ARM:
5629          *context_cpu_flags = MD_CONTEXT_ARM;
5630          break;
5631        case MD_CPU_ARCHITECTURE_ARM64:
5632          *context_cpu_flags = MD_CONTEXT_ARM64;
5633          break;
5634        case MD_CPU_ARCHITECTURE_ARM64_OLD:
5635          *context_cpu_flags = MD_CONTEXT_ARM64_OLD;
5636          break;
5637        case MD_CPU_ARCHITECTURE_IA64:
5638          *context_cpu_flags = MD_CONTEXT_IA64;
5639          break;
5640        case MD_CPU_ARCHITECTURE_ALPHA64:
5641          *context_cpu_flags = 0;
5642          break;
5643        case MD_CPU_ARCHITECTURE_MSIL:
5644          *context_cpu_flags = 0;
5645          break;
5646        case MD_CPU_ARCHITECTURE_AMD64:
5647          *context_cpu_flags = MD_CONTEXT_AMD64;
5648          break;
5649        case MD_CPU_ARCHITECTURE_X86_WIN64:
5650          *context_cpu_flags = 0;
5651          break;
5652        case MD_CPU_ARCHITECTURE_SPARC:
5653          *context_cpu_flags = MD_CONTEXT_SPARC;
5654          break;
5655        case MD_CPU_ARCHITECTURE_RISCV:
5656          *context_cpu_flags = MD_CONTEXT_RISCV;
5657          break;
5658        case MD_CPU_ARCHITECTURE_RISCV64:
5659          *context_cpu_flags = MD_CONTEXT_RISCV64;
5660          break;
5661        case MD_CPU_ARCHITECTURE_UNKNOWN:
5662          *context_cpu_flags = 0;
5663          break;
5664        default:
5665          *context_cpu_flags = 0;
5666          break;
5667      }
5668    }
5669  
5670    // Restore position and return
5671    return SeekSet(saved_position);
5672  }
5673  
5674  
5675  bool Minidump::Read() {
5676    // Invalidate cached data.
5677    delete directory_;
5678    directory_ = NULL;
5679    stream_map_->clear();
5680  
5681    valid_ = false;
5682  
5683    if (!Open()) {
5684      BPLOG(ERROR) << "Minidump cannot open minidump";
5685      return false;
5686    }
5687  
5688    if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
5689      BPLOG(ERROR) << "Minidump cannot read header";
5690      return false;
5691    }
5692  
5693    if (header_.signature != MD_HEADER_SIGNATURE) {
5694      // The file may be byte-swapped.  Under the present architecture, these
5695      // classes don't know or need to know what CPU (or endianness) the
5696      // minidump was produced on in order to parse it.  Use the signature as
5697      // a byte order marker.
5698      uint32_t signature_swapped = header_.signature;
5699      Swap(&signature_swapped);
5700      if (signature_swapped != MD_HEADER_SIGNATURE) {
5701        // This isn't a minidump or a byte-swapped minidump.
5702        BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
5703                        HexString(header_.signature) << ", " <<
5704                        HexString(signature_swapped) << ") != " <<
5705                        HexString(MD_HEADER_SIGNATURE);
5706        return false;
5707      }
5708      swap_ = true;
5709    } else {
5710      // The file is not byte-swapped.  Set swap_ false (it may have been true
5711      // if the object is being reused?)
5712      swap_ = false;
5713    }
5714  
5715  #if defined(__BIG_ENDIAN__) || \
5716    (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
5717    is_big_endian_ = !swap_;
5718  #else
5719    is_big_endian_ = swap_;
5720  #endif
5721  
5722    BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
5723                   "byte-swapping minidump";
5724  
5725    if (swap_) {
5726      Swap(&header_.signature);
5727      Swap(&header_.version);
5728      Swap(&header_.stream_count);
5729      Swap(&header_.stream_directory_rva);
5730      Swap(&header_.checksum);
5731      Swap(&header_.time_date_stamp);
5732      Swap(&header_.flags);
5733    }
5734  
5735    // Version check.  The high 16 bits of header_.version contain something
5736    // else "implementation specific."
5737    if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
5738      BPLOG(ERROR) << "Minidump version mismatch: " <<
5739                      HexString(header_.version & 0x0000ffff) << " != " <<
5740                      HexString(MD_HEADER_VERSION);
5741      return false;
5742    }
5743  
5744    if (!SeekSet(header_.stream_directory_rva)) {
5745      BPLOG(ERROR) << "Minidump cannot seek to stream directory";
5746      return false;
5747    }
5748  
5749    if (header_.stream_count > max_streams_) {
5750      BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
5751                      " exceeds maximum " << max_streams_;
5752      return false;
5753    }
5754  
5755    if (header_.stream_count != 0) {
5756      scoped_ptr<MinidumpDirectoryEntries> directory(
5757          new MinidumpDirectoryEntries(header_.stream_count));
5758  
5759      // Read the entire array in one fell swoop, instead of reading one entry
5760      // at a time in the loop.
5761      if (!ReadBytes(&(*directory)[0],
5762                     sizeof(MDRawDirectory) * header_.stream_count)) {
5763        BPLOG(ERROR) << "Minidump cannot read stream directory";
5764        return false;
5765      }
5766  
5767      for (unsigned int stream_index = 0;
5768           stream_index < header_.stream_count;
5769           ++stream_index) {
5770        MDRawDirectory* directory_entry = &(*directory)[stream_index];
5771  
5772        if (swap_) {
5773          Swap(&directory_entry->stream_type);
5774          Swap(&directory_entry->location);
5775        }
5776  
5777        // Initialize the stream_map_ map, which speeds locating a stream by
5778        // type.
5779        unsigned int stream_type = directory_entry->stream_type;
5780        switch (stream_type) {
5781          case MD_THREAD_LIST_STREAM:
5782          case MD_THREAD_NAME_LIST_STREAM:
5783          case MD_MODULE_LIST_STREAM:
5784          case MD_MEMORY_LIST_STREAM:
5785          case MD_EXCEPTION_STREAM:
5786          case MD_SYSTEM_INFO_STREAM:
5787          case MD_MISC_INFO_STREAM:
5788          case MD_BREAKPAD_INFO_STREAM:
5789          case MD_CRASHPAD_INFO_STREAM: {
5790            if (stream_map_->find(stream_type) != stream_map_->end()) {
5791              // Another stream with this type was already found.  A minidump
5792              // file should contain at most one of each of these stream types.
5793              BPLOG(ERROR) << "Minidump found multiple streams of type " <<
5794                              stream_type << ", but can only deal with one";
5795              return false;
5796            }
5797            BP_FALLTHROUGH;
5798          }
5799  
5800          default: {
5801            // Overwrites for stream types other than those above, but it's
5802            // expected to be the user's burden in that case.
5803            (*stream_map_)[stream_type].stream_index = stream_index;
5804          }
5805        }
5806      }
5807  
5808      directory_ = directory.release();
5809    }
5810  
5811    valid_ = true;
5812    return true;
5813  }
5814  
5815  
5816  MinidumpThreadList* Minidump::GetThreadList() {
5817    MinidumpThreadList* thread_list;
5818    return GetStream(&thread_list);
5819  }
5820  
5821  MinidumpThreadNameList* Minidump::GetThreadNameList() {
5822    MinidumpThreadNameList* thread_name_list;
5823    return GetStream(&thread_name_list);
5824  }
5825  
5826  MinidumpModuleList* Minidump::GetModuleList() {
5827    MinidumpModuleList* module_list;
5828    return GetStream(&module_list);
5829  }
5830  
5831  
5832  MinidumpMemoryList* Minidump::GetMemoryList() {
5833    MinidumpMemoryList* memory_list;
5834    return GetStream(&memory_list);
5835  }
5836  
5837  
5838  MinidumpException* Minidump::GetException() {
5839    MinidumpException* exception;
5840    return GetStream(&exception);
5841  }
5842  
5843  MinidumpAssertion* Minidump::GetAssertion() {
5844    MinidumpAssertion* assertion;
5845    return GetStream(&assertion);
5846  }
5847  
5848  
5849  MinidumpSystemInfo* Minidump::GetSystemInfo() {
5850    MinidumpSystemInfo* system_info;
5851    return GetStream(&system_info);
5852  }
5853  
5854  
5855  MinidumpUnloadedModuleList* Minidump::GetUnloadedModuleList() {
5856    MinidumpUnloadedModuleList* unloaded_module_list;
5857    return GetStream(&unloaded_module_list);
5858  }
5859  
5860  
5861  MinidumpMiscInfo* Minidump::GetMiscInfo() {
5862    MinidumpMiscInfo* misc_info;
5863    return GetStream(&misc_info);
5864  }
5865  
5866  
5867  MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
5868    MinidumpBreakpadInfo* breakpad_info;
5869    return GetStream(&breakpad_info);
5870  }
5871  
5872  MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
5873    MinidumpMemoryInfoList* memory_info_list;
5874    return GetStream(&memory_info_list);
5875  }
5876  
5877  MinidumpLinuxMapsList* Minidump::GetLinuxMapsList() {
5878    MinidumpLinuxMapsList* linux_maps_list;
5879    return GetStream(&linux_maps_list);
5880  }
5881  
5882  bool Minidump::IsAndroid() {
5883    MDOSPlatform platform;
5884    return GetPlatform(&platform) && platform == MD_OS_ANDROID;
5885  }
5886  
5887  bool Minidump::GetPlatform(MDOSPlatform* platform) {
5888    // Save the current stream position
5889    off_t saved_position = Tell();
5890    if (saved_position == -1) {
5891      return false;
5892    }
5893    const MDRawSystemInfo* system_info =
5894      GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
5895  
5896    // Restore position and return
5897    if (!SeekSet(saved_position)) {
5898      BPLOG(ERROR) << "Couldn't seek back to saved position";
5899      return false;
5900    }
5901  
5902    if (!system_info) {
5903      return false;
5904    }
5905    *platform = static_cast<MDOSPlatform>(system_info->platform_id);
5906    return true;
5907  }
5908  
5909  MinidumpCrashpadInfo* Minidump::GetCrashpadInfo() {
5910    MinidumpCrashpadInfo* crashpad_info;
5911    return GetStream(&crashpad_info);
5912  }
5913  
5914  static const char* get_stream_name(uint32_t stream_type) {
5915    switch (stream_type) {
5916    case MD_UNUSED_STREAM:
5917      return "MD_UNUSED_STREAM";
5918    case MD_RESERVED_STREAM_0:
5919      return "MD_RESERVED_STREAM_0";
5920    case MD_RESERVED_STREAM_1:
5921      return "MD_RESERVED_STREAM_1";
5922    case MD_THREAD_LIST_STREAM:
5923      return "MD_THREAD_LIST_STREAM";
5924    case MD_THREAD_NAME_LIST_STREAM:
5925      return "MD_THREAD_NAME_LIST_STREAM";
5926    case MD_MODULE_LIST_STREAM:
5927      return "MD_MODULE_LIST_STREAM";
5928    case MD_MEMORY_LIST_STREAM:
5929      return "MD_MEMORY_LIST_STREAM";
5930    case MD_EXCEPTION_STREAM:
5931      return "MD_EXCEPTION_STREAM";
5932    case MD_SYSTEM_INFO_STREAM:
5933      return "MD_SYSTEM_INFO_STREAM";
5934    case MD_THREAD_EX_LIST_STREAM:
5935      return "MD_THREAD_EX_LIST_STREAM";
5936    case MD_MEMORY_64_LIST_STREAM:
5937      return "MD_MEMORY_64_LIST_STREAM";
5938    case MD_COMMENT_STREAM_A:
5939      return "MD_COMMENT_STREAM_A";
5940    case MD_COMMENT_STREAM_W:
5941      return "MD_COMMENT_STREAM_W";
5942    case MD_HANDLE_DATA_STREAM:
5943      return "MD_HANDLE_DATA_STREAM";
5944    case MD_FUNCTION_TABLE_STREAM:
5945      return "MD_FUNCTION_TABLE_STREAM";
5946    case MD_UNLOADED_MODULE_LIST_STREAM:
5947      return "MD_UNLOADED_MODULE_LIST_STREAM";
5948    case MD_MISC_INFO_STREAM:
5949      return "MD_MISC_INFO_STREAM";
5950    case MD_MEMORY_INFO_LIST_STREAM:
5951      return "MD_MEMORY_INFO_LIST_STREAM";
5952    case MD_THREAD_INFO_LIST_STREAM:
5953      return "MD_THREAD_INFO_LIST_STREAM";
5954    case MD_HANDLE_OPERATION_LIST_STREAM:
5955      return "MD_HANDLE_OPERATION_LIST_STREAM";
5956    case MD_TOKEN_STREAM:
5957      return "MD_TOKEN_STREAM";
5958    case MD_JAVASCRIPT_DATA_STREAM:
5959      return "MD_JAVASCRIPT_DATA_STREAM";
5960    case MD_SYSTEM_MEMORY_INFO_STREAM:
5961      return "MD_SYSTEM_MEMORY_INFO_STREAM";
5962    case MD_PROCESS_VM_COUNTERS_STREAM:
5963      return "MD_PROCESS_VM_COUNTERS_STREAM";
5964    case MD_LAST_RESERVED_STREAM:
5965      return "MD_LAST_RESERVED_STREAM";
5966    case MD_BREAKPAD_INFO_STREAM:
5967      return "MD_BREAKPAD_INFO_STREAM";
5968    case MD_ASSERTION_INFO_STREAM:
5969      return "MD_ASSERTION_INFO_STREAM";
5970    case MD_LINUX_CPU_INFO:
5971      return "MD_LINUX_CPU_INFO";
5972    case MD_LINUX_PROC_STATUS:
5973      return "MD_LINUX_PROC_STATUS";
5974    case MD_LINUX_LSB_RELEASE:
5975      return "MD_LINUX_LSB_RELEASE";
5976    case MD_LINUX_CMD_LINE:
5977      return "MD_LINUX_CMD_LINE";
5978    case MD_LINUX_ENVIRON:
5979      return "MD_LINUX_ENVIRON";
5980    case MD_LINUX_AUXV:
5981      return "MD_LINUX_AUXV";
5982    case MD_LINUX_MAPS:
5983      return "MD_LINUX_MAPS";
5984    case MD_LINUX_DSO_DEBUG:
5985      return "MD_LINUX_DSO_DEBUG";
5986    case MD_CRASHPAD_INFO_STREAM:
5987      return "MD_CRASHPAD_INFO_STREAM";
5988    default:
5989      return "unknown";
5990    }
5991  }
5992  
5993  void Minidump::Print() {
5994    if (!valid_) {
5995      BPLOG(ERROR) << "Minidump cannot print invalid data";
5996      return;
5997    }
5998  
5999    printf("MDRawHeader\n");
6000    printf("  signature            = 0x%x\n",    header_.signature);
6001    printf("  version              = 0x%x\n",    header_.version);
6002    printf("  stream_count         = %d\n",      header_.stream_count);
6003    printf("  stream_directory_rva = 0x%x\n",    header_.stream_directory_rva);
6004    printf("  checksum             = 0x%x\n",    header_.checksum);
6005    printf("  time_date_stamp      = 0x%x %s\n",
6006           header_.time_date_stamp,
6007           TimeTToUTCString(header_.time_date_stamp).c_str());
6008    printf("  flags                = 0x%" PRIx64 "\n",  header_.flags);
6009    printf("\n");
6010  
6011    for (unsigned int stream_index = 0;
6012         stream_index < header_.stream_count;
6013         ++stream_index) {
6014      MDRawDirectory* directory_entry = &(*directory_)[stream_index];
6015  
6016      printf("mDirectory[%d]\n", stream_index);
6017      printf("MDRawDirectory\n");
6018      printf("  stream_type        = 0x%x (%s)\n", directory_entry->stream_type,
6019             get_stream_name(directory_entry->stream_type));
6020      printf("  location.data_size = %d\n",
6021             directory_entry->location.data_size);
6022      printf("  location.rva       = 0x%x\n", directory_entry->location.rva);
6023      printf("\n");
6024    }
6025  
6026    printf("Streams:\n");
6027    for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
6028         iterator != stream_map_->end();
6029         ++iterator) {
6030      uint32_t stream_type = iterator->first;
6031      const MinidumpStreamInfo& info = iterator->second;
6032      printf("  stream type 0x%x (%s) at index %d\n", stream_type,
6033             get_stream_name(stream_type),
6034             info.stream_index);
6035    }
6036    printf("\n");
6037  }
6038  
6039  
6040  const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
6041        const {
6042    if (!valid_) {
6043      BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
6044      return NULL;
6045    }
6046  
6047    if (index >= header_.stream_count) {
6048      BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
6049                      index << "/" << header_.stream_count;
6050      return NULL;
6051    }
6052  
6053    return &(*directory_)[index];
6054  }
6055  
6056  
6057  bool Minidump::ReadBytes(void* bytes, size_t count) {
6058    // Can't check valid_ because Read needs to call this method before
6059    // validity can be determined.
6060    if (!stream_) {
6061      return false;
6062    }
6063    stream_->read(static_cast<char*>(bytes), count);
6064    std::streamsize bytes_read = stream_->gcount();
6065    if (bytes_read == -1) {
6066      string error_string;
6067      int error_code = ErrnoString(&error_string);
6068      BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
6069      return false;
6070    }
6071  
6072    // Convert to size_t and check for data loss
6073    size_t bytes_read_converted = static_cast<size_t>(bytes_read);
6074    if (static_cast<std::streamsize>(bytes_read_converted) != bytes_read) {
6075      BPLOG(ERROR) << "ReadBytes: conversion data loss detected when converting "
6076                   << bytes_read << " to " << bytes_read_converted;
6077      return false;
6078    }
6079  
6080    if (bytes_read_converted != count) {
6081      BPLOG(ERROR) << "ReadBytes: read " << bytes_read_converted << "/" << count;
6082      return false;
6083    }
6084  
6085    return true;
6086  }
6087  
6088  
6089  bool Minidump::SeekSet(off_t offset) {
6090    // Can't check valid_ because Read needs to call this method before
6091    // validity can be determined.
6092    if (!stream_) {
6093      return false;
6094    }
6095    stream_->seekg(offset, std::ios_base::beg);
6096    if (!stream_->good()) {
6097      string error_string;
6098      int error_code = ErrnoString(&error_string);
6099      BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
6100      return false;
6101    }
6102    return true;
6103  }
6104  
6105  off_t Minidump::Tell() {
6106    if (!valid_ || !stream_) {
6107      return (off_t)-1;
6108    }
6109  
6110    // Check for conversion data loss
6111    std::streamoff std_streamoff = stream_->tellg();
6112    off_t rv = static_cast<off_t>(std_streamoff);
6113    if (static_cast<std::streamoff>(rv) == std_streamoff) {
6114      return rv;
6115    } else {
6116      BPLOG(ERROR) << "Data loss detected";
6117      return (off_t)-1;
6118    }
6119  }
6120  
6121  
6122  string* Minidump::ReadString(off_t offset) {
6123    if (!valid_) {
6124      BPLOG(ERROR) << "Invalid Minidump for ReadString";
6125      return NULL;
6126    }
6127    if (!SeekSet(offset)) {
6128      BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
6129      return NULL;
6130    }
6131  
6132    uint32_t bytes;
6133    if (!ReadBytes(&bytes, sizeof(bytes))) {
6134      BPLOG(ERROR) << "ReadString could not read string size at offset " <<
6135                      offset;
6136      return NULL;
6137    }
6138    if (swap_)
6139      Swap(&bytes);
6140  
6141    if (bytes % 2 != 0) {
6142      BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
6143                      "-byte string at offset " << offset;
6144      return NULL;
6145    }
6146    unsigned int utf16_words = bytes / 2;
6147  
6148    if (utf16_words > max_string_length_) {
6149      BPLOG(ERROR) << "ReadString string length " << utf16_words <<
6150                      " exceeds maximum " << max_string_length_ <<
6151                      " at offset " << offset;
6152      return NULL;
6153    }
6154  
6155    vector<uint16_t> string_utf16(utf16_words);
6156  
6157    if (utf16_words) {
6158      if (!ReadBytes(&string_utf16[0], bytes)) {
6159        BPLOG(ERROR) << "ReadString could not read " << bytes <<
6160                        "-byte string at offset " << offset;
6161        return NULL;
6162      }
6163    }
6164  
6165    return UTF16ToUTF8(string_utf16, swap_);
6166  }
6167  
6168  
6169  bool Minidump::ReadUTF8String(off_t offset, string* string_utf8) {
6170    if (!valid_) {
6171      BPLOG(ERROR) << "Invalid Minidump for ReadString";
6172      return false;
6173    }
6174    if (!SeekSet(offset)) {
6175      BPLOG(ERROR) << "ReadUTF8String could not seek to string at offset "
6176                   << offset;
6177      return false;
6178    }
6179  
6180    uint32_t bytes;
6181    if (!ReadBytes(&bytes, sizeof(bytes))) {
6182      BPLOG(ERROR) << "ReadUTF8String could not read string size at offset " <<
6183                      offset;
6184      return false;
6185    }
6186  
6187    if (swap_) {
6188      Swap(&bytes);
6189    }
6190  
6191    if (bytes > max_string_length_) {
6192      BPLOG(ERROR) << "ReadUTF8String string length " << bytes <<
6193                      " exceeds maximum " << max_string_length_ <<
6194                      " at offset " << offset;
6195      return false;
6196    }
6197  
6198    string_utf8->resize(bytes);
6199  
6200    if (!ReadBytes(&(*string_utf8)[0], bytes)) {
6201      BPLOG(ERROR) << "ReadUTF8String could not read " << bytes <<
6202                      "-byte string at offset " << offset;
6203      return false;
6204    }
6205  
6206    return true;
6207  }
6208  
6209  
6210  bool Minidump::ReadStringList(
6211      off_t offset,
6212      std::vector<std::string>* string_list) {
6213    string_list->clear();
6214  
6215    if (!SeekSet(offset)) {
6216      BPLOG(ERROR) << "Minidump cannot seek to string_list";
6217      return false;
6218    }
6219  
6220    uint32_t count;
6221    if (!ReadBytes(&count, sizeof(count))) {
6222      BPLOG(ERROR) << "Minidump cannot read string_list count";
6223      return false;
6224    }
6225  
6226    if (swap_) {
6227      Swap(&count);
6228    }
6229  
6230    scoped_array<MDRVA> rvas(new MDRVA[count]);
6231  
6232    // Read the entire array in one fell swoop, instead of reading one entry
6233    // at a time in the loop.
6234    if (!ReadBytes(&rvas[0], sizeof(MDRVA) * count)) {
6235      BPLOG(ERROR) << "Minidump could not read string_list";
6236      return false;
6237    }
6238  
6239    for (uint32_t index = 0; index < count; ++index) {
6240      if (swap()) {
6241        Swap(&rvas[index]);
6242      }
6243  
6244      string entry;
6245      if (!ReadUTF8String(rvas[index], &entry)) {
6246        BPLOG(ERROR) << "Minidump could not read string_list entry";
6247        return false;
6248      }
6249  
6250      string_list->push_back(entry);
6251    }
6252  
6253    return true;
6254  }
6255  
6256  
6257  bool Minidump::ReadSimpleStringDictionary(
6258      off_t offset,
6259      std::map<std::string, std::string>* simple_string_dictionary) {
6260    simple_string_dictionary->clear();
6261  
6262    if (!SeekSet(offset)) {
6263      BPLOG(ERROR) << "Minidump cannot seek to simple_string_dictionary";
6264      return false;
6265    }
6266  
6267    uint32_t count;
6268    if (!ReadBytes(&count, sizeof(count))) {
6269      BPLOG(ERROR)
6270          << "Minidump cannot read simple_string_dictionary count";
6271      return false;
6272    }
6273  
6274    if (swap()) {
6275      Swap(&count);
6276    }
6277  
6278    scoped_array<MDRawSimpleStringDictionaryEntry> entries(
6279        new MDRawSimpleStringDictionaryEntry[count]);
6280  
6281    // Read the entire array in one fell swoop, instead of reading one entry
6282    // at a time in the loop.
6283    if (!ReadBytes(
6284            &entries[0],
6285            sizeof(MDRawSimpleStringDictionaryEntry) * count)) {
6286      BPLOG(ERROR) << "Minidump could not read simple_string_dictionary";
6287      return false;
6288    }
6289  
6290    for (uint32_t index = 0; index < count; ++index) {
6291      if (swap()) {
6292        Swap(&entries[index]);
6293      }
6294  
6295      string key;
6296      if (!ReadUTF8String(entries[index].key, &key)) {
6297        BPLOG(ERROR) << "Minidump could not read simple_string_dictionary key";
6298        return false;
6299      }
6300  
6301      string value;
6302      if (!ReadUTF8String(entries[index].value, &value)) {
6303        BPLOG(ERROR) << "Minidump could not read simple_string_dictionary value";
6304        return false;
6305      }
6306  
6307      if (simple_string_dictionary->find(key) !=
6308          simple_string_dictionary->end()) {
6309        BPLOG(ERROR)
6310            << "Minidump: discarding duplicate simple_string_dictionary value "
6311            << value << " for key " << key;
6312      } else {
6313        simple_string_dictionary->insert(std::make_pair(key, value));
6314      }
6315    }
6316  
6317    return true;
6318  }
6319  
6320  bool Minidump::ReadCrashpadAnnotationsList(
6321      off_t offset,
6322      std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list) {
6323    annotations_list->clear();
6324  
6325    if (!SeekSet(offset)) {
6326      BPLOG(ERROR) << "Minidump cannot seek to annotations_list";
6327      return false;
6328    }
6329  
6330    uint32_t count;
6331    if (!ReadBytes(&count, sizeof(count))) {
6332      BPLOG(ERROR) << "Minidump cannot read annotations_list count";
6333      return false;
6334    }
6335  
6336    if (swap_) {
6337      Swap(&count);
6338    }
6339  
6340    scoped_array<MDRawCrashpadAnnotation> objects(
6341        new MDRawCrashpadAnnotation[count]);
6342  
6343    // Read the entire array in one fell swoop, instead of reading one entry
6344    // at a time in the loop.
6345    if (!ReadBytes(&objects[0], sizeof(MDRawCrashpadAnnotation) * count)) {
6346      BPLOG(ERROR) << "Minidump could not read annotations_list";
6347      return false;
6348    }
6349  
6350    for (uint32_t index = 0; index < count; ++index) {
6351      MDRawCrashpadAnnotation annotation = objects[index];
6352  
6353      if (swap_) {
6354        Swap(&annotation);
6355      }
6356  
6357      string name;
6358      if (!ReadUTF8String(annotation.name, &name)) {
6359        BPLOG(ERROR) << "Minidump could not read annotation name";
6360        return false;
6361      }
6362  
6363      if (!SeekSet(annotation.value)) {
6364        BPLOG(ERROR) << "Minidump cannot seek to annotations value";
6365        return false;
6366      }
6367  
6368      uint32_t value_length;
6369      if (!ReadBytes(&value_length, sizeof(value_length))) {
6370        BPLOG(ERROR) << "Minidump could not read annotation value length";
6371        return false;
6372      }
6373  
6374      std::vector<uint8_t> value_data(value_length);
6375      if (!ReadBytes(value_data.data(), value_length)) {
6376        BPLOG(ERROR) << "Minidump could not read annotation value";
6377        return false;
6378      }
6379  
6380      MinidumpCrashpadInfo::AnnotationObject object = {annotation.type, name,
6381                                                       value_data};
6382      annotations_list->push_back(object);
6383    }
6384  
6385    return true;
6386  }
6387  
6388  bool Minidump::SeekToStreamType(uint32_t  stream_type,
6389                                  uint32_t* stream_length) {
6390    BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
6391                                       "|stream_length|";
6392    assert(stream_length);
6393    *stream_length = 0;
6394  
6395    if (!valid_) {
6396      BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
6397      return false;
6398    }
6399  
6400    MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
6401    if (iterator == stream_map_->end()) {
6402      // This stream type didn't exist in the directory.
6403      BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
6404      return false;
6405    }
6406  
6407    const MinidumpStreamInfo& info = iterator->second;
6408    if (info.stream_index >= header_.stream_count) {
6409      BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
6410                      " out of range: " <<
6411                      info.stream_index << "/" << header_.stream_count;
6412      return false;
6413    }
6414  
6415    MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
6416    if (!SeekSet(directory_entry->location.rva)) {
6417      BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
6418                      stream_type;
6419      return false;
6420    }
6421  
6422    *stream_length = directory_entry->location.data_size;
6423  
6424    return true;
6425  }
6426  
6427  
6428  template<typename T>
6429  T* Minidump::GetStream(T** stream) {
6430    // stream is a garbage parameter that's present only to account for C++'s
6431    // inability to overload a method based solely on its return type.
6432  
6433    const uint32_t stream_type = T::kStreamType;
6434  
6435    BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
6436                                " requires |stream|";
6437    assert(stream);
6438    *stream = NULL;
6439  
6440    if (!valid_) {
6441      BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
6442      return NULL;
6443    }
6444  
6445    MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
6446    if (iterator == stream_map_->end()) {
6447      // This stream type didn't exist in the directory.
6448      BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
6449      return NULL;
6450    }
6451  
6452    // Get a pointer so that the stored stream field can be altered.
6453    MinidumpStreamInfo* info = &iterator->second;
6454  
6455    if (info->stream) {
6456      // This cast is safe because info.stream is only populated by this
6457      // method, and there is a direct correlation between T and stream_type.
6458      *stream = static_cast<T*>(info->stream);
6459      return *stream;
6460    }
6461  
6462    uint32_t stream_length;
6463    if (!SeekToStreamType(stream_type, &stream_length)) {
6464      BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
6465      return NULL;
6466    }
6467  
6468    scoped_ptr<T> new_stream(new T(this));
6469  
6470    if (!new_stream->Read(stream_length)) {
6471      BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
6472      return NULL;
6473    }
6474  
6475    *stream = new_stream.release();
6476    info->stream = *stream;
6477    return *stream;
6478  }
6479  
6480  }  // namespace google_breakpad