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