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