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