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