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