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