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