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