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