minidump.cc revision 3562017ff5a65fff770cd798903ee294db912aa2
1// Copyright (c) 2010 Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// minidump.cc: A minidump reader.
31//
32// See minidump.h for documentation.
33//
34// Author: Mark Mentovai
35
36#include "google_breakpad/processor/minidump.h"
37
38#include <assert.h>
39#include <fcntl.h>
40#include <stddef.h>
41#include <stdio.h>
42#include <string.h>
43#include <time.h>
44
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
54
55#include <fstream>
56#include <iostream>
57#include <limits>
58#include <map>
59#include <vector>
60
61#include "processor/range_map-inl.h"
62
63#include "common/scoped_ptr.h"
64#include "processor/basic_code_module.h"
65#include "processor/basic_code_modules.h"
66#include "processor/logging.h"
67
68namespace google_breakpad {
69
70
71using std::istream;
72using std::ifstream;
73using std::numeric_limits;
74using std::vector;
75
76
77//
78// Swapping routines
79//
80// Inlining these doesn't increase code size significantly, and it saves
81// a whole lot of unnecessary jumping back and forth.
82//
83
84
85// Swapping an 8-bit quantity is a no-op.  This function is only provided
86// to account for certain templatized operations that require swapping for
87// wider types but handle uint8_t too
88// (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
89static inline void Swap(uint8_t* value) {
90}
91
92
93// Optimization: don't need to AND the furthest right shift, because we're
94// shifting an unsigned quantity.  The standard requires zero-filling in this
95// case.  If the quantities were signed, a bitmask whould be needed for this
96// right shift to avoid an arithmetic shift (which retains the sign bit).
97// The furthest left shift never needs to be ANDed bitmask.
98
99
100static inline void Swap(uint16_t* value) {
101  *value = (*value >> 8) |
102           (*value << 8);
103}
104
105
106static inline void Swap(uint32_t* value) {
107  *value =  (*value >> 24) |
108           ((*value >> 8)  & 0x0000ff00) |
109           ((*value << 8)  & 0x00ff0000) |
110            (*value << 24);
111}
112
113
114static inline void Swap(uint64_t* value) {
115  uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
116  Swap(&value32[0]);
117  Swap(&value32[1]);
118  uint32_t temp = value32[0];
119  value32[0] = value32[1];
120  value32[1] = temp;
121}
122
123
124// Given a pointer to a 128-bit int in the minidump data, set the "low"
125// and "high" fields appropriately.
126static void Normalize128(uint128_struct* value, bool is_big_endian) {
127  // The struct format is [high, low], so if the format is big-endian,
128  // the most significant bytes will already be in the high field.
129  if (!is_big_endian) {
130    uint64_t temp = value->low;
131    value->low = value->high;
132    value->high = temp;
133  }
134}
135
136// This just swaps each int64 half of the 128-bit value.
137// The value should also be normalized by calling Normalize128().
138static void Swap(uint128_struct* value) {
139  Swap(&value->low);
140  Swap(&value->high);
141}
142
143// Swapping signed integers
144static inline void Swap(int16_t* value) {
145  Swap(reinterpret_cast<uint16_t*>(value));
146}
147
148static inline void Swap(int32_t* value) {
149  Swap(reinterpret_cast<uint32_t*>(value));
150}
151
152static inline void Swap(int64_t* value) {
153  Swap(reinterpret_cast<uint64_t*>(value));
154}
155
156
157static inline void Swap(MDLocationDescriptor* location_descriptor) {
158  Swap(&location_descriptor->data_size);
159  Swap(&location_descriptor->rva);
160}
161
162
163static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
164  Swap(&memory_descriptor->start_of_memory_range);
165  Swap(&memory_descriptor->memory);
166}
167
168
169static inline void Swap(MDGUID* guid) {
170  Swap(&guid->data1);
171  Swap(&guid->data2);
172  Swap(&guid->data3);
173  // Don't swap guid->data4[] because it contains 8-bit quantities.
174}
175
176static inline void Swap(MDSystemTime* system_time) {
177  Swap(&system_time->year);
178  Swap(&system_time->month);
179  Swap(&system_time->day_of_week);
180  Swap(&system_time->day);
181  Swap(&system_time->hour);
182  Swap(&system_time->minute);
183  Swap(&system_time->second);
184  Swap(&system_time->milliseconds);
185}
186
187static inline void Swap(uint16_t* data, size_t size_in_bytes) {
188  size_t data_length = size_in_bytes / sizeof(data[0]);
189  for (size_t i = 0; i < data_length; i++) {
190    Swap(&data[i]);
191  }
192}
193
194//
195// Character conversion routines
196//
197
198
199// Standard wide-character conversion routines depend on the system's own
200// idea of what width a wide character should be: some use 16 bits, and
201// some use 32 bits.  For the purposes of a minidump, wide strings are
202// always represented with 16-bit UTF-16 chracters.  iconv isn't available
203// everywhere, and its interface varies where it is available.  iconv also
204// deals purely with char* pointers, so in addition to considering the swap
205// parameter, a converter that uses iconv would also need to take the host
206// CPU's endianness into consideration.  It doesn't seems worth the trouble
207// of making it a dependency when we don't care about anything but UTF-16.
208static string* UTF16ToUTF8(const vector<uint16_t>& in,
209                           bool swap) {
210  scoped_ptr<string> out(new string());
211
212  // Set the string's initial capacity to the number of UTF-16 characters,
213  // because the UTF-8 representation will always be at least this long.
214  // If the UTF-8 representation is longer, the string will grow dynamically.
215  out->reserve(in.size());
216
217  for (vector<uint16_t>::const_iterator iterator = in.begin();
218       iterator != in.end();
219       ++iterator) {
220    // Get a 16-bit value from the input
221    uint16_t in_word = *iterator;
222    if (swap)
223      Swap(&in_word);
224
225    // Convert the input value (in_word) into a Unicode code point (unichar).
226    uint32_t unichar;
227    if (in_word >= 0xdc00 && in_word <= 0xdcff) {
228      BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
229                      HexString(in_word) << " without high";
230      return NULL;
231    } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
232      // High surrogate.
233      unichar = (in_word - 0xd7c0) << 10;
234      if (++iterator == in.end()) {
235        BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
236                        HexString(in_word) << " at end of string";
237        return NULL;
238      }
239      uint32_t high_word = in_word;
240      in_word = *iterator;
241      if (in_word < 0xdc00 || in_word > 0xdcff) {
242        BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
243                        HexString(high_word) << " without low " <<
244                        HexString(in_word);
245        return NULL;
246      }
247      unichar |= in_word & 0x03ff;
248    } else {
249      // The ordinary case, a single non-surrogate Unicode character encoded
250      // as a single 16-bit value.
251      unichar = in_word;
252    }
253
254    // Convert the Unicode code point (unichar) into its UTF-8 representation,
255    // appending it to the out string.
256    if (unichar < 0x80) {
257      (*out) += static_cast<char>(unichar);
258    } else if (unichar < 0x800) {
259      (*out) += 0xc0 | static_cast<char>(unichar >> 6);
260      (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
261    } else if (unichar < 0x10000) {
262      (*out) += 0xe0 | static_cast<char>(unichar >> 12);
263      (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
264      (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
265    } else if (unichar < 0x200000) {
266      (*out) += 0xf0 | static_cast<char>(unichar >> 18);
267      (*out) += 0x80 | static_cast<char>((unichar >> 12) & 0x3f);
268      (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
269      (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
270    } else {
271      BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
272                      HexString(unichar) << " in UTF-8";
273      return NULL;
274    }
275  }
276
277  return out.release();
278}
279
280// Return the smaller of the number of code units in the UTF-16 string,
281// not including the terminating null word, or maxlen.
282static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) {
283  size_t count = 0;
284  while (count < maxlen && string[count] != 0)
285    count++;
286  return count;
287}
288
289static inline void Swap(MDTimeZoneInformation* time_zone) {
290  Swap(&time_zone->bias);
291  // Skip time_zone->standard_name.  No need to swap UTF-16 fields.
292  // The swap will be done as part of the conversion to UTF-8.
293  Swap(&time_zone->standard_date);
294  Swap(&time_zone->standard_bias);
295  // Skip time_zone->daylight_name.  No need to swap UTF-16 fields.
296  // The swap will be done as part of the conversion to UTF-8.
297  Swap(&time_zone->daylight_date);
298  Swap(&time_zone->daylight_bias);
299}
300
301static void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data,
302                                           size_t max_length_in_bytes,
303                                           string* utf8_result,
304                                           bool swap) {
305  // Since there is no explicit byte length for each string, use
306  // UTF16codeunits to calculate word length, then derive byte
307  // length from that.
308  size_t max_word_length = max_length_in_bytes / sizeof(utf16_data[0]);
309  size_t word_length = UTF16codeunits(utf16_data, max_word_length);
310  if (word_length > 0) {
311    size_t byte_length = word_length * sizeof(utf16_data[0]);
312    vector<uint16_t> utf16_vector(word_length);
313    memcpy(&utf16_vector[0], &utf16_data[0], byte_length);
314    scoped_ptr<string> temp(UTF16ToUTF8(utf16_vector, swap));
315    if (temp.get()) {
316      utf8_result->assign(*temp);
317    }
318  } else {
319    utf8_result->clear();
320  }
321}
322
323//
324// MinidumpObject
325//
326
327
328MinidumpObject::MinidumpObject(Minidump* minidump)
329    : minidump_(minidump),
330      valid_(false) {
331}
332
333
334//
335// MinidumpStream
336//
337
338
339MinidumpStream::MinidumpStream(Minidump* minidump)
340    : MinidumpObject(minidump) {
341}
342
343
344//
345// MinidumpContext
346//
347
348
349MinidumpContext::MinidumpContext(Minidump* minidump)
350    : MinidumpStream(minidump),
351      context_(),
352      context_flags_(0) {
353}
354
355
356MinidumpContext::~MinidumpContext() {
357  FreeContext();
358}
359
360
361bool MinidumpContext::Read(uint32_t expected_size) {
362  valid_ = false;
363
364  FreeContext();
365
366  // First, figure out what type of CPU this context structure is for.
367  // For some reason, the AMD64 Context doesn't have context_flags
368  // at the beginning of the structure, so special case it here.
369  if (expected_size == sizeof(MDRawContextAMD64)) {
370    BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
371
372    scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
373    if (!minidump_->ReadBytes(context_amd64.get(),
374                              sizeof(MDRawContextAMD64))) {
375      BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
376      return false;
377    }
378
379    if (minidump_->swap())
380      Swap(&context_amd64->context_flags);
381
382    uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
383    if (cpu_type == 0) {
384      if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
385        context_amd64->context_flags |= cpu_type;
386      } else {
387        BPLOG(ERROR) << "Failed to preserve the current stream position";
388        return false;
389      }
390    }
391
392    if (cpu_type != MD_CONTEXT_AMD64) {
393      // TODO: fall through to switch below?
394      // need a Tell method to be able to SeekSet back to beginning
395      // http://code.google.com/p/google-breakpad/issues/detail?id=224
396      BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
397      return false;
398    }
399
400    // Do this after reading the entire MDRawContext structure because
401    // GetSystemInfo may seek minidump to a new position.
402    if (!CheckAgainstSystemInfo(cpu_type)) {
403      BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
404      return false;
405    }
406
407    // Normalize the 128-bit types in the dump.
408    // Since this is AMD64, by definition, the values are little-endian.
409    for (unsigned int vr_index = 0;
410         vr_index < MD_CONTEXT_AMD64_VR_COUNT;
411         ++vr_index)
412      Normalize128(&context_amd64->vector_register[vr_index], false);
413
414    if (minidump_->swap()) {
415      Swap(&context_amd64->p1_home);
416      Swap(&context_amd64->p2_home);
417      Swap(&context_amd64->p3_home);
418      Swap(&context_amd64->p4_home);
419      Swap(&context_amd64->p5_home);
420      Swap(&context_amd64->p6_home);
421      // context_flags is already swapped
422      Swap(&context_amd64->mx_csr);
423      Swap(&context_amd64->cs);
424      Swap(&context_amd64->ds);
425      Swap(&context_amd64->es);
426      Swap(&context_amd64->fs);
427      Swap(&context_amd64->ss);
428      Swap(&context_amd64->eflags);
429      Swap(&context_amd64->dr0);
430      Swap(&context_amd64->dr1);
431      Swap(&context_amd64->dr2);
432      Swap(&context_amd64->dr3);
433      Swap(&context_amd64->dr6);
434      Swap(&context_amd64->dr7);
435      Swap(&context_amd64->rax);
436      Swap(&context_amd64->rcx);
437      Swap(&context_amd64->rdx);
438      Swap(&context_amd64->rbx);
439      Swap(&context_amd64->rsp);
440      Swap(&context_amd64->rbp);
441      Swap(&context_amd64->rsi);
442      Swap(&context_amd64->rdi);
443      Swap(&context_amd64->r8);
444      Swap(&context_amd64->r9);
445      Swap(&context_amd64->r10);
446      Swap(&context_amd64->r11);
447      Swap(&context_amd64->r12);
448      Swap(&context_amd64->r13);
449      Swap(&context_amd64->r14);
450      Swap(&context_amd64->r15);
451      Swap(&context_amd64->rip);
452      // FIXME: I'm not sure what actually determines
453      // which member of the union {flt_save, sse_registers}
454      // is valid.  We're not currently using either,
455      // but it would be good to have them swapped properly.
456
457      for (unsigned int vr_index = 0;
458           vr_index < MD_CONTEXT_AMD64_VR_COUNT;
459           ++vr_index)
460        Swap(&context_amd64->vector_register[vr_index]);
461      Swap(&context_amd64->vector_control);
462      Swap(&context_amd64->debug_control);
463      Swap(&context_amd64->last_branch_to_rip);
464      Swap(&context_amd64->last_branch_from_rip);
465      Swap(&context_amd64->last_exception_to_rip);
466      Swap(&context_amd64->last_exception_from_rip);
467    }
468
469    context_flags_ = context_amd64->context_flags;
470
471    context_.amd64 = context_amd64.release();
472  } else if (expected_size == sizeof(MDRawContextPPC64)) {
473    // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext
474    // in the else case have 32 bits |context_flags|, so special case it here.
475    uint64_t context_flags;
476    if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
477      BPLOG(ERROR) << "MinidumpContext could not read context flags";
478      return false;
479    }
480    if (minidump_->swap())
481      Swap(&context_flags);
482
483    uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
484    scoped_ptr<MDRawContextPPC64> context_ppc64(new MDRawContextPPC64());
485
486
487    // Set the context_flags member, which has already been read, and
488    // read the rest of the structure beginning with the first member
489    // after context_flags.
490    context_ppc64->context_flags = context_flags;
491
492    size_t flags_size = sizeof(context_ppc64->context_flags);
493    uint8_t* context_after_flags =
494          reinterpret_cast<uint8_t*>(context_ppc64.get()) + flags_size;
495    if (!minidump_->ReadBytes(context_after_flags,
496                              sizeof(MDRawContextPPC64) - flags_size)) {
497      BPLOG(ERROR) << "MinidumpContext could not read ppc64 context";
498      return false;
499    }
500
501    // Do this after reading the entire MDRawContext structure because
502    // GetSystemInfo may seek minidump to a new position.
503    if (!CheckAgainstSystemInfo(cpu_type)) {
504      BPLOG(ERROR) << "MinidumpContext ppc64 does not match system info";
505      return false;
506    }
507    if (minidump_->swap()) {
508      // context_ppc64->context_flags was already swapped.
509      Swap(&context_ppc64->srr0);
510      Swap(&context_ppc64->srr1);
511      for (unsigned int gpr_index = 0;
512           gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
513           ++gpr_index) {
514        Swap(&context_ppc64->gpr[gpr_index]);
515      }
516      Swap(&context_ppc64->cr);
517      Swap(&context_ppc64->xer);
518      Swap(&context_ppc64->lr);
519      Swap(&context_ppc64->ctr);
520      Swap(&context_ppc64->vrsave);
521      for (unsigned int fpr_index = 0;
522           fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
523           ++fpr_index) {
524        Swap(&context_ppc64->float_save.fpregs[fpr_index]);
525      }
526      // Don't swap context_ppc64->float_save.fpscr_pad because it is only
527      // used for padding.
528      Swap(&context_ppc64->float_save.fpscr);
529      for (unsigned int vr_index = 0;
530           vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
531           ++vr_index) {
532        Normalize128(&context_ppc64->vector_save.save_vr[vr_index], true);
533        Swap(&context_ppc64->vector_save.save_vr[vr_index]);
534      }
535      Swap(&context_ppc64->vector_save.save_vscr);
536      // Don't swap the padding fields in vector_save.
537      Swap(&context_ppc64->vector_save.save_vrvalid);
538    }
539
540    context_flags_ = static_cast<uint32_t>(context_ppc64->context_flags);
541
542    // Check for data loss when converting context flags from uint64_t into
543    // uint32_t
544    if (static_cast<uint64_t>(context_flags_) !=
545        context_ppc64->context_flags) {
546      BPLOG(ERROR) << "Data loss detected when converting PPC64 context_flags";
547      return false;
548    }
549
550    context_.ppc64 = context_ppc64.release();
551  } else {
552    uint32_t context_flags;
553    if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
554      BPLOG(ERROR) << "MinidumpContext could not read context flags";
555      return false;
556    }
557    if (minidump_->swap())
558      Swap(&context_flags);
559
560    uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
561    if (cpu_type == 0) {
562      // Unfortunately the flag for MD_CONTEXT_ARM that was taken
563      // from a Windows CE SDK header conflicts in practice with
564      // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
565      // but handle dumps with the legacy value gracefully here.
566      if (context_flags & MD_CONTEXT_ARM_OLD) {
567        context_flags |= MD_CONTEXT_ARM;
568        context_flags &= ~MD_CONTEXT_ARM_OLD;
569        cpu_type = MD_CONTEXT_ARM;
570      }
571    }
572
573    if (cpu_type == 0) {
574      if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
575        context_flags |= cpu_type;
576      } else {
577        BPLOG(ERROR) << "Failed to preserve the current stream position";
578        return false;
579      }
580    }
581
582    // Allocate the context structure for the correct CPU and fill it.  The
583    // casts are slightly unorthodox, but it seems better to do that than to
584    // maintain a separate pointer for each type of CPU context structure
585    // when only one of them will be used.
586    switch (cpu_type) {
587      case MD_CONTEXT_X86: {
588        if (expected_size != sizeof(MDRawContextX86)) {
589          BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
590            expected_size << " != " << sizeof(MDRawContextX86);
591          return false;
592        }
593
594        scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
595
596        // Set the context_flags member, which has already been read, and
597        // read the rest of the structure beginning with the first member
598        // after context_flags.
599        context_x86->context_flags = context_flags;
600
601        size_t flags_size = sizeof(context_x86->context_flags);
602        uint8_t* context_after_flags =
603          reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
604        if (!minidump_->ReadBytes(context_after_flags,
605                                  sizeof(MDRawContextX86) - flags_size)) {
606          BPLOG(ERROR) << "MinidumpContext could not read x86 context";
607          return false;
608        }
609
610        // Do this after reading the entire MDRawContext structure because
611        // GetSystemInfo may seek minidump to a new position.
612        if (!CheckAgainstSystemInfo(cpu_type)) {
613          BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
614          return false;
615        }
616
617        if (minidump_->swap()) {
618          // context_x86->context_flags was already swapped.
619          Swap(&context_x86->dr0);
620          Swap(&context_x86->dr1);
621          Swap(&context_x86->dr2);
622          Swap(&context_x86->dr3);
623          Swap(&context_x86->dr6);
624          Swap(&context_x86->dr7);
625          Swap(&context_x86->float_save.control_word);
626          Swap(&context_x86->float_save.status_word);
627          Swap(&context_x86->float_save.tag_word);
628          Swap(&context_x86->float_save.error_offset);
629          Swap(&context_x86->float_save.error_selector);
630          Swap(&context_x86->float_save.data_offset);
631          Swap(&context_x86->float_save.data_selector);
632          // context_x86->float_save.register_area[] contains 8-bit quantities
633          // and does not need to be swapped.
634          Swap(&context_x86->float_save.cr0_npx_state);
635          Swap(&context_x86->gs);
636          Swap(&context_x86->fs);
637          Swap(&context_x86->es);
638          Swap(&context_x86->ds);
639          Swap(&context_x86->edi);
640          Swap(&context_x86->esi);
641          Swap(&context_x86->ebx);
642          Swap(&context_x86->edx);
643          Swap(&context_x86->ecx);
644          Swap(&context_x86->eax);
645          Swap(&context_x86->ebp);
646          Swap(&context_x86->eip);
647          Swap(&context_x86->cs);
648          Swap(&context_x86->eflags);
649          Swap(&context_x86->esp);
650          Swap(&context_x86->ss);
651          // context_x86->extended_registers[] contains 8-bit quantities and
652          // does not need to be swapped.
653        }
654
655        context_.x86 = context_x86.release();
656
657        break;
658      }
659
660      case MD_CONTEXT_PPC: {
661        if (expected_size != sizeof(MDRawContextPPC)) {
662          BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
663            expected_size << " != " << sizeof(MDRawContextPPC);
664          return false;
665        }
666
667        scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
668
669        // Set the context_flags member, which has already been read, and
670        // read the rest of the structure beginning with the first member
671        // after context_flags.
672        context_ppc->context_flags = context_flags;
673
674        size_t flags_size = sizeof(context_ppc->context_flags);
675        uint8_t* context_after_flags =
676          reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
677        if (!minidump_->ReadBytes(context_after_flags,
678                                  sizeof(MDRawContextPPC) - flags_size)) {
679          BPLOG(ERROR) << "MinidumpContext could not read ppc context";
680          return false;
681        }
682
683        // Do this after reading the entire MDRawContext structure because
684        // GetSystemInfo may seek minidump to a new position.
685        if (!CheckAgainstSystemInfo(cpu_type)) {
686          BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
687          return false;
688        }
689
690        // Normalize the 128-bit types in the dump.
691        // Since this is PowerPC, by definition, the values are big-endian.
692        for (unsigned int vr_index = 0;
693             vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
694             ++vr_index) {
695          Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
696        }
697
698        if (minidump_->swap()) {
699          // context_ppc->context_flags was already swapped.
700          Swap(&context_ppc->srr0);
701          Swap(&context_ppc->srr1);
702          for (unsigned int gpr_index = 0;
703               gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
704               ++gpr_index) {
705            Swap(&context_ppc->gpr[gpr_index]);
706          }
707          Swap(&context_ppc->cr);
708          Swap(&context_ppc->xer);
709          Swap(&context_ppc->lr);
710          Swap(&context_ppc->ctr);
711          Swap(&context_ppc->mq);
712          Swap(&context_ppc->vrsave);
713          for (unsigned int fpr_index = 0;
714               fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
715               ++fpr_index) {
716            Swap(&context_ppc->float_save.fpregs[fpr_index]);
717          }
718          // Don't swap context_ppc->float_save.fpscr_pad because it is only
719          // used for padding.
720          Swap(&context_ppc->float_save.fpscr);
721          for (unsigned int vr_index = 0;
722               vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
723               ++vr_index) {
724            Swap(&context_ppc->vector_save.save_vr[vr_index]);
725          }
726          Swap(&context_ppc->vector_save.save_vscr);
727          // Don't swap the padding fields in vector_save.
728          Swap(&context_ppc->vector_save.save_vrvalid);
729        }
730
731        context_.ppc = context_ppc.release();
732
733        break;
734      }
735
736      case MD_CONTEXT_SPARC: {
737        if (expected_size != sizeof(MDRawContextSPARC)) {
738          BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
739            expected_size << " != " << sizeof(MDRawContextSPARC);
740          return false;
741        }
742
743        scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
744
745        // Set the context_flags member, which has already been read, and
746        // read the rest of the structure beginning with the first member
747        // after context_flags.
748        context_sparc->context_flags = context_flags;
749
750        size_t flags_size = sizeof(context_sparc->context_flags);
751        uint8_t* context_after_flags =
752            reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
753        if (!minidump_->ReadBytes(context_after_flags,
754                                  sizeof(MDRawContextSPARC) - flags_size)) {
755          BPLOG(ERROR) << "MinidumpContext could not read sparc context";
756          return false;
757        }
758
759        // Do this after reading the entire MDRawContext structure because
760        // GetSystemInfo may seek minidump to a new position.
761        if (!CheckAgainstSystemInfo(cpu_type)) {
762          BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
763          return false;
764        }
765
766        if (minidump_->swap()) {
767          // context_sparc->context_flags was already swapped.
768          for (unsigned int gpr_index = 0;
769               gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
770               ++gpr_index) {
771            Swap(&context_sparc->g_r[gpr_index]);
772          }
773          Swap(&context_sparc->ccr);
774          Swap(&context_sparc->pc);
775          Swap(&context_sparc->npc);
776          Swap(&context_sparc->y);
777          Swap(&context_sparc->asi);
778          Swap(&context_sparc->fprs);
779          for (unsigned int fpr_index = 0;
780               fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
781               ++fpr_index) {
782            Swap(&context_sparc->float_save.regs[fpr_index]);
783          }
784          Swap(&context_sparc->float_save.filler);
785          Swap(&context_sparc->float_save.fsr);
786        }
787        context_.ctx_sparc = context_sparc.release();
788
789        break;
790      }
791
792      case MD_CONTEXT_ARM: {
793        if (expected_size != sizeof(MDRawContextARM)) {
794          BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
795            expected_size << " != " << sizeof(MDRawContextARM);
796          return false;
797        }
798
799        scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
800
801        // Set the context_flags member, which has already been read, and
802        // read the rest of the structure beginning with the first member
803        // after context_flags.
804        context_arm->context_flags = context_flags;
805
806        size_t flags_size = sizeof(context_arm->context_flags);
807        uint8_t* context_after_flags =
808            reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
809        if (!minidump_->ReadBytes(context_after_flags,
810                                  sizeof(MDRawContextARM) - flags_size)) {
811          BPLOG(ERROR) << "MinidumpContext could not read arm context";
812          return false;
813        }
814
815        // Do this after reading the entire MDRawContext structure because
816        // GetSystemInfo may seek minidump to a new position.
817        if (!CheckAgainstSystemInfo(cpu_type)) {
818          BPLOG(ERROR) << "MinidumpContext arm does not match system info";
819          return false;
820        }
821
822        if (minidump_->swap()) {
823          // context_arm->context_flags was already swapped.
824          for (unsigned int ireg_index = 0;
825               ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
826               ++ireg_index) {
827            Swap(&context_arm->iregs[ireg_index]);
828          }
829          Swap(&context_arm->cpsr);
830          Swap(&context_arm->float_save.fpscr);
831          for (unsigned int fpr_index = 0;
832               fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
833               ++fpr_index) {
834            Swap(&context_arm->float_save.regs[fpr_index]);
835          }
836          for (unsigned int fpe_index = 0;
837               fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
838               ++fpe_index) {
839            Swap(&context_arm->float_save.extra[fpe_index]);
840          }
841        }
842        context_.arm = context_arm.release();
843
844        break;
845      }
846
847      default: {
848        // Unknown context type - Don't log as an error yet. Let the
849        // caller work that out.
850        BPLOG(INFO) << "MinidumpContext unknown context type " <<
851          HexString(cpu_type);
852        return false;
853        break;
854      }
855    }
856    context_flags_ = context_flags;
857  }
858
859  valid_ = true;
860  return true;
861}
862
863
864uint32_t MinidumpContext::GetContextCPU() const {
865  if (!valid_) {
866    // Don't log a message, GetContextCPU can be legitimately called with
867    // valid_ false by FreeContext, which is called by Read.
868    return 0;
869  }
870
871  return context_flags_ & MD_CONTEXT_CPU_MASK;
872}
873
874bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const {
875  BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer "
876                          "requires |ip|";
877  assert(ip);
878  *ip = 0;
879
880  if (!valid_) {
881    BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer";
882    return false;
883  }
884
885  switch (context_flags_ & MD_CONTEXT_CPU_MASK) {
886  case MD_CONTEXT_AMD64:
887    *ip = context_.amd64->rip;
888    break;
889  case MD_CONTEXT_ARM:
890    *ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC];
891    break;
892  case MD_CONTEXT_PPC:
893    *ip = context_.ppc->srr0;
894    break;
895  case MD_CONTEXT_PPC64:
896    *ip = context_.ppc64->srr0;
897    break;
898  case MD_CONTEXT_SPARC:
899    *ip = context_.ctx_sparc->pc;
900    break;
901  case MD_CONTEXT_X86:
902    *ip = context_.x86->eip;
903    break;
904  default:
905    // This should never happen.
906    BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
907    return false;
908  }
909  return true;
910}
911
912
913const MDRawContextX86* MinidumpContext::GetContextX86() const {
914  if (GetContextCPU() != MD_CONTEXT_X86) {
915    BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
916    return NULL;
917  }
918
919  return context_.x86;
920}
921
922
923const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
924  if (GetContextCPU() != MD_CONTEXT_PPC) {
925    BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
926    return NULL;
927  }
928
929  return context_.ppc;
930}
931
932const MDRawContextPPC64* MinidumpContext::GetContextPPC64() const {
933  if (GetContextCPU() != MD_CONTEXT_PPC64) {
934    BPLOG(ERROR) << "MinidumpContext cannot get ppc64 context";
935    return NULL;
936  }
937
938  return context_.ppc64;
939}
940
941const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
942  if (GetContextCPU() != MD_CONTEXT_AMD64) {
943    BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
944    return NULL;
945  }
946
947  return context_.amd64;
948}
949
950const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
951  if (GetContextCPU() != MD_CONTEXT_SPARC) {
952    BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
953    return NULL;
954  }
955
956  return context_.ctx_sparc;
957}
958
959const MDRawContextARM* MinidumpContext::GetContextARM() const {
960  if (GetContextCPU() != MD_CONTEXT_ARM) {
961    BPLOG(ERROR) << "MinidumpContext cannot get arm context";
962    return NULL;
963  }
964
965  return context_.arm;
966}
967
968void MinidumpContext::FreeContext() {
969  switch (GetContextCPU()) {
970    case MD_CONTEXT_X86:
971      delete context_.x86;
972      break;
973
974    case MD_CONTEXT_PPC:
975      delete context_.ppc;
976      break;
977
978    case MD_CONTEXT_PPC64:
979      delete context_.ppc64;
980      break;
981
982    case MD_CONTEXT_AMD64:
983      delete context_.amd64;
984      break;
985
986    case MD_CONTEXT_SPARC:
987      delete context_.ctx_sparc;
988      break;
989
990    case MD_CONTEXT_ARM:
991      delete context_.arm;
992      break;
993
994    default:
995      // There is no context record (valid_ is false) or there's a
996      // context record for an unknown CPU (shouldn't happen, only known
997      // records are stored by Read).
998      break;
999  }
1000
1001  context_flags_ = 0;
1002  context_.base = NULL;
1003}
1004
1005
1006bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
1007  // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
1008  // as this function just implements a sanity check.
1009  MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
1010  if (!system_info) {
1011    BPLOG(INFO) << "MinidumpContext could not be compared against "
1012                   "MinidumpSystemInfo";
1013    return true;
1014  }
1015
1016  // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
1017  const MDRawSystemInfo* raw_system_info = system_info->system_info();
1018  if (!raw_system_info) {
1019    BPLOG(INFO) << "MinidumpContext could not be compared against "
1020                   "MDRawSystemInfo";
1021    return false;
1022  }
1023
1024  MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
1025      raw_system_info->processor_architecture);
1026
1027  // Compare the CPU type of the context record to the CPU type in the
1028  // minidump's system info stream.
1029  bool return_value = false;
1030  switch (context_cpu_type) {
1031    case MD_CONTEXT_X86:
1032      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
1033          system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
1034          system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
1035        return_value = true;
1036      }
1037      break;
1038
1039    case MD_CONTEXT_PPC:
1040      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
1041        return_value = true;
1042      break;
1043
1044    case MD_CONTEXT_PPC64:
1045      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC64)
1046        return_value = true;
1047      break;
1048
1049    case MD_CONTEXT_AMD64:
1050      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
1051        return_value = true;
1052      break;
1053
1054    case MD_CONTEXT_SPARC:
1055      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
1056        return_value = true;
1057      break;
1058
1059    case MD_CONTEXT_ARM:
1060      if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
1061        return_value = true;
1062      break;
1063  }
1064
1065  BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
1066                                    HexString(context_cpu_type) <<
1067                                    " wrong for MinidumpSystemInfo CPU " <<
1068                                    HexString(system_info_cpu_type);
1069
1070  return return_value;
1071}
1072
1073
1074void MinidumpContext::Print() {
1075  if (!valid_) {
1076    BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
1077    return;
1078  }
1079
1080  switch (GetContextCPU()) {
1081    case MD_CONTEXT_X86: {
1082      const MDRawContextX86* context_x86 = GetContextX86();
1083      printf("MDRawContextX86\n");
1084      printf("  context_flags                = 0x%x\n",
1085             context_x86->context_flags);
1086      printf("  dr0                          = 0x%x\n", context_x86->dr0);
1087      printf("  dr1                          = 0x%x\n", context_x86->dr1);
1088      printf("  dr2                          = 0x%x\n", context_x86->dr2);
1089      printf("  dr3                          = 0x%x\n", context_x86->dr3);
1090      printf("  dr6                          = 0x%x\n", context_x86->dr6);
1091      printf("  dr7                          = 0x%x\n", context_x86->dr7);
1092      printf("  float_save.control_word      = 0x%x\n",
1093             context_x86->float_save.control_word);
1094      printf("  float_save.status_word       = 0x%x\n",
1095             context_x86->float_save.status_word);
1096      printf("  float_save.tag_word          = 0x%x\n",
1097             context_x86->float_save.tag_word);
1098      printf("  float_save.error_offset      = 0x%x\n",
1099             context_x86->float_save.error_offset);
1100      printf("  float_save.error_selector    = 0x%x\n",
1101             context_x86->float_save.error_selector);
1102      printf("  float_save.data_offset       = 0x%x\n",
1103             context_x86->float_save.data_offset);
1104      printf("  float_save.data_selector     = 0x%x\n",
1105             context_x86->float_save.data_selector);
1106      printf("  float_save.register_area[%2d] = 0x",
1107             MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
1108      for (unsigned int register_index = 0;
1109           register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
1110           ++register_index) {
1111        printf("%02x", context_x86->float_save.register_area[register_index]);
1112      }
1113      printf("\n");
1114      printf("  float_save.cr0_npx_state     = 0x%x\n",
1115             context_x86->float_save.cr0_npx_state);
1116      printf("  gs                           = 0x%x\n", context_x86->gs);
1117      printf("  fs                           = 0x%x\n", context_x86->fs);
1118      printf("  es                           = 0x%x\n", context_x86->es);
1119      printf("  ds                           = 0x%x\n", context_x86->ds);
1120      printf("  edi                          = 0x%x\n", context_x86->edi);
1121      printf("  esi                          = 0x%x\n", context_x86->esi);
1122      printf("  ebx                          = 0x%x\n", context_x86->ebx);
1123      printf("  edx                          = 0x%x\n", context_x86->edx);
1124      printf("  ecx                          = 0x%x\n", context_x86->ecx);
1125      printf("  eax                          = 0x%x\n", context_x86->eax);
1126      printf("  ebp                          = 0x%x\n", context_x86->ebp);
1127      printf("  eip                          = 0x%x\n", context_x86->eip);
1128      printf("  cs                           = 0x%x\n", context_x86->cs);
1129      printf("  eflags                       = 0x%x\n", context_x86->eflags);
1130      printf("  esp                          = 0x%x\n", context_x86->esp);
1131      printf("  ss                           = 0x%x\n", context_x86->ss);
1132      printf("  extended_registers[%3d]      = 0x",
1133             MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
1134      for (unsigned int register_index = 0;
1135           register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
1136           ++register_index) {
1137        printf("%02x", context_x86->extended_registers[register_index]);
1138      }
1139      printf("\n\n");
1140
1141      break;
1142    }
1143
1144    case MD_CONTEXT_PPC: {
1145      const MDRawContextPPC* context_ppc = GetContextPPC();
1146      printf("MDRawContextPPC\n");
1147      printf("  context_flags            = 0x%x\n",
1148             context_ppc->context_flags);
1149      printf("  srr0                     = 0x%x\n", context_ppc->srr0);
1150      printf("  srr1                     = 0x%x\n", context_ppc->srr1);
1151      for (unsigned int gpr_index = 0;
1152           gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
1153           ++gpr_index) {
1154        printf("  gpr[%2d]                  = 0x%x\n",
1155               gpr_index, context_ppc->gpr[gpr_index]);
1156      }
1157      printf("  cr                       = 0x%x\n", context_ppc->cr);
1158      printf("  xer                      = 0x%x\n", context_ppc->xer);
1159      printf("  lr                       = 0x%x\n", context_ppc->lr);
1160      printf("  ctr                      = 0x%x\n", context_ppc->ctr);
1161      printf("  mq                       = 0x%x\n", context_ppc->mq);
1162      printf("  vrsave                   = 0x%x\n", context_ppc->vrsave);
1163      for (unsigned int fpr_index = 0;
1164           fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
1165           ++fpr_index) {
1166        printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
1167               fpr_index, context_ppc->float_save.fpregs[fpr_index]);
1168      }
1169      printf("  float_save.fpscr         = 0x%x\n",
1170             context_ppc->float_save.fpscr);
1171      // TODO(mmentovai): print the 128-bit quantities in
1172      // context_ppc->vector_save.  This isn't done yet because printf
1173      // doesn't support 128-bit quantities, and printing them using
1174      // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
1175      // byte ordering.
1176      printf("  vector_save.save_vrvalid = 0x%x\n",
1177             context_ppc->vector_save.save_vrvalid);
1178      printf("\n");
1179
1180      break;
1181    }
1182
1183    case MD_CONTEXT_PPC64: {
1184      const MDRawContextPPC64* context_ppc64 = GetContextPPC64();
1185      printf("MDRawContextPPC64\n");
1186      printf("  context_flags            = 0x%" PRIx64 "\n",
1187             context_ppc64->context_flags);
1188      printf("  srr0                     = 0x%" PRIx64 "\n",
1189             context_ppc64->srr0);
1190      printf("  srr1                     = 0x%" PRIx64 "\n",
1191             context_ppc64->srr1);
1192      for (unsigned int gpr_index = 0;
1193           gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
1194           ++gpr_index) {
1195        printf("  gpr[%2d]                  = 0x%" PRIx64 "\n",
1196               gpr_index, context_ppc64->gpr[gpr_index]);
1197      }
1198      printf("  cr                       = 0x%" PRIx64 "\n", context_ppc64->cr);
1199      printf("  xer                      = 0x%" PRIx64 "\n",
1200             context_ppc64->xer);
1201      printf("  lr                       = 0x%" PRIx64 "\n", context_ppc64->lr);
1202      printf("  ctr                      = 0x%" PRIx64 "\n",
1203             context_ppc64->ctr);
1204      printf("  vrsave                   = 0x%" PRIx64 "\n",
1205             context_ppc64->vrsave);
1206      for (unsigned int fpr_index = 0;
1207           fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
1208           ++fpr_index) {
1209        printf("  float_save.fpregs[%2d]    = 0x%" PRIx64 "\n",
1210               fpr_index, context_ppc64->float_save.fpregs[fpr_index]);
1211      }
1212      printf("  float_save.fpscr         = 0x%x\n",
1213             context_ppc64->float_save.fpscr);
1214      // TODO(mmentovai): print the 128-bit quantities in
1215      // context_ppc64->vector_save.  This isn't done yet because printf
1216      // doesn't support 128-bit quantities, and printing them using
1217      // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
1218      // byte ordering.
1219      printf("  vector_save.save_vrvalid = 0x%x\n",
1220             context_ppc64->vector_save.save_vrvalid);
1221      printf("\n");
1222
1223      break;
1224    }
1225
1226    case MD_CONTEXT_AMD64: {
1227      const MDRawContextAMD64* context_amd64 = GetContextAMD64();
1228      printf("MDRawContextAMD64\n");
1229      printf("  p1_home       = 0x%" PRIx64 "\n",
1230             context_amd64->p1_home);
1231      printf("  p2_home       = 0x%" PRIx64 "\n",
1232             context_amd64->p2_home);
1233      printf("  p3_home       = 0x%" PRIx64 "\n",
1234             context_amd64->p3_home);
1235      printf("  p4_home       = 0x%" PRIx64 "\n",
1236             context_amd64->p4_home);
1237      printf("  p5_home       = 0x%" PRIx64 "\n",
1238             context_amd64->p5_home);
1239      printf("  p6_home       = 0x%" PRIx64 "\n",
1240             context_amd64->p6_home);
1241      printf("  context_flags = 0x%x\n",
1242             context_amd64->context_flags);
1243      printf("  mx_csr        = 0x%x\n",
1244             context_amd64->mx_csr);
1245      printf("  cs            = 0x%x\n", context_amd64->cs);
1246      printf("  ds            = 0x%x\n", context_amd64->ds);
1247      printf("  es            = 0x%x\n", context_amd64->es);
1248      printf("  fs            = 0x%x\n", context_amd64->fs);
1249      printf("  gs            = 0x%x\n", context_amd64->gs);
1250      printf("  ss            = 0x%x\n", context_amd64->ss);
1251      printf("  eflags        = 0x%x\n", context_amd64->eflags);
1252      printf("  dr0           = 0x%" PRIx64 "\n", context_amd64->dr0);
1253      printf("  dr1           = 0x%" PRIx64 "\n", context_amd64->dr1);
1254      printf("  dr2           = 0x%" PRIx64 "\n", context_amd64->dr2);
1255      printf("  dr3           = 0x%" PRIx64 "\n", context_amd64->dr3);
1256      printf("  dr6           = 0x%" PRIx64 "\n", context_amd64->dr6);
1257      printf("  dr7           = 0x%" PRIx64 "\n", context_amd64->dr7);
1258      printf("  rax           = 0x%" PRIx64 "\n", context_amd64->rax);
1259      printf("  rcx           = 0x%" PRIx64 "\n", context_amd64->rcx);
1260      printf("  rdx           = 0x%" PRIx64 "\n", context_amd64->rdx);
1261      printf("  rbx           = 0x%" PRIx64 "\n", context_amd64->rbx);
1262      printf("  rsp           = 0x%" PRIx64 "\n", context_amd64->rsp);
1263      printf("  rbp           = 0x%" PRIx64 "\n", context_amd64->rbp);
1264      printf("  rsi           = 0x%" PRIx64 "\n", context_amd64->rsi);
1265      printf("  rdi           = 0x%" PRIx64 "\n", context_amd64->rdi);
1266      printf("  r8            = 0x%" PRIx64 "\n", context_amd64->r8);
1267      printf("  r9            = 0x%" PRIx64 "\n", context_amd64->r9);
1268      printf("  r10           = 0x%" PRIx64 "\n", context_amd64->r10);
1269      printf("  r11           = 0x%" PRIx64 "\n", context_amd64->r11);
1270      printf("  r12           = 0x%" PRIx64 "\n", context_amd64->r12);
1271      printf("  r13           = 0x%" PRIx64 "\n", context_amd64->r13);
1272      printf("  r14           = 0x%" PRIx64 "\n", context_amd64->r14);
1273      printf("  r15           = 0x%" PRIx64 "\n", context_amd64->r15);
1274      printf("  rip           = 0x%" PRIx64 "\n", context_amd64->rip);
1275      // TODO: print xmm, vector, debug registers
1276      printf("\n");
1277      break;
1278    }
1279
1280    case MD_CONTEXT_SPARC: {
1281      const MDRawContextSPARC* context_sparc = GetContextSPARC();
1282      printf("MDRawContextSPARC\n");
1283      printf("  context_flags       = 0x%x\n",
1284             context_sparc->context_flags);
1285      for (unsigned int g_r_index = 0;
1286           g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
1287           ++g_r_index) {
1288        printf("  g_r[%2d]             = 0x%" PRIx64 "\n",
1289               g_r_index, context_sparc->g_r[g_r_index]);
1290      }
1291      printf("  ccr                 = 0x%" PRIx64 "\n", context_sparc->ccr);
1292      printf("  pc                  = 0x%" PRIx64 "\n", context_sparc->pc);
1293      printf("  npc                 = 0x%" PRIx64 "\n", context_sparc->npc);
1294      printf("  y                   = 0x%" PRIx64 "\n", context_sparc->y);
1295      printf("  asi                 = 0x%" PRIx64 "\n", context_sparc->asi);
1296      printf("  fprs                = 0x%" PRIx64 "\n", context_sparc->fprs);
1297
1298      for (unsigned int fpr_index = 0;
1299           fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
1300           ++fpr_index) {
1301        printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
1302               fpr_index, context_sparc->float_save.regs[fpr_index]);
1303      }
1304      printf("  float_save.filler   = 0x%" PRIx64 "\n",
1305             context_sparc->float_save.filler);
1306      printf("  float_save.fsr      = 0x%" PRIx64 "\n",
1307             context_sparc->float_save.fsr);
1308      break;
1309    }
1310
1311    case MD_CONTEXT_ARM: {
1312      const MDRawContextARM* context_arm = GetContextARM();
1313      printf("MDRawContextARM\n");
1314      printf("  context_flags       = 0x%x\n",
1315             context_arm->context_flags);
1316      for (unsigned int ireg_index = 0;
1317           ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
1318           ++ireg_index) {
1319        printf("  iregs[%2d]            = 0x%x\n",
1320               ireg_index, context_arm->iregs[ireg_index]);
1321      }
1322      printf("  cpsr                = 0x%x\n", context_arm->cpsr);
1323      printf("  float_save.fpscr     = 0x%" PRIx64 "\n",
1324             context_arm->float_save.fpscr);
1325      for (unsigned int fpr_index = 0;
1326           fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
1327           ++fpr_index) {
1328        printf("  float_save.regs[%2d] = 0x%" PRIx64 "\n",
1329               fpr_index, context_arm->float_save.regs[fpr_index]);
1330      }
1331      for (unsigned int fpe_index = 0;
1332           fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
1333           ++fpe_index) {
1334        printf("  float_save.extra[%2d] = 0x%" PRIx32 "\n",
1335               fpe_index, context_arm->float_save.extra[fpe_index]);
1336      }
1337
1338      break;
1339    }
1340
1341    default: {
1342      break;
1343    }
1344  }
1345}
1346
1347
1348//
1349// MinidumpMemoryRegion
1350//
1351
1352
1353uint32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024;  // 1MB
1354
1355
1356MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
1357    : MinidumpObject(minidump),
1358      descriptor_(NULL),
1359      memory_(NULL) {
1360}
1361
1362
1363MinidumpMemoryRegion::~MinidumpMemoryRegion() {
1364  delete memory_;
1365}
1366
1367
1368void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
1369  descriptor_ = descriptor;
1370  valid_ = descriptor &&
1371           descriptor_->memory.data_size <=
1372               numeric_limits<uint64_t>::max() -
1373               descriptor_->start_of_memory_range;
1374}
1375
1376
1377const uint8_t* MinidumpMemoryRegion::GetMemory() const {
1378  if (!valid_) {
1379    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
1380    return NULL;
1381  }
1382
1383  if (!memory_) {
1384    if (descriptor_->memory.data_size == 0) {
1385      BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
1386      return NULL;
1387    }
1388
1389    if (!minidump_->SeekSet(descriptor_->memory.rva)) {
1390      BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
1391      return NULL;
1392    }
1393
1394    if (descriptor_->memory.data_size > max_bytes_) {
1395      BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
1396                      descriptor_->memory.data_size << " exceeds maximum " <<
1397                      max_bytes_;
1398      return NULL;
1399    }
1400
1401    scoped_ptr< vector<uint8_t> > memory(
1402        new vector<uint8_t>(descriptor_->memory.data_size));
1403
1404    if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
1405      BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
1406      return NULL;
1407    }
1408
1409    memory_ = memory.release();
1410  }
1411
1412  return &(*memory_)[0];
1413}
1414
1415
1416uint64_t MinidumpMemoryRegion::GetBase() const {
1417  if (!valid_) {
1418    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
1419    return static_cast<uint64_t>(-1);
1420  }
1421
1422  return descriptor_->start_of_memory_range;
1423}
1424
1425
1426uint32_t MinidumpMemoryRegion::GetSize() const {
1427  if (!valid_) {
1428    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
1429    return 0;
1430  }
1431
1432  return descriptor_->memory.data_size;
1433}
1434
1435
1436void MinidumpMemoryRegion::FreeMemory() {
1437  delete memory_;
1438  memory_ = NULL;
1439}
1440
1441
1442template<typename T>
1443bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
1444                                                      T*        value) const {
1445  BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
1446                             "requires |value|";
1447  assert(value);
1448  *value = 0;
1449
1450  if (!valid_) {
1451    BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
1452                    "GetMemoryAtAddressInternal";
1453    return false;
1454  }
1455
1456  // Common failure case
1457  if (address < descriptor_->start_of_memory_range ||
1458      sizeof(T) > numeric_limits<uint64_t>::max() - address ||
1459      address + sizeof(T) > descriptor_->start_of_memory_range +
1460                            descriptor_->memory.data_size) {
1461    BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
1462                    HexString(address) << "+" << sizeof(T) << "/" <<
1463                    HexString(descriptor_->start_of_memory_range) << "+" <<
1464                    HexString(descriptor_->memory.data_size);
1465    return false;
1466  }
1467
1468  const uint8_t* memory = GetMemory();
1469  if (!memory) {
1470    // GetMemory already logged a perfectly good message.
1471    return false;
1472  }
1473
1474  // If the CPU requires memory accesses to be aligned, this can crash.
1475  // x86 and ppc are able to cope, though.
1476  *value = *reinterpret_cast<const T*>(
1477      &memory[address - descriptor_->start_of_memory_range]);
1478
1479  if (minidump_->swap())
1480    Swap(value);
1481
1482  return true;
1483}
1484
1485
1486bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1487                                              uint8_t*  value) const {
1488  return GetMemoryAtAddressInternal(address, value);
1489}
1490
1491
1492bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1493                                              uint16_t* value) const {
1494  return GetMemoryAtAddressInternal(address, value);
1495}
1496
1497
1498bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1499                                              uint32_t* value) const {
1500  return GetMemoryAtAddressInternal(address, value);
1501}
1502
1503
1504bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1505                                              uint64_t* value) const {
1506  return GetMemoryAtAddressInternal(address, value);
1507}
1508
1509
1510void MinidumpMemoryRegion::Print() {
1511  if (!valid_) {
1512    BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
1513    return;
1514  }
1515
1516  const uint8_t* memory = GetMemory();
1517  if (memory) {
1518    printf("0x");
1519    for (unsigned int byte_index = 0;
1520         byte_index < descriptor_->memory.data_size;
1521         byte_index++) {
1522      printf("%02x", memory[byte_index]);
1523    }
1524    printf("\n");
1525  } else {
1526    printf("No memory\n");
1527  }
1528}
1529
1530
1531//
1532// MinidumpThread
1533//
1534
1535
1536MinidumpThread::MinidumpThread(Minidump* minidump)
1537    : MinidumpObject(minidump),
1538      thread_(),
1539      memory_(NULL),
1540      context_(NULL) {
1541}
1542
1543
1544MinidumpThread::~MinidumpThread() {
1545  delete memory_;
1546  delete context_;
1547}
1548
1549
1550bool MinidumpThread::Read() {
1551  // Invalidate cached data.
1552  delete memory_;
1553  memory_ = NULL;
1554  delete context_;
1555  context_ = NULL;
1556
1557  valid_ = false;
1558
1559  if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
1560    BPLOG(ERROR) << "MinidumpThread cannot read thread";
1561    return false;
1562  }
1563
1564  if (minidump_->swap()) {
1565    Swap(&thread_.thread_id);
1566    Swap(&thread_.suspend_count);
1567    Swap(&thread_.priority_class);
1568    Swap(&thread_.priority);
1569    Swap(&thread_.teb);
1570    Swap(&thread_.stack);
1571    Swap(&thread_.thread_context);
1572  }
1573
1574  // Check for base + size overflow or undersize.
1575  if (thread_.stack.memory.rva == 0 ||
1576      thread_.stack.memory.data_size == 0 ||
1577      thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
1578                                       thread_.stack.start_of_memory_range) {
1579    // This is ok, but log an error anyway.
1580    BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
1581                    HexString(thread_.stack.start_of_memory_range) << "+" <<
1582                    HexString(thread_.stack.memory.data_size) <<
1583                    ", RVA 0x" << HexString(thread_.stack.memory.rva);
1584  } else {
1585    memory_ = new MinidumpMemoryRegion(minidump_);
1586    memory_->SetDescriptor(&thread_.stack);
1587  }
1588
1589  valid_ = true;
1590  return true;
1591}
1592
1593uint64_t MinidumpThread::GetStartOfStackMemoryRange() const {
1594  if (!valid_) {
1595    BPLOG(ERROR) << "GetStartOfStackMemoryRange: Invalid MinidumpThread";
1596    return 0;
1597  }
1598
1599  return thread_.stack.start_of_memory_range;
1600}
1601
1602MinidumpMemoryRegion* MinidumpThread::GetMemory() {
1603  if (!valid_) {
1604    BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
1605    return NULL;
1606  }
1607
1608  return memory_;
1609}
1610
1611
1612MinidumpContext* MinidumpThread::GetContext() {
1613  if (!valid_) {
1614    BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
1615    return NULL;
1616  }
1617
1618  if (!context_) {
1619    if (!minidump_->SeekSet(thread_.thread_context.rva)) {
1620      BPLOG(ERROR) << "MinidumpThread cannot seek to context";
1621      return NULL;
1622    }
1623
1624    scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
1625
1626    if (!context->Read(thread_.thread_context.data_size)) {
1627      BPLOG(ERROR) << "MinidumpThread cannot read context";
1628      return NULL;
1629    }
1630
1631    context_ = context.release();
1632  }
1633
1634  return context_;
1635}
1636
1637
1638bool MinidumpThread::GetThreadID(uint32_t *thread_id) const {
1639  BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
1640                                 "|thread_id|";
1641  assert(thread_id);
1642  *thread_id = 0;
1643
1644  if (!valid_) {
1645    BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
1646    return false;
1647  }
1648
1649  *thread_id = thread_.thread_id;
1650  return true;
1651}
1652
1653
1654void MinidumpThread::Print() {
1655  if (!valid_) {
1656    BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
1657    return;
1658  }
1659
1660  printf("MDRawThread\n");
1661  printf("  thread_id                   = 0x%x\n",   thread_.thread_id);
1662  printf("  suspend_count               = %d\n",     thread_.suspend_count);
1663  printf("  priority_class              = 0x%x\n",   thread_.priority_class);
1664  printf("  priority                    = 0x%x\n",   thread_.priority);
1665  printf("  teb                         = 0x%" PRIx64 "\n", thread_.teb);
1666  printf("  stack.start_of_memory_range = 0x%" PRIx64 "\n",
1667         thread_.stack.start_of_memory_range);
1668  printf("  stack.memory.data_size      = 0x%x\n",
1669         thread_.stack.memory.data_size);
1670  printf("  stack.memory.rva            = 0x%x\n",   thread_.stack.memory.rva);
1671  printf("  thread_context.data_size    = 0x%x\n",
1672         thread_.thread_context.data_size);
1673  printf("  thread_context.rva          = 0x%x\n",
1674         thread_.thread_context.rva);
1675
1676  MinidumpContext* context = GetContext();
1677  if (context) {
1678    printf("\n");
1679    context->Print();
1680  } else {
1681    printf("  (no context)\n");
1682    printf("\n");
1683  }
1684
1685  MinidumpMemoryRegion* memory = GetMemory();
1686  if (memory) {
1687    printf("Stack\n");
1688    memory->Print();
1689  } else {
1690    printf("No stack\n");
1691  }
1692  printf("\n");
1693}
1694
1695
1696//
1697// MinidumpThreadList
1698//
1699
1700
1701uint32_t MinidumpThreadList::max_threads_ = 4096;
1702
1703
1704MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
1705    : MinidumpStream(minidump),
1706      id_to_thread_map_(),
1707      threads_(NULL),
1708      thread_count_(0) {
1709}
1710
1711
1712MinidumpThreadList::~MinidumpThreadList() {
1713  delete threads_;
1714}
1715
1716
1717bool MinidumpThreadList::Read(uint32_t expected_size) {
1718  // Invalidate cached data.
1719  id_to_thread_map_.clear();
1720  delete threads_;
1721  threads_ = NULL;
1722  thread_count_ = 0;
1723
1724  valid_ = false;
1725
1726  uint32_t thread_count;
1727  if (expected_size < sizeof(thread_count)) {
1728    BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
1729                    expected_size << " < " << sizeof(thread_count);
1730    return false;
1731  }
1732  if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
1733    BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
1734    return false;
1735  }
1736
1737  if (minidump_->swap())
1738    Swap(&thread_count);
1739
1740  if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
1741    BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
1742                    " would cause multiplication overflow";
1743    return false;
1744  }
1745
1746  if (expected_size != sizeof(thread_count) +
1747                       thread_count * sizeof(MDRawThread)) {
1748    // may be padded with 4 bytes on 64bit ABIs for alignment
1749    if (expected_size == sizeof(thread_count) + 4 +
1750                         thread_count * sizeof(MDRawThread)) {
1751      uint32_t useless;
1752      if (!minidump_->ReadBytes(&useless, 4)) {
1753        BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded "
1754                        "bytes";
1755        return false;
1756      }
1757    } else {
1758      BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
1759                    " != " << sizeof(thread_count) +
1760                    thread_count * sizeof(MDRawThread);
1761      return false;
1762    }
1763  }
1764
1765
1766  if (thread_count > max_threads_) {
1767    BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
1768                    " exceeds maximum " << max_threads_;
1769    return false;
1770  }
1771
1772  if (thread_count != 0) {
1773    scoped_ptr<MinidumpThreads> threads(
1774        new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
1775
1776    for (unsigned int thread_index = 0;
1777         thread_index < thread_count;
1778         ++thread_index) {
1779      MinidumpThread* thread = &(*threads)[thread_index];
1780
1781      // Assume that the file offset is correct after the last read.
1782      if (!thread->Read()) {
1783        BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
1784                        thread_index << "/" << thread_count;
1785        return false;
1786      }
1787
1788      uint32_t thread_id;
1789      if (!thread->GetThreadID(&thread_id)) {
1790        BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
1791                        thread_index << "/" << thread_count;
1792        return false;
1793      }
1794
1795      if (GetThreadByID(thread_id)) {
1796        // Another thread with this ID is already in the list.  Data error.
1797        BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
1798                        HexString(thread_id) << " at thread " <<
1799                        thread_index << "/" << thread_count;
1800        return false;
1801      }
1802      id_to_thread_map_[thread_id] = thread;
1803    }
1804
1805    threads_ = threads.release();
1806  }
1807
1808  thread_count_ = thread_count;
1809
1810  valid_ = true;
1811  return true;
1812}
1813
1814
1815MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
1816    const {
1817  if (!valid_) {
1818    BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
1819    return NULL;
1820  }
1821
1822  if (index >= thread_count_) {
1823    BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
1824                    index << "/" << thread_count_;
1825    return NULL;
1826  }
1827
1828  return &(*threads_)[index];
1829}
1830
1831
1832MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
1833  // Don't check valid_.  Read calls this method before everything is
1834  // validated.  It is safe to not check valid_ here.
1835  return id_to_thread_map_[thread_id];
1836}
1837
1838
1839void MinidumpThreadList::Print() {
1840  if (!valid_) {
1841    BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
1842    return;
1843  }
1844
1845  printf("MinidumpThreadList\n");
1846  printf("  thread_count = %d\n", thread_count_);
1847  printf("\n");
1848
1849  for (unsigned int thread_index = 0;
1850       thread_index < thread_count_;
1851       ++thread_index) {
1852    printf("thread[%d]\n", thread_index);
1853
1854    (*threads_)[thread_index].Print();
1855  }
1856}
1857
1858
1859//
1860// MinidumpModule
1861//
1862
1863
1864uint32_t MinidumpModule::max_cv_bytes_ = 32768;
1865uint32_t MinidumpModule::max_misc_bytes_ = 32768;
1866
1867
1868MinidumpModule::MinidumpModule(Minidump* minidump)
1869    : MinidumpObject(minidump),
1870      module_valid_(false),
1871      has_debug_info_(false),
1872      module_(),
1873      name_(NULL),
1874      cv_record_(NULL),
1875      cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
1876      misc_record_(NULL) {
1877}
1878
1879
1880MinidumpModule::~MinidumpModule() {
1881  delete name_;
1882  delete cv_record_;
1883  delete misc_record_;
1884}
1885
1886
1887bool MinidumpModule::Read() {
1888  // Invalidate cached data.
1889  delete name_;
1890  name_ = NULL;
1891  delete cv_record_;
1892  cv_record_ = NULL;
1893  cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
1894  delete misc_record_;
1895  misc_record_ = NULL;
1896
1897  module_valid_ = false;
1898  has_debug_info_ = false;
1899  valid_ = false;
1900
1901  if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
1902    BPLOG(ERROR) << "MinidumpModule cannot read module";
1903    return false;
1904  }
1905
1906  if (minidump_->swap()) {
1907    Swap(&module_.base_of_image);
1908    Swap(&module_.size_of_image);
1909    Swap(&module_.checksum);
1910    Swap(&module_.time_date_stamp);
1911    Swap(&module_.module_name_rva);
1912    Swap(&module_.version_info.signature);
1913    Swap(&module_.version_info.struct_version);
1914    Swap(&module_.version_info.file_version_hi);
1915    Swap(&module_.version_info.file_version_lo);
1916    Swap(&module_.version_info.product_version_hi);
1917    Swap(&module_.version_info.product_version_lo);
1918    Swap(&module_.version_info.file_flags_mask);
1919    Swap(&module_.version_info.file_flags);
1920    Swap(&module_.version_info.file_os);
1921    Swap(&module_.version_info.file_type);
1922    Swap(&module_.version_info.file_subtype);
1923    Swap(&module_.version_info.file_date_hi);
1924    Swap(&module_.version_info.file_date_lo);
1925    Swap(&module_.cv_record);
1926    Swap(&module_.misc_record);
1927    // Don't swap reserved fields because their contents are unknown (as
1928    // are their proper widths).
1929  }
1930
1931  // Check for base + size overflow or undersize.
1932  if (module_.size_of_image == 0 ||
1933      module_.size_of_image >
1934          numeric_limits<uint64_t>::max() - module_.base_of_image) {
1935    BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
1936                    HexString(module_.base_of_image) << "+" <<
1937                    HexString(module_.size_of_image);
1938    return false;
1939  }
1940
1941  module_valid_ = true;
1942  return true;
1943}
1944
1945
1946bool MinidumpModule::ReadAuxiliaryData() {
1947  if (!module_valid_) {
1948    BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
1949    return false;
1950  }
1951
1952  // Each module must have a name.
1953  name_ = minidump_->ReadString(module_.module_name_rva);
1954  if (!name_) {
1955    BPLOG(ERROR) << "MinidumpModule could not read name";
1956    return false;
1957  }
1958
1959  // At this point, we have enough info for the module to be valid.
1960  valid_ = true;
1961
1962  // CodeView and miscellaneous debug records are only required if the
1963  // module indicates that they exist.
1964  if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
1965    BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
1966                    "but one was expected";
1967    return false;
1968  }
1969
1970  if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
1971    BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
1972                    "but one was expected";
1973    return false;
1974  }
1975
1976  has_debug_info_ = true;
1977  return true;
1978}
1979
1980
1981string MinidumpModule::code_file() const {
1982  if (!valid_) {
1983    BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
1984    return "";
1985  }
1986
1987  return *name_;
1988}
1989
1990
1991string MinidumpModule::code_identifier() const {
1992  if (!valid_) {
1993    BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
1994    return "";
1995  }
1996
1997  if (!has_debug_info_)
1998    return "";
1999
2000  MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
2001  if (!minidump_system_info) {
2002    BPLOG(ERROR) << "MinidumpModule code_identifier requires "
2003                    "MinidumpSystemInfo";
2004    return "";
2005  }
2006
2007  const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
2008  if (!raw_system_info) {
2009    BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
2010    return "";
2011  }
2012
2013  string identifier;
2014
2015  switch (raw_system_info->platform_id) {
2016    case MD_OS_WIN32_NT:
2017    case MD_OS_WIN32_WINDOWS: {
2018      // Use the same format that the MS symbol server uses in filesystem
2019      // hierarchies.
2020      char identifier_string[17];
2021      snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
2022               module_.time_date_stamp, module_.size_of_image);
2023      identifier = identifier_string;
2024      break;
2025    }
2026
2027    case MD_OS_MAC_OS_X:
2028    case MD_OS_IOS:
2029    case MD_OS_SOLARIS:
2030    case MD_OS_ANDROID:
2031    case MD_OS_LINUX:
2032    case MD_OS_PS3: {
2033      // TODO(mmentovai): support uuid extension if present, otherwise fall
2034      // back to version (from LC_ID_DYLIB?), otherwise fall back to something
2035      // else.
2036      identifier = "id";
2037      break;
2038    }
2039
2040    default: {
2041      // Without knowing what OS generated the dump, we can't generate a good
2042      // identifier.  Return an empty string, signalling failure.
2043      BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
2044                      "found " << HexString(raw_system_info->platform_id);
2045      break;
2046    }
2047  }
2048
2049  return identifier;
2050}
2051
2052
2053string MinidumpModule::debug_file() const {
2054  if (!valid_) {
2055    BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
2056    return "";
2057  }
2058
2059  if (!has_debug_info_)
2060    return "";
2061
2062  string file;
2063  // Prefer the CodeView record if present.
2064  if (cv_record_) {
2065    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2066      // It's actually an MDCVInfoPDB70 structure.
2067      const MDCVInfoPDB70* cv_record_70 =
2068          reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2069      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2070
2071      // GetCVRecord guarantees pdb_file_name is null-terminated.
2072      file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
2073    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2074      // It's actually an MDCVInfoPDB20 structure.
2075      const MDCVInfoPDB20* cv_record_20 =
2076          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2077      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2078
2079      // GetCVRecord guarantees pdb_file_name is null-terminated.
2080      file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
2081    }
2082
2083    // If there's a CodeView record but it doesn't match a known signature,
2084    // try the miscellaneous record.
2085  }
2086
2087  if (file.empty()) {
2088    // No usable CodeView record.  Try the miscellaneous debug record.
2089    if (misc_record_) {
2090      const MDImageDebugMisc* misc_record =
2091          reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
2092      if (!misc_record->unicode) {
2093        // If it's not Unicode, just stuff it into the string.  It's unclear
2094        // if misc_record->data is 0-terminated, so use an explicit size.
2095        file = string(
2096            reinterpret_cast<const char*>(misc_record->data),
2097            module_.misc_record.data_size - MDImageDebugMisc_minsize);
2098      } else {
2099        // There's a misc_record but it encodes the debug filename in UTF-16.
2100        // (Actually, because miscellaneous records are so old, it's probably
2101        // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
2102        // that this method (and all other methods in the Minidump family)
2103        // return.
2104
2105        unsigned int bytes =
2106            module_.misc_record.data_size - MDImageDebugMisc_minsize;
2107        if (bytes % 2 == 0) {
2108          unsigned int utf16_words = bytes / 2;
2109
2110          // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
2111          // and copy the UTF-16 data into it.
2112          vector<uint16_t> string_utf16(utf16_words);
2113          if (utf16_words)
2114            memcpy(&string_utf16[0], &misc_record->data, bytes);
2115
2116          // GetMiscRecord already byte-swapped the data[] field if it contains
2117          // UTF-16, so pass false as the swap argument.
2118          scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
2119          file = *new_file;
2120        }
2121      }
2122    }
2123  }
2124
2125  // Relatively common case
2126  BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
2127                                  "debug_file for " << *name_;
2128
2129  return file;
2130}
2131
2132
2133string MinidumpModule::debug_identifier() const {
2134  if (!valid_) {
2135    BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
2136    return "";
2137  }
2138
2139  if (!has_debug_info_)
2140    return "";
2141
2142  string identifier;
2143
2144  // Use the CodeView record if present.
2145  if (cv_record_) {
2146    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2147      // It's actually an MDCVInfoPDB70 structure.
2148      const MDCVInfoPDB70* cv_record_70 =
2149          reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2150      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2151
2152      // Use the same format that the MS symbol server uses in filesystem
2153      // hierarchies.
2154      char identifier_string[41];
2155      snprintf(identifier_string, sizeof(identifier_string),
2156               "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
2157               cv_record_70->signature.data1,
2158               cv_record_70->signature.data2,
2159               cv_record_70->signature.data3,
2160               cv_record_70->signature.data4[0],
2161               cv_record_70->signature.data4[1],
2162               cv_record_70->signature.data4[2],
2163               cv_record_70->signature.data4[3],
2164               cv_record_70->signature.data4[4],
2165               cv_record_70->signature.data4[5],
2166               cv_record_70->signature.data4[6],
2167               cv_record_70->signature.data4[7],
2168               cv_record_70->age);
2169      identifier = identifier_string;
2170    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2171      // It's actually an MDCVInfoPDB20 structure.
2172      const MDCVInfoPDB20* cv_record_20 =
2173          reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2174      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2175
2176      // Use the same format that the MS symbol server uses in filesystem
2177      // hierarchies.
2178      char identifier_string[17];
2179      snprintf(identifier_string, sizeof(identifier_string),
2180               "%08X%x", cv_record_20->signature, cv_record_20->age);
2181      identifier = identifier_string;
2182    }
2183  }
2184
2185  // TODO(mmentovai): if there's no usable CodeView record, there might be a
2186  // miscellaneous debug record.  It only carries a filename, though, and no
2187  // identifier.  I'm not sure what the right thing to do for the identifier
2188  // is in that case, but I don't expect to find many modules without a
2189  // CodeView record (or some other Breakpad extension structure in place of
2190  // a CodeView record).  Treat it as an error (empty identifier) for now.
2191
2192  // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
2193
2194  // Relatively common case
2195  BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
2196                                        "debug_identifier for " << *name_;
2197
2198  return identifier;
2199}
2200
2201
2202string MinidumpModule::version() const {
2203  if (!valid_) {
2204    BPLOG(ERROR) << "Invalid MinidumpModule for version";
2205    return "";
2206  }
2207
2208  string version;
2209
2210  if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
2211      module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
2212    char version_string[24];
2213    snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
2214             module_.version_info.file_version_hi >> 16,
2215             module_.version_info.file_version_hi & 0xffff,
2216             module_.version_info.file_version_lo >> 16,
2217             module_.version_info.file_version_lo & 0xffff);
2218    version = version_string;
2219  }
2220
2221  // TODO(mmentovai): possibly support other struct types in place of
2222  // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
2223  // a different structure that better represents versioning facilities on
2224  // Mac OS X and Linux, instead of forcing them to adhere to the dotted
2225  // quad of 16-bit ints that Windows uses.
2226
2227  BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
2228                                     "version for " << *name_;
2229
2230  return version;
2231}
2232
2233
2234const CodeModule* MinidumpModule::Copy() const {
2235  return new BasicCodeModule(this);
2236}
2237
2238
2239const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
2240  if (!module_valid_) {
2241    BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
2242    return NULL;
2243  }
2244
2245  if (!cv_record_) {
2246    // This just guards against 0-sized CodeView records; more specific checks
2247    // are used when the signature is checked against various structure types.
2248    if (module_.cv_record.data_size == 0) {
2249      return NULL;
2250    }
2251
2252    if (!minidump_->SeekSet(module_.cv_record.rva)) {
2253      BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
2254      return NULL;
2255    }
2256
2257    if (module_.cv_record.data_size > max_cv_bytes_) {
2258      BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
2259                      module_.cv_record.data_size << " exceeds maximum " <<
2260                      max_cv_bytes_;
2261      return NULL;
2262    }
2263
2264    // Allocating something that will be accessed as MDCVInfoPDB70 or
2265    // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
2266    // problems.  x86 and ppc are able to cope, though.  This allocation
2267    // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
2268    // variable-sized due to their pdb_file_name fields; these structures
2269    // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
2270    // them as such would result in incomplete structures or overruns.
2271    scoped_ptr< vector<uint8_t> > cv_record(
2272        new vector<uint8_t>(module_.cv_record.data_size));
2273
2274    if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
2275      BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
2276      return NULL;
2277    }
2278
2279    uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
2280    if (module_.cv_record.data_size > sizeof(signature)) {
2281      MDCVInfoPDB70* cv_record_signature =
2282          reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2283      signature = cv_record_signature->cv_signature;
2284      if (minidump_->swap())
2285        Swap(&signature);
2286    }
2287
2288    if (signature == MD_CVINFOPDB70_SIGNATURE) {
2289      // Now that the structure type is known, recheck the size.
2290      if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
2291        BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
2292                        MDCVInfoPDB70_minsize << " > " <<
2293                        module_.cv_record.data_size;
2294        return NULL;
2295      }
2296
2297      if (minidump_->swap()) {
2298        MDCVInfoPDB70* cv_record_70 =
2299            reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2300        Swap(&cv_record_70->cv_signature);
2301        Swap(&cv_record_70->signature);
2302        Swap(&cv_record_70->age);
2303        // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
2304        // quantities.  (It's a path, is it UTF-8?)
2305      }
2306
2307      // The last field of either structure is null-terminated 8-bit character
2308      // data.  Ensure that it's null-terminated.
2309      if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2310        BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
2311                        "0-terminated";
2312        return NULL;
2313      }
2314    } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
2315      // Now that the structure type is known, recheck the size.
2316      if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
2317        BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
2318                        MDCVInfoPDB20_minsize << " > " <<
2319                        module_.cv_record.data_size;
2320        return NULL;
2321      }
2322      if (minidump_->swap()) {
2323        MDCVInfoPDB20* cv_record_20 =
2324            reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
2325        Swap(&cv_record_20->cv_header.signature);
2326        Swap(&cv_record_20->cv_header.offset);
2327        Swap(&cv_record_20->signature);
2328        Swap(&cv_record_20->age);
2329        // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
2330        // quantities.  (It's a path, is it UTF-8?)
2331      }
2332
2333      // The last field of either structure is null-terminated 8-bit character
2334      // data.  Ensure that it's null-terminated.
2335      if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2336        BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
2337                        "0-terminated";
2338        return NULL;
2339      }
2340    }
2341
2342    // If the signature doesn't match something above, it's not something
2343    // that Breakpad can presently handle directly.  Because some modules in
2344    // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
2345    // don't bail out here - allow the data to be returned to the user,
2346    // although byte-swapping can't be done.
2347
2348    // Store the vector type because that's how storage was allocated, but
2349    // return it casted to uint8_t*.
2350    cv_record_ = cv_record.release();
2351    cv_record_signature_ = signature;
2352  }
2353
2354  if (size)
2355    *size = module_.cv_record.data_size;
2356
2357  return &(*cv_record_)[0];
2358}
2359
2360
2361const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
2362  if (!module_valid_) {
2363    BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
2364    return NULL;
2365  }
2366
2367  if (!misc_record_) {
2368    if (module_.misc_record.data_size == 0) {
2369      return NULL;
2370    }
2371
2372    if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
2373      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
2374                      "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
2375                      module_.misc_record.data_size;
2376      return NULL;
2377    }
2378
2379    if (!minidump_->SeekSet(module_.misc_record.rva)) {
2380      BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
2381                      "debugging record";
2382      return NULL;
2383    }
2384
2385    if (module_.misc_record.data_size > max_misc_bytes_) {
2386      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
2387                      module_.misc_record.data_size << " exceeds maximum " <<
2388                      max_misc_bytes_;
2389      return NULL;
2390    }
2391
2392    // Allocating something that will be accessed as MDImageDebugMisc but
2393    // is allocated as uint8_t[] can cause alignment problems.  x86 and
2394    // ppc are able to cope, though.  This allocation style is needed
2395    // because the MDImageDebugMisc is variable-sized due to its data field;
2396    // this structure is not MDImageDebugMisc_minsize and treating it as such
2397    // would result in an incomplete structure or an overrun.
2398    scoped_ptr< vector<uint8_t> > misc_record_mem(
2399        new vector<uint8_t>(module_.misc_record.data_size));
2400    MDImageDebugMisc* misc_record =
2401        reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
2402
2403    if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
2404      BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
2405                      "record";
2406      return NULL;
2407    }
2408
2409    if (minidump_->swap()) {
2410      Swap(&misc_record->data_type);
2411      Swap(&misc_record->length);
2412      // Don't swap misc_record.unicode because it's an 8-bit quantity.
2413      // Don't swap the reserved fields for the same reason, and because
2414      // they don't contain any valid data.
2415      if (misc_record->unicode) {
2416        // There is a potential alignment problem, but shouldn't be a problem
2417        // in practice due to the layout of MDImageDebugMisc.
2418        uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
2419        unsigned int dataBytes = module_.misc_record.data_size -
2420                                 MDImageDebugMisc_minsize;
2421        Swap(data16, dataBytes);
2422      }
2423    }
2424
2425    if (module_.misc_record.data_size != misc_record->length) {
2426      BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
2427                      "size mismatch, " << module_.misc_record.data_size <<
2428                      " != " << misc_record->length;
2429      return NULL;
2430    }
2431
2432    // Store the vector type because that's how storage was allocated, but
2433    // return it casted to MDImageDebugMisc*.
2434    misc_record_ = misc_record_mem.release();
2435  }
2436
2437  if (size)
2438    *size = module_.misc_record.data_size;
2439
2440  return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
2441}
2442
2443
2444void MinidumpModule::Print() {
2445  if (!valid_) {
2446    BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
2447    return;
2448  }
2449
2450  printf("MDRawModule\n");
2451  printf("  base_of_image                   = 0x%" PRIx64 "\n",
2452         module_.base_of_image);
2453  printf("  size_of_image                   = 0x%x\n",
2454         module_.size_of_image);
2455  printf("  checksum                        = 0x%x\n",
2456         module_.checksum);
2457  printf("  time_date_stamp                 = 0x%x\n",
2458         module_.time_date_stamp);
2459  printf("  module_name_rva                 = 0x%x\n",
2460         module_.module_name_rva);
2461  printf("  version_info.signature          = 0x%x\n",
2462         module_.version_info.signature);
2463  printf("  version_info.struct_version     = 0x%x\n",
2464         module_.version_info.struct_version);
2465  printf("  version_info.file_version       = 0x%x:0x%x\n",
2466         module_.version_info.file_version_hi,
2467         module_.version_info.file_version_lo);
2468  printf("  version_info.product_version    = 0x%x:0x%x\n",
2469         module_.version_info.product_version_hi,
2470         module_.version_info.product_version_lo);
2471  printf("  version_info.file_flags_mask    = 0x%x\n",
2472         module_.version_info.file_flags_mask);
2473  printf("  version_info.file_flags         = 0x%x\n",
2474         module_.version_info.file_flags);
2475  printf("  version_info.file_os            = 0x%x\n",
2476         module_.version_info.file_os);
2477  printf("  version_info.file_type          = 0x%x\n",
2478         module_.version_info.file_type);
2479  printf("  version_info.file_subtype       = 0x%x\n",
2480         module_.version_info.file_subtype);
2481  printf("  version_info.file_date          = 0x%x:0x%x\n",
2482         module_.version_info.file_date_hi,
2483         module_.version_info.file_date_lo);
2484  printf("  cv_record.data_size             = %d\n",
2485         module_.cv_record.data_size);
2486  printf("  cv_record.rva                   = 0x%x\n",
2487         module_.cv_record.rva);
2488  printf("  misc_record.data_size           = %d\n",
2489         module_.misc_record.data_size);
2490  printf("  misc_record.rva                 = 0x%x\n",
2491         module_.misc_record.rva);
2492
2493  printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
2494  printf("  (code_identifier)               = \"%s\"\n",
2495         code_identifier().c_str());
2496
2497  uint32_t cv_record_size;
2498  const uint8_t *cv_record = GetCVRecord(&cv_record_size);
2499  if (cv_record) {
2500    if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2501      const MDCVInfoPDB70* cv_record_70 =
2502          reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
2503      assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2504
2505      printf("  (cv_record).cv_signature        = 0x%x\n",
2506             cv_record_70->cv_signature);
2507      printf("  (cv_record).signature           = %08x-%04x-%04x-%02x%02x-",
2508             cv_record_70->signature.data1,
2509             cv_record_70->signature.data2,
2510             cv_record_70->signature.data3,
2511             cv_record_70->signature.data4[0],
2512             cv_record_70->signature.data4[1]);
2513      for (unsigned int guidIndex = 2;
2514           guidIndex < 8;
2515           ++guidIndex) {
2516        printf("%02x", cv_record_70->signature.data4[guidIndex]);
2517      }
2518      printf("\n");
2519      printf("  (cv_record).age                 = %d\n",
2520             cv_record_70->age);
2521      printf("  (cv_record).pdb_file_name       = \"%s\"\n",
2522             cv_record_70->pdb_file_name);
2523    } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2524      const MDCVInfoPDB20* cv_record_20 =
2525          reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
2526      assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2527
2528      printf("  (cv_record).cv_header.signature = 0x%x\n",
2529             cv_record_20->cv_header.signature);
2530      printf("  (cv_record).cv_header.offset    = 0x%x\n",
2531             cv_record_20->cv_header.offset);
2532      printf("  (cv_record).signature           = 0x%x\n",
2533             cv_record_20->signature);
2534      printf("  (cv_record).age                 = %d\n",
2535             cv_record_20->age);
2536      printf("  (cv_record).pdb_file_name       = \"%s\"\n",
2537             cv_record_20->pdb_file_name);
2538    } else {
2539      printf("  (cv_record)                     = ");
2540      for (unsigned int cv_byte_index = 0;
2541           cv_byte_index < cv_record_size;
2542           ++cv_byte_index) {
2543        printf("%02x", cv_record[cv_byte_index]);
2544      }
2545      printf("\n");
2546    }
2547  } else {
2548    printf("  (cv_record)                     = (null)\n");
2549  }
2550
2551  const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
2552  if (misc_record) {
2553    printf("  (misc_record).data_type         = 0x%x\n",
2554           misc_record->data_type);
2555    printf("  (misc_record).length            = 0x%x\n",
2556           misc_record->length);
2557    printf("  (misc_record).unicode           = %d\n",
2558           misc_record->unicode);
2559    // Don't bother printing the UTF-16, we don't really even expect to ever
2560    // see this misc_record anyway.
2561    if (misc_record->unicode)
2562      printf("  (misc_record).data              = \"%s\"\n",
2563             misc_record->data);
2564    else
2565      printf("  (misc_record).data              = (UTF-16)\n");
2566  } else {
2567    printf("  (misc_record)                   = (null)\n");
2568  }
2569
2570  printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
2571  printf("  (debug_identifier)              = \"%s\"\n",
2572         debug_identifier().c_str());
2573  printf("  (version)                       = \"%s\"\n", version().c_str());
2574  printf("\n");
2575}
2576
2577
2578//
2579// MinidumpModuleList
2580//
2581
2582
2583uint32_t MinidumpModuleList::max_modules_ = 1024;
2584
2585
2586MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
2587    : MinidumpStream(minidump),
2588      range_map_(new RangeMap<uint64_t, unsigned int>()),
2589      modules_(NULL),
2590      module_count_(0) {
2591}
2592
2593
2594MinidumpModuleList::~MinidumpModuleList() {
2595  delete range_map_;
2596  delete modules_;
2597}
2598
2599
2600bool MinidumpModuleList::Read(uint32_t expected_size) {
2601  // Invalidate cached data.
2602  range_map_->Clear();
2603  delete modules_;
2604  modules_ = NULL;
2605  module_count_ = 0;
2606
2607  valid_ = false;
2608
2609  uint32_t module_count;
2610  if (expected_size < sizeof(module_count)) {
2611    BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
2612                    expected_size << " < " << sizeof(module_count);
2613    return false;
2614  }
2615  if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
2616    BPLOG(ERROR) << "MinidumpModuleList could not read module count";
2617    return false;
2618  }
2619
2620  if (minidump_->swap())
2621    Swap(&module_count);
2622
2623  if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
2624    BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
2625                    " would cause multiplication overflow";
2626    return false;
2627  }
2628
2629  if (expected_size != sizeof(module_count) +
2630                       module_count * MD_MODULE_SIZE) {
2631    // may be padded with 4 bytes on 64bit ABIs for alignment
2632    if (expected_size == sizeof(module_count) + 4 +
2633                         module_count * MD_MODULE_SIZE) {
2634      uint32_t useless;
2635      if (!minidump_->ReadBytes(&useless, 4)) {
2636        BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded "
2637                        "bytes";
2638        return false;
2639      }
2640    } else {
2641      BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
2642                      " != " << sizeof(module_count) +
2643                      module_count * MD_MODULE_SIZE;
2644      return false;
2645    }
2646  }
2647
2648  if (module_count > max_modules_) {
2649    BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
2650                    " exceeds maximum " << max_modules_;
2651    return false;
2652  }
2653
2654  if (module_count != 0) {
2655    scoped_ptr<MinidumpModules> modules(
2656        new MinidumpModules(module_count, MinidumpModule(minidump_)));
2657
2658    for (unsigned int module_index = 0;
2659         module_index < module_count;
2660         ++module_index) {
2661      MinidumpModule* module = &(*modules)[module_index];
2662
2663      // Assume that the file offset is correct after the last read.
2664      if (!module->Read()) {
2665        BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
2666                        module_index << "/" << module_count;
2667        return false;
2668      }
2669    }
2670
2671    // Loop through the module list once more to read additional data and
2672    // build the range map.  This is done in a second pass because
2673    // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
2674    // included in the loop above, additional seeks would be needed where
2675    // none are now to read contiguous data.
2676    for (unsigned int module_index = 0;
2677         module_index < module_count;
2678         ++module_index) {
2679      MinidumpModule* module = &(*modules)[module_index];
2680
2681      // ReadAuxiliaryData fails if any data that the module indicates should
2682      // exist is missing, but we treat some such cases as valid anyway.  See
2683      // issue #222: if a debugging record is of a format that's too large to
2684      // handle, it shouldn't render the entire dump invalid.  Check module
2685      // validity before giving up.
2686      if (!module->ReadAuxiliaryData() && !module->valid()) {
2687        BPLOG(ERROR) << "MinidumpModuleList could not read required module "
2688                        "auxiliary data for module " <<
2689                        module_index << "/" << module_count;
2690        return false;
2691      }
2692
2693      // It is safe to use module->code_file() after successfully calling
2694      // module->ReadAuxiliaryData or noting that the module is valid.
2695
2696      uint64_t base_address = module->base_address();
2697      uint64_t module_size = module->size();
2698      if (base_address == static_cast<uint64_t>(-1)) {
2699        BPLOG(ERROR) << "MinidumpModuleList found bad base address "
2700                        "for module " << module_index << "/" << module_count <<
2701                        ", " << module->code_file();
2702        return false;
2703      }
2704
2705      if (!range_map_->StoreRange(base_address, module_size, module_index)) {
2706        BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
2707                        module_index << "/" << module_count << ", " <<
2708                        module->code_file() << ", " <<
2709                        HexString(base_address) << "+" <<
2710                        HexString(module_size);
2711        return false;
2712      }
2713    }
2714
2715    modules_ = modules.release();
2716  }
2717
2718  module_count_ = module_count;
2719
2720  valid_ = true;
2721  return true;
2722}
2723
2724
2725const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
2726    uint64_t address) const {
2727  if (!valid_) {
2728    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
2729    return NULL;
2730  }
2731
2732  unsigned int module_index;
2733  if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) {
2734    BPLOG(INFO) << "MinidumpModuleList has no module at " <<
2735                   HexString(address);
2736    return NULL;
2737  }
2738
2739  return GetModuleAtIndex(module_index);
2740}
2741
2742
2743const MinidumpModule* MinidumpModuleList::GetMainModule() const {
2744  if (!valid_) {
2745    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
2746    return NULL;
2747  }
2748
2749  // The main code module is the first one present in a minidump file's
2750  // MDRawModuleList.
2751  return GetModuleAtIndex(0);
2752}
2753
2754
2755const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
2756    unsigned int sequence) const {
2757  if (!valid_) {
2758    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
2759    return NULL;
2760  }
2761
2762  if (sequence >= module_count_) {
2763    BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
2764                    sequence << "/" << module_count_;
2765    return NULL;
2766  }
2767
2768  unsigned int module_index;
2769  if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) {
2770    BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
2771    return NULL;
2772  }
2773
2774  return GetModuleAtIndex(module_index);
2775}
2776
2777
2778const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
2779    unsigned int index) const {
2780  if (!valid_) {
2781    BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
2782    return NULL;
2783  }
2784
2785  if (index >= module_count_) {
2786    BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
2787                    index << "/" << module_count_;
2788    return NULL;
2789  }
2790
2791  return &(*modules_)[index];
2792}
2793
2794
2795const CodeModules* MinidumpModuleList::Copy() const {
2796  return new BasicCodeModules(this);
2797}
2798
2799
2800void MinidumpModuleList::Print() {
2801  if (!valid_) {
2802    BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
2803    return;
2804  }
2805
2806  printf("MinidumpModuleList\n");
2807  printf("  module_count = %d\n", module_count_);
2808  printf("\n");
2809
2810  for (unsigned int module_index = 0;
2811       module_index < module_count_;
2812       ++module_index) {
2813    printf("module[%d]\n", module_index);
2814
2815    (*modules_)[module_index].Print();
2816  }
2817}
2818
2819
2820//
2821// MinidumpMemoryList
2822//
2823
2824
2825uint32_t MinidumpMemoryList::max_regions_ = 4096;
2826
2827
2828MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
2829    : MinidumpStream(minidump),
2830      range_map_(new RangeMap<uint64_t, unsigned int>()),
2831      descriptors_(NULL),
2832      regions_(NULL),
2833      region_count_(0) {
2834}
2835
2836
2837MinidumpMemoryList::~MinidumpMemoryList() {
2838  delete range_map_;
2839  delete descriptors_;
2840  delete regions_;
2841}
2842
2843
2844bool MinidumpMemoryList::Read(uint32_t expected_size) {
2845  // Invalidate cached data.
2846  delete descriptors_;
2847  descriptors_ = NULL;
2848  delete regions_;
2849  regions_ = NULL;
2850  range_map_->Clear();
2851  region_count_ = 0;
2852
2853  valid_ = false;
2854
2855  uint32_t region_count;
2856  if (expected_size < sizeof(region_count)) {
2857    BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
2858                    expected_size << " < " << sizeof(region_count);
2859    return false;
2860  }
2861  if (!minidump_->ReadBytes(&region_count, sizeof(region_count))) {
2862    BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
2863    return false;
2864  }
2865
2866  if (minidump_->swap())
2867    Swap(&region_count);
2868
2869  if (region_count >
2870          numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
2871    BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
2872                    " would cause multiplication overflow";
2873    return false;
2874  }
2875
2876  if (expected_size != sizeof(region_count) +
2877                       region_count * sizeof(MDMemoryDescriptor)) {
2878    // may be padded with 4 bytes on 64bit ABIs for alignment
2879    if (expected_size == sizeof(region_count) + 4 +
2880                         region_count * sizeof(MDMemoryDescriptor)) {
2881      uint32_t useless;
2882      if (!minidump_->ReadBytes(&useless, 4)) {
2883        BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded "
2884                        "bytes";
2885        return false;
2886      }
2887    } else {
2888      BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
2889                      " != " << sizeof(region_count) +
2890                      region_count * sizeof(MDMemoryDescriptor);
2891      return false;
2892    }
2893  }
2894
2895  if (region_count > max_regions_) {
2896    BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
2897                    " exceeds maximum " << max_regions_;
2898    return false;
2899  }
2900
2901  if (region_count != 0) {
2902    scoped_ptr<MemoryDescriptors> descriptors(
2903        new MemoryDescriptors(region_count));
2904
2905    // Read the entire array in one fell swoop, instead of reading one entry
2906    // at a time in the loop.
2907    if (!minidump_->ReadBytes(&(*descriptors)[0],
2908                              sizeof(MDMemoryDescriptor) * region_count)) {
2909      BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
2910      return false;
2911    }
2912
2913    scoped_ptr<MemoryRegions> regions(
2914        new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
2915
2916    for (unsigned int region_index = 0;
2917         region_index < region_count;
2918         ++region_index) {
2919      MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
2920
2921      if (minidump_->swap())
2922        Swap(descriptor);
2923
2924      uint64_t base_address = descriptor->start_of_memory_range;
2925      uint32_t region_size = descriptor->memory.data_size;
2926
2927      // Check for base + size overflow or undersize.
2928      if (region_size == 0 ||
2929          region_size > numeric_limits<uint64_t>::max() - base_address) {
2930        BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
2931                        " region " << region_index << "/" << region_count <<
2932                        ", " << HexString(base_address) << "+" <<
2933                        HexString(region_size);
2934        return false;
2935      }
2936
2937      if (!range_map_->StoreRange(base_address, region_size, region_index)) {
2938        BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
2939                        region_index << "/" << region_count << ", " <<
2940                        HexString(base_address) << "+" <<
2941                        HexString(region_size);
2942        return false;
2943      }
2944
2945      (*regions)[region_index].SetDescriptor(descriptor);
2946    }
2947
2948    descriptors_ = descriptors.release();
2949    regions_ = regions.release();
2950  }
2951
2952  region_count_ = region_count;
2953
2954  valid_ = true;
2955  return true;
2956}
2957
2958
2959MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
2960      unsigned int index) {
2961  if (!valid_) {
2962    BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
2963    return NULL;
2964  }
2965
2966  if (index >= region_count_) {
2967    BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
2968                    index << "/" << region_count_;
2969    return NULL;
2970  }
2971
2972  return &(*regions_)[index];
2973}
2974
2975
2976MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
2977    uint64_t address) {
2978  if (!valid_) {
2979    BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
2980    return NULL;
2981  }
2982
2983  unsigned int region_index;
2984  if (!range_map_->RetrieveRange(address, &region_index, NULL, NULL)) {
2985    BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
2986                   HexString(address);
2987    return NULL;
2988  }
2989
2990  return GetMemoryRegionAtIndex(region_index);
2991}
2992
2993
2994void MinidumpMemoryList::Print() {
2995  if (!valid_) {
2996    BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
2997    return;
2998  }
2999
3000  printf("MinidumpMemoryList\n");
3001  printf("  region_count = %d\n", region_count_);
3002  printf("\n");
3003
3004  for (unsigned int region_index = 0;
3005       region_index < region_count_;
3006       ++region_index) {
3007    MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
3008    printf("region[%d]\n", region_index);
3009    printf("MDMemoryDescriptor\n");
3010    printf("  start_of_memory_range = 0x%" PRIx64 "\n",
3011           descriptor->start_of_memory_range);
3012    printf("  memory.data_size      = 0x%x\n", descriptor->memory.data_size);
3013    printf("  memory.rva            = 0x%x\n", descriptor->memory.rva);
3014    MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
3015    if (region) {
3016      printf("Memory\n");
3017      region->Print();
3018    } else {
3019      printf("No memory\n");
3020    }
3021    printf("\n");
3022  }
3023}
3024
3025
3026//
3027// MinidumpException
3028//
3029
3030
3031MinidumpException::MinidumpException(Minidump* minidump)
3032    : MinidumpStream(minidump),
3033      exception_(),
3034      context_(NULL) {
3035}
3036
3037
3038MinidumpException::~MinidumpException() {
3039  delete context_;
3040}
3041
3042
3043bool MinidumpException::Read(uint32_t expected_size) {
3044  // Invalidate cached data.
3045  delete context_;
3046  context_ = NULL;
3047
3048  valid_ = false;
3049
3050  if (expected_size != sizeof(exception_)) {
3051    BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
3052                    " != " << sizeof(exception_);
3053    return false;
3054  }
3055
3056  if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
3057    BPLOG(ERROR) << "MinidumpException cannot read exception";
3058    return false;
3059  }
3060
3061  if (minidump_->swap()) {
3062    Swap(&exception_.thread_id);
3063    // exception_.__align is for alignment only and does not need to be
3064    // swapped.
3065    Swap(&exception_.exception_record.exception_code);
3066    Swap(&exception_.exception_record.exception_flags);
3067    Swap(&exception_.exception_record.exception_record);
3068    Swap(&exception_.exception_record.exception_address);
3069    Swap(&exception_.exception_record.number_parameters);
3070    // exception_.exception_record.__align is for alignment only and does not
3071    // need to be swapped.
3072    for (unsigned int parameter_index = 0;
3073         parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
3074         ++parameter_index) {
3075      Swap(&exception_.exception_record.exception_information[parameter_index]);
3076    }
3077    Swap(&exception_.thread_context);
3078  }
3079
3080  valid_ = true;
3081  return true;
3082}
3083
3084
3085bool MinidumpException::GetThreadID(uint32_t *thread_id) const {
3086  BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
3087                                 "|thread_id|";
3088  assert(thread_id);
3089  *thread_id = 0;
3090
3091  if (!valid_) {
3092    BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
3093    return false;
3094  }
3095
3096  *thread_id = exception_.thread_id;
3097  return true;
3098}
3099
3100
3101MinidumpContext* MinidumpException::GetContext() {
3102  if (!valid_) {
3103    BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
3104    return NULL;
3105  }
3106
3107  if (!context_) {
3108    if (!minidump_->SeekSet(exception_.thread_context.rva)) {
3109      BPLOG(ERROR) << "MinidumpException cannot seek to context";
3110      return NULL;
3111    }
3112
3113    scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
3114
3115    // Don't log as an error if we can still fall back on the thread's context
3116    // (which must be possible if we got this far.)
3117    if (!context->Read(exception_.thread_context.data_size)) {
3118      BPLOG(INFO) << "MinidumpException cannot read context";
3119      return NULL;
3120    }
3121
3122    context_ = context.release();
3123  }
3124
3125  return context_;
3126}
3127
3128
3129void MinidumpException::Print() {
3130  if (!valid_) {
3131    BPLOG(ERROR) << "MinidumpException cannot print invalid data";
3132    return;
3133  }
3134
3135  printf("MDException\n");
3136  printf("  thread_id                                  = 0x%x\n",
3137         exception_.thread_id);
3138  printf("  exception_record.exception_code            = 0x%x\n",
3139         exception_.exception_record.exception_code);
3140  printf("  exception_record.exception_flags           = 0x%x\n",
3141         exception_.exception_record.exception_flags);
3142  printf("  exception_record.exception_record          = 0x%" PRIx64 "\n",
3143         exception_.exception_record.exception_record);
3144  printf("  exception_record.exception_address         = 0x%" PRIx64 "\n",
3145         exception_.exception_record.exception_address);
3146  printf("  exception_record.number_parameters         = %d\n",
3147         exception_.exception_record.number_parameters);
3148  for (unsigned int parameterIndex = 0;
3149       parameterIndex < exception_.exception_record.number_parameters;
3150       ++parameterIndex) {
3151    printf("  exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
3152           parameterIndex,
3153           exception_.exception_record.exception_information[parameterIndex]);
3154  }
3155  printf("  thread_context.data_size                   = %d\n",
3156         exception_.thread_context.data_size);
3157  printf("  thread_context.rva                         = 0x%x\n",
3158         exception_.thread_context.rva);
3159  MinidumpContext* context = GetContext();
3160  if (context) {
3161    printf("\n");
3162    context->Print();
3163  } else {
3164    printf("  (no context)\n");
3165    printf("\n");
3166  }
3167}
3168
3169//
3170// MinidumpAssertion
3171//
3172
3173
3174MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
3175    : MinidumpStream(minidump),
3176      assertion_(),
3177      expression_(),
3178      function_(),
3179      file_() {
3180}
3181
3182
3183MinidumpAssertion::~MinidumpAssertion() {
3184}
3185
3186
3187bool MinidumpAssertion::Read(uint32_t expected_size) {
3188  // Invalidate cached data.
3189  valid_ = false;
3190
3191  if (expected_size != sizeof(assertion_)) {
3192    BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
3193                    " != " << sizeof(assertion_);
3194    return false;
3195  }
3196
3197  if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
3198    BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
3199    return false;
3200  }
3201
3202  // Each of {expression, function, file} is a UTF-16 string,
3203  // we'll convert them to UTF-8 for ease of use.
3204  ConvertUTF16BufferToUTF8String(assertion_.expression,
3205                                 sizeof(assertion_.expression), &expression_,
3206                                 minidump_->swap());
3207  ConvertUTF16BufferToUTF8String(assertion_.function,
3208                                 sizeof(assertion_.function), &function_,
3209                                 minidump_->swap());
3210  ConvertUTF16BufferToUTF8String(assertion_.file, sizeof(assertion_.file),
3211                                 &file_, minidump_->swap());
3212
3213  if (minidump_->swap()) {
3214    Swap(&assertion_.line);
3215    Swap(&assertion_.type);
3216  }
3217
3218  valid_ = true;
3219  return true;
3220}
3221
3222void MinidumpAssertion::Print() {
3223  if (!valid_) {
3224    BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
3225    return;
3226  }
3227
3228  printf("MDAssertion\n");
3229  printf("  expression                                 = %s\n",
3230         expression_.c_str());
3231  printf("  function                                   = %s\n",
3232         function_.c_str());
3233  printf("  file                                       = %s\n",
3234         file_.c_str());
3235  printf("  line                                       = %u\n",
3236         assertion_.line);
3237  printf("  type                                       = %u\n",
3238         assertion_.type);
3239  printf("\n");
3240}
3241
3242//
3243// MinidumpSystemInfo
3244//
3245
3246
3247MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
3248    : MinidumpStream(minidump),
3249      system_info_(),
3250      csd_version_(NULL),
3251      cpu_vendor_(NULL) {
3252}
3253
3254
3255MinidumpSystemInfo::~MinidumpSystemInfo() {
3256  delete csd_version_;
3257  delete cpu_vendor_;
3258}
3259
3260
3261bool MinidumpSystemInfo::Read(uint32_t expected_size) {
3262  // Invalidate cached data.
3263  delete csd_version_;
3264  csd_version_ = NULL;
3265  delete cpu_vendor_;
3266  cpu_vendor_ = NULL;
3267
3268  valid_ = false;
3269
3270  if (expected_size != sizeof(system_info_)) {
3271    BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
3272                    " != " << sizeof(system_info_);
3273    return false;
3274  }
3275
3276  if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
3277    BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
3278    return false;
3279  }
3280
3281  if (minidump_->swap()) {
3282    Swap(&system_info_.processor_architecture);
3283    Swap(&system_info_.processor_level);
3284    Swap(&system_info_.processor_revision);
3285    // number_of_processors and product_type are 8-bit quantities and need no
3286    // swapping.
3287    Swap(&system_info_.major_version);
3288    Swap(&system_info_.minor_version);
3289    Swap(&system_info_.build_number);
3290    Swap(&system_info_.platform_id);
3291    Swap(&system_info_.csd_version_rva);
3292    Swap(&system_info_.suite_mask);
3293    // Don't swap the reserved2 field because its contents are unknown.
3294
3295    if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3296        system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
3297      for (unsigned int i = 0; i < 3; ++i)
3298        Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
3299      Swap(&system_info_.cpu.x86_cpu_info.version_information);
3300      Swap(&system_info_.cpu.x86_cpu_info.feature_information);
3301      Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3302    } else {
3303      for (unsigned int i = 0; i < 2; ++i)
3304        Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
3305    }
3306  }
3307
3308  valid_ = true;
3309  return true;
3310}
3311
3312
3313string MinidumpSystemInfo::GetOS() {
3314  string os;
3315
3316  if (!valid_) {
3317    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
3318    return os;
3319  }
3320
3321  switch (system_info_.platform_id) {
3322    case MD_OS_WIN32_NT:
3323    case MD_OS_WIN32_WINDOWS:
3324      os = "windows";
3325      break;
3326
3327    case MD_OS_MAC_OS_X:
3328      os = "mac";
3329      break;
3330
3331    case MD_OS_IOS:
3332      os = "ios";
3333      break;
3334
3335    case MD_OS_LINUX:
3336      os = "linux";
3337      break;
3338
3339    case MD_OS_SOLARIS:
3340      os = "solaris";
3341      break;
3342
3343    case MD_OS_ANDROID:
3344      os = "android";
3345      break;
3346
3347    case MD_OS_PS3:
3348      os = "ps3";
3349      break;
3350
3351    case MD_OS_NACL:
3352      os = "nacl";
3353      break;
3354
3355    default:
3356      BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
3357                      HexString(system_info_.platform_id);
3358      break;
3359  }
3360
3361  return os;
3362}
3363
3364
3365string MinidumpSystemInfo::GetCPU() {
3366  if (!valid_) {
3367    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
3368    return "";
3369  }
3370
3371  string cpu;
3372
3373  switch (system_info_.processor_architecture) {
3374    case MD_CPU_ARCHITECTURE_X86:
3375    case MD_CPU_ARCHITECTURE_X86_WIN64:
3376      cpu = "x86";
3377      break;
3378
3379    case MD_CPU_ARCHITECTURE_AMD64:
3380      cpu = "x86-64";
3381      break;
3382
3383    case MD_CPU_ARCHITECTURE_PPC:
3384      cpu = "ppc";
3385      break;
3386
3387    case MD_CPU_ARCHITECTURE_PPC64:
3388      cpu = "ppc64";
3389      break;
3390
3391    case MD_CPU_ARCHITECTURE_SPARC:
3392      cpu = "sparc";
3393      break;
3394
3395    case MD_CPU_ARCHITECTURE_ARM:
3396      cpu = "arm";
3397      break;
3398
3399    default:
3400      BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
3401                      HexString(system_info_.processor_architecture);
3402      break;
3403  }
3404
3405  return cpu;
3406}
3407
3408
3409const string* MinidumpSystemInfo::GetCSDVersion() {
3410  if (!valid_) {
3411    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
3412    return NULL;
3413  }
3414
3415  if (!csd_version_)
3416    csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
3417
3418  BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
3419                                    "CSD version";
3420
3421  return csd_version_;
3422}
3423
3424
3425const string* MinidumpSystemInfo::GetCPUVendor() {
3426  if (!valid_) {
3427    BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
3428    return NULL;
3429  }
3430
3431  // CPU vendor information can only be determined from x86 minidumps.
3432  if (!cpu_vendor_ &&
3433      (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3434       system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
3435    char cpu_vendor_string[13];
3436    snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
3437             "%c%c%c%c%c%c%c%c%c%c%c%c",
3438              system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
3439             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
3440             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
3441             (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
3442              system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
3443             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
3444             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
3445             (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
3446              system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
3447             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
3448             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
3449             (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
3450    cpu_vendor_ = new string(cpu_vendor_string);
3451  }
3452
3453  return cpu_vendor_;
3454}
3455
3456
3457void MinidumpSystemInfo::Print() {
3458  if (!valid_) {
3459    BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
3460    return;
3461  }
3462
3463  printf("MDRawSystemInfo\n");
3464  printf("  processor_architecture                     = %d\n",
3465         system_info_.processor_architecture);
3466  printf("  processor_level                            = %d\n",
3467         system_info_.processor_level);
3468  printf("  processor_revision                         = 0x%x\n",
3469         system_info_.processor_revision);
3470  printf("  number_of_processors                       = %d\n",
3471         system_info_.number_of_processors);
3472  printf("  product_type                               = %d\n",
3473         system_info_.product_type);
3474  printf("  major_version                              = %d\n",
3475         system_info_.major_version);
3476  printf("  minor_version                              = %d\n",
3477         system_info_.minor_version);
3478  printf("  build_number                               = %d\n",
3479         system_info_.build_number);
3480  printf("  platform_id                                = %d\n",
3481         system_info_.platform_id);
3482  printf("  csd_version_rva                            = 0x%x\n",
3483         system_info_.csd_version_rva);
3484  printf("  suite_mask                                 = 0x%x\n",
3485         system_info_.suite_mask);
3486  for (unsigned int i = 0; i < 3; ++i) {
3487    printf("  cpu.x86_cpu_info.vendor_id[%d]              = 0x%x\n",
3488           i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
3489  }
3490  printf("  cpu.x86_cpu_info.version_information       = 0x%x\n",
3491         system_info_.cpu.x86_cpu_info.version_information);
3492  printf("  cpu.x86_cpu_info.feature_information       = 0x%x\n",
3493         system_info_.cpu.x86_cpu_info.feature_information);
3494  printf("  cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
3495         system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3496  const string* csd_version = GetCSDVersion();
3497  if (csd_version) {
3498    printf("  (csd_version)                              = \"%s\"\n",
3499           csd_version->c_str());
3500  } else {
3501    printf("  (csd_version)                              = (null)\n");
3502  }
3503  const string* cpu_vendor = GetCPUVendor();
3504  if (cpu_vendor) {
3505    printf("  (cpu_vendor)                               = \"%s\"\n",
3506           cpu_vendor->c_str());
3507  } else {
3508    printf("  (cpu_vendor)                               = (null)\n");
3509  }
3510  printf("\n");
3511}
3512
3513
3514//
3515// MinidumpMiscInfo
3516//
3517
3518
3519MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
3520    : MinidumpStream(minidump),
3521      misc_info_() {
3522}
3523
3524
3525bool MinidumpMiscInfo::Read(uint32_t expected_size) {
3526  valid_ = false;
3527
3528  if (expected_size != MD_MISCINFO_SIZE &&
3529      expected_size != MD_MISCINFO2_SIZE &&
3530      expected_size != MD_MISCINFO3_SIZE &&
3531      expected_size != MD_MISCINFO4_SIZE) {
3532    BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size
3533                 << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE
3534                 << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE
3535                 << ")";
3536    return false;
3537  }
3538
3539  if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
3540    BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
3541    return false;
3542  }
3543
3544  if (minidump_->swap()) {
3545    // Swap version 1 fields
3546    Swap(&misc_info_.size_of_info);
3547    Swap(&misc_info_.flags1);
3548    Swap(&misc_info_.process_id);
3549    Swap(&misc_info_.process_create_time);
3550    Swap(&misc_info_.process_user_time);
3551    Swap(&misc_info_.process_kernel_time);
3552    if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3553      // Swap version 2 fields
3554      Swap(&misc_info_.processor_max_mhz);
3555      Swap(&misc_info_.processor_current_mhz);
3556      Swap(&misc_info_.processor_mhz_limit);
3557      Swap(&misc_info_.processor_max_idle_state);
3558      Swap(&misc_info_.processor_current_idle_state);
3559    }
3560    if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
3561      // Swap version 3 fields
3562      Swap(&misc_info_.process_integrity_level);
3563      Swap(&misc_info_.process_execute_flags);
3564      Swap(&misc_info_.protected_process);
3565      Swap(&misc_info_.time_zone_id);
3566      Swap(&misc_info_.time_zone);
3567    }
3568    if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
3569      // Swap version 4 fields.
3570      // Do not swap UTF-16 strings.  The swap is done as part of the
3571      // conversion to UTF-8 (code follows below).
3572    }
3573  }
3574
3575  if (expected_size != misc_info_.size_of_info) {
3576    BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
3577                    expected_size << " != " << misc_info_.size_of_info;
3578    return false;
3579  }
3580
3581  // Convert UTF-16 strings
3582  if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
3583    // Convert UTF-16 strings in version 3 fields
3584    ConvertUTF16BufferToUTF8String(misc_info_.time_zone.standard_name,
3585                                   sizeof(misc_info_.time_zone.standard_name),
3586                                   &standard_name_, minidump_->swap());
3587    ConvertUTF16BufferToUTF8String(misc_info_.time_zone.daylight_name,
3588                                   sizeof(misc_info_.time_zone.daylight_name),
3589                                   &daylight_name_, minidump_->swap());
3590  }
3591  if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
3592    // Convert UTF-16 strings in version 4 fields
3593    ConvertUTF16BufferToUTF8String(misc_info_.build_string,
3594                                   sizeof(misc_info_.build_string),
3595                                   &build_string_, minidump_->swap());
3596    ConvertUTF16BufferToUTF8String(misc_info_.dbg_bld_str,
3597                                   sizeof(misc_info_.dbg_bld_str),
3598                                   &dbg_bld_str_, minidump_->swap());
3599  }
3600
3601  valid_ = true;
3602  return true;
3603}
3604
3605
3606void MinidumpMiscInfo::Print() {
3607  if (!valid_) {
3608    BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
3609    return;
3610  }
3611
3612  printf("MDRawMiscInfo\n");
3613  // Print version 1 fields
3614  printf("  size_of_info                 = %d\n",   misc_info_.size_of_info);
3615  printf("  flags1                       = 0x%x\n", misc_info_.flags1);
3616  printf("  process_id                   = 0x%x\n", misc_info_.process_id);
3617  printf("  process_create_time          = 0x%x\n",
3618         misc_info_.process_create_time);
3619  printf("  process_user_time            = 0x%x\n",
3620         misc_info_.process_user_time);
3621  printf("  process_kernel_time          = 0x%x\n",
3622         misc_info_.process_kernel_time);
3623  if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3624    // Print version 2 fields
3625    printf("  processor_max_mhz            = %d\n",
3626           misc_info_.processor_max_mhz);
3627    printf("  processor_current_mhz        = %d\n",
3628           misc_info_.processor_current_mhz);
3629    printf("  processor_mhz_limit          = %d\n",
3630           misc_info_.processor_mhz_limit);
3631    printf("  processor_max_idle_state     = 0x%x\n",
3632           misc_info_.processor_max_idle_state);
3633    printf("  processor_current_idle_state = 0x%x\n",
3634           misc_info_.processor_current_idle_state);
3635  }
3636  if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
3637    // Print version 3 fields
3638    printf("  process_integrity_level      = 0x%x\n",
3639           misc_info_.process_integrity_level);
3640    printf("  process_execute_flags        = 0x%x\n",
3641           misc_info_.process_execute_flags);
3642    printf("  protected_process            = %d\n",
3643           misc_info_.protected_process);
3644    printf("  time_zone_id                 = %d\n", misc_info_.time_zone_id);
3645    printf("  time_zone.bias               = %d\n", misc_info_.time_zone.bias);
3646    printf("  time_zone.standard_name      = %s\n", standard_name_.c_str());
3647    printf("  time_zone.daylight_name      = %s\n", daylight_name_.c_str());
3648  }
3649  if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
3650    // Print version 4 fields
3651    printf("  build_string                 = %s\n", build_string_.c_str());
3652    printf("  dbg_bld_str                  = %s\n", dbg_bld_str_.c_str());
3653  }
3654  printf("\n");
3655}
3656
3657
3658//
3659// MinidumpBreakpadInfo
3660//
3661
3662
3663MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
3664    : MinidumpStream(minidump),
3665      breakpad_info_() {
3666}
3667
3668
3669bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
3670  valid_ = false;
3671
3672  if (expected_size != sizeof(breakpad_info_)) {
3673    BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
3674                    " != " << sizeof(breakpad_info_);
3675    return false;
3676  }
3677
3678  if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
3679    BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
3680    return false;
3681  }
3682
3683  if (minidump_->swap()) {
3684    Swap(&breakpad_info_.validity);
3685    Swap(&breakpad_info_.dump_thread_id);
3686    Swap(&breakpad_info_.requesting_thread_id);
3687  }
3688
3689  valid_ = true;
3690  return true;
3691}
3692
3693
3694bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
3695  BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
3696                                 "requires |thread_id|";
3697  assert(thread_id);
3698  *thread_id = 0;
3699
3700  if (!valid_) {
3701    BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
3702    return false;
3703  }
3704
3705  if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
3706    BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
3707    return false;
3708  }
3709
3710  *thread_id = breakpad_info_.dump_thread_id;
3711  return true;
3712}
3713
3714
3715bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id)
3716    const {
3717  BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
3718                                 "requires |thread_id|";
3719  assert(thread_id);
3720  *thread_id = 0;
3721
3722  if (!thread_id || !valid_) {
3723    BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
3724    return false;
3725  }
3726
3727  if (!(breakpad_info_.validity &
3728            MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
3729    BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
3730    return false;
3731  }
3732
3733  *thread_id = breakpad_info_.requesting_thread_id;
3734  return true;
3735}
3736
3737
3738void MinidumpBreakpadInfo::Print() {
3739  if (!valid_) {
3740    BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
3741    return;
3742  }
3743
3744  printf("MDRawBreakpadInfo\n");
3745  printf("  validity             = 0x%x\n", breakpad_info_.validity);
3746
3747  if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3748    printf("  dump_thread_id       = 0x%x\n", breakpad_info_.dump_thread_id);
3749  } else {
3750    printf("  dump_thread_id       = (invalid)\n");
3751  }
3752
3753  if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3754    printf("  requesting_thread_id = 0x%x\n",
3755           breakpad_info_.requesting_thread_id);
3756  } else {
3757    printf("  requesting_thread_id = (invalid)\n");
3758  }
3759
3760  printf("\n");
3761}
3762
3763
3764//
3765// MinidumpMemoryInfo
3766//
3767
3768
3769MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
3770    : MinidumpObject(minidump),
3771      memory_info_() {
3772}
3773
3774
3775bool MinidumpMemoryInfo::IsExecutable() const {
3776  uint32_t protection =
3777      memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
3778  return protection == MD_MEMORY_PROTECT_EXECUTE ||
3779      protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
3780      protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
3781}
3782
3783
3784bool MinidumpMemoryInfo::IsWritable() const {
3785  uint32_t protection =
3786      memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
3787  return protection == MD_MEMORY_PROTECT_READWRITE ||
3788    protection == MD_MEMORY_PROTECT_WRITECOPY ||
3789    protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
3790    protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
3791}
3792
3793
3794bool MinidumpMemoryInfo::Read() {
3795  valid_ = false;
3796
3797  if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
3798    BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
3799    return false;
3800  }
3801
3802  if (minidump_->swap()) {
3803    Swap(&memory_info_.base_address);
3804    Swap(&memory_info_.allocation_base);
3805    Swap(&memory_info_.allocation_protection);
3806    Swap(&memory_info_.region_size);
3807    Swap(&memory_info_.state);
3808    Swap(&memory_info_.protection);
3809    Swap(&memory_info_.type);
3810  }
3811
3812  // Check for base + size overflow or undersize.
3813  if (memory_info_.region_size == 0 ||
3814      memory_info_.region_size > numeric_limits<uint64_t>::max() -
3815                                     memory_info_.base_address) {
3816    BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
3817                    HexString(memory_info_.base_address) << "+" <<
3818                    HexString(memory_info_.region_size);
3819    return false;
3820  }
3821
3822  valid_ = true;
3823  return true;
3824}
3825
3826
3827void MinidumpMemoryInfo::Print() {
3828  if (!valid_) {
3829    BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
3830    return;
3831  }
3832
3833  printf("MDRawMemoryInfo\n");
3834  printf("  base_address          = 0x%" PRIx64 "\n",
3835         memory_info_.base_address);
3836  printf("  allocation_base       = 0x%" PRIx64 "\n",
3837         memory_info_.allocation_base);
3838  printf("  allocation_protection = 0x%x\n",
3839         memory_info_.allocation_protection);
3840  printf("  region_size           = 0x%" PRIx64 "\n", memory_info_.region_size);
3841  printf("  state                 = 0x%x\n", memory_info_.state);
3842  printf("  protection            = 0x%x\n", memory_info_.protection);
3843  printf("  type                  = 0x%x\n", memory_info_.type);
3844}
3845
3846
3847//
3848// MinidumpMemoryInfoList
3849//
3850
3851
3852MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
3853    : MinidumpStream(minidump),
3854      range_map_(new RangeMap<uint64_t, unsigned int>()),
3855      infos_(NULL),
3856      info_count_(0) {
3857}
3858
3859
3860MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
3861  delete range_map_;
3862  delete infos_;
3863}
3864
3865
3866bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
3867  // Invalidate cached data.
3868  delete infos_;
3869  infos_ = NULL;
3870  range_map_->Clear();
3871  info_count_ = 0;
3872
3873  valid_ = false;
3874
3875  MDRawMemoryInfoList header;
3876  if (expected_size < sizeof(MDRawMemoryInfoList)) {
3877    BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
3878                    expected_size << " < " << sizeof(MDRawMemoryInfoList);
3879    return false;
3880  }
3881  if (!minidump_->ReadBytes(&header, sizeof(header))) {
3882    BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
3883    return false;
3884  }
3885
3886  if (minidump_->swap()) {
3887    Swap(&header.size_of_header);
3888    Swap(&header.size_of_entry);
3889    Swap(&header.number_of_entries);
3890  }
3891
3892  // Sanity check that the header is the expected size.
3893  // TODO(ted): could possibly handle this more gracefully, assuming
3894  // that future versions of the structs would be backwards-compatible.
3895  if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
3896    BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
3897                    header.size_of_header << " != " <<
3898                    sizeof(MDRawMemoryInfoList);
3899    return false;
3900  }
3901
3902  // Sanity check that the entries are the expected size.
3903  if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
3904    BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
3905                    header.size_of_entry << " != " <<
3906                    sizeof(MDRawMemoryInfo);
3907    return false;
3908  }
3909
3910  if (header.number_of_entries >
3911          numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
3912    BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
3913                    header.number_of_entries <<
3914                    " would cause multiplication overflow";
3915    return false;
3916  }
3917
3918  if (expected_size != sizeof(MDRawMemoryInfoList) +
3919                        header.number_of_entries * sizeof(MDRawMemoryInfo)) {
3920    BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
3921                    " != " << sizeof(MDRawMemoryInfoList) +
3922                        header.number_of_entries * sizeof(MDRawMemoryInfo);
3923    return false;
3924  }
3925
3926  // Check for data loss when converting header.number_of_entries from
3927  // uint64_t into MinidumpMemoryInfos::size_type (uint32_t)
3928  MinidumpMemoryInfos::size_type header_number_of_entries =
3929      static_cast<unsigned int>(header.number_of_entries);
3930  if (static_cast<uint64_t>(header_number_of_entries) !=
3931      header.number_of_entries) {
3932    BPLOG(ERROR) << "Data loss detected when converting "
3933                    "the header's number_of_entries";
3934    return false;
3935  }
3936
3937  if (header.number_of_entries != 0) {
3938    scoped_ptr<MinidumpMemoryInfos> infos(
3939        new MinidumpMemoryInfos(header_number_of_entries,
3940                                MinidumpMemoryInfo(minidump_)));
3941
3942    for (unsigned int index = 0;
3943         index < header.number_of_entries;
3944         ++index) {
3945      MinidumpMemoryInfo* info = &(*infos)[index];
3946
3947      // Assume that the file offset is correct after the last read.
3948      if (!info->Read()) {
3949        BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
3950                        index << "/" << header.number_of_entries;
3951        return false;
3952      }
3953
3954      uint64_t base_address = info->GetBase();
3955      uint64_t region_size = info->GetSize();
3956
3957      if (!range_map_->StoreRange(base_address, region_size, index)) {
3958        BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
3959                        " memory region " <<
3960                        index << "/" << header.number_of_entries << ", " <<
3961                        HexString(base_address) << "+" <<
3962                        HexString(region_size);
3963        return false;
3964      }
3965    }
3966
3967    infos_ = infos.release();
3968  }
3969
3970  info_count_ = header_number_of_entries;
3971
3972  valid_ = true;
3973  return true;
3974}
3975
3976
3977const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
3978      unsigned int index) const {
3979  if (!valid_) {
3980    BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
3981    return NULL;
3982  }
3983
3984  if (index >= info_count_) {
3985    BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
3986                    index << "/" << info_count_;
3987    return NULL;
3988  }
3989
3990  return &(*infos_)[index];
3991}
3992
3993
3994const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
3995    uint64_t address) const {
3996  if (!valid_) {
3997    BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
3998                    " GetMemoryInfoForAddress";
3999    return NULL;
4000  }
4001
4002  unsigned int info_index;
4003  if (!range_map_->RetrieveRange(address, &info_index, NULL, NULL)) {
4004    BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
4005                   HexString(address);
4006    return NULL;
4007  }
4008
4009  return GetMemoryInfoAtIndex(info_index);
4010}
4011
4012
4013void MinidumpMemoryInfoList::Print() {
4014  if (!valid_) {
4015    BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
4016    return;
4017  }
4018
4019  printf("MinidumpMemoryInfoList\n");
4020  printf("  info_count = %d\n", info_count_);
4021  printf("\n");
4022
4023  for (unsigned int info_index = 0;
4024       info_index < info_count_;
4025       ++info_index) {
4026    printf("info[%d]\n", info_index);
4027    (*infos_)[info_index].Print();
4028    printf("\n");
4029  }
4030}
4031
4032
4033//
4034// Minidump
4035//
4036
4037
4038uint32_t Minidump::max_streams_ = 128;
4039unsigned int Minidump::max_string_length_ = 1024;
4040
4041
4042Minidump::Minidump(const string& path)
4043    : header_(),
4044      directory_(NULL),
4045      stream_map_(new MinidumpStreamMap()),
4046      path_(path),
4047      stream_(NULL),
4048      swap_(false),
4049      valid_(false) {
4050}
4051
4052Minidump::Minidump(istream& stream)
4053    : header_(),
4054      directory_(NULL),
4055      stream_map_(new MinidumpStreamMap()),
4056      path_(),
4057      stream_(&stream),
4058      swap_(false),
4059      valid_(false) {
4060}
4061
4062Minidump::~Minidump() {
4063  if (stream_) {
4064    BPLOG(INFO) << "Minidump closing minidump";
4065  }
4066  if (!path_.empty()) {
4067    delete stream_;
4068  }
4069  delete directory_;
4070  delete stream_map_;
4071}
4072
4073
4074bool Minidump::Open() {
4075  if (stream_ != NULL) {
4076    BPLOG(INFO) << "Minidump reopening minidump " << path_;
4077
4078    // The file is already open.  Seek to the beginning, which is the position
4079    // the file would be at if it were opened anew.
4080    return SeekSet(0);
4081  }
4082
4083  stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
4084  if (!stream_ || !stream_->good()) {
4085    string error_string;
4086    int error_code = ErrnoString(&error_string);
4087    BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
4088                    ", error " << error_code << ": " << error_string;
4089    return false;
4090  }
4091
4092  BPLOG(INFO) << "Minidump opened minidump " << path_;
4093  return true;
4094}
4095
4096bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
4097  // Initialize output parameters
4098  *context_cpu_flags = 0;
4099
4100  // Save the current stream position
4101  off_t saved_position = Tell();
4102  if (saved_position == -1) {
4103    // Failed to save the current stream position.
4104    // Returns true because the current position of the stream is preserved.
4105    return true;
4106  }
4107
4108  const MDRawSystemInfo* system_info =
4109    GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
4110
4111  if (system_info != NULL) {
4112    switch (system_info->processor_architecture) {
4113      case MD_CPU_ARCHITECTURE_X86:
4114        *context_cpu_flags = MD_CONTEXT_X86;
4115        break;
4116      case MD_CPU_ARCHITECTURE_MIPS:
4117        *context_cpu_flags = MD_CONTEXT_MIPS;
4118        break;
4119      case MD_CPU_ARCHITECTURE_ALPHA:
4120        *context_cpu_flags = MD_CONTEXT_ALPHA;
4121        break;
4122      case MD_CPU_ARCHITECTURE_PPC:
4123        *context_cpu_flags = MD_CONTEXT_PPC;
4124        break;
4125      case MD_CPU_ARCHITECTURE_PPC64:
4126        *context_cpu_flags = MD_CONTEXT_PPC64;
4127        break;
4128      case MD_CPU_ARCHITECTURE_SHX:
4129        *context_cpu_flags = MD_CONTEXT_SHX;
4130        break;
4131      case MD_CPU_ARCHITECTURE_ARM:
4132        *context_cpu_flags = MD_CONTEXT_ARM;
4133        break;
4134      case MD_CPU_ARCHITECTURE_IA64:
4135        *context_cpu_flags = MD_CONTEXT_IA64;
4136        break;
4137      case MD_CPU_ARCHITECTURE_ALPHA64:
4138        *context_cpu_flags = 0;
4139        break;
4140      case MD_CPU_ARCHITECTURE_MSIL:
4141        *context_cpu_flags = 0;
4142        break;
4143      case MD_CPU_ARCHITECTURE_AMD64:
4144        *context_cpu_flags = MD_CONTEXT_AMD64;
4145        break;
4146      case MD_CPU_ARCHITECTURE_X86_WIN64:
4147        *context_cpu_flags = 0;
4148        break;
4149      case MD_CPU_ARCHITECTURE_SPARC:
4150        *context_cpu_flags = MD_CONTEXT_SPARC;
4151        break;
4152      case MD_CPU_ARCHITECTURE_UNKNOWN:
4153        *context_cpu_flags = 0;
4154        break;
4155      default:
4156        *context_cpu_flags = 0;
4157        break;
4158    }
4159  }
4160
4161  // Restore position and return
4162  return SeekSet(saved_position);
4163}
4164
4165
4166bool Minidump::Read() {
4167  // Invalidate cached data.
4168  delete directory_;
4169  directory_ = NULL;
4170  stream_map_->clear();
4171
4172  valid_ = false;
4173
4174  if (!Open()) {
4175    BPLOG(ERROR) << "Minidump cannot open minidump";
4176    return false;
4177  }
4178
4179  if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
4180    BPLOG(ERROR) << "Minidump cannot read header";
4181    return false;
4182  }
4183
4184  if (header_.signature != MD_HEADER_SIGNATURE) {
4185    // The file may be byte-swapped.  Under the present architecture, these
4186    // classes don't know or need to know what CPU (or endianness) the
4187    // minidump was produced on in order to parse it.  Use the signature as
4188    // a byte order marker.
4189    uint32_t signature_swapped = header_.signature;
4190    Swap(&signature_swapped);
4191    if (signature_swapped != MD_HEADER_SIGNATURE) {
4192      // This isn't a minidump or a byte-swapped minidump.
4193      BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
4194                      HexString(header_.signature) << ", " <<
4195                      HexString(signature_swapped) << ") != " <<
4196                      HexString(MD_HEADER_SIGNATURE);
4197      return false;
4198    }
4199    swap_ = true;
4200  } else {
4201    // The file is not byte-swapped.  Set swap_ false (it may have been true
4202    // if the object is being reused?)
4203    swap_ = false;
4204  }
4205
4206  BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
4207                 "byte-swapping minidump";
4208
4209  if (swap_) {
4210    Swap(&header_.signature);
4211    Swap(&header_.version);
4212    Swap(&header_.stream_count);
4213    Swap(&header_.stream_directory_rva);
4214    Swap(&header_.checksum);
4215    Swap(&header_.time_date_stamp);
4216    Swap(&header_.flags);
4217  }
4218
4219  // Version check.  The high 16 bits of header_.version contain something
4220  // else "implementation specific."
4221  if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
4222    BPLOG(ERROR) << "Minidump version mismatch: " <<
4223                    HexString(header_.version & 0x0000ffff) << " != " <<
4224                    HexString(MD_HEADER_VERSION);
4225    return false;
4226  }
4227
4228  if (!SeekSet(header_.stream_directory_rva)) {
4229    BPLOG(ERROR) << "Minidump cannot seek to stream directory";
4230    return false;
4231  }
4232
4233  if (header_.stream_count > max_streams_) {
4234    BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
4235                    " exceeds maximum " << max_streams_;
4236    return false;
4237  }
4238
4239  if (header_.stream_count != 0) {
4240    scoped_ptr<MinidumpDirectoryEntries> directory(
4241        new MinidumpDirectoryEntries(header_.stream_count));
4242
4243    // Read the entire array in one fell swoop, instead of reading one entry
4244    // at a time in the loop.
4245    if (!ReadBytes(&(*directory)[0],
4246                   sizeof(MDRawDirectory) * header_.stream_count)) {
4247      BPLOG(ERROR) << "Minidump cannot read stream directory";
4248      return false;
4249    }
4250
4251    for (unsigned int stream_index = 0;
4252         stream_index < header_.stream_count;
4253         ++stream_index) {
4254      MDRawDirectory* directory_entry = &(*directory)[stream_index];
4255
4256      if (swap_) {
4257        Swap(&directory_entry->stream_type);
4258        Swap(&directory_entry->location);
4259      }
4260
4261      // Initialize the stream_map_ map, which speeds locating a stream by
4262      // type.
4263      unsigned int stream_type = directory_entry->stream_type;
4264      switch (stream_type) {
4265        case MD_THREAD_LIST_STREAM:
4266        case MD_MODULE_LIST_STREAM:
4267        case MD_MEMORY_LIST_STREAM:
4268        case MD_EXCEPTION_STREAM:
4269        case MD_SYSTEM_INFO_STREAM:
4270        case MD_MISC_INFO_STREAM:
4271        case MD_BREAKPAD_INFO_STREAM: {
4272          if (stream_map_->find(stream_type) != stream_map_->end()) {
4273            // Another stream with this type was already found.  A minidump
4274            // file should contain at most one of each of these stream types.
4275            BPLOG(ERROR) << "Minidump found multiple streams of type " <<
4276                            stream_type << ", but can only deal with one";
4277            return false;
4278          }
4279          // Fall through to default
4280        }
4281
4282        default: {
4283          // Overwrites for stream types other than those above, but it's
4284          // expected to be the user's burden in that case.
4285          (*stream_map_)[stream_type].stream_index = stream_index;
4286        }
4287      }
4288    }
4289
4290    directory_ = directory.release();
4291  }
4292
4293  valid_ = true;
4294  return true;
4295}
4296
4297
4298MinidumpThreadList* Minidump::GetThreadList() {
4299  MinidumpThreadList* thread_list;
4300  return GetStream(&thread_list);
4301}
4302
4303
4304MinidumpModuleList* Minidump::GetModuleList() {
4305  MinidumpModuleList* module_list;
4306  return GetStream(&module_list);
4307}
4308
4309
4310MinidumpMemoryList* Minidump::GetMemoryList() {
4311  MinidumpMemoryList* memory_list;
4312  return GetStream(&memory_list);
4313}
4314
4315
4316MinidumpException* Minidump::GetException() {
4317  MinidumpException* exception;
4318  return GetStream(&exception);
4319}
4320
4321MinidumpAssertion* Minidump::GetAssertion() {
4322  MinidumpAssertion* assertion;
4323  return GetStream(&assertion);
4324}
4325
4326
4327MinidumpSystemInfo* Minidump::GetSystemInfo() {
4328  MinidumpSystemInfo* system_info;
4329  return GetStream(&system_info);
4330}
4331
4332
4333MinidumpMiscInfo* Minidump::GetMiscInfo() {
4334  MinidumpMiscInfo* misc_info;
4335  return GetStream(&misc_info);
4336}
4337
4338
4339MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
4340  MinidumpBreakpadInfo* breakpad_info;
4341  return GetStream(&breakpad_info);
4342}
4343
4344MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
4345  MinidumpMemoryInfoList* memory_info_list;
4346  return GetStream(&memory_info_list);
4347}
4348
4349
4350void Minidump::Print() {
4351  if (!valid_) {
4352    BPLOG(ERROR) << "Minidump cannot print invalid data";
4353    return;
4354  }
4355
4356  printf("MDRawHeader\n");
4357  printf("  signature            = 0x%x\n",    header_.signature);
4358  printf("  version              = 0x%x\n",    header_.version);
4359  printf("  stream_count         = %d\n",      header_.stream_count);
4360  printf("  stream_directory_rva = 0x%x\n",    header_.stream_directory_rva);
4361  printf("  checksum             = 0x%x\n",    header_.checksum);
4362  struct tm timestruct;
4363#ifdef _WIN32
4364  gmtime_s(&timestruct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
4365#else
4366  gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), &timestruct);
4367#endif
4368  char timestr[20];
4369  strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
4370  printf("  time_date_stamp      = 0x%x %s\n", header_.time_date_stamp,
4371                                               timestr);
4372  printf("  flags                = 0x%" PRIx64 "\n",  header_.flags);
4373  printf("\n");
4374
4375  for (unsigned int stream_index = 0;
4376       stream_index < header_.stream_count;
4377       ++stream_index) {
4378    MDRawDirectory* directory_entry = &(*directory_)[stream_index];
4379
4380    printf("mDirectory[%d]\n", stream_index);
4381    printf("MDRawDirectory\n");
4382    printf("  stream_type        = %d\n",   directory_entry->stream_type);
4383    printf("  location.data_size = %d\n",
4384           directory_entry->location.data_size);
4385    printf("  location.rva       = 0x%x\n", directory_entry->location.rva);
4386    printf("\n");
4387  }
4388
4389  printf("Streams:\n");
4390  for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
4391       iterator != stream_map_->end();
4392       ++iterator) {
4393    uint32_t stream_type = iterator->first;
4394    MinidumpStreamInfo info = iterator->second;
4395    printf("  stream type 0x%x at index %d\n", stream_type, info.stream_index);
4396  }
4397  printf("\n");
4398}
4399
4400
4401const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
4402      const {
4403  if (!valid_) {
4404    BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
4405    return NULL;
4406  }
4407
4408  if (index >= header_.stream_count) {
4409    BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
4410                    index << "/" << header_.stream_count;
4411    return NULL;
4412  }
4413
4414  return &(*directory_)[index];
4415}
4416
4417
4418bool Minidump::ReadBytes(void* bytes, size_t count) {
4419  // Can't check valid_ because Read needs to call this method before
4420  // validity can be determined.
4421  if (!stream_) {
4422    return false;
4423  }
4424  stream_->read(static_cast<char*>(bytes), count);
4425  std::streamsize bytes_read = stream_->gcount();
4426  if (bytes_read == -1) {
4427    string error_string;
4428    int error_code = ErrnoString(&error_string);
4429    BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
4430    return false;
4431  }
4432
4433  // Convert to size_t and check for data loss
4434  size_t bytes_read_converted = static_cast<size_t>(bytes_read);
4435  if (static_cast<std::streamsize>(bytes_read_converted) != bytes_read) {
4436    BPLOG(ERROR) << "ReadBytes: conversion data loss detected when converting "
4437                 << bytes_read << " to " << bytes_read_converted;
4438    return false;
4439  }
4440
4441  if (bytes_read_converted != count) {
4442    BPLOG(ERROR) << "ReadBytes: read " << bytes_read_converted << "/" << count;
4443    return false;
4444  }
4445
4446  return true;
4447}
4448
4449
4450bool Minidump::SeekSet(off_t offset) {
4451  // Can't check valid_ because Read needs to call this method before
4452  // validity can be determined.
4453  if (!stream_) {
4454    return false;
4455  }
4456  stream_->seekg(offset, std::ios_base::beg);
4457  if (!stream_->good()) {
4458    string error_string;
4459    int error_code = ErrnoString(&error_string);
4460    BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
4461    return false;
4462  }
4463  return true;
4464}
4465
4466off_t Minidump::Tell() {
4467  if (!valid_ || !stream_) {
4468    return (off_t)-1;
4469  }
4470
4471  // Check for conversion data loss
4472  std::streamoff std_streamoff = stream_->tellg();
4473  off_t rv = static_cast<off_t>(std_streamoff);
4474  if (static_cast<std::streamoff>(rv) == std_streamoff) {
4475    return rv;
4476  } else {
4477    BPLOG(ERROR) << "Data loss detected";
4478    return (off_t)-1;
4479  }
4480}
4481
4482
4483string* Minidump::ReadString(off_t offset) {
4484  if (!valid_) {
4485    BPLOG(ERROR) << "Invalid Minidump for ReadString";
4486    return NULL;
4487  }
4488  if (!SeekSet(offset)) {
4489    BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
4490    return NULL;
4491  }
4492
4493  uint32_t bytes;
4494  if (!ReadBytes(&bytes, sizeof(bytes))) {
4495    BPLOG(ERROR) << "ReadString could not read string size at offset " <<
4496                    offset;
4497    return NULL;
4498  }
4499  if (swap_)
4500    Swap(&bytes);
4501
4502  if (bytes % 2 != 0) {
4503    BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
4504                    "-byte string at offset " << offset;
4505    return NULL;
4506  }
4507  unsigned int utf16_words = bytes / 2;
4508
4509  if (utf16_words > max_string_length_) {
4510    BPLOG(ERROR) << "ReadString string length " << utf16_words <<
4511                    " exceeds maximum " << max_string_length_ <<
4512                    " at offset " << offset;
4513    return NULL;
4514  }
4515
4516  vector<uint16_t> string_utf16(utf16_words);
4517
4518  if (utf16_words) {
4519    if (!ReadBytes(&string_utf16[0], bytes)) {
4520      BPLOG(ERROR) << "ReadString could not read " << bytes <<
4521                      "-byte string at offset " << offset;
4522      return NULL;
4523    }
4524  }
4525
4526  return UTF16ToUTF8(string_utf16, swap_);
4527}
4528
4529
4530bool Minidump::SeekToStreamType(uint32_t  stream_type,
4531                                uint32_t* stream_length) {
4532  BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
4533                                     "|stream_length|";
4534  assert(stream_length);
4535  *stream_length = 0;
4536
4537  if (!valid_) {
4538    BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
4539    return false;
4540  }
4541
4542  MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
4543  if (iterator == stream_map_->end()) {
4544    // This stream type didn't exist in the directory.
4545    BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
4546    return false;
4547  }
4548
4549  MinidumpStreamInfo info = iterator->second;
4550  if (info.stream_index >= header_.stream_count) {
4551    BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
4552                    " out of range: " <<
4553                    info.stream_index << "/" << header_.stream_count;
4554    return false;
4555  }
4556
4557  MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
4558  if (!SeekSet(directory_entry->location.rva)) {
4559    BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
4560                    stream_type;
4561    return false;
4562  }
4563
4564  *stream_length = directory_entry->location.data_size;
4565
4566  return true;
4567}
4568
4569
4570template<typename T>
4571T* Minidump::GetStream(T** stream) {
4572  // stream is a garbage parameter that's present only to account for C++'s
4573  // inability to overload a method based solely on its return type.
4574
4575  const uint32_t stream_type = T::kStreamType;
4576
4577  BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
4578                              " requires |stream|";
4579  assert(stream);
4580  *stream = NULL;
4581
4582  if (!valid_) {
4583    BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
4584    return NULL;
4585  }
4586
4587  MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
4588  if (iterator == stream_map_->end()) {
4589    // This stream type didn't exist in the directory.
4590    BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
4591    return NULL;
4592  }
4593
4594  // Get a pointer so that the stored stream field can be altered.
4595  MinidumpStreamInfo* info = &iterator->second;
4596
4597  if (info->stream) {
4598    // This cast is safe because info.stream is only populated by this
4599    // method, and there is a direct correlation between T and stream_type.
4600    *stream = static_cast<T*>(info->stream);
4601    return *stream;
4602  }
4603
4604  uint32_t stream_length;
4605  if (!SeekToStreamType(stream_type, &stream_length)) {
4606    BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
4607    return NULL;
4608  }
4609
4610  scoped_ptr<T> new_stream(new T(this));
4611
4612  if (!new_stream->Read(stream_length)) {
4613    BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
4614    return NULL;
4615  }
4616
4617  *stream = new_stream.release();
4618  info->stream = *stream;
4619  return *stream;
4620}
4621
4622
4623}  // namespace google_breakpad
4624