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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2010 Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30 // minidump.cc: A minidump reader.
    31 //
    32 // See minidump.h for documentation.
    33 //
    34 // Author: Mark Mentovai
    36 #include "google_breakpad/processor/minidump.h"
    38 #include <assert.h>
    39 #include <fcntl.h>
    40 #include <stddef.h>
    41 #include <stdio.h>
    42 #include <string.h>
    43 #include <time.h>
    45 #ifdef _WIN32
    46 #include <io.h>
    47 #define PRIx64 "llx"
    48 #define PRIx32 "lx"
    49 #define snprintf _snprintf
    50 #else  // _WIN32
    51 #include <unistd.h>
    52 #define O_BINARY 0
    53 #endif  // _WIN32
    55 #include <fstream>
    56 #include <iostream>
    57 #include <limits>
    58 #include <map>
    59 #include <vector>
    61 #include "processor/range_map-inl.h"
    63 #include "common/scoped_ptr.h"
    64 #include "processor/basic_code_module.h"
    65 #include "processor/basic_code_modules.h"
    66 #include "common/logging.h"
    70 namespace google_breakpad {
    73 using std::istream;
    74 using std::ifstream;
    75 using std::numeric_limits;
    76 using std::vector;
    79 //
    80 // Swapping routines
    81 //
    82 // Inlining these doesn't increase code size significantly, and it saves
    83 // a whole lot of unnecessary jumping back and forth.
    84 //
    87 // Swapping an 8-bit quantity is a no-op.  This function is only provided
    88 // to account for certain templatized operations that require swapping for
    89 // wider types but handle uint8_t too
    90 // (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
    91 static inline void Swap(uint8_t* value) {
    92 }
    95 // Optimization: don't need to AND the furthest right shift, because we're
    96 // shifting an unsigned quantity.  The standard requires zero-filling in this
    97 // case.  If the quantities were signed, a bitmask whould be needed for this
    98 // right shift to avoid an arithmetic shift (which retains the sign bit).
    99 // The furthest left shift never needs to be ANDed bitmask.
   102 static inline void Swap(uint16_t* value) {
   103   *value = (*value >> 8) |
   104            (*value << 8);
   105 }
   108 static inline void Swap(uint32_t* value) {
   109   *value =  (*value >> 24) |
   110            ((*value >> 8)  & 0x0000ff00) |
   111            ((*value << 8)  & 0x00ff0000) |
   112             (*value << 24);
   113 }
   116 static inline void Swap(uint64_t* value) {
   117   uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
   118   Swap(&value32[0]);
   119   Swap(&value32[1]);
   120   uint32_t temp = value32[0];
   121   value32[0] = value32[1];
   122   value32[1] = temp;
   123 }
   126 // Given a pointer to a 128-bit int in the minidump data, set the "low"
   127 // and "high" fields appropriately.
   128 static void Normalize128(uint128_struct* value, bool is_big_endian) {
   129   // The struct format is [high, low], so if the format is big-endian,
   130   // the most significant bytes will already be in the high field.
   131   if (!is_big_endian) {
   132     uint64_t temp = value->low;
   133     value->low = value->high;
   134     value->high = temp;
   135   }
   136 }
   138 // This just swaps each int64 half of the 128-bit value.
   139 // The value should also be normalized by calling Normalize128().
   140 static void Swap(uint128_struct* value) {
   141   Swap(&value->low);
   142   Swap(&value->high);
   143 }
   146 static inline void Swap(MDLocationDescriptor* location_descriptor) {
   147   Swap(&location_descriptor->data_size);
   148   Swap(&location_descriptor->rva);
   149 }
   152 static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
   153   Swap(&memory_descriptor->start_of_memory_range);
   154   Swap(&memory_descriptor->memory);
   155 }
   158 static inline void Swap(MDGUID* guid) {
   159   Swap(&guid->data1);
   160   Swap(&guid->data2);
   161   Swap(&guid->data3);
   162   // Don't swap guid->data4[] because it contains 8-bit quantities.
   163 }
   166 //
   167 // Character conversion routines
   168 //
   171 // Standard wide-character conversion routines depend on the system's own
   172 // idea of what width a wide character should be: some use 16 bits, and
   173 // some use 32 bits.  For the purposes of a minidump, wide strings are
   174 // always represented with 16-bit UTF-16 chracters.  iconv isn't available
   175 // everywhere, and its interface varies where it is available.  iconv also
   176 // deals purely with char* pointers, so in addition to considering the swap
   177 // parameter, a converter that uses iconv would also need to take the host
   178 // CPU's endianness into consideration.  It doesn't seems worth the trouble
   179 // of making it a dependency when we don't care about anything but UTF-16.
   180 static string* UTF16ToUTF8(const vector<uint16_t>& in,
   181                            bool                     swap) {
   182   scoped_ptr<string> out(new string());
   184   // Set the string's initial capacity to the number of UTF-16 characters,
   185   // because the UTF-8 representation will always be at least this long.
   186   // If the UTF-8 representation is longer, the string will grow dynamically.
   187   out->reserve(in.size());
   189   for (vector<uint16_t>::const_iterator iterator = in.begin();
   190        iterator != in.end();
   191        ++iterator) {
   192     // Get a 16-bit value from the input
   193     uint16_t in_word = *iterator;
   194     if (swap)
   195       Swap(&in_word);
   197     // Convert the input value (in_word) into a Unicode code point (unichar).
   198     uint32_t unichar;
   199     if (in_word >= 0xdc00 && in_word <= 0xdcff) {
   200       BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
   201                       HexString(in_word) << " without high";
   202       return NULL;
   203     } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
   204       // High surrogate.
   205       unichar = (in_word - 0xd7c0) << 10;
   206       if (++iterator == in.end()) {
   207         BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
   208                         HexString(in_word) << " at end of string";
   209         return NULL;
   210       }
   211       uint32_t high_word = in_word;
   212       in_word = *iterator;
   213       if (in_word < 0xdc00 || in_word > 0xdcff) {
   214         BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
   215                         HexString(high_word) << " without low " <<
   216                         HexString(in_word);
   217         return NULL;
   218       }
   219       unichar |= in_word & 0x03ff;
   220     } else {
   221       // The ordinary case, a single non-surrogate Unicode character encoded
   222       // as a single 16-bit value.
   223       unichar = in_word;
   224     }
   226     // Convert the Unicode code point (unichar) into its UTF-8 representation,
   227     // appending it to the out string.
   228     if (unichar < 0x80) {
   229       (*out) += unichar;
   230     } else if (unichar < 0x800) {
   231       (*out) += 0xc0 | (unichar >> 6);
   232       (*out) += 0x80 | (unichar & 0x3f);
   233     } else if (unichar < 0x10000) {
   234       (*out) += 0xe0 | (unichar >> 12);
   235       (*out) += 0x80 | ((unichar >> 6) & 0x3f);
   236       (*out) += 0x80 | (unichar & 0x3f);
   237     } else if (unichar < 0x200000) {
   238       (*out) += 0xf0 | (unichar >> 18);
   239       (*out) += 0x80 | ((unichar >> 12) & 0x3f);
   240       (*out) += 0x80 | ((unichar >> 6) & 0x3f);
   241       (*out) += 0x80 | (unichar & 0x3f);
   242     } else {
   243       BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
   244                       HexString(unichar) << " in UTF-8";
   245       return NULL;
   246     }
   247   }
   249   return out.release();
   250 }
   252 // Return the smaller of the number of code units in the UTF-16 string,
   253 // not including the terminating null word, or maxlen.
   254 static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) {
   255   size_t count = 0;
   256   while (count < maxlen && string[count] != 0)
   257     count++;
   258   return count;
   259 }
   262 //
   263 // MinidumpObject
   264 //
   267 MinidumpObject::MinidumpObject(Minidump* minidump)
   268     : minidump_(minidump),
   269       valid_(false) {
   270 }
   273 //
   274 // MinidumpStream
   275 //
   278 MinidumpStream::MinidumpStream(Minidump* minidump)
   279     : MinidumpObject(minidump) {
   280 }
   283 //
   284 // MinidumpContext
   285 //
   288 MinidumpContext::MinidumpContext(Minidump* minidump)
   289     : MinidumpStream(minidump),
   290       context_(),
   291       context_flags_(0) {
   292 }
   295 MinidumpContext::~MinidumpContext() {
   296   FreeContext();
   297 }
   300 bool MinidumpContext::Read(uint32_t expected_size) {
   301   valid_ = false;
   303   FreeContext();
   305   // First, figure out what type of CPU this context structure is for.
   306   // For some reason, the AMD64 Context doesn't have context_flags
   307   // at the beginning of the structure, so special case it here.
   308   if (expected_size == sizeof(MDRawContextAMD64)) {
   309     BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
   311     scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
   312     if (!minidump_->ReadBytes(context_amd64.get(),
   313                               sizeof(MDRawContextAMD64))) {
   314       BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
   315       return false;
   316     }
   318     if (minidump_->swap())
   319       Swap(&context_amd64->context_flags);
   321     uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
   322     if (cpu_type == 0) {
   323       if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
   324         context_amd64->context_flags |= cpu_type;
   325       } else {
   326         BPLOG(ERROR) << "Failed to preserve the current stream position";
   327         return false;
   328       }
   329     }
   331     if (cpu_type != MD_CONTEXT_AMD64) {
   332       //TODO: fall through to switch below?
   333       // need a Tell method to be able to SeekSet back to beginning
   334       // http://code.google.com/p/google-breakpad/issues/detail?id=224
   335       BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
   336       return false;
   337     }
   339     // Do this after reading the entire MDRawContext structure because
   340     // GetSystemInfo may seek minidump to a new position.
   341     if (!CheckAgainstSystemInfo(cpu_type)) {
   342       BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
   343       return false;
   344     }
   346     // Normalize the 128-bit types in the dump.
   347     // Since this is AMD64, by definition, the values are little-endian.
   348     for (unsigned int vr_index = 0;
   349          vr_index < MD_CONTEXT_AMD64_VR_COUNT;
   350          ++vr_index)
   351       Normalize128(&context_amd64->vector_register[vr_index], false);
   353     if (minidump_->swap()) {
   354       Swap(&context_amd64->p1_home);
   355       Swap(&context_amd64->p2_home);
   356       Swap(&context_amd64->p3_home);
   357       Swap(&context_amd64->p4_home);
   358       Swap(&context_amd64->p5_home);
   359       Swap(&context_amd64->p6_home);
   360       // context_flags is already swapped
   361       Swap(&context_amd64->mx_csr);
   362       Swap(&context_amd64->cs);
   363       Swap(&context_amd64->ds);
   364       Swap(&context_amd64->es);
   365       Swap(&context_amd64->fs);
   366       Swap(&context_amd64->ss);
   367       Swap(&context_amd64->eflags);
   368       Swap(&context_amd64->dr0);
   369       Swap(&context_amd64->dr1);
   370       Swap(&context_amd64->dr2);
   371       Swap(&context_amd64->dr3);
   372       Swap(&context_amd64->dr6);
   373       Swap(&context_amd64->dr7);
   374       Swap(&context_amd64->rax);
   375       Swap(&context_amd64->rcx);
   376       Swap(&context_amd64->rdx);
   377       Swap(&context_amd64->rbx);
   378       Swap(&context_amd64->rsp);
   379       Swap(&context_amd64->rbp);
   380       Swap(&context_amd64->rsi);
   381       Swap(&context_amd64->rdi);
   382       Swap(&context_amd64->r8);
   383       Swap(&context_amd64->r9);
   384       Swap(&context_amd64->r10);
   385       Swap(&context_amd64->r11);
   386       Swap(&context_amd64->r12);
   387       Swap(&context_amd64->r13);
   388       Swap(&context_amd64->r14);
   389       Swap(&context_amd64->r15);
   390       Swap(&context_amd64->rip);
   391       //FIXME: I'm not sure what actually determines
   392       // which member of the union {flt_save, sse_registers}
   393       // is valid.  We're not currently using either,
   394       // but it would be good to have them swapped properly.
   396       for (unsigned int vr_index = 0;
   397            vr_index < MD_CONTEXT_AMD64_VR_COUNT;
   398            ++vr_index)
   399         Swap(&context_amd64->vector_register[vr_index]);
   400       Swap(&context_amd64->vector_control);
   401       Swap(&context_amd64->debug_control);
   402       Swap(&context_amd64->last_branch_to_rip);
   403       Swap(&context_amd64->last_branch_from_rip);
   404       Swap(&context_amd64->last_exception_to_rip);
   405       Swap(&context_amd64->last_exception_from_rip);
   406     }
   408     context_flags_ = context_amd64->context_flags;
   410     context_.amd64 = context_amd64.release();
   411   }
   412   else {
   413     uint32_t context_flags;
   414     if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
   415       BPLOG(ERROR) << "MinidumpContext could not read context flags";
   416       return false;
   417     }
   418     if (minidump_->swap())
   419       Swap(&context_flags);
   421     uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
   422     if (cpu_type == 0) {
   423       // Unfortunately the flag for MD_CONTEXT_ARM that was taken
   424       // from a Windows CE SDK header conflicts in practice with
   425       // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
   426       // but handle dumps with the legacy value gracefully here.
   427       if (context_flags & MD_CONTEXT_ARM_OLD) {
   428         context_flags |= MD_CONTEXT_ARM;
   429         context_flags &= ~MD_CONTEXT_ARM_OLD;
   430         cpu_type = MD_CONTEXT_ARM;
   431       }
   432     }
   434     if (cpu_type == 0) {
   435       if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
   436         context_flags |= cpu_type;
   437       } else {
   438         BPLOG(ERROR) << "Failed to preserve the current stream position";
   439         return false;
   440       }
   441     }
   443     // Allocate the context structure for the correct CPU and fill it.  The
   444     // casts are slightly unorthodox, but it seems better to do that than to
   445     // maintain a separate pointer for each type of CPU context structure
   446     // when only one of them will be used.
   447     switch (cpu_type) {
   448       case MD_CONTEXT_X86: {
   449         if (expected_size != sizeof(MDRawContextX86)) {
   450           BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
   451             expected_size << " != " << sizeof(MDRawContextX86);
   452           return false;
   453         }
   455         scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
   457         // Set the context_flags member, which has already been read, and
   458         // read the rest of the structure beginning with the first member
   459         // after context_flags.
   460         context_x86->context_flags = context_flags;
   462         size_t flags_size = sizeof(context_x86->context_flags);
   463         uint8_t* context_after_flags =
   464           reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
   465         if (!minidump_->ReadBytes(context_after_flags,
   466                                   sizeof(MDRawContextX86) - flags_size)) {
   467           BPLOG(ERROR) << "MinidumpContext could not read x86 context";
   468           return false;
   469         }
   471         // Do this after reading the entire MDRawContext structure because
   472         // GetSystemInfo may seek minidump to a new position.
   473         if (!CheckAgainstSystemInfo(cpu_type)) {
   474           BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
   475           return false;
   476         }
   478         if (minidump_->swap()) {
   479           // context_x86->context_flags was already swapped.
   480           Swap(&context_x86->dr0);
   481           Swap(&context_x86->dr1);
   482           Swap(&context_x86->dr2);
   483           Swap(&context_x86->dr3);
   484           Swap(&context_x86->dr6);
   485           Swap(&context_x86->dr7);
   486           Swap(&context_x86->float_save.control_word);
   487           Swap(&context_x86->float_save.status_word);
   488           Swap(&context_x86->float_save.tag_word);
   489           Swap(&context_x86->float_save.error_offset);
   490           Swap(&context_x86->float_save.error_selector);
   491           Swap(&context_x86->float_save.data_offset);
   492           Swap(&context_x86->float_save.data_selector);
   493           // context_x86->float_save.register_area[] contains 8-bit quantities
   494           // and does not need to be swapped.
   495           Swap(&context_x86->float_save.cr0_npx_state);
   496           Swap(&context_x86->gs);
   497           Swap(&context_x86->fs);
   498           Swap(&context_x86->es);
   499           Swap(&context_x86->ds);
   500           Swap(&context_x86->edi);
   501           Swap(&context_x86->esi);
   502           Swap(&context_x86->ebx);
   503           Swap(&context_x86->edx);
   504           Swap(&context_x86->ecx);
   505           Swap(&context_x86->eax);
   506           Swap(&context_x86->ebp);
   507           Swap(&context_x86->eip);
   508           Swap(&context_x86->cs);
   509           Swap(&context_x86->eflags);
   510           Swap(&context_x86->esp);
   511           Swap(&context_x86->ss);
   512           // context_x86->extended_registers[] contains 8-bit quantities and
   513           // does not need to be swapped.
   514         }
   516         context_.x86 = context_x86.release();
   518         break;
   519       }
   521       case MD_CONTEXT_PPC: {
   522         if (expected_size != sizeof(MDRawContextPPC)) {
   523           BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
   524             expected_size << " != " << sizeof(MDRawContextPPC);
   525           return false;
   526         }
   528         scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
   530         // Set the context_flags member, which has already been read, and
   531         // read the rest of the structure beginning with the first member
   532         // after context_flags.
   533         context_ppc->context_flags = context_flags;
   535         size_t flags_size = sizeof(context_ppc->context_flags);
   536         uint8_t* context_after_flags =
   537           reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
   538         if (!minidump_->ReadBytes(context_after_flags,
   539                                   sizeof(MDRawContextPPC) - flags_size)) {
   540           BPLOG(ERROR) << "MinidumpContext could not read ppc context";
   541           return false;
   542         }
   544         // Do this after reading the entire MDRawContext structure because
   545         // GetSystemInfo may seek minidump to a new position.
   546         if (!CheckAgainstSystemInfo(cpu_type)) {
   547           BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
   548           return false;
   549         }
   551         // Normalize the 128-bit types in the dump.
   552         // Since this is PowerPC, by definition, the values are big-endian.
   553         for (unsigned int vr_index = 0;
   554              vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
   555              ++vr_index) {
   556           Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
   557         }
   559         if (minidump_->swap()) {
   560           // context_ppc->context_flags was already swapped.
   561           Swap(&context_ppc->srr0);
   562           Swap(&context_ppc->srr1);
   563           for (unsigned int gpr_index = 0;
   564                gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
   565                ++gpr_index) {
   566             Swap(&context_ppc->gpr[gpr_index]);
   567           }
   568           Swap(&context_ppc->cr);
   569           Swap(&context_ppc->xer);
   570           Swap(&context_ppc->lr);
   571           Swap(&context_ppc->ctr);
   572           Swap(&context_ppc->mq);
   573           Swap(&context_ppc->vrsave);
   574           for (unsigned int fpr_index = 0;
   575                fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
   576                ++fpr_index) {
   577             Swap(&context_ppc->float_save.fpregs[fpr_index]);
   578           }
   579           // Don't swap context_ppc->float_save.fpscr_pad because it is only
   580           // used for padding.
   581           Swap(&context_ppc->float_save.fpscr);
   582           for (unsigned int vr_index = 0;
   583                vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
   584                ++vr_index) {
   585             Swap(&context_ppc->vector_save.save_vr[vr_index]);
   586           }
   587           Swap(&context_ppc->vector_save.save_vscr);
   588           // Don't swap the padding fields in vector_save.
   589           Swap(&context_ppc->vector_save.save_vrvalid);
   590         }
   592         context_.ppc = context_ppc.release();
   594         break;
   595       }
   597       case MD_CONTEXT_SPARC: {
   598         if (expected_size != sizeof(MDRawContextSPARC)) {
   599           BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
   600             expected_size << " != " << sizeof(MDRawContextSPARC);
   601           return false;
   602         }
   604         scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
   606         // Set the context_flags member, which has already been read, and
   607         // read the rest of the structure beginning with the first member
   608         // after context_flags.
   609         context_sparc->context_flags = context_flags;
   611         size_t flags_size = sizeof(context_sparc->context_flags);
   612         uint8_t* context_after_flags =
   613             reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
   614         if (!minidump_->ReadBytes(context_after_flags,
   615                                   sizeof(MDRawContextSPARC) - flags_size)) {
   616           BPLOG(ERROR) << "MinidumpContext could not read sparc context";
   617           return false;
   618         }
   620         // Do this after reading the entire MDRawContext structure because
   621         // GetSystemInfo may seek minidump to a new position.
   622         if (!CheckAgainstSystemInfo(cpu_type)) {
   623           BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
   624           return false;
   625         }
   627         if (minidump_->swap()) {
   628           // context_sparc->context_flags was already swapped.
   629           for (unsigned int gpr_index = 0;
   630                gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
   631                ++gpr_index) {
   632             Swap(&context_sparc->g_r[gpr_index]);
   633           }
   634           Swap(&context_sparc->ccr);
   635           Swap(&context_sparc->pc);
   636           Swap(&context_sparc->npc);
   637           Swap(&context_sparc->y);
   638           Swap(&context_sparc->asi);
   639           Swap(&context_sparc->fprs);
   640           for (unsigned int fpr_index = 0;
   641                fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
   642                ++fpr_index) {
   643             Swap(&context_sparc->float_save.regs[fpr_index]);
   644           }
   645           Swap(&context_sparc->float_save.filler);
   646           Swap(&context_sparc->float_save.fsr);
   647         }
   648         context_.ctx_sparc = context_sparc.release();
   650         break;
   651       }
   653       case MD_CONTEXT_ARM: {
   654         if (expected_size != sizeof(MDRawContextARM)) {
   655           BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
   656             expected_size << " != " << sizeof(MDRawContextARM);
   657           return false;
   658         }
   660         scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
   662         // Set the context_flags member, which has already been read, and
   663         // read the rest of the structure beginning with the first member
   664         // after context_flags.
   665         context_arm->context_flags = context_flags;
   667         size_t flags_size = sizeof(context_arm->context_flags);
   668         uint8_t* context_after_flags =
   669             reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
   670         if (!minidump_->ReadBytes(context_after_flags,
   671                                   sizeof(MDRawContextARM) - flags_size)) {
   672           BPLOG(ERROR) << "MinidumpContext could not read arm context";
   673           return false;
   674         }
   676         // Do this after reading the entire MDRawContext structure because
   677         // GetSystemInfo may seek minidump to a new position.
   678         if (!CheckAgainstSystemInfo(cpu_type)) {
   679           BPLOG(ERROR) << "MinidumpContext arm does not match system info";
   680           return false;
   681         }
   683         if (minidump_->swap()) {
   684           // context_arm->context_flags was already swapped.
   685           for (unsigned int ireg_index = 0;
   686                ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
   687                ++ireg_index) {
   688             Swap(&context_arm->iregs[ireg_index]);
   689           }
   690           Swap(&context_arm->cpsr);
   691           Swap(&context_arm->float_save.fpscr);
   692           for (unsigned int fpr_index = 0;
   693                fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
   694                ++fpr_index) {
   695             Swap(&context_arm->float_save.regs[fpr_index]);
   696           }
   697           for (unsigned int fpe_index = 0;
   698                fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
   699                ++fpe_index) {
   700             Swap(&context_arm->float_save.extra[fpe_index]);
   701           }
   702         }
   703         context_.arm = context_arm.release();
   705         break;
   706       }
   708       default: {
   709         // Unknown context type - Don't log as an error yet. Let the
   710         // caller work that out.
   711         BPLOG(INFO) << "MinidumpContext unknown context type " <<
   712           HexString(cpu_type);
   713         return false;
   714         break;
   715       }
   716     }
   717     context_flags_ = context_flags;
   718   }
   720   valid_ = true;
   721   return true;
   722 }
   725 uint32_t MinidumpContext::GetContextCPU() const {
   726   if (!valid_) {
   727     // Don't log a message, GetContextCPU can be legitimately called with
   728     // valid_ false by FreeContext, which is called by Read.
   729     return 0;
   730   }
   732   return context_flags_ & MD_CONTEXT_CPU_MASK;
   733 }
   735 bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const {
   736   BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer "
   737                           "requires |ip|";
   738   assert(ip);
   739   *ip = 0;
   741   if (!valid_) {
   742     BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer";
   743     return false;
   744   }
   746   switch (context_flags_ & MD_CONTEXT_CPU_MASK) {
   747   case MD_CONTEXT_AMD64:
   748     *ip = context_.amd64->rip;
   749     break;
   750   case MD_CONTEXT_ARM:
   751     *ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC];
   752     break;
   753   case MD_CONTEXT_PPC:
   754     *ip = context_.ppc->srr0;
   755     break;
   756   case MD_CONTEXT_SPARC:
   757     *ip = context_.ctx_sparc->pc;
   758     break;
   759   case MD_CONTEXT_X86:
   760     *ip = context_.x86->eip;
   761     break;
   762   default:
   763     // This should never happen.
   764     BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
   765     return false;
   766   }
   767   return true;
   768 }
   771 const MDRawContextX86* MinidumpContext::GetContextX86() const {
   772   if (GetContextCPU() != MD_CONTEXT_X86) {
   773     BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
   774     return NULL;
   775   }
   777   return context_.x86;
   778 }
   781 const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
   782   if (GetContextCPU() != MD_CONTEXT_PPC) {
   783     BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
   784     return NULL;
   785   }
   787   return context_.ppc;
   788 }
   790 const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
   791   if (GetContextCPU() != MD_CONTEXT_AMD64) {
   792     BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
   793     return NULL;
   794   }
   796   return context_.amd64;
   797 }
   799 const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
   800   if (GetContextCPU() != MD_CONTEXT_SPARC) {
   801     BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
   802     return NULL;
   803   }
   805   return context_.ctx_sparc;
   806 }
   808 const MDRawContextARM* MinidumpContext::GetContextARM() const {
   809   if (GetContextCPU() != MD_CONTEXT_ARM) {
   810     BPLOG(ERROR) << "MinidumpContext cannot get arm context";
   811     return NULL;
   812   }
   814   return context_.arm;
   815 }
   817 void MinidumpContext::FreeContext() {
   818   switch (GetContextCPU()) {
   819     case MD_CONTEXT_X86:
   820       delete context_.x86;
   821       break;
   823     case MD_CONTEXT_PPC:
   824       delete context_.ppc;
   825       break;
   827     case MD_CONTEXT_AMD64:
   828       delete context_.amd64;
   829       break;
   831     case MD_CONTEXT_SPARC:
   832       delete context_.ctx_sparc;
   833       break;
   835     case MD_CONTEXT_ARM:
   836       delete context_.arm;
   837       break;
   839     default:
   840       // There is no context record (valid_ is false) or there's a
   841       // context record for an unknown CPU (shouldn't happen, only known
   842       // records are stored by Read).
   843       break;
   844   }
   846   context_flags_ = 0;
   847   context_.base = NULL;
   848 }
   851 bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
   852   // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
   853   // as this function just implements a sanity check.
   854   MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
   855   if (!system_info) {
   856     BPLOG(INFO) << "MinidumpContext could not be compared against "
   857                    "MinidumpSystemInfo";
   858     return true;
   859   }
   861   // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
   862   const MDRawSystemInfo* raw_system_info = system_info->system_info();
   863   if (!raw_system_info) {
   864     BPLOG(INFO) << "MinidumpContext could not be compared against "
   865                    "MDRawSystemInfo";
   866     return false;
   867   }
   869   MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
   870       raw_system_info->processor_architecture);
   872   // Compare the CPU type of the context record to the CPU type in the
   873   // minidump's system info stream.
   874   bool return_value = false;
   875   switch (context_cpu_type) {
   876     case MD_CONTEXT_X86:
   877       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
   878           system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
   879           system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
   880         return_value = true;
   881       }
   882       break;
   884     case MD_CONTEXT_PPC:
   885       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
   886         return_value = true;
   887       break;
   889     case MD_CONTEXT_AMD64:
   890       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
   891         return_value = true;
   892       break;
   894     case MD_CONTEXT_SPARC:
   895       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
   896         return_value = true;
   897       break;
   899     case MD_CONTEXT_ARM:
   900       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
   901         return_value = true;
   902       break;
   903   }
   905   BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
   906                                     HexString(context_cpu_type) <<
   907                                     " wrong for MinidumpSystemInfo CPU " <<
   908                                     HexString(system_info_cpu_type);
   910   return return_value;
   911 }
   914 void MinidumpContext::Print() {
   915   if (!valid_) {
   916     BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
   917     return;
   918   }
   920   switch (GetContextCPU()) {
   921     case MD_CONTEXT_X86: {
   922       const MDRawContextX86* context_x86 = GetContextX86();
   923       printf("MDRawContextX86\n");
   924       printf("  context_flags                = 0x%x\n",
   925              context_x86->context_flags);
   926       printf("  dr0                          = 0x%x\n", context_x86->dr0);
   927       printf("  dr1                          = 0x%x\n", context_x86->dr1);
   928       printf("  dr2                          = 0x%x\n", context_x86->dr2);
   929       printf("  dr3                          = 0x%x\n", context_x86->dr3);
   930       printf("  dr6                          = 0x%x\n", context_x86->dr6);
   931       printf("  dr7                          = 0x%x\n", context_x86->dr7);
   932       printf("  float_save.control_word      = 0x%x\n",
   933              context_x86->float_save.control_word);
   934       printf("  float_save.status_word       = 0x%x\n",
   935              context_x86->float_save.status_word);
   936       printf("  float_save.tag_word          = 0x%x\n",
   937              context_x86->float_save.tag_word);
   938       printf("  float_save.error_offset      = 0x%x\n",
   939              context_x86->float_save.error_offset);
   940       printf("  float_save.error_selector    = 0x%x\n",
   941              context_x86->float_save.error_selector);
   942       printf("  float_save.data_offset       = 0x%x\n",
   943              context_x86->float_save.data_offset);
   944       printf("  float_save.data_selector     = 0x%x\n",
   945              context_x86->float_save.data_selector);
   946       printf("  float_save.register_area[%2d] = 0x",
   947              MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
   948       for (unsigned int register_index = 0;
   949            register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
   950            ++register_index) {
   951         printf("%02x", context_x86->float_save.register_area[register_index]);
   952       }
   953       printf("\n");
   954       printf("  float_save.cr0_npx_state     = 0x%x\n",
   955              context_x86->float_save.cr0_npx_state);
   956       printf("  gs                           = 0x%x\n", context_x86->gs);
   957       printf("  fs                           = 0x%x\n", context_x86->fs);
   958       printf("  es                           = 0x%x\n", context_x86->es);
   959       printf("  ds                           = 0x%x\n", context_x86->ds);
   960       printf("  edi                          = 0x%x\n", context_x86->edi);
   961       printf("  esi                          = 0x%x\n", context_x86->esi);
   962       printf("  ebx                          = 0x%x\n", context_x86->ebx);
   963       printf("  edx                          = 0x%x\n", context_x86->edx);
   964       printf("  ecx                          = 0x%x\n", context_x86->ecx);
   965       printf("  eax                          = 0x%x\n", context_x86->eax);
   966       printf("  ebp                          = 0x%x\n", context_x86->ebp);
   967       printf("  eip                          = 0x%x\n", context_x86->eip);
   968       printf("  cs                           = 0x%x\n", context_x86->cs);
   969       printf("  eflags                       = 0x%x\n", context_x86->eflags);
   970       printf("  esp                          = 0x%x\n", context_x86->esp);
   971       printf("  ss                           = 0x%x\n", context_x86->ss);
   972       printf("  extended_registers[%3d]      = 0x",
   973              MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
   974       for (unsigned int register_index = 0;
   975            register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
   976            ++register_index) {
   977         printf("%02x", context_x86->extended_registers[register_index]);
   978       }
   979       printf("\n\n");
   981       break;
   982     }
   984     case MD_CONTEXT_PPC: {
   985       const MDRawContextPPC* context_ppc = GetContextPPC();
   986       printf("MDRawContextPPC\n");
   987       printf("  context_flags            = 0x%x\n",
   988              context_ppc->context_flags);
   989       printf("  srr0                     = 0x%x\n", context_ppc->srr0);
   990       printf("  srr1                     = 0x%x\n", context_ppc->srr1);
   991       for (unsigned int gpr_index = 0;
   992            gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
   993            ++gpr_index) {
   994         printf("  gpr[%2d]                  = 0x%x\n",
   995                gpr_index, context_ppc->gpr[gpr_index]);
   996       }
   997       printf("  cr                       = 0x%x\n", context_ppc->cr);
   998       printf("  xer                      = 0x%x\n", context_ppc->xer);
   999       printf("  lr                       = 0x%x\n", context_ppc->lr);
  1000       printf("  ctr                      = 0x%x\n", context_ppc->ctr);
  1001       printf("  mq                       = 0x%x\n", context_ppc->mq);
  1002       printf("  vrsave                   = 0x%x\n", context_ppc->vrsave);
  1003       for (unsigned int fpr_index = 0;
  1004            fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
  1005            ++fpr_index) {
  1006         printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
  1007                fpr_index, context_ppc->float_save.fpregs[fpr_index]);
  1009       printf("  float_save.fpscr         = 0x%x\n",
  1010              context_ppc->float_save.fpscr);
  1011       // TODO(mmentovai): print the 128-bit quantities in
  1012       // context_ppc->vector_save.  This isn't done yet because printf
  1013       // doesn't support 128-bit quantities, and printing them using
  1014       // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
  1015       // byte ordering.
  1016       printf("  vector_save.save_vrvalid = 0x%x\n",
  1017              context_ppc->vector_save.save_vrvalid);
  1018       printf("\n");
  1020       break;
  1023     case MD_CONTEXT_AMD64: {
  1024       const MDRawContextAMD64* context_amd64 = GetContextAMD64();
  1025       printf("MDRawContextAMD64\n");
  1026       printf("  p1_home       = 0x%" PRIx64 "\n",
  1027              context_amd64->p1_home);
  1028       printf("  p2_home       = 0x%" PRIx64 "\n",
  1029              context_amd64->p2_home);
  1030       printf("  p3_home       = 0x%" PRIx64 "\n",
  1031              context_amd64->p3_home);
  1032       printf("  p4_home       = 0x%" PRIx64 "\n",
  1033              context_amd64->p4_home);
  1034       printf("  p5_home       = 0x%" PRIx64 "\n",
  1035              context_amd64->p5_home);
  1036       printf("  p6_home       = 0x%" PRIx64 "\n",
  1037              context_amd64->p6_home);
  1038       printf("  context_flags = 0x%x\n",
  1039              context_amd64->context_flags);
  1040       printf("  mx_csr        = 0x%x\n",
  1041              context_amd64->mx_csr);
  1042       printf("  cs            = 0x%x\n", context_amd64->cs);
  1043       printf("  ds            = 0x%x\n", context_amd64->ds);
  1044       printf("  es            = 0x%x\n", context_amd64->es);
  1045       printf("  fs            = 0x%x\n", context_amd64->fs);
  1046       printf("  gs            = 0x%x\n", context_amd64->gs);
  1047       printf("  ss            = 0x%x\n", context_amd64->ss);
  1048       printf("  eflags        = 0x%x\n", context_amd64->eflags);
  1049       printf("  dr0           = 0x%" PRIx64 "\n", context_amd64->dr0);
  1050       printf("  dr1           = 0x%" PRIx64 "\n", context_amd64->dr1);
  1051       printf("  dr2           = 0x%" PRIx64 "\n", context_amd64->dr2);
  1052       printf("  dr3           = 0x%" PRIx64 "\n", context_amd64->dr3);
  1053       printf("  dr6           = 0x%" PRIx64 "\n", context_amd64->dr6);
  1054       printf("  dr7           = 0x%" PRIx64 "\n", context_amd64->dr7);
  1055       printf("  rax           = 0x%" PRIx64 "\n", context_amd64->rax);
  1056       printf("  rcx           = 0x%" PRIx64 "\n", context_amd64->rcx);
  1057       printf("  rdx           = 0x%" PRIx64 "\n", context_amd64->rdx);
  1058       printf("  rbx           = 0x%" PRIx64 "\n", context_amd64->rbx);
  1059       printf("  rsp           = 0x%" PRIx64 "\n", context_amd64->rsp);
  1060       printf("  rbp           = 0x%" PRIx64 "\n", context_amd64->rbp);
  1061       printf("  rsi           = 0x%" PRIx64 "\n", context_amd64->rsi);
  1062       printf("  rdi           = 0x%" PRIx64 "\n", context_amd64->rdi);
  1063       printf("  r8            = 0x%" PRIx64 "\n", context_amd64->r8);
  1064       printf("  r9            = 0x%" PRIx64 "\n", context_amd64->r9);
  1065       printf("  r10           = 0x%" PRIx64 "\n", context_amd64->r10);
  1066       printf("  r11           = 0x%" PRIx64 "\n", context_amd64->r11);
  1067       printf("  r12           = 0x%" PRIx64 "\n", context_amd64->r12);
  1068       printf("  r13           = 0x%" PRIx64 "\n", context_amd64->r13);
  1069       printf("  r14           = 0x%" PRIx64 "\n", context_amd64->r14);
  1070       printf("  r15           = 0x%" PRIx64 "\n", context_amd64->r15);
  1071       printf("  rip           = 0x%" PRIx64 "\n", context_amd64->rip);
  1072       //TODO: print xmm, vector, debug registers
  1073       printf("\n");
  1074       break;
  1077     case MD_CONTEXT_SPARC: {
  1078       const MDRawContextSPARC* context_sparc = GetContextSPARC();
  1079       printf("MDRawContextSPARC\n");
  1080       printf("  context_flags       = 0x%x\n",
  1081              context_sparc->context_flags);
  1082       for (unsigned int g_r_index = 0;
  1083            g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
  1084            ++g_r_index) {
  1085         printf("  g_r[%2d]             = 0x%" PRIx64 "\n",
  1086                g_r_index, context_sparc->g_r[g_r_index]);
  1088       printf("  ccr                 = 0x%" PRIx64 "\n", context_sparc->ccr);
  1089       printf("  pc                  = 0x%" PRIx64 "\n", context_sparc->pc);
  1090       printf("  npc                 = 0x%" PRIx64 "\n", context_sparc->npc);
  1091       printf("  y                   = 0x%" PRIx64 "\n", context_sparc->y);
  1092       printf("  asi                 = 0x%" PRIx64 "\n", context_sparc->asi);
  1093       printf("  fprs                = 0x%" PRIx64 "\n", context_sparc->fprs);
  1095       for (unsigned int fpr_index = 0;
  1096            fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
  1097            ++fpr_index) {
  1098         printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
  1099                fpr_index, context_sparc->float_save.regs[fpr_index]);
  1101       printf("  float_save.filler   = 0x%" PRIx64 "\n",
  1102              context_sparc->float_save.filler);
  1103       printf("  float_save.fsr      = 0x%" PRIx64 "\n",
  1104              context_sparc->float_save.fsr);
  1105       break;
  1108     case MD_CONTEXT_ARM: {
  1109       const MDRawContextARM* context_arm = GetContextARM();
  1110       printf("MDRawContextARM\n");
  1111       printf("  context_flags       = 0x%x\n",
  1112              context_arm->context_flags);
  1113       for (unsigned int ireg_index = 0;
  1114            ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
  1115            ++ireg_index) {
  1116         printf("  iregs[%2d]            = 0x%x\n",
  1117                ireg_index, context_arm->iregs[ireg_index]);
  1119       printf("  cpsr                = 0x%x\n", context_arm->cpsr);
  1120       printf("  float_save.fpscr     = 0x%" PRIx64 "\n",
  1121              context_arm->float_save.fpscr);
  1122       for (unsigned int fpr_index = 0;
  1123            fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
  1124            ++fpr_index) {
  1125         printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
  1126                fpr_index, context_arm->float_save.regs[fpr_index]);
  1128       for (unsigned int fpe_index = 0;
  1129            fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
  1130            ++fpe_index) {
  1131         printf("  float_save.extra[%2d] = 0x%" PRIx32 "\n",
  1132                fpe_index, context_arm->float_save.extra[fpe_index]);
  1135       break;
  1138     default: {
  1139       break;
  1145 //
  1146 // MinidumpMemoryRegion
  1147 //
  1150 uint32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024;  // 1MB
  1153 MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
  1154     : MinidumpObject(minidump),
  1155       descriptor_(NULL),
  1156       memory_(NULL) {
  1160 MinidumpMemoryRegion::~MinidumpMemoryRegion() {
  1161   delete memory_;
  1165 void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
  1166   descriptor_ = descriptor;
  1167   valid_ = descriptor &&
  1168            descriptor_->memory.data_size <=
  1169                numeric_limits<uint64_t>::max() -
  1170                descriptor_->start_of_memory_range;
  1174 const uint8_t* MinidumpMemoryRegion::GetMemory() const {
  1175   if (!valid_) {
  1176     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
  1177     return NULL;
  1180   if (!memory_) {
  1181     if (descriptor_->memory.data_size == 0) {
  1182       BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
  1183       return NULL;
  1186     if (!minidump_->SeekSet(descriptor_->memory.rva)) {
  1187       BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
  1188       return NULL;
  1191     if (descriptor_->memory.data_size > max_bytes_) {
  1192       BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
  1193                       descriptor_->memory.data_size << " exceeds maximum " <<
  1194                       max_bytes_;
  1195       return NULL;
  1198     scoped_ptr< vector<uint8_t> > memory(
  1199         new vector<uint8_t>(descriptor_->memory.data_size));
  1201     if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
  1202       BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
  1203       return NULL;
  1206     memory_ = memory.release();
  1209   return &(*memory_)[0];
  1213 uint64_t MinidumpMemoryRegion::GetBase() const {
  1214   if (!valid_) {
  1215     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
  1216     return static_cast<uint64_t>(-1);
  1219   return descriptor_->start_of_memory_range;
  1223 uint32_t MinidumpMemoryRegion::GetSize() const {
  1224   if (!valid_) {
  1225     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
  1226     return 0;
  1229   return descriptor_->memory.data_size;
  1233 void MinidumpMemoryRegion::FreeMemory() {
  1234   delete memory_;
  1235   memory_ = NULL;
  1239 template<typename T>
  1240 bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
  1241                                                       T*        value) const {
  1242   BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
  1243                              "requires |value|";
  1244   assert(value);
  1245   *value = 0;
  1247   if (!valid_) {
  1248     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
  1249                     "GetMemoryAtAddressInternal";
  1250     return false;
  1253   // Common failure case
  1254   if (address < descriptor_->start_of_memory_range ||
  1255       sizeof(T) > numeric_limits<uint64_t>::max() - address ||
  1256       address + sizeof(T) > descriptor_->start_of_memory_range +
  1257                             descriptor_->memory.data_size) {
  1258     BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
  1259                     HexString(address) << "+" << sizeof(T) << "/" <<
  1260                     HexString(descriptor_->start_of_memory_range) << "+" <<
  1261                     HexString(descriptor_->memory.data_size);
  1262     return false;
  1265   const uint8_t* memory = GetMemory();
  1266   if (!memory) {
  1267     // GetMemory already logged a perfectly good message.
  1268     return false;
  1271   // If the CPU requires memory accesses to be aligned, this can crash.
  1272   // x86 and ppc are able to cope, though.
  1273   *value = *reinterpret_cast<const T*>(
  1274       &memory[address - descriptor_->start_of_memory_range]);
  1276   if (minidump_->swap())
  1277     Swap(value);
  1279   return true;
  1283 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1284                                               uint8_t*  value) const {
  1285   return GetMemoryAtAddressInternal(address, value);
  1289 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1290                                               uint16_t* value) const {
  1291   return GetMemoryAtAddressInternal(address, value);
  1295 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1296                                               uint32_t* value) const {
  1297   return GetMemoryAtAddressInternal(address, value);
  1301 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
  1302                                               uint64_t* value) const {
  1303   return GetMemoryAtAddressInternal(address, value);
  1307 void MinidumpMemoryRegion::Print() {
  1308   if (!valid_) {
  1309     BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
  1310     return;
  1313   const uint8_t* memory = GetMemory();
  1314   if (memory) {
  1315     printf("0x");
  1316     for (unsigned int byte_index = 0;
  1317          byte_index < descriptor_->memory.data_size;
  1318          byte_index++) {
  1319       printf("%02x", memory[byte_index]);
  1321     printf("\n");
  1322   } else {
  1323     printf("No memory\n");
  1328 //
  1329 // MinidumpThread
  1330 //
  1333 MinidumpThread::MinidumpThread(Minidump* minidump)
  1334     : MinidumpObject(minidump),
  1335       thread_(),
  1336       memory_(NULL),
  1337       context_(NULL) {
  1341 MinidumpThread::~MinidumpThread() {
  1342   delete memory_;
  1343   delete context_;
  1347 bool MinidumpThread::Read() {
  1348   // Invalidate cached data.
  1349   delete memory_;
  1350   memory_ = NULL;
  1351   delete context_;
  1352   context_ = NULL;
  1354   valid_ = false;
  1356   if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
  1357     BPLOG(ERROR) << "MinidumpThread cannot read thread";
  1358     return false;
  1361   if (minidump_->swap()) {
  1362     Swap(&thread_.thread_id);
  1363     Swap(&thread_.suspend_count);
  1364     Swap(&thread_.priority_class);
  1365     Swap(&thread_.priority);
  1366     Swap(&thread_.teb);
  1367     Swap(&thread_.stack);
  1368     Swap(&thread_.thread_context);
  1371   // Check for base + size overflow or undersize.
  1372   if (thread_.stack.memory.data_size == 0 ||
  1373       thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
  1374                                        thread_.stack.start_of_memory_range) {
  1375     // This is ok, but log an error anyway.
  1376     BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
  1377                     HexString(thread_.stack.start_of_memory_range) << "+" <<
  1378                     HexString(thread_.stack.memory.data_size);
  1379   } else {
  1380     memory_ = new MinidumpMemoryRegion(minidump_);
  1381     memory_->SetDescriptor(&thread_.stack);
  1384   valid_ = true;
  1385   return true;
  1389 MinidumpMemoryRegion* MinidumpThread::GetMemory() {
  1390   if (!valid_) {
  1391     BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
  1392     return NULL;
  1395   return memory_;
  1399 MinidumpContext* MinidumpThread::GetContext() {
  1400   if (!valid_) {
  1401     BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
  1402     return NULL;
  1405   if (!context_) {
  1406     if (!minidump_->SeekSet(thread_.thread_context.rva)) {
  1407       BPLOG(ERROR) << "MinidumpThread cannot seek to context";
  1408       return NULL;
  1411     scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
  1413     if (!context->Read(thread_.thread_context.data_size)) {
  1414       BPLOG(ERROR) << "MinidumpThread cannot read context";
  1415       return NULL;
  1418     context_ = context.release();
  1421   return context_;
  1425 bool MinidumpThread::GetThreadID(uint32_t *thread_id) const {
  1426   BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
  1427                                  "|thread_id|";
  1428   assert(thread_id);
  1429   *thread_id = 0;
  1431   if (!valid_) {
  1432     BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
  1433     return false;
  1436   *thread_id = thread_.thread_id;
  1437   return true;
  1441 void MinidumpThread::Print() {
  1442   if (!valid_) {
  1443     BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
  1444     return;
  1447   printf("MDRawThread\n");
  1448   printf("  thread_id                   = 0x%x\n",   thread_.thread_id);
  1449   printf("  suspend_count               = %d\n",     thread_.suspend_count);
  1450   printf("  priority_class              = 0x%x\n",   thread_.priority_class);
  1451   printf("  priority                    = 0x%x\n",   thread_.priority);
  1452   printf("  teb                         = 0x%" PRIx64 "\n", thread_.teb);
  1453   printf("  stack.start_of_memory_range = 0x%" PRIx64 "\n",
  1454          thread_.stack.start_of_memory_range);
  1455   printf("  stack.memory.data_size      = 0x%x\n",
  1456          thread_.stack.memory.data_size);
  1457   printf("  stack.memory.rva            = 0x%x\n",   thread_.stack.memory.rva);
  1458   printf("  thread_context.data_size    = 0x%x\n",
  1459          thread_.thread_context.data_size);
  1460   printf("  thread_context.rva          = 0x%x\n",
  1461          thread_.thread_context.rva);
  1463   MinidumpContext* context = GetContext();
  1464   if (context) {
  1465     printf("\n");
  1466     context->Print();
  1467   } else {
  1468     printf("  (no context)\n");
  1469     printf("\n");
  1472   MinidumpMemoryRegion* memory = GetMemory();
  1473   if (memory) {
  1474     printf("Stack\n");
  1475     memory->Print();
  1476   } else {
  1477     printf("No stack\n");
  1479   printf("\n");
  1483 //
  1484 // MinidumpThreadList
  1485 //
  1488 uint32_t MinidumpThreadList::max_threads_ = 4096;
  1491 MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
  1492     : MinidumpStream(minidump),
  1493       id_to_thread_map_(),
  1494       threads_(NULL),
  1495       thread_count_(0) {
  1499 MinidumpThreadList::~MinidumpThreadList() {
  1500   delete threads_;
  1504 bool MinidumpThreadList::Read(uint32_t expected_size) {
  1505   // Invalidate cached data.
  1506   id_to_thread_map_.clear();
  1507   delete threads_;
  1508   threads_ = NULL;
  1509   thread_count_ = 0;
  1511   valid_ = false;
  1513   uint32_t thread_count;
  1514   if (expected_size < sizeof(thread_count)) {
  1515     BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
  1516                     expected_size << " < " << sizeof(thread_count);
  1517     return false;
  1519   if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
  1520     BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
  1521     return false;
  1524   if (minidump_->swap())
  1525     Swap(&thread_count);
  1527   if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
  1528     BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
  1529                     " would cause multiplication overflow";
  1530     return false;
  1533   if (expected_size != sizeof(thread_count) +
  1534                        thread_count * sizeof(MDRawThread)) {
  1535     // may be padded with 4 bytes on 64bit ABIs for alignment
  1536     if (expected_size == sizeof(thread_count) + 4 +
  1537                          thread_count * sizeof(MDRawThread)) {
  1538       uint32_t useless;
  1539       if (!minidump_->ReadBytes(&useless, 4)) {
  1540         BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes";
  1541         return false;
  1543     } else {
  1544       BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
  1545                     " != " << sizeof(thread_count) +
  1546                     thread_count * sizeof(MDRawThread);
  1547       return false;
  1552   if (thread_count > max_threads_) {
  1553     BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
  1554                     " exceeds maximum " << max_threads_;
  1555     return false;
  1558   if (thread_count != 0) {
  1559     scoped_ptr<MinidumpThreads> threads(
  1560         new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
  1562     for (unsigned int thread_index = 0;
  1563          thread_index < thread_count;
  1564          ++thread_index) {
  1565       MinidumpThread* thread = &(*threads)[thread_index];
  1567       // Assume that the file offset is correct after the last read.
  1568       if (!thread->Read()) {
  1569         BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
  1570                         thread_index << "/" << thread_count;
  1571         return false;
  1574       uint32_t thread_id;
  1575       if (!thread->GetThreadID(&thread_id)) {
  1576         BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
  1577                         thread_index << "/" << thread_count;
  1578         return false;
  1581       if (GetThreadByID(thread_id)) {
  1582         // Another thread with this ID is already in the list.  Data error.
  1583         BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
  1584                         HexString(thread_id) << " at thread " <<
  1585                         thread_index << "/" << thread_count;
  1586         return false;
  1588       id_to_thread_map_[thread_id] = thread;
  1591     threads_ = threads.release();
  1594   thread_count_ = thread_count;
  1596   valid_ = true;
  1597   return true;
  1601 MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
  1602     const {
  1603   if (!valid_) {
  1604     BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
  1605     return NULL;
  1608   if (index >= thread_count_) {
  1609     BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
  1610                     index << "/" << thread_count_;
  1611     return NULL;
  1614   return &(*threads_)[index];
  1618 MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
  1619   // Don't check valid_.  Read calls this method before everything is
  1620   // validated.  It is safe to not check valid_ here.
  1621   return id_to_thread_map_[thread_id];
  1625 void MinidumpThreadList::Print() {
  1626   if (!valid_) {
  1627     BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
  1628     return;
  1631   printf("MinidumpThreadList\n");
  1632   printf("  thread_count = %d\n", thread_count_);
  1633   printf("\n");
  1635   for (unsigned int thread_index = 0;
  1636        thread_index < thread_count_;
  1637        ++thread_index) {
  1638     printf("thread[%d]\n", thread_index);
  1640     (*threads_)[thread_index].Print();
  1645 //
  1646 // MinidumpModule
  1647 //
  1650 uint32_t MinidumpModule::max_cv_bytes_ = 32768;
  1651 uint32_t MinidumpModule::max_misc_bytes_ = 32768;
  1654 MinidumpModule::MinidumpModule(Minidump* minidump)
  1655     : MinidumpObject(minidump),
  1656       module_valid_(false),
  1657       has_debug_info_(false),
  1658       module_(),
  1659       name_(NULL),
  1660       cv_record_(NULL),
  1661       cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
  1662       misc_record_(NULL) {
  1666 MinidumpModule::~MinidumpModule() {
  1667   delete name_;
  1668   delete cv_record_;
  1669   delete misc_record_;
  1673 bool MinidumpModule::Read() {
  1674   // Invalidate cached data.
  1675   delete name_;
  1676   name_ = NULL;
  1677   delete cv_record_;
  1678   cv_record_ = NULL;
  1679   cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
  1680   delete misc_record_;
  1681   misc_record_ = NULL;
  1683   module_valid_ = false;
  1684   has_debug_info_ = false;
  1685   valid_ = false;
  1687   if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
  1688     BPLOG(ERROR) << "MinidumpModule cannot read module";
  1689     return false;
  1692   if (minidump_->swap()) {
  1693     Swap(&module_.base_of_image);
  1694     Swap(&module_.size_of_image);
  1695     Swap(&module_.checksum);
  1696     Swap(&module_.time_date_stamp);
  1697     Swap(&module_.module_name_rva);
  1698     Swap(&module_.version_info.signature);
  1699     Swap(&module_.version_info.struct_version);
  1700     Swap(&module_.version_info.file_version_hi);
  1701     Swap(&module_.version_info.file_version_lo);
  1702     Swap(&module_.version_info.product_version_hi);
  1703     Swap(&module_.version_info.product_version_lo);
  1704     Swap(&module_.version_info.file_flags_mask);
  1705     Swap(&module_.version_info.file_flags);
  1706     Swap(&module_.version_info.file_os);
  1707     Swap(&module_.version_info.file_type);
  1708     Swap(&module_.version_info.file_subtype);
  1709     Swap(&module_.version_info.file_date_hi);
  1710     Swap(&module_.version_info.file_date_lo);
  1711     Swap(&module_.cv_record);
  1712     Swap(&module_.misc_record);
  1713     // Don't swap reserved fields because their contents are unknown (as
  1714     // are their proper widths).
  1717   // Check for base + size overflow or undersize.
  1718   if (module_.size_of_image == 0 ||
  1719       module_.size_of_image >
  1720           numeric_limits<uint64_t>::max() - module_.base_of_image) {
  1721     BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
  1722                     HexString(module_.base_of_image) << "+" <<
  1723                     HexString(module_.size_of_image);
  1724     return false;
  1727   module_valid_ = true;
  1728   return true;
  1732 bool MinidumpModule::ReadAuxiliaryData() {
  1733   if (!module_valid_) {
  1734     BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
  1735     return false;
  1738   // Each module must have a name.
  1739   name_ = minidump_->ReadString(module_.module_name_rva);
  1740   if (!name_) {
  1741     BPLOG(ERROR) << "MinidumpModule could not read name";
  1742     return false;
  1745   // At this point, we have enough info for the module to be valid.
  1746   valid_ = true;
  1748   // CodeView and miscellaneous debug records are only required if the
  1749   // module indicates that they exist.
  1750   if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
  1751     BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
  1752                     "but one was expected";
  1753     return false;
  1756   if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
  1757     BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
  1758                     "but one was expected";
  1759     return false;
  1762   has_debug_info_ = true;
  1763   return true;
  1767 string MinidumpModule::code_file() const {
  1768   if (!valid_) {
  1769     BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
  1770     return "";
  1773   return *name_;
  1777 string MinidumpModule::code_identifier() const {
  1778   if (!valid_) {
  1779     BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
  1780     return "";
  1783   if (!has_debug_info_)
  1784     return "";
  1786   MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
  1787   if (!minidump_system_info) {
  1788     BPLOG(ERROR) << "MinidumpModule code_identifier requires "
  1789                     "MinidumpSystemInfo";
  1790     return "";
  1793   const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
  1794   if (!raw_system_info) {
  1795     BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
  1796     return "";
  1799   string identifier;
  1801   switch (raw_system_info->platform_id) {
  1802     case MD_OS_WIN32_NT:
  1803     case MD_OS_WIN32_WINDOWS: {
  1804       // Use the same format that the MS symbol server uses in filesystem
  1805       // hierarchies.
  1806       char identifier_string[17];
  1807       snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
  1808                module_.time_date_stamp, module_.size_of_image);
  1809       identifier = identifier_string;
  1810       break;
  1813     case MD_OS_MAC_OS_X:
  1814     case MD_OS_IOS:
  1815     case MD_OS_SOLARIS:
  1816     case MD_OS_ANDROID:
  1817     case MD_OS_LINUX: {
  1818       // TODO(mmentovai): support uuid extension if present, otherwise fall
  1819       // back to version (from LC_ID_DYLIB?), otherwise fall back to something
  1820       // else.
  1821       identifier = "id";
  1822       break;
  1825     default: {
  1826       // Without knowing what OS generated the dump, we can't generate a good
  1827       // identifier.  Return an empty string, signalling failure.
  1828       BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
  1829                       "found " << HexString(raw_system_info->platform_id);
  1830       break;
  1834   return identifier;
  1838 string MinidumpModule::debug_file() const {
  1839   if (!valid_) {
  1840     BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
  1841     return "";
  1844   if (!has_debug_info_)
  1845     return "";
  1847   string file;
  1848   // Prefer the CodeView record if present.
  1849   if (cv_record_) {
  1850     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  1851       // It's actually an MDCVInfoPDB70 structure.
  1852       const MDCVInfoPDB70* cv_record_70 =
  1853           reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
  1854       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  1856       // GetCVRecord guarantees pdb_file_name is null-terminated.
  1857       file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
  1858     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  1859       // It's actually an MDCVInfoPDB20 structure.
  1860       const MDCVInfoPDB20* cv_record_20 =
  1861           reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
  1862       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  1864       // GetCVRecord guarantees pdb_file_name is null-terminated.
  1865       file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
  1868     // If there's a CodeView record but it doesn't match a known signature,
  1869     // try the miscellaneous record.
  1872   if (file.empty()) {
  1873     // No usable CodeView record.  Try the miscellaneous debug record.
  1874     if (misc_record_) {
  1875       const MDImageDebugMisc* misc_record =
  1876           reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
  1877       if (!misc_record->unicode) {
  1878         // If it's not Unicode, just stuff it into the string.  It's unclear
  1879         // if misc_record->data is 0-terminated, so use an explicit size.
  1880         file = string(
  1881             reinterpret_cast<const char*>(misc_record->data),
  1882             module_.misc_record.data_size - MDImageDebugMisc_minsize);
  1883       } else {
  1884         // There's a misc_record but it encodes the debug filename in UTF-16.
  1885         // (Actually, because miscellaneous records are so old, it's probably
  1886         // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
  1887         // that this method (and all other methods in the Minidump family)
  1888         // return.
  1890         unsigned int bytes =
  1891             module_.misc_record.data_size - MDImageDebugMisc_minsize;
  1892         if (bytes % 2 == 0) {
  1893           unsigned int utf16_words = bytes / 2;
  1895           // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
  1896           // and copy the UTF-16 data into it.
  1897           vector<uint16_t> string_utf16(utf16_words);
  1898           if (utf16_words)
  1899             memcpy(&string_utf16[0], &misc_record->data, bytes);
  1901           // GetMiscRecord already byte-swapped the data[] field if it contains
  1902           // UTF-16, so pass false as the swap argument.
  1903           scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
  1904           file = *new_file;
  1910   // Relatively common case
  1911   BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
  1912                                   "debug_file for " << *name_;
  1914   return file;
  1918 string MinidumpModule::debug_identifier() const {
  1919   if (!valid_) {
  1920     BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
  1921     return "";
  1924   if (!has_debug_info_)
  1925     return "";
  1927   string identifier;
  1929   // Use the CodeView record if present.
  1930   if (cv_record_) {
  1931     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  1932       // It's actually an MDCVInfoPDB70 structure.
  1933       const MDCVInfoPDB70* cv_record_70 =
  1934           reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
  1935       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  1937       // Use the same format that the MS symbol server uses in filesystem
  1938       // hierarchies.
  1939       char identifier_string[41];
  1940       snprintf(identifier_string, sizeof(identifier_string),
  1941                "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
  1942                cv_record_70->signature.data1,
  1943                cv_record_70->signature.data2,
  1944                cv_record_70->signature.data3,
  1945                cv_record_70->signature.data4[0],
  1946                cv_record_70->signature.data4[1],
  1947                cv_record_70->signature.data4[2],
  1948                cv_record_70->signature.data4[3],
  1949                cv_record_70->signature.data4[4],
  1950                cv_record_70->signature.data4[5],
  1951                cv_record_70->signature.data4[6],
  1952                cv_record_70->signature.data4[7],
  1953                cv_record_70->age);
  1954       identifier = identifier_string;
  1955     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  1956       // It's actually an MDCVInfoPDB20 structure.
  1957       const MDCVInfoPDB20* cv_record_20 =
  1958           reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
  1959       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  1961       // Use the same format that the MS symbol server uses in filesystem
  1962       // hierarchies.
  1963       char identifier_string[17];
  1964       snprintf(identifier_string, sizeof(identifier_string),
  1965                "%08X%x", cv_record_20->signature, cv_record_20->age);
  1966       identifier = identifier_string;
  1970   // TODO(mmentovai): if there's no usable CodeView record, there might be a
  1971   // miscellaneous debug record.  It only carries a filename, though, and no
  1972   // identifier.  I'm not sure what the right thing to do for the identifier
  1973   // is in that case, but I don't expect to find many modules without a
  1974   // CodeView record (or some other Breakpad extension structure in place of
  1975   // a CodeView record).  Treat it as an error (empty identifier) for now.
  1977   // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
  1979   // Relatively common case
  1980   BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
  1981                                         "debug_identifier for " << *name_;
  1983   return identifier;
  1987 string MinidumpModule::version() const {
  1988   if (!valid_) {
  1989     BPLOG(ERROR) << "Invalid MinidumpModule for version";
  1990     return "";
  1993   string version;
  1995   if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
  1996       module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
  1997     char version_string[24];
  1998     snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
  1999              module_.version_info.file_version_hi >> 16,
  2000              module_.version_info.file_version_hi & 0xffff,
  2001              module_.version_info.file_version_lo >> 16,
  2002              module_.version_info.file_version_lo & 0xffff);
  2003     version = version_string;
  2006   // TODO(mmentovai): possibly support other struct types in place of
  2007   // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
  2008   // a different structure that better represents versioning facilities on
  2009   // Mac OS X and Linux, instead of forcing them to adhere to the dotted
  2010   // quad of 16-bit ints that Windows uses.
  2012   BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
  2013                                      "version for " << *name_;
  2015   return version;
  2019 const CodeModule* MinidumpModule::Copy() const {
  2020   return new BasicCodeModule(this);
  2024 const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
  2025   if (!module_valid_) {
  2026     BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
  2027     return NULL;
  2030   if (!cv_record_) {
  2031     // This just guards against 0-sized CodeView records; more specific checks
  2032     // are used when the signature is checked against various structure types.
  2033     if (module_.cv_record.data_size == 0) {
  2034       return NULL;
  2037     if (!minidump_->SeekSet(module_.cv_record.rva)) {
  2038       BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
  2039       return NULL;
  2042     if (module_.cv_record.data_size > max_cv_bytes_) {
  2043       BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
  2044                       module_.cv_record.data_size << " exceeds maximum " <<
  2045                       max_cv_bytes_;
  2046       return NULL;
  2049     // Allocating something that will be accessed as MDCVInfoPDB70 or
  2050     // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
  2051     // problems.  x86 and ppc are able to cope, though.  This allocation
  2052     // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
  2053     // variable-sized due to their pdb_file_name fields; these structures
  2054     // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
  2055     // them as such would result in incomplete structures or overruns.
  2056     scoped_ptr< vector<uint8_t> > cv_record(
  2057         new vector<uint8_t>(module_.cv_record.data_size));
  2059     if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
  2060       BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
  2061       return NULL;
  2064     uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
  2065     if (module_.cv_record.data_size > sizeof(signature)) {
  2066       MDCVInfoPDB70* cv_record_signature =
  2067           reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
  2068       signature = cv_record_signature->cv_signature;
  2069       if (minidump_->swap())
  2070         Swap(&signature);
  2073     if (signature == MD_CVINFOPDB70_SIGNATURE) {
  2074       // Now that the structure type is known, recheck the size.
  2075       if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
  2076         BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
  2077                         MDCVInfoPDB70_minsize << " > " <<
  2078                         module_.cv_record.data_size;
  2079         return NULL;
  2082       if (minidump_->swap()) {
  2083         MDCVInfoPDB70* cv_record_70 =
  2084             reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
  2085         Swap(&cv_record_70->cv_signature);
  2086         Swap(&cv_record_70->signature);
  2087         Swap(&cv_record_70->age);
  2088         // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
  2089         // quantities.  (It's a path, is it UTF-8?)
  2092       // The last field of either structure is null-terminated 8-bit character
  2093       // data.  Ensure that it's null-terminated.
  2094       if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
  2095         BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
  2096                         "0-terminated";
  2097         return NULL;
  2099     } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
  2100       // Now that the structure type is known, recheck the size.
  2101       if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
  2102         BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
  2103                         MDCVInfoPDB20_minsize << " > " <<
  2104                         module_.cv_record.data_size;
  2105         return NULL;
  2107       if (minidump_->swap()) {
  2108         MDCVInfoPDB20* cv_record_20 =
  2109             reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
  2110         Swap(&cv_record_20->cv_header.signature);
  2111         Swap(&cv_record_20->cv_header.offset);
  2112         Swap(&cv_record_20->signature);
  2113         Swap(&cv_record_20->age);
  2114         // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
  2115         // quantities.  (It's a path, is it UTF-8?)
  2118       // The last field of either structure is null-terminated 8-bit character
  2119       // data.  Ensure that it's null-terminated.
  2120       if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
  2121         BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
  2122                         "0-terminated";
  2123         return NULL;
  2127     // If the signature doesn't match something above, it's not something
  2128     // that Breakpad can presently handle directly.  Because some modules in
  2129     // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
  2130     // don't bail out here - allow the data to be returned to the user,
  2131     // although byte-swapping can't be done.
  2133     // Store the vector type because that's how storage was allocated, but
  2134     // return it casted to uint8_t*.
  2135     cv_record_ = cv_record.release();
  2136     cv_record_signature_ = signature;
  2139   if (size)
  2140     *size = module_.cv_record.data_size;
  2142   return &(*cv_record_)[0];
  2146 const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
  2147   if (!module_valid_) {
  2148     BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
  2149     return NULL;
  2152   if (!misc_record_) {
  2153     if (module_.misc_record.data_size == 0) {
  2154       return NULL;
  2157     if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
  2158       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
  2159                       "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
  2160                       module_.misc_record.data_size;
  2161       return NULL;
  2164     if (!minidump_->SeekSet(module_.misc_record.rva)) {
  2165       BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
  2166                       "debugging record";
  2167       return NULL;
  2170     if (module_.misc_record.data_size > max_misc_bytes_) {
  2171       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
  2172                       module_.misc_record.data_size << " exceeds maximum " <<
  2173                       max_misc_bytes_;
  2174       return NULL;
  2177     // Allocating something that will be accessed as MDImageDebugMisc but
  2178     // is allocated as uint8_t[] can cause alignment problems.  x86 and
  2179     // ppc are able to cope, though.  This allocation style is needed
  2180     // because the MDImageDebugMisc is variable-sized due to its data field;
  2181     // this structure is not MDImageDebugMisc_minsize and treating it as such
  2182     // would result in an incomplete structure or an overrun.
  2183     scoped_ptr< vector<uint8_t> > misc_record_mem(
  2184         new vector<uint8_t>(module_.misc_record.data_size));
  2185     MDImageDebugMisc* misc_record =
  2186         reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
  2188     if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
  2189       BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
  2190                       "record";
  2191       return NULL;
  2194     if (minidump_->swap()) {
  2195       Swap(&misc_record->data_type);
  2196       Swap(&misc_record->length);
  2197       // Don't swap misc_record.unicode because it's an 8-bit quantity.
  2198       // Don't swap the reserved fields for the same reason, and because
  2199       // they don't contain any valid data.
  2200       if (misc_record->unicode) {
  2201         // There is a potential alignment problem, but shouldn't be a problem
  2202         // in practice due to the layout of MDImageDebugMisc.
  2203         uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
  2204         unsigned int dataBytes = module_.misc_record.data_size -
  2205                                  MDImageDebugMisc_minsize;
  2206         unsigned int dataLength = dataBytes / 2;
  2207         for (unsigned int characterIndex = 0;
  2208              characterIndex < dataLength;
  2209              ++characterIndex) {
  2210           Swap(&data16[characterIndex]);
  2215     if (module_.misc_record.data_size != misc_record->length) {
  2216       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
  2217                       "size mismatch, " << module_.misc_record.data_size <<
  2218                       " != " << misc_record->length;
  2219       return NULL;
  2222     // Store the vector type because that's how storage was allocated, but
  2223     // return it casted to MDImageDebugMisc*.
  2224     misc_record_ = misc_record_mem.release();
  2227   if (size)
  2228     *size = module_.misc_record.data_size;
  2230   return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
  2234 void MinidumpModule::Print() {
  2235   if (!valid_) {
  2236     BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
  2237     return;
  2240   printf("MDRawModule\n");
  2241   printf("  base_of_image                   = 0x%" PRIx64 "\n",
  2242          module_.base_of_image);
  2243   printf("  size_of_image                   = 0x%x\n",
  2244          module_.size_of_image);
  2245   printf("  checksum                        = 0x%x\n",
  2246          module_.checksum);
  2247   printf("  time_date_stamp                 = 0x%x\n",
  2248          module_.time_date_stamp);
  2249   printf("  module_name_rva                 = 0x%x\n",
  2250          module_.module_name_rva);
  2251   printf("  version_info.signature          = 0x%x\n",
  2252          module_.version_info.signature);
  2253   printf("  version_info.struct_version     = 0x%x\n",
  2254          module_.version_info.struct_version);
  2255   printf("  version_info.file_version       = 0x%x:0x%x\n",
  2256          module_.version_info.file_version_hi,
  2257          module_.version_info.file_version_lo);
  2258   printf("  version_info.product_version    = 0x%x:0x%x\n",
  2259          module_.version_info.product_version_hi,
  2260          module_.version_info.product_version_lo);
  2261   printf("  version_info.file_flags_mask    = 0x%x\n",
  2262          module_.version_info.file_flags_mask);
  2263   printf("  version_info.file_flags         = 0x%x\n",
  2264          module_.version_info.file_flags);
  2265   printf("  version_info.file_os            = 0x%x\n",
  2266          module_.version_info.file_os);
  2267   printf("  version_info.file_type          = 0x%x\n",
  2268          module_.version_info.file_type);
  2269   printf("  version_info.file_subtype       = 0x%x\n",
  2270          module_.version_info.file_subtype);
  2271   printf("  version_info.file_date          = 0x%x:0x%x\n",
  2272          module_.version_info.file_date_hi,
  2273          module_.version_info.file_date_lo);
  2274   printf("  cv_record.data_size             = %d\n",
  2275          module_.cv_record.data_size);
  2276   printf("  cv_record.rva                   = 0x%x\n",
  2277          module_.cv_record.rva);
  2278   printf("  misc_record.data_size           = %d\n",
  2279          module_.misc_record.data_size);
  2280   printf("  misc_record.rva                 = 0x%x\n",
  2281          module_.misc_record.rva);
  2283   printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
  2284   printf("  (code_identifier)               = \"%s\"\n",
  2285          code_identifier().c_str());
  2287   uint32_t cv_record_size;
  2288   const uint8_t *cv_record = GetCVRecord(&cv_record_size);
  2289   if (cv_record) {
  2290     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
  2291       const MDCVInfoPDB70* cv_record_70 =
  2292           reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
  2293       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
  2295       printf("  (cv_record).cv_signature        = 0x%x\n",
  2296              cv_record_70->cv_signature);
  2297       printf("  (cv_record).signature           = %08x-%04x-%04x-%02x%02x-",
  2298              cv_record_70->signature.data1,
  2299              cv_record_70->signature.data2,
  2300              cv_record_70->signature.data3,
  2301              cv_record_70->signature.data4[0],
  2302              cv_record_70->signature.data4[1]);
  2303       for (unsigned int guidIndex = 2;
  2304            guidIndex < 8;
  2305            ++guidIndex) {
  2306         printf("%02x", cv_record_70->signature.data4[guidIndex]);
  2308       printf("\n");
  2309       printf("  (cv_record).age                 = %d\n",
  2310              cv_record_70->age);
  2311       printf("  (cv_record).pdb_file_name       = \"%s\"\n",
  2312              cv_record_70->pdb_file_name);
  2313     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
  2314       const MDCVInfoPDB20* cv_record_20 =
  2315           reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
  2316       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
  2318       printf("  (cv_record).cv_header.signature = 0x%x\n",
  2319              cv_record_20->cv_header.signature);
  2320       printf("  (cv_record).cv_header.offset    = 0x%x\n",
  2321              cv_record_20->cv_header.offset);
  2322       printf("  (cv_record).signature           = 0x%x\n",
  2323              cv_record_20->signature);
  2324       printf("  (cv_record).age                 = %d\n",
  2325              cv_record_20->age);
  2326       printf("  (cv_record).pdb_file_name       = \"%s\"\n",
  2327              cv_record_20->pdb_file_name);
  2328     } else {
  2329       printf("  (cv_record)                     = ");
  2330       for (unsigned int cv_byte_index = 0;
  2331            cv_byte_index < cv_record_size;
  2332            ++cv_byte_index) {
  2333         printf("%02x", cv_record[cv_byte_index]);
  2335       printf("\n");
  2337   } else {
  2338     printf("  (cv_record)                     = (null)\n");
  2341   const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
  2342   if (misc_record) {
  2343     printf("  (misc_record).data_type         = 0x%x\n",
  2344            misc_record->data_type);
  2345     printf("  (misc_record).length            = 0x%x\n",
  2346            misc_record->length);
  2347     printf("  (misc_record).unicode           = %d\n",
  2348            misc_record->unicode);
  2349     // Don't bother printing the UTF-16, we don't really even expect to ever
  2350     // see this misc_record anyway.
  2351     if (misc_record->unicode)
  2352       printf("  (misc_record).data              = \"%s\"\n",
  2353              misc_record->data);
  2354     else
  2355       printf("  (misc_record).data              = (UTF-16)\n");
  2356   } else {
  2357     printf("  (misc_record)                   = (null)\n");
  2360   printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
  2361   printf("  (debug_identifier)              = \"%s\"\n",
  2362          debug_identifier().c_str());
  2363   printf("  (version)                       = \"%s\"\n", version().c_str());
  2364   printf("\n");
  2368 //
  2369 // MinidumpModuleList
  2370 //
  2373 uint32_t MinidumpModuleList::max_modules_ = 1024;
  2376 MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
  2377     : MinidumpStream(minidump),
  2378       range_map_(new RangeMap<uint64_t, unsigned int>()),
  2379       modules_(NULL),
  2380       module_count_(0) {
  2384 MinidumpModuleList::~MinidumpModuleList() {
  2385   delete range_map_;
  2386   delete modules_;
  2390 bool MinidumpModuleList::Read(uint32_t expected_size) {
  2391   // Invalidate cached data.
  2392   range_map_->Clear();
  2393   delete modules_;
  2394   modules_ = NULL;
  2395   module_count_ = 0;
  2397   valid_ = false;
  2399   uint32_t module_count;
  2400   if (expected_size < sizeof(module_count)) {
  2401     BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
  2402                     expected_size << " < " << sizeof(module_count);
  2403     return false;
  2405   if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
  2406     BPLOG(ERROR) << "MinidumpModuleList could not read module count";
  2407     return false;
  2410   if (minidump_->swap())
  2411     Swap(&module_count);
  2413   if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
  2414     BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
  2415                     " would cause multiplication overflow";
  2416     return false;
  2419   if (expected_size != sizeof(module_count) +
  2420                        module_count * MD_MODULE_SIZE) {
  2421     // may be padded with 4 bytes on 64bit ABIs for alignment
  2422     if (expected_size == sizeof(module_count) + 4 +
  2423                          module_count * MD_MODULE_SIZE) {
  2424       uint32_t useless;
  2425       if (!minidump_->ReadBytes(&useless, 4)) {
  2426         BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes";
  2427         return false;
  2429     } else {
  2430       BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
  2431                       " != " << sizeof(module_count) +
  2432                       module_count * MD_MODULE_SIZE;
  2433       return false;
  2437   if (module_count > max_modules_) {
  2438     BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
  2439                     " exceeds maximum " << max_modules_;
  2440     return false;
  2443   if (module_count != 0) {
  2444     scoped_ptr<MinidumpModules> modules(
  2445         new MinidumpModules(module_count, MinidumpModule(minidump_)));
  2447     for (unsigned int module_index = 0;
  2448          module_index < module_count;
  2449          ++module_index) {
  2450       MinidumpModule* module = &(*modules)[module_index];
  2452       // Assume that the file offset is correct after the last read.
  2453       if (!module->Read()) {
  2454         BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
  2455                         module_index << "/" << module_count;
  2456         return false;
  2460     // Loop through the module list once more to read additional data and
  2461     // build the range map.  This is done in a second pass because
  2462     // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
  2463     // included in the loop above, additional seeks would be needed where
  2464     // none are now to read contiguous data.
  2465     for (unsigned int module_index = 0;
  2466          module_index < module_count;
  2467          ++module_index) {
  2468       MinidumpModule* module = &(*modules)[module_index];
  2470       // ReadAuxiliaryData fails if any data that the module indicates should
  2471       // exist is missing, but we treat some such cases as valid anyway.  See
  2472       // issue #222: if a debugging record is of a format that's too large to
  2473       // handle, it shouldn't render the entire dump invalid.  Check module
  2474       // validity before giving up.
  2475       if (!module->ReadAuxiliaryData() && !module->valid()) {
  2476         BPLOG(ERROR) << "MinidumpModuleList could not read required module "
  2477                         "auxiliary data for module " <<
  2478                         module_index << "/" << module_count;
  2479         return false;
  2482       // It is safe to use module->code_file() after successfully calling
  2483       // module->ReadAuxiliaryData or noting that the module is valid.
  2485       uint64_t base_address = module->base_address();
  2486       uint64_t module_size = module->size();
  2487       if (base_address == static_cast<uint64_t>(-1)) {
  2488         BPLOG(ERROR) << "MinidumpModuleList found bad base address "
  2489                         "for module " << module_index << "/" << module_count <<
  2490                         ", " << module->code_file();
  2491         return false;
  2494       if (!range_map_->StoreRange(base_address, module_size, module_index)) {
  2495         BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
  2496                         module_index << "/" << module_count << ", " <<
  2497                         module->code_file() << ", " <<
  2498                         HexString(base_address) << "+" <<
  2499                         HexString(module_size);
  2500         return false;
  2504     modules_ = modules.release();
  2507   module_count_ = module_count;
  2509   valid_ = true;
  2510   return true;
  2514 const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
  2515     uint64_t address) const {
  2516   if (!valid_) {
  2517     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
  2518     return NULL;
  2521   unsigned int module_index;
  2522   if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) {
  2523     BPLOG(INFO) << "MinidumpModuleList has no module at " <<
  2524                    HexString(address);
  2525     return NULL;
  2528   return GetModuleAtIndex(module_index);
  2532 const MinidumpModule* MinidumpModuleList::GetMainModule() const {
  2533   if (!valid_) {
  2534     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
  2535     return NULL;
  2538   // The main code module is the first one present in a minidump file's
  2539   // MDRawModuleList.
  2540   return GetModuleAtIndex(0);
  2544 const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
  2545     unsigned int sequence) const {
  2546   if (!valid_) {
  2547     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
  2548     return NULL;
  2551   if (sequence >= module_count_) {
  2552     BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
  2553                     sequence << "/" << module_count_;
  2554     return NULL;
  2557   unsigned int module_index;
  2558   if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) {
  2559     BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
  2560     return NULL;
  2563   return GetModuleAtIndex(module_index);
  2567 const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
  2568     unsigned int index) const {
  2569   if (!valid_) {
  2570     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
  2571     return NULL;
  2574   if (index >= module_count_) {
  2575     BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
  2576                     index << "/" << module_count_;
  2577     return NULL;
  2580   return &(*modules_)[index];
  2584 const CodeModules* MinidumpModuleList::Copy() const {
  2585   return new BasicCodeModules(this);
  2589 void MinidumpModuleList::Print() {
  2590   if (!valid_) {
  2591     BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
  2592     return;
  2595   printf("MinidumpModuleList\n");
  2596   printf("  module_count = %d\n", module_count_);
  2597   printf("\n");
  2599   for (unsigned int module_index = 0;
  2600        module_index < module_count_;
  2601        ++module_index) {
  2602     printf("module[%d]\n", module_index);
  2604     (*modules_)[module_index].Print();
  2609 //
  2610 // MinidumpMemoryList
  2611 //
  2614 uint32_t MinidumpMemoryList::max_regions_ = 4096;
  2617 MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
  2618     : MinidumpStream(minidump),
  2619       range_map_(new RangeMap<uint64_t, unsigned int>()),
  2620       descriptors_(NULL),
  2621       regions_(NULL),
  2622       region_count_(0) {
  2626 MinidumpMemoryList::~MinidumpMemoryList() {
  2627   delete range_map_;
  2628   delete descriptors_;
  2629   delete regions_;
  2633 bool MinidumpMemoryList::Read(uint32_t expected_size) {
  2634   // Invalidate cached data.
  2635   delete descriptors_;
  2636   descriptors_ = NULL;
  2637   delete regions_;
  2638   regions_ = NULL;
  2639   range_map_->Clear();
  2640   region_count_ = 0;
  2642   valid_ = false;
  2644   uint32_t region_count;
  2645   if (expected_size < sizeof(region_count)) {
  2646     BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
  2647                     expected_size << " < " << sizeof(region_count);
  2648     return false;
  2650   if (!minidump_->ReadBytes(&region_count, sizeof(region_count))) {
  2651     BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
  2652     return false;
  2655   if (minidump_->swap())
  2656     Swap(&region_count);
  2658   if (region_count >
  2659           numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
  2660     BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
  2661                     " would cause multiplication overflow";
  2662     return false;
  2665   if (expected_size != sizeof(region_count) +
  2666                        region_count * sizeof(MDMemoryDescriptor)) {
  2667     // may be padded with 4 bytes on 64bit ABIs for alignment
  2668     if (expected_size == sizeof(region_count) + 4 +
  2669                          region_count * sizeof(MDMemoryDescriptor)) {
  2670       uint32_t useless;
  2671       if (!minidump_->ReadBytes(&useless, 4)) {
  2672         BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes";
  2673         return false;
  2675     } else {
  2676       BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
  2677                       " != " << sizeof(region_count) + 
  2678                       region_count * sizeof(MDMemoryDescriptor);
  2679       return false;
  2683   if (region_count > max_regions_) {
  2684     BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
  2685                     " exceeds maximum " << max_regions_;
  2686     return false;
  2689   if (region_count != 0) {
  2690     scoped_ptr<MemoryDescriptors> descriptors(
  2691         new MemoryDescriptors(region_count));
  2693     // Read the entire array in one fell swoop, instead of reading one entry
  2694     // at a time in the loop.
  2695     if (!minidump_->ReadBytes(&(*descriptors)[0],
  2696                               sizeof(MDMemoryDescriptor) * region_count)) {
  2697       BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
  2698       return false;
  2701     scoped_ptr<MemoryRegions> regions(
  2702         new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
  2704     for (unsigned int region_index = 0;
  2705          region_index < region_count;
  2706          ++region_index) {
  2707       MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
  2709       if (minidump_->swap())
  2710         Swap(descriptor);
  2712       uint64_t base_address = descriptor->start_of_memory_range;
  2713       uint32_t region_size = descriptor->memory.data_size;
  2715       // Check for base + size overflow or undersize.
  2716       if (region_size == 0 ||
  2717           region_size > numeric_limits<uint64_t>::max() - base_address) {
  2718         BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
  2719                         " region " << region_index << "/" << region_count <<
  2720                         ", " << HexString(base_address) << "+" <<
  2721                         HexString(region_size);
  2722         return false;
  2725       if (!range_map_->StoreRange(base_address, region_size, region_index)) {
  2726         BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
  2727                         region_index << "/" << region_count << ", " <<
  2728                         HexString(base_address) << "+" <<
  2729                         HexString(region_size);
  2730         return false;
  2733       (*regions)[region_index].SetDescriptor(descriptor);
  2736     descriptors_ = descriptors.release();
  2737     regions_ = regions.release();
  2740   region_count_ = region_count;
  2742   valid_ = true;
  2743   return true;
  2747 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
  2748       unsigned int index) {
  2749   if (!valid_) {
  2750     BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
  2751     return NULL;
  2754   if (index >= region_count_) {
  2755     BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
  2756                     index << "/" << region_count_;
  2757     return NULL;
  2760   return &(*regions_)[index];
  2764 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
  2765     uint64_t address) {
  2766   if (!valid_) {
  2767     BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
  2768     return NULL;
  2771   unsigned int region_index;
  2772   if (!range_map_->RetrieveRange(address, &region_index, NULL, NULL)) {
  2773     BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
  2774                    HexString(address);
  2775     return NULL;
  2778   return GetMemoryRegionAtIndex(region_index);
  2782 void MinidumpMemoryList::Print() {
  2783   if (!valid_) {
  2784     BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
  2785     return;
  2788   printf("MinidumpMemoryList\n");
  2789   printf("  region_count = %d\n", region_count_);
  2790   printf("\n");
  2792   for (unsigned int region_index = 0;
  2793        region_index < region_count_;
  2794        ++region_index) {
  2795     MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
  2796     printf("region[%d]\n", region_index);
  2797     printf("MDMemoryDescriptor\n");
  2798     printf("  start_of_memory_range = 0x%" PRIx64 "\n",
  2799            descriptor->start_of_memory_range);
  2800     printf("  memory.data_size      = 0x%x\n", descriptor->memory.data_size);
  2801     printf("  memory.rva            = 0x%x\n", descriptor->memory.rva);
  2802     MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
  2803     if (region) {
  2804       printf("Memory\n");
  2805       region->Print();
  2806     } else {
  2807       printf("No memory\n");
  2809     printf("\n");
  2814 //
  2815 // MinidumpException
  2816 //
  2819 MinidumpException::MinidumpException(Minidump* minidump)
  2820     : MinidumpStream(minidump),
  2821       exception_(),
  2822       context_(NULL) {
  2826 MinidumpException::~MinidumpException() {
  2827   delete context_;
  2831 bool MinidumpException::Read(uint32_t expected_size) {
  2832   // Invalidate cached data.
  2833   delete context_;
  2834   context_ = NULL;
  2836   valid_ = false;
  2838   if (expected_size != sizeof(exception_)) {
  2839     BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
  2840                     " != " << sizeof(exception_);
  2841     return false;
  2844   if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
  2845     BPLOG(ERROR) << "MinidumpException cannot read exception";
  2846     return false;
  2849   if (minidump_->swap()) {
  2850     Swap(&exception_.thread_id);
  2851     // exception_.__align is for alignment only and does not need to be
  2852     // swapped.
  2853     Swap(&exception_.exception_record.exception_code);
  2854     Swap(&exception_.exception_record.exception_flags);
  2855     Swap(&exception_.exception_record.exception_record);
  2856     Swap(&exception_.exception_record.exception_address);
  2857     Swap(&exception_.exception_record.number_parameters);
  2858     // exception_.exception_record.__align is for alignment only and does not
  2859     // need to be swapped.
  2860     for (unsigned int parameter_index = 0;
  2861          parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
  2862          ++parameter_index) {
  2863       Swap(&exception_.exception_record.exception_information[parameter_index]);
  2865     Swap(&exception_.thread_context);
  2868   valid_ = true;
  2869   return true;
  2873 bool MinidumpException::GetThreadID(uint32_t *thread_id) const {
  2874   BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
  2875                                  "|thread_id|";
  2876   assert(thread_id);
  2877   *thread_id = 0;
  2879   if (!valid_) {
  2880     BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
  2881     return false;
  2884   *thread_id = exception_.thread_id;
  2885   return true;
  2889 MinidumpContext* MinidumpException::GetContext() {
  2890   if (!valid_) {
  2891     BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
  2892     return NULL;
  2895   if (!context_) {
  2896     if (!minidump_->SeekSet(exception_.thread_context.rva)) {
  2897       BPLOG(ERROR) << "MinidumpException cannot seek to context";
  2898       return NULL;
  2901     scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
  2903     // Don't log as an error if we can still fall back on the thread's context
  2904     // (which must be possible if we got this far.)
  2905     if (!context->Read(exception_.thread_context.data_size)) {
  2906       BPLOG(INFO) << "MinidumpException cannot read context";
  2907       return NULL;
  2910     context_ = context.release();
  2913   return context_;
  2917 void MinidumpException::Print() {
  2918   if (!valid_) {
  2919     BPLOG(ERROR) << "MinidumpException cannot print invalid data";
  2920     return;
  2923   printf("MDException\n");
  2924   printf("  thread_id                                  = 0x%x\n",
  2925          exception_.thread_id);
  2926   printf("  exception_record.exception_code            = 0x%x\n",
  2927          exception_.exception_record.exception_code);
  2928   printf("  exception_record.exception_flags           = 0x%x\n",
  2929          exception_.exception_record.exception_flags);
  2930   printf("  exception_record.exception_record          = 0x%" PRIx64 "\n",
  2931          exception_.exception_record.exception_record);
  2932   printf("  exception_record.exception_address         = 0x%" PRIx64 "\n",
  2933          exception_.exception_record.exception_address);
  2934   printf("  exception_record.number_parameters         = %d\n",
  2935          exception_.exception_record.number_parameters);
  2936   for (unsigned int parameterIndex = 0;
  2937        parameterIndex < exception_.exception_record.number_parameters;
  2938        ++parameterIndex) {
  2939     printf("  exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
  2940            parameterIndex,
  2941            exception_.exception_record.exception_information[parameterIndex]);
  2943   printf("  thread_context.data_size                   = %d\n",
  2944          exception_.thread_context.data_size);
  2945   printf("  thread_context.rva                         = 0x%x\n",
  2946          exception_.thread_context.rva);
  2947   MinidumpContext* context = GetContext();
  2948   if (context) {
  2949     printf("\n");
  2950     context->Print();
  2951   } else {
  2952     printf("  (no context)\n");
  2953     printf("\n");
  2957 //
  2958 // MinidumpAssertion
  2959 //
  2962 MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
  2963     : MinidumpStream(minidump),
  2964       assertion_(),
  2965       expression_(),
  2966       function_(),
  2967       file_() {
  2971 MinidumpAssertion::~MinidumpAssertion() {
  2975 bool MinidumpAssertion::Read(uint32_t expected_size) {
  2976   // Invalidate cached data.
  2977   valid_ = false;
  2979   if (expected_size != sizeof(assertion_)) {
  2980     BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
  2981                     " != " << sizeof(assertion_);
  2982     return false;
  2985   if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
  2986     BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
  2987     return false;
  2990   // Each of {expression, function, file} is a UTF-16 string,
  2991   // we'll convert them to UTF-8 for ease of use.
  2992   // expression
  2993   // Since we don't have an explicit byte length for each string,
  2994   // we use UTF16codeunits to calculate word length, then derive byte
  2995   // length from that.
  2996   uint32_t word_length = UTF16codeunits(assertion_.expression,
  2997                                          sizeof(assertion_.expression));
  2998   if (word_length > 0) {
  2999     uint32_t byte_length = word_length * 2;
  3000     vector<uint16_t> expression_utf16(word_length);
  3001     memcpy(&expression_utf16[0], &assertion_.expression[0], byte_length);
  3003     scoped_ptr<string> new_expression(UTF16ToUTF8(expression_utf16,
  3004                                                   minidump_->swap()));
  3005     if (new_expression.get())
  3006       expression_ = *new_expression;
  3009   // assertion
  3010   word_length = UTF16codeunits(assertion_.function,
  3011                                sizeof(assertion_.function));
  3012   if (word_length) {
  3013     uint32_t byte_length = word_length * 2;
  3014     vector<uint16_t> function_utf16(word_length);
  3015     memcpy(&function_utf16[0], &assertion_.function[0], byte_length);
  3016     scoped_ptr<string> new_function(UTF16ToUTF8(function_utf16,
  3017                                                 minidump_->swap()));
  3018     if (new_function.get())
  3019       function_ = *new_function;
  3022   // file
  3023   word_length = UTF16codeunits(assertion_.file,
  3024                                sizeof(assertion_.file));
  3025   if (word_length > 0) {
  3026     uint32_t byte_length = word_length * 2;
  3027     vector<uint16_t> file_utf16(word_length);
  3028     memcpy(&file_utf16[0], &assertion_.file[0], byte_length);
  3029     scoped_ptr<string> new_file(UTF16ToUTF8(file_utf16,
  3030                                             minidump_->swap()));
  3031     if (new_file.get())
  3032       file_ = *new_file;
  3035   if (minidump_->swap()) {
  3036     Swap(&assertion_.line);
  3037     Swap(&assertion_.type);
  3040   valid_ = true;
  3041   return true;
  3044 void MinidumpAssertion::Print() {
  3045   if (!valid_) {
  3046     BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
  3047     return;
  3050   printf("MDAssertion\n");
  3051   printf("  expression                                 = %s\n",
  3052          expression_.c_str());
  3053   printf("  function                                   = %s\n",
  3054          function_.c_str());
  3055   printf("  file                                       = %s\n",
  3056          file_.c_str());
  3057   printf("  line                                       = %u\n",
  3058          assertion_.line);
  3059   printf("  type                                       = %u\n",
  3060          assertion_.type);
  3061   printf("\n");
  3064 //
  3065 // MinidumpSystemInfo
  3066 //
  3069 MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
  3070     : MinidumpStream(minidump),
  3071       system_info_(),
  3072       csd_version_(NULL),
  3073       cpu_vendor_(NULL) {
  3077 MinidumpSystemInfo::~MinidumpSystemInfo() {
  3078   delete csd_version_;
  3079   delete cpu_vendor_;
  3083 bool MinidumpSystemInfo::Read(uint32_t expected_size) {
  3084   // Invalidate cached data.
  3085   delete csd_version_;
  3086   csd_version_ = NULL;
  3087   delete cpu_vendor_;
  3088   cpu_vendor_ = NULL;
  3090   valid_ = false;
  3092   if (expected_size != sizeof(system_info_)) {
  3093     BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
  3094                     " != " << sizeof(system_info_);
  3095     return false;
  3098   if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
  3099     BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
  3100     return false;
  3103   if (minidump_->swap()) {
  3104     Swap(&system_info_.processor_architecture);
  3105     Swap(&system_info_.processor_level);
  3106     Swap(&system_info_.processor_revision);
  3107     // number_of_processors and product_type are 8-bit quantities and need no
  3108     // swapping.
  3109     Swap(&system_info_.major_version);
  3110     Swap(&system_info_.minor_version);
  3111     Swap(&system_info_.build_number);
  3112     Swap(&system_info_.platform_id);
  3113     Swap(&system_info_.csd_version_rva);
  3114     Swap(&system_info_.suite_mask);
  3115     // Don't swap the reserved2 field because its contents are unknown.
  3117     if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
  3118         system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
  3119       for (unsigned int i = 0; i < 3; ++i)
  3120         Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
  3121       Swap(&system_info_.cpu.x86_cpu_info.version_information);
  3122       Swap(&system_info_.cpu.x86_cpu_info.feature_information);
  3123       Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
  3124     } else {
  3125       for (unsigned int i = 0; i < 2; ++i)
  3126         Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
  3130   valid_ = true;
  3131   return true;
  3135 string MinidumpSystemInfo::GetOS() {
  3136   string os;
  3138   if (!valid_) {
  3139     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
  3140     return os;
  3143   switch (system_info_.platform_id) {
  3144     case MD_OS_WIN32_NT:
  3145     case MD_OS_WIN32_WINDOWS:
  3146       os = "windows";
  3147       break;
  3149     case MD_OS_MAC_OS_X:
  3150       os = "mac";
  3151       break;
  3153     case MD_OS_IOS:
  3154       os = "ios";
  3155       break;
  3157     case MD_OS_LINUX:
  3158       os = "linux";
  3159       break;
  3161     case MD_OS_SOLARIS:
  3162       os = "solaris";
  3163       break;
  3165     case MD_OS_ANDROID:
  3166       os = "android";
  3167       break;
  3169     default:
  3170       BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
  3171                       HexString(system_info_.platform_id);
  3172       break;
  3175   return os;
  3179 string MinidumpSystemInfo::GetCPU() {
  3180   if (!valid_) {
  3181     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
  3182     return "";
  3185   string cpu;
  3187   switch (system_info_.processor_architecture) {
  3188     case MD_CPU_ARCHITECTURE_X86:
  3189     case MD_CPU_ARCHITECTURE_X86_WIN64:
  3190       cpu = "x86";
  3191       break;
  3193     case MD_CPU_ARCHITECTURE_AMD64:
  3194       cpu = "x86-64";
  3195       break;
  3197     case MD_CPU_ARCHITECTURE_PPC:
  3198       cpu = "ppc";
  3199       break;
  3201     case MD_CPU_ARCHITECTURE_SPARC:
  3202       cpu = "sparc";
  3203       break;
  3205     case MD_CPU_ARCHITECTURE_ARM:
  3206       cpu = "arm";
  3207       break;
  3209     default:
  3210       BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
  3211                       HexString(system_info_.processor_architecture);
  3212       break;
  3215   return cpu;
  3219 const string* MinidumpSystemInfo::GetCSDVersion() {
  3220   if (!valid_) {
  3221     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
  3222     return NULL;
  3225   if (!csd_version_)
  3226     csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
  3228   BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
  3229                                     "CSD version";
  3231   return csd_version_;
  3235 const string* MinidumpSystemInfo::GetCPUVendor() {
  3236   if (!valid_) {
  3237     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
  3238     return NULL;
  3241   // CPU vendor information can only be determined from x86 minidumps.
  3242   if (!cpu_vendor_ &&
  3243       (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
  3244        system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
  3245     char cpu_vendor_string[13];
  3246     snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
  3247              "%c%c%c%c%c%c%c%c%c%c%c%c",
  3248               system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
  3249              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
  3250              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
  3251              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
  3252               system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
  3253              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
  3254              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
  3255              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
  3256               system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
  3257              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
  3258              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
  3259              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
  3260     cpu_vendor_ = new string(cpu_vendor_string);
  3263   return cpu_vendor_;
  3267 void MinidumpSystemInfo::Print() {
  3268   if (!valid_) {
  3269     BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
  3270     return;
  3273   printf("MDRawSystemInfo\n");
  3274   printf("  processor_architecture                     = %d\n",
  3275          system_info_.processor_architecture);
  3276   printf("  processor_level                            = %d\n",
  3277          system_info_.processor_level);
  3278   printf("  processor_revision                         = 0x%x\n",
  3279          system_info_.processor_revision);
  3280   printf("  number_of_processors                       = %d\n",
  3281          system_info_.number_of_processors);
  3282   printf("  product_type                               = %d\n",
  3283          system_info_.product_type);
  3284   printf("  major_version                              = %d\n",
  3285          system_info_.major_version);
  3286   printf("  minor_version                              = %d\n",
  3287          system_info_.minor_version);
  3288   printf("  build_number                               = %d\n",
  3289          system_info_.build_number);
  3290   printf("  platform_id                                = %d\n",
  3291          system_info_.platform_id);
  3292   printf("  csd_version_rva                            = 0x%x\n",
  3293          system_info_.csd_version_rva);
  3294   printf("  suite_mask                                 = 0x%x\n",
  3295          system_info_.suite_mask);
  3296   for (unsigned int i = 0; i < 3; ++i) {
  3297     printf("  cpu.x86_cpu_info.vendor_id[%d]              = 0x%x\n",
  3298            i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
  3300   printf("  cpu.x86_cpu_info.version_information       = 0x%x\n",
  3301          system_info_.cpu.x86_cpu_info.version_information);
  3302   printf("  cpu.x86_cpu_info.feature_information       = 0x%x\n",
  3303          system_info_.cpu.x86_cpu_info.feature_information);
  3304   printf("  cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
  3305          system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
  3306   const string* csd_version = GetCSDVersion();
  3307   if (csd_version) {
  3308     printf("  (csd_version)                              = \"%s\"\n",
  3309            csd_version->c_str());
  3310   } else {
  3311     printf("  (csd_version)                              = (null)\n");
  3313   const string* cpu_vendor = GetCPUVendor();
  3314   if (cpu_vendor) {
  3315     printf("  (cpu_vendor)                               = \"%s\"\n",
  3316            cpu_vendor->c_str());
  3317   } else {
  3318     printf("  (cpu_vendor)                               = (null)\n");
  3320   printf("\n");
  3324 //
  3325 // MinidumpMiscInfo
  3326 //
  3329 MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
  3330     : MinidumpStream(minidump),
  3331       misc_info_() {
  3335 bool MinidumpMiscInfo::Read(uint32_t expected_size) {
  3336   valid_ = false;
  3338   if (expected_size != MD_MISCINFO_SIZE &&
  3339       expected_size != MD_MISCINFO2_SIZE) {
  3340     BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size <<
  3341                     " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE <<
  3342                     ")";
  3343     return false;
  3346   if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
  3347     BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
  3348     return false;
  3351   if (minidump_->swap()) {
  3352     Swap(&misc_info_.size_of_info);
  3353     Swap(&misc_info_.flags1);
  3354     Swap(&misc_info_.process_id);
  3355     Swap(&misc_info_.process_create_time);
  3356     Swap(&misc_info_.process_user_time);
  3357     Swap(&misc_info_.process_kernel_time);
  3358     if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
  3359       Swap(&misc_info_.processor_max_mhz);
  3360       Swap(&misc_info_.processor_current_mhz);
  3361       Swap(&misc_info_.processor_mhz_limit);
  3362       Swap(&misc_info_.processor_max_idle_state);
  3363       Swap(&misc_info_.processor_current_idle_state);
  3367   if (expected_size != misc_info_.size_of_info) {
  3368     BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
  3369                     expected_size << " != " << misc_info_.size_of_info;
  3370     return false;
  3373   valid_ = true;
  3374   return true;
  3378 void MinidumpMiscInfo::Print() {
  3379   if (!valid_) {
  3380     BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
  3381     return;
  3384   printf("MDRawMiscInfo\n");
  3385   printf("  size_of_info                 = %d\n",   misc_info_.size_of_info);
  3386   printf("  flags1                       = 0x%x\n", misc_info_.flags1);
  3387   printf("  process_id                   = 0x%x\n", misc_info_.process_id);
  3388   printf("  process_create_time          = 0x%x\n",
  3389          misc_info_.process_create_time);
  3390   printf("  process_user_time            = 0x%x\n",
  3391          misc_info_.process_user_time);
  3392   printf("  process_kernel_time          = 0x%x\n",
  3393          misc_info_.process_kernel_time);
  3394   if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
  3395     printf("  processor_max_mhz            = %d\n",
  3396            misc_info_.processor_max_mhz);
  3397     printf("  processor_current_mhz        = %d\n",
  3398            misc_info_.processor_current_mhz);
  3399     printf("  processor_mhz_limit          = %d\n",
  3400            misc_info_.processor_mhz_limit);
  3401     printf("  processor_max_idle_state     = 0x%x\n",
  3402            misc_info_.processor_max_idle_state);
  3403     printf("  processor_current_idle_state = 0x%x\n",
  3404            misc_info_.processor_current_idle_state);
  3406   printf("\n");
  3410 //
  3411 // MinidumpBreakpadInfo
  3412 //
  3415 MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
  3416     : MinidumpStream(minidump),
  3417       breakpad_info_() {
  3421 bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
  3422   valid_ = false;
  3424   if (expected_size != sizeof(breakpad_info_)) {
  3425     BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
  3426                     " != " << sizeof(breakpad_info_);
  3427     return false;
  3430   if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
  3431     BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
  3432     return false;
  3435   if (minidump_->swap()) {
  3436     Swap(&breakpad_info_.validity);
  3437     Swap(&breakpad_info_.dump_thread_id);
  3438     Swap(&breakpad_info_.requesting_thread_id);
  3441   valid_ = true;
  3442   return true;
  3446 bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
  3447   BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
  3448                                  "requires |thread_id|";
  3449   assert(thread_id);
  3450   *thread_id = 0;
  3452   if (!valid_) {
  3453     BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
  3454     return false;
  3457   if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
  3458     BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
  3459     return false;
  3462   *thread_id = breakpad_info_.dump_thread_id;
  3463   return true;
  3467 bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id)
  3468     const {
  3469   BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
  3470                                  "requires |thread_id|";
  3471   assert(thread_id);
  3472   *thread_id = 0;
  3474   if (!thread_id || !valid_) {
  3475     BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
  3476     return false;
  3479   if (!(breakpad_info_.validity &
  3480             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
  3481     BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
  3482     return false;
  3485   *thread_id = breakpad_info_.requesting_thread_id;
  3486   return true;
  3490 void MinidumpBreakpadInfo::Print() {
  3491   if (!valid_) {
  3492     BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
  3493     return;
  3496   printf("MDRawBreakpadInfo\n");
  3497   printf("  validity             = 0x%x\n", breakpad_info_.validity);
  3499   if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
  3500     printf("  dump_thread_id       = 0x%x\n", breakpad_info_.dump_thread_id);
  3501   } else {
  3502     printf("  dump_thread_id       = (invalid)\n");
  3505   if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
  3506     printf("  requesting_thread_id = 0x%x\n",
  3507            breakpad_info_.requesting_thread_id);
  3508   } else {
  3509     printf("  requesting_thread_id = (invalid)\n");
  3512   printf("\n");
  3516 //
  3517 // MinidumpMemoryInfo
  3518 //
  3521 MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
  3522     : MinidumpObject(minidump),
  3523       memory_info_() {
  3527 bool MinidumpMemoryInfo::IsExecutable() const {
  3528   uint32_t protection =
  3529       memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
  3530   return protection == MD_MEMORY_PROTECT_EXECUTE ||
  3531       protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
  3532       protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
  3536 bool MinidumpMemoryInfo::IsWritable() const {
  3537   uint32_t protection =
  3538       memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
  3539   return protection == MD_MEMORY_PROTECT_READWRITE ||
  3540     protection == MD_MEMORY_PROTECT_WRITECOPY ||
  3541     protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
  3542     protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
  3546 bool MinidumpMemoryInfo::Read() {
  3547   valid_ = false;
  3549   if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
  3550     BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
  3551     return false;
  3554   if (minidump_->swap()) {
  3555     Swap(&memory_info_.base_address);
  3556     Swap(&memory_info_.allocation_base);
  3557     Swap(&memory_info_.allocation_protection);
  3558     Swap(&memory_info_.region_size);
  3559     Swap(&memory_info_.state);
  3560     Swap(&memory_info_.protection);
  3561     Swap(&memory_info_.type);
  3564   // Check for base + size overflow or undersize.
  3565   if (memory_info_.region_size == 0 ||
  3566       memory_info_.region_size > numeric_limits<uint64_t>::max() -
  3567                                      memory_info_.base_address) {
  3568     BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
  3569                     HexString(memory_info_.base_address) << "+" <<
  3570                     HexString(memory_info_.region_size);
  3571     return false;
  3574   valid_ = true;
  3575   return true;
  3579 void MinidumpMemoryInfo::Print() {
  3580   if (!valid_) {
  3581     BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
  3582     return;
  3585   printf("MDRawMemoryInfo\n");
  3586   printf("  base_address          = 0x%" PRIx64 "\n",
  3587          memory_info_.base_address);
  3588   printf("  allocation_base       = 0x%" PRIx64 "\n",
  3589          memory_info_.allocation_base);
  3590   printf("  allocation_protection = 0x%x\n",
  3591          memory_info_.allocation_protection);
  3592   printf("  region_size           = 0x%" PRIx64 "\n", memory_info_.region_size);
  3593   printf("  state                 = 0x%x\n", memory_info_.state);
  3594   printf("  protection            = 0x%x\n", memory_info_.protection);
  3595   printf("  type                  = 0x%x\n", memory_info_.type);
  3599 //
  3600 // MinidumpMemoryInfoList
  3601 //
  3604 MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
  3605     : MinidumpStream(minidump),
  3606       range_map_(new RangeMap<uint64_t, unsigned int>()),
  3607       infos_(NULL),
  3608       info_count_(0) {
  3612 MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
  3613   delete range_map_;
  3614   delete infos_;
  3618 bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
  3619   // Invalidate cached data.
  3620   delete infos_;
  3621   infos_ = NULL;
  3622   range_map_->Clear();
  3623   info_count_ = 0;
  3625   valid_ = false;
  3627   MDRawMemoryInfoList header;
  3628   if (expected_size < sizeof(MDRawMemoryInfoList)) {
  3629     BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
  3630                     expected_size << " < " << sizeof(MDRawMemoryInfoList);
  3631     return false;
  3633   if (!minidump_->ReadBytes(&header, sizeof(header))) {
  3634     BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
  3635     return false;
  3638   if (minidump_->swap()) {
  3639     Swap(&header.size_of_header);
  3640     Swap(&header.size_of_entry);
  3641     Swap(&header.number_of_entries);
  3644   // Sanity check that the header is the expected size.
  3645   //TODO(ted): could possibly handle this more gracefully, assuming
  3646   // that future versions of the structs would be backwards-compatible.
  3647   if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
  3648     BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
  3649                     header.size_of_header << " != " <<
  3650                     sizeof(MDRawMemoryInfoList);
  3651     return false;
  3654   // Sanity check that the entries are the expected size.
  3655   if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
  3656     BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
  3657                     header.size_of_entry << " != " <<
  3658                     sizeof(MDRawMemoryInfo);
  3659     return false;
  3662   if (header.number_of_entries >
  3663           numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
  3664     BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
  3665                     header.number_of_entries <<
  3666                     " would cause multiplication overflow";
  3667     return false;
  3670   if (expected_size != sizeof(MDRawMemoryInfoList) +
  3671                         header.number_of_entries * sizeof(MDRawMemoryInfo)) {
  3672     BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
  3673                     " != " << sizeof(MDRawMemoryInfoList) +
  3674                         header.number_of_entries * sizeof(MDRawMemoryInfo);
  3675     return false;
  3678   if (header.number_of_entries != 0) {
  3679     scoped_ptr<MinidumpMemoryInfos> infos(
  3680         new MinidumpMemoryInfos(header.number_of_entries,
  3681                                 MinidumpMemoryInfo(minidump_)));
  3683     for (unsigned int index = 0;
  3684          index < header.number_of_entries;
  3685          ++index) {
  3686       MinidumpMemoryInfo* info = &(*infos)[index];
  3688       // Assume that the file offset is correct after the last read.
  3689       if (!info->Read()) {
  3690         BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
  3691                         index << "/" << header.number_of_entries;
  3692         return false;
  3695       uint64_t base_address = info->GetBase();
  3696       uint32_t region_size = info->GetSize();
  3698       if (!range_map_->StoreRange(base_address, region_size, index)) {
  3699         BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
  3700                         " memory region " <<
  3701                         index << "/" << header.number_of_entries << ", " <<
  3702                         HexString(base_address) << "+" <<
  3703                         HexString(region_size);
  3704         return false;
  3708     infos_ = infos.release();
  3711   info_count_ = header.number_of_entries;
  3713   valid_ = true;
  3714   return true;
  3718 const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
  3719       unsigned int index) const {
  3720   if (!valid_) {
  3721     BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
  3722     return NULL;
  3725   if (index >= info_count_) {
  3726     BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
  3727                     index << "/" << info_count_;
  3728     return NULL;
  3731   return &(*infos_)[index];
  3735 const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
  3736     uint64_t address) const {
  3737   if (!valid_) {
  3738     BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
  3739                     " GetMemoryInfoForAddress";
  3740     return NULL;
  3743   unsigned int info_index;
  3744   if (!range_map_->RetrieveRange(address, &info_index, NULL, NULL)) {
  3745     BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
  3746                    HexString(address);
  3747     return NULL;
  3750   return GetMemoryInfoAtIndex(info_index);
  3754 void MinidumpMemoryInfoList::Print() {
  3755   if (!valid_) {
  3756     BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
  3757     return;
  3760   printf("MinidumpMemoryInfoList\n");
  3761   printf("  info_count = %d\n", info_count_);
  3762   printf("\n");
  3764   for (unsigned int info_index = 0;
  3765        info_index < info_count_;
  3766        ++info_index) {
  3767     printf("info[%d]\n", info_index);
  3768     (*infos_)[info_index].Print();
  3769     printf("\n");
  3774 //
  3775 // Minidump
  3776 //
  3779 uint32_t Minidump::max_streams_ = 128;
  3780 unsigned int Minidump::max_string_length_ = 1024;
  3783 Minidump::Minidump(const string& path)
  3784     : header_(),
  3785       directory_(NULL),
  3786       stream_map_(new MinidumpStreamMap()),
  3787       path_(path),
  3788       stream_(NULL),
  3789       swap_(false),
  3790       valid_(false) {
  3793 Minidump::Minidump(istream& stream)
  3794     : header_(),
  3795       directory_(NULL),
  3796       stream_map_(new MinidumpStreamMap()),
  3797       path_(),
  3798       stream_(&stream),
  3799       swap_(false),
  3800       valid_(false) {
  3803 Minidump::~Minidump() {
  3804   if (stream_) {
  3805     BPLOG(INFO) << "Minidump closing minidump";
  3807   if (!path_.empty()) {
  3808     delete stream_;
  3810   delete directory_;
  3811   delete stream_map_;
  3815 bool Minidump::Open() {
  3816   if (stream_ != NULL) {
  3817     BPLOG(INFO) << "Minidump reopening minidump " << path_;
  3819     // The file is already open.  Seek to the beginning, which is the position
  3820     // the file would be at if it were opened anew.
  3821     return SeekSet(0);
  3824   stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
  3825   if (!stream_ || !stream_->good()) {
  3826     string error_string;
  3827     int error_code = ErrnoString(&error_string);
  3828     BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
  3829                     ", error " << error_code << ": " << error_string;
  3830     return false;
  3833   BPLOG(INFO) << "Minidump opened minidump " << path_;
  3834   return true;
  3837 bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
  3838   // Initialize output parameters
  3839   *context_cpu_flags = 0;
  3841   // Save the current stream position
  3842   off_t saved_position = Tell();
  3843   if (saved_position == -1) {
  3844     // Failed to save the current stream position.
  3845     // Returns true because the current position of the stream is preserved.
  3846     return true;
  3849   const MDRawSystemInfo* system_info =
  3850     GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
  3852   if (system_info != NULL) {
  3853     switch (system_info->processor_architecture) {
  3854       case MD_CPU_ARCHITECTURE_X86:
  3855         *context_cpu_flags = MD_CONTEXT_X86;
  3856         break;
  3857       case MD_CPU_ARCHITECTURE_MIPS:
  3858         *context_cpu_flags = MD_CONTEXT_MIPS;
  3859         break;
  3860       case MD_CPU_ARCHITECTURE_ALPHA:
  3861         *context_cpu_flags = MD_CONTEXT_ALPHA;
  3862         break;
  3863       case MD_CPU_ARCHITECTURE_PPC:
  3864         *context_cpu_flags = MD_CONTEXT_PPC;
  3865         break;
  3866       case MD_CPU_ARCHITECTURE_SHX:
  3867         *context_cpu_flags = MD_CONTEXT_SHX;
  3868         break;
  3869       case MD_CPU_ARCHITECTURE_ARM:
  3870         *context_cpu_flags = MD_CONTEXT_ARM;
  3871         break;
  3872       case MD_CPU_ARCHITECTURE_IA64:
  3873         *context_cpu_flags = MD_CONTEXT_IA64;
  3874         break;
  3875       case MD_CPU_ARCHITECTURE_ALPHA64:
  3876         *context_cpu_flags = 0;
  3877         break;
  3878       case MD_CPU_ARCHITECTURE_MSIL:
  3879         *context_cpu_flags = 0;
  3880         break;
  3881       case MD_CPU_ARCHITECTURE_AMD64:
  3882         *context_cpu_flags = MD_CONTEXT_AMD64;
  3883         break;
  3884       case MD_CPU_ARCHITECTURE_X86_WIN64:
  3885         *context_cpu_flags = 0;
  3886         break;
  3887       case MD_CPU_ARCHITECTURE_SPARC:
  3888         *context_cpu_flags = MD_CONTEXT_SPARC;
  3889         break;
  3890       case MD_CPU_ARCHITECTURE_UNKNOWN:
  3891         *context_cpu_flags = 0;
  3892         break;
  3893       default:
  3894         *context_cpu_flags = 0;
  3895         break;
  3899   // Restore position and return
  3900   return SeekSet(saved_position);
  3904 bool Minidump::Read() {
  3905   // Invalidate cached data.
  3906   delete directory_;
  3907   directory_ = NULL;
  3908   stream_map_->clear();
  3910   valid_ = false;
  3912   if (!Open()) {
  3913     BPLOG(ERROR) << "Minidump cannot open minidump";
  3914     return false;
  3917   if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
  3918     BPLOG(ERROR) << "Minidump cannot read header";
  3919     return false;
  3922   if (header_.signature != MD_HEADER_SIGNATURE) {
  3923     // The file may be byte-swapped.  Under the present architecture, these
  3924     // classes don't know or need to know what CPU (or endianness) the
  3925     // minidump was produced on in order to parse it.  Use the signature as
  3926     // a byte order marker.
  3927     uint32_t signature_swapped = header_.signature;
  3928     Swap(&signature_swapped);
  3929     if (signature_swapped != MD_HEADER_SIGNATURE) {
  3930       // This isn't a minidump or a byte-swapped minidump.
  3931       BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
  3932                       HexString(header_.signature) << ", " <<
  3933                       HexString(signature_swapped) << ") != " <<
  3934                       HexString(MD_HEADER_SIGNATURE);
  3935       return false;
  3937     swap_ = true;
  3938   } else {
  3939     // The file is not byte-swapped.  Set swap_ false (it may have been true
  3940     // if the object is being reused?)
  3941     swap_ = false;
  3944   BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
  3945                  "byte-swapping minidump";
  3947   if (swap_) {
  3948     Swap(&header_.signature);
  3949     Swap(&header_.version);
  3950     Swap(&header_.stream_count);
  3951     Swap(&header_.stream_directory_rva);
  3952     Swap(&header_.checksum);
  3953     Swap(&header_.time_date_stamp);
  3954     Swap(&header_.flags);
  3957   // Version check.  The high 16 bits of header_.version contain something
  3958   // else "implementation specific."
  3959   if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
  3960     BPLOG(ERROR) << "Minidump version mismatch: " <<
  3961                     HexString(header_.version & 0x0000ffff) << " != " <<
  3962                     HexString(MD_HEADER_VERSION);
  3963     return false;
  3966   if (!SeekSet(header_.stream_directory_rva)) {
  3967     BPLOG(ERROR) << "Minidump cannot seek to stream directory";
  3968     return false;
  3971   if (header_.stream_count > max_streams_) {
  3972     BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
  3973                     " exceeds maximum " << max_streams_;
  3974     return false;
  3977   if (header_.stream_count != 0) {
  3978     scoped_ptr<MinidumpDirectoryEntries> directory(
  3979         new MinidumpDirectoryEntries(header_.stream_count));
  3981     // Read the entire array in one fell swoop, instead of reading one entry
  3982     // at a time in the loop.
  3983     if (!ReadBytes(&(*directory)[0],
  3984                    sizeof(MDRawDirectory) * header_.stream_count)) {
  3985       BPLOG(ERROR) << "Minidump cannot read stream directory";
  3986       return false;
  3989     for (unsigned int stream_index = 0;
  3990          stream_index < header_.stream_count;
  3991          ++stream_index) {
  3992       MDRawDirectory* directory_entry = &(*directory)[stream_index];
  3994       if (swap_) {
  3995         Swap(&directory_entry->stream_type);
  3996         Swap(&directory_entry->location);
  3999       // Initialize the stream_map_ map, which speeds locating a stream by
  4000       // type.
  4001       unsigned int stream_type = directory_entry->stream_type;
  4002       switch (stream_type) {
  4003         case MD_THREAD_LIST_STREAM:
  4004         case MD_MODULE_LIST_STREAM:
  4005         case MD_MEMORY_LIST_STREAM:
  4006         case MD_EXCEPTION_STREAM:
  4007         case MD_SYSTEM_INFO_STREAM:
  4008         case MD_MISC_INFO_STREAM:
  4009         case MD_BREAKPAD_INFO_STREAM: {
  4010           if (stream_map_->find(stream_type) != stream_map_->end()) {
  4011             // Another stream with this type was already found.  A minidump
  4012             // file should contain at most one of each of these stream types.
  4013             BPLOG(ERROR) << "Minidump found multiple streams of type " <<
  4014                             stream_type << ", but can only deal with one";
  4015             return false;
  4017           // Fall through to default
  4020         default: {
  4021           // Overwrites for stream types other than those above, but it's
  4022           // expected to be the user's burden in that case.
  4023           (*stream_map_)[stream_type].stream_index = stream_index;
  4028     directory_ = directory.release();
  4031   valid_ = true;
  4032   return true;
  4036 MinidumpThreadList* Minidump::GetThreadList() {
  4037   MinidumpThreadList* thread_list;
  4038   return GetStream(&thread_list);
  4042 MinidumpModuleList* Minidump::GetModuleList() {
  4043   MinidumpModuleList* module_list;
  4044   return GetStream(&module_list);
  4048 MinidumpMemoryList* Minidump::GetMemoryList() {
  4049   MinidumpMemoryList* memory_list;
  4050   return GetStream(&memory_list);
  4054 MinidumpException* Minidump::GetException() {
  4055   MinidumpException* exception;
  4056   return GetStream(&exception);
  4059 MinidumpAssertion* Minidump::GetAssertion() {
  4060   MinidumpAssertion* assertion;
  4061   return GetStream(&assertion);
  4065 MinidumpSystemInfo* Minidump::GetSystemInfo() {
  4066   MinidumpSystemInfo* system_info;
  4067   return GetStream(&system_info);
  4071 MinidumpMiscInfo* Minidump::GetMiscInfo() {
  4072   MinidumpMiscInfo* misc_info;
  4073   return GetStream(&misc_info);
  4077 MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
  4078   MinidumpBreakpadInfo* breakpad_info;
  4079   return GetStream(&breakpad_info);
  4082 MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
  4083   MinidumpMemoryInfoList* memory_info_list;
  4084   return GetStream(&memory_info_list);
  4088 void Minidump::Print() {
  4089   if (!valid_) {
  4090     BPLOG(ERROR) << "Minidump cannot print invalid data";
  4091     return;
  4094   printf("MDRawHeader\n");
  4095   printf("  signature            = 0x%x\n",    header_.signature);
  4096   printf("  version              = 0x%x\n",    header_.version);
  4097   printf("  stream_count         = %d\n",      header_.stream_count);
  4098   printf("  stream_directory_rva = 0x%x\n",    header_.stream_directory_rva);
  4099   printf("  checksum             = 0x%x\n",    header_.checksum);
  4100   struct tm timestruct;
  4101 #ifdef _WIN32
  4102   gmtime_s(&timestruct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
  4103 #else
  4104   gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), &timestruct);
  4105 #endif
  4106   char timestr[20];
  4107   strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
  4108   printf("  time_date_stamp      = 0x%x %s\n", header_.time_date_stamp,
  4109                                                timestr);
  4110   printf("  flags                = 0x%" PRIx64 "\n",  header_.flags);
  4111   printf("\n");
  4113   for (unsigned int stream_index = 0;
  4114        stream_index < header_.stream_count;
  4115        ++stream_index) {
  4116     MDRawDirectory* directory_entry = &(*directory_)[stream_index];
  4118     printf("mDirectory[%d]\n", stream_index);
  4119     printf("MDRawDirectory\n");
  4120     printf("  stream_type        = %d\n",   directory_entry->stream_type);
  4121     printf("  location.data_size = %d\n",
  4122            directory_entry->location.data_size);
  4123     printf("  location.rva       = 0x%x\n", directory_entry->location.rva);
  4124     printf("\n");
  4127   printf("Streams:\n");
  4128   for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
  4129        iterator != stream_map_->end();
  4130        ++iterator) {
  4131     uint32_t stream_type = iterator->first;
  4132     MinidumpStreamInfo info = iterator->second;
  4133     printf("  stream type 0x%x at index %d\n", stream_type, info.stream_index);
  4135   printf("\n");
  4139 const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
  4140       const {
  4141   if (!valid_) {
  4142     BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
  4143     return NULL;
  4146   if (index >= header_.stream_count) {
  4147     BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
  4148                     index << "/" << header_.stream_count;
  4149     return NULL;
  4152   return &(*directory_)[index];
  4156 bool Minidump::ReadBytes(void* bytes, size_t count) {
  4157   // Can't check valid_ because Read needs to call this method before
  4158   // validity can be determined.
  4159   if (!stream_) {
  4160     return false;
  4162   stream_->read(static_cast<char*>(bytes), count);
  4163   size_t bytes_read = stream_->gcount();
  4164   if (bytes_read != count) {
  4165     if (bytes_read == size_t(-1)) {
  4166       string error_string;
  4167       int error_code = ErrnoString(&error_string);
  4168       BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
  4169     } else {
  4170       BPLOG(ERROR) << "ReadBytes: read " << bytes_read << "/" << count;
  4172     return false;
  4174   return true;
  4178 bool Minidump::SeekSet(off_t offset) {
  4179   // Can't check valid_ because Read needs to call this method before
  4180   // validity can be determined.
  4181   if (!stream_) {
  4182     return false;
  4184   stream_->seekg(offset, std::ios_base::beg);
  4185   if (!stream_->good()) {
  4186     string error_string;
  4187     int error_code = ErrnoString(&error_string);
  4188     BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
  4189     return false;
  4191   return true;
  4194 off_t Minidump::Tell() {
  4195   if (!valid_ || !stream_) {
  4196     return (off_t)-1;
  4199   return stream_->tellg();
  4203 string* Minidump::ReadString(off_t offset) {
  4204   if (!valid_) {
  4205     BPLOG(ERROR) << "Invalid Minidump for ReadString";
  4206     return NULL;
  4208   if (!SeekSet(offset)) {
  4209     BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
  4210     return NULL;
  4213   uint32_t bytes;
  4214   if (!ReadBytes(&bytes, sizeof(bytes))) {
  4215     BPLOG(ERROR) << "ReadString could not read string size at offset " <<
  4216                     offset;
  4217     return NULL;
  4219   if (swap_)
  4220     Swap(&bytes);
  4222   if (bytes % 2 != 0) {
  4223     BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
  4224                     "-byte string at offset " << offset;
  4225     return NULL;
  4227   unsigned int utf16_words = bytes / 2;
  4229   if (utf16_words > max_string_length_) {
  4230     BPLOG(ERROR) << "ReadString string length " << utf16_words <<
  4231                     " exceeds maximum " << max_string_length_ <<
  4232                     " at offset " << offset;
  4233     return NULL;
  4236   vector<uint16_t> string_utf16(utf16_words);
  4238   if (utf16_words) {
  4239     if (!ReadBytes(&string_utf16[0], bytes)) {
  4240       BPLOG(ERROR) << "ReadString could not read " << bytes <<
  4241                       "-byte string at offset " << offset;
  4242       return NULL;
  4246   return UTF16ToUTF8(string_utf16, swap_);
  4250 bool Minidump::SeekToStreamType(uint32_t  stream_type,
  4251                                 uint32_t* stream_length) {
  4252   BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
  4253                                      "|stream_length|";
  4254   assert(stream_length);
  4255   *stream_length = 0;
  4257   if (!valid_) {
  4258     BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
  4259     return false;
  4262   MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
  4263   if (iterator == stream_map_->end()) {
  4264     // This stream type didn't exist in the directory.
  4265     BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
  4266     return false;
  4269   MinidumpStreamInfo info = iterator->second;
  4270   if (info.stream_index >= header_.stream_count) {
  4271     BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
  4272                     " out of range: " <<
  4273                     info.stream_index << "/" << header_.stream_count;
  4274     return false;
  4277   MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
  4278   if (!SeekSet(directory_entry->location.rva)) {
  4279     BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
  4280                     stream_type;
  4281     return false;
  4284   *stream_length = directory_entry->location.data_size;
  4286   return true;
  4290 template<typename T>
  4291 T* Minidump::GetStream(T** stream) {
  4292   // stream is a garbage parameter that's present only to account for C++'s
  4293   // inability to overload a method based solely on its return type.
  4295   const uint32_t stream_type = T::kStreamType;
  4297   BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
  4298                               " requires |stream|";
  4299   assert(stream);
  4300   *stream = NULL;
  4302   if (!valid_) {
  4303     BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
  4304     return NULL;
  4307   MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
  4308   if (iterator == stream_map_->end()) {
  4309     // This stream type didn't exist in the directory.
  4310     BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
  4311     return NULL;
  4314   // Get a pointer so that the stored stream field can be altered.
  4315   MinidumpStreamInfo* info = &iterator->second;
  4317   if (info->stream) {
  4318     // This cast is safe because info.stream is only populated by this
  4319     // method, and there is a direct correlation between T and stream_type.
  4320     *stream = static_cast<T*>(info->stream);
  4321     return *stream;
  4324   uint32_t stream_length;
  4325   if (!SeekToStreamType(stream_type, &stream_length)) {
  4326     BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
  4327     return NULL;
  4330   scoped_ptr<T> new_stream(new T(this));
  4332   if (!new_stream->Read(stream_length)) {
  4333     BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
  4334     return NULL;
  4337   *stream = new_stream.release();
  4338   info->stream = *stream;
  4339   return *stream;
  4343 }  // namespace google_breakpad

mercurial