Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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.
30 // minidump.cc: A minidump reader.
31 //
32 // See minidump.h for documentation.
33 //
34 // Author: Mark Mentovai
36 #include "google_breakpad/processor/minidump.h"
38 #include <assert.h>
39 #include <fcntl.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <time.h>
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 #define O_BINARY 0
53 #endif // _WIN32
55 #include <fstream>
56 #include <iostream>
57 #include <limits>
58 #include <map>
59 #include <vector>
61 #include "processor/range_map-inl.h"
63 #include "common/scoped_ptr.h"
64 #include "processor/basic_code_module.h"
65 #include "processor/basic_code_modules.h"
66 #include "common/logging.h"
70 namespace google_breakpad {
73 using std::istream;
74 using std::ifstream;
75 using std::numeric_limits;
76 using std::vector;
79 //
80 // Swapping routines
81 //
82 // Inlining these doesn't increase code size significantly, and it saves
83 // a whole lot of unnecessary jumping back and forth.
84 //
87 // Swapping an 8-bit quantity is a no-op. This function is only provided
88 // to account for certain templatized operations that require swapping for
89 // wider types but handle uint8_t too
90 // (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
91 static inline void Swap(uint8_t* value) {
92 }
95 // Optimization: don't need to AND the furthest right shift, because we're
96 // shifting an unsigned quantity. The standard requires zero-filling in this
97 // case. If the quantities were signed, a bitmask whould be needed for this
98 // right shift to avoid an arithmetic shift (which retains the sign bit).
99 // The furthest left shift never needs to be ANDed bitmask.
102 static inline void Swap(uint16_t* value) {
103 *value = (*value >> 8) |
104 (*value << 8);
105 }
108 static inline void Swap(uint32_t* value) {
109 *value = (*value >> 24) |
110 ((*value >> 8) & 0x0000ff00) |
111 ((*value << 8) & 0x00ff0000) |
112 (*value << 24);
113 }
116 static inline void Swap(uint64_t* value) {
117 uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
118 Swap(&value32[0]);
119 Swap(&value32[1]);
120 uint32_t temp = value32[0];
121 value32[0] = value32[1];
122 value32[1] = temp;
123 }
126 // Given a pointer to a 128-bit int in the minidump data, set the "low"
127 // and "high" fields appropriately.
128 static void Normalize128(uint128_struct* value, bool is_big_endian) {
129 // The struct format is [high, low], so if the format is big-endian,
130 // the most significant bytes will already be in the high field.
131 if (!is_big_endian) {
132 uint64_t temp = value->low;
133 value->low = value->high;
134 value->high = temp;
135 }
136 }
138 // This just swaps each int64 half of the 128-bit value.
139 // The value should also be normalized by calling Normalize128().
140 static void Swap(uint128_struct* value) {
141 Swap(&value->low);
142 Swap(&value->high);
143 }
146 static inline void Swap(MDLocationDescriptor* location_descriptor) {
147 Swap(&location_descriptor->data_size);
148 Swap(&location_descriptor->rva);
149 }
152 static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
153 Swap(&memory_descriptor->start_of_memory_range);
154 Swap(&memory_descriptor->memory);
155 }
158 static inline void Swap(MDGUID* guid) {
159 Swap(&guid->data1);
160 Swap(&guid->data2);
161 Swap(&guid->data3);
162 // Don't swap guid->data4[] because it contains 8-bit quantities.
163 }
166 //
167 // Character conversion routines
168 //
171 // Standard wide-character conversion routines depend on the system's own
172 // idea of what width a wide character should be: some use 16 bits, and
173 // some use 32 bits. For the purposes of a minidump, wide strings are
174 // always represented with 16-bit UTF-16 chracters. iconv isn't available
175 // everywhere, and its interface varies where it is available. iconv also
176 // deals purely with char* pointers, so in addition to considering the swap
177 // parameter, a converter that uses iconv would also need to take the host
178 // CPU's endianness into consideration. It doesn't seems worth the trouble
179 // of making it a dependency when we don't care about anything but UTF-16.
180 static string* UTF16ToUTF8(const vector<uint16_t>& in,
181 bool swap) {
182 scoped_ptr<string> out(new string());
184 // Set the string's initial capacity to the number of UTF-16 characters,
185 // because the UTF-8 representation will always be at least this long.
186 // If the UTF-8 representation is longer, the string will grow dynamically.
187 out->reserve(in.size());
189 for (vector<uint16_t>::const_iterator iterator = in.begin();
190 iterator != in.end();
191 ++iterator) {
192 // Get a 16-bit value from the input
193 uint16_t in_word = *iterator;
194 if (swap)
195 Swap(&in_word);
197 // Convert the input value (in_word) into a Unicode code point (unichar).
198 uint32_t unichar;
199 if (in_word >= 0xdc00 && in_word <= 0xdcff) {
200 BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
201 HexString(in_word) << " without high";
202 return NULL;
203 } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
204 // High surrogate.
205 unichar = (in_word - 0xd7c0) << 10;
206 if (++iterator == in.end()) {
207 BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
208 HexString(in_word) << " at end of string";
209 return NULL;
210 }
211 uint32_t high_word = in_word;
212 in_word = *iterator;
213 if (in_word < 0xdc00 || in_word > 0xdcff) {
214 BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
215 HexString(high_word) << " without low " <<
216 HexString(in_word);
217 return NULL;
218 }
219 unichar |= in_word & 0x03ff;
220 } else {
221 // The ordinary case, a single non-surrogate Unicode character encoded
222 // as a single 16-bit value.
223 unichar = in_word;
224 }
226 // Convert the Unicode code point (unichar) into its UTF-8 representation,
227 // appending it to the out string.
228 if (unichar < 0x80) {
229 (*out) += unichar;
230 } else if (unichar < 0x800) {
231 (*out) += 0xc0 | (unichar >> 6);
232 (*out) += 0x80 | (unichar & 0x3f);
233 } else if (unichar < 0x10000) {
234 (*out) += 0xe0 | (unichar >> 12);
235 (*out) += 0x80 | ((unichar >> 6) & 0x3f);
236 (*out) += 0x80 | (unichar & 0x3f);
237 } else if (unichar < 0x200000) {
238 (*out) += 0xf0 | (unichar >> 18);
239 (*out) += 0x80 | ((unichar >> 12) & 0x3f);
240 (*out) += 0x80 | ((unichar >> 6) & 0x3f);
241 (*out) += 0x80 | (unichar & 0x3f);
242 } else {
243 BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
244 HexString(unichar) << " in UTF-8";
245 return NULL;
246 }
247 }
249 return out.release();
250 }
252 // Return the smaller of the number of code units in the UTF-16 string,
253 // not including the terminating null word, or maxlen.
254 static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) {
255 size_t count = 0;
256 while (count < maxlen && string[count] != 0)
257 count++;
258 return count;
259 }
262 //
263 // MinidumpObject
264 //
267 MinidumpObject::MinidumpObject(Minidump* minidump)
268 : minidump_(minidump),
269 valid_(false) {
270 }
273 //
274 // MinidumpStream
275 //
278 MinidumpStream::MinidumpStream(Minidump* minidump)
279 : MinidumpObject(minidump) {
280 }
283 //
284 // MinidumpContext
285 //
288 MinidumpContext::MinidumpContext(Minidump* minidump)
289 : MinidumpStream(minidump),
290 context_(),
291 context_flags_(0) {
292 }
295 MinidumpContext::~MinidumpContext() {
296 FreeContext();
297 }
300 bool MinidumpContext::Read(uint32_t expected_size) {
301 valid_ = false;
303 FreeContext();
305 // First, figure out what type of CPU this context structure is for.
306 // For some reason, the AMD64 Context doesn't have context_flags
307 // at the beginning of the structure, so special case it here.
308 if (expected_size == sizeof(MDRawContextAMD64)) {
309 BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
311 scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
312 if (!minidump_->ReadBytes(context_amd64.get(),
313 sizeof(MDRawContextAMD64))) {
314 BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
315 return false;
316 }
318 if (minidump_->swap())
319 Swap(&context_amd64->context_flags);
321 uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
322 if (cpu_type == 0) {
323 if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
324 context_amd64->context_flags |= cpu_type;
325 } else {
326 BPLOG(ERROR) << "Failed to preserve the current stream position";
327 return false;
328 }
329 }
331 if (cpu_type != MD_CONTEXT_AMD64) {
332 //TODO: fall through to switch below?
333 // need a Tell method to be able to SeekSet back to beginning
334 // http://code.google.com/p/google-breakpad/issues/detail?id=224
335 BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
336 return false;
337 }
339 // Do this after reading the entire MDRawContext structure because
340 // GetSystemInfo may seek minidump to a new position.
341 if (!CheckAgainstSystemInfo(cpu_type)) {
342 BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
343 return false;
344 }
346 // Normalize the 128-bit types in the dump.
347 // Since this is AMD64, by definition, the values are little-endian.
348 for (unsigned int vr_index = 0;
349 vr_index < MD_CONTEXT_AMD64_VR_COUNT;
350 ++vr_index)
351 Normalize128(&context_amd64->vector_register[vr_index], false);
353 if (minidump_->swap()) {
354 Swap(&context_amd64->p1_home);
355 Swap(&context_amd64->p2_home);
356 Swap(&context_amd64->p3_home);
357 Swap(&context_amd64->p4_home);
358 Swap(&context_amd64->p5_home);
359 Swap(&context_amd64->p6_home);
360 // context_flags is already swapped
361 Swap(&context_amd64->mx_csr);
362 Swap(&context_amd64->cs);
363 Swap(&context_amd64->ds);
364 Swap(&context_amd64->es);
365 Swap(&context_amd64->fs);
366 Swap(&context_amd64->ss);
367 Swap(&context_amd64->eflags);
368 Swap(&context_amd64->dr0);
369 Swap(&context_amd64->dr1);
370 Swap(&context_amd64->dr2);
371 Swap(&context_amd64->dr3);
372 Swap(&context_amd64->dr6);
373 Swap(&context_amd64->dr7);
374 Swap(&context_amd64->rax);
375 Swap(&context_amd64->rcx);
376 Swap(&context_amd64->rdx);
377 Swap(&context_amd64->rbx);
378 Swap(&context_amd64->rsp);
379 Swap(&context_amd64->rbp);
380 Swap(&context_amd64->rsi);
381 Swap(&context_amd64->rdi);
382 Swap(&context_amd64->r8);
383 Swap(&context_amd64->r9);
384 Swap(&context_amd64->r10);
385 Swap(&context_amd64->r11);
386 Swap(&context_amd64->r12);
387 Swap(&context_amd64->r13);
388 Swap(&context_amd64->r14);
389 Swap(&context_amd64->r15);
390 Swap(&context_amd64->rip);
391 //FIXME: I'm not sure what actually determines
392 // which member of the union {flt_save, sse_registers}
393 // is valid. We're not currently using either,
394 // but it would be good to have them swapped properly.
396 for (unsigned int vr_index = 0;
397 vr_index < MD_CONTEXT_AMD64_VR_COUNT;
398 ++vr_index)
399 Swap(&context_amd64->vector_register[vr_index]);
400 Swap(&context_amd64->vector_control);
401 Swap(&context_amd64->debug_control);
402 Swap(&context_amd64->last_branch_to_rip);
403 Swap(&context_amd64->last_branch_from_rip);
404 Swap(&context_amd64->last_exception_to_rip);
405 Swap(&context_amd64->last_exception_from_rip);
406 }
408 context_flags_ = context_amd64->context_flags;
410 context_.amd64 = context_amd64.release();
411 }
412 else {
413 uint32_t context_flags;
414 if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
415 BPLOG(ERROR) << "MinidumpContext could not read context flags";
416 return false;
417 }
418 if (minidump_->swap())
419 Swap(&context_flags);
421 uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
422 if (cpu_type == 0) {
423 // Unfortunately the flag for MD_CONTEXT_ARM that was taken
424 // from a Windows CE SDK header conflicts in practice with
425 // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
426 // but handle dumps with the legacy value gracefully here.
427 if (context_flags & MD_CONTEXT_ARM_OLD) {
428 context_flags |= MD_CONTEXT_ARM;
429 context_flags &= ~MD_CONTEXT_ARM_OLD;
430 cpu_type = MD_CONTEXT_ARM;
431 }
432 }
434 if (cpu_type == 0) {
435 if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
436 context_flags |= cpu_type;
437 } else {
438 BPLOG(ERROR) << "Failed to preserve the current stream position";
439 return false;
440 }
441 }
443 // Allocate the context structure for the correct CPU and fill it. The
444 // casts are slightly unorthodox, but it seems better to do that than to
445 // maintain a separate pointer for each type of CPU context structure
446 // when only one of them will be used.
447 switch (cpu_type) {
448 case MD_CONTEXT_X86: {
449 if (expected_size != sizeof(MDRawContextX86)) {
450 BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
451 expected_size << " != " << sizeof(MDRawContextX86);
452 return false;
453 }
455 scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
457 // Set the context_flags member, which has already been read, and
458 // read the rest of the structure beginning with the first member
459 // after context_flags.
460 context_x86->context_flags = context_flags;
462 size_t flags_size = sizeof(context_x86->context_flags);
463 uint8_t* context_after_flags =
464 reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
465 if (!minidump_->ReadBytes(context_after_flags,
466 sizeof(MDRawContextX86) - flags_size)) {
467 BPLOG(ERROR) << "MinidumpContext could not read x86 context";
468 return false;
469 }
471 // Do this after reading the entire MDRawContext structure because
472 // GetSystemInfo may seek minidump to a new position.
473 if (!CheckAgainstSystemInfo(cpu_type)) {
474 BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
475 return false;
476 }
478 if (minidump_->swap()) {
479 // context_x86->context_flags was already swapped.
480 Swap(&context_x86->dr0);
481 Swap(&context_x86->dr1);
482 Swap(&context_x86->dr2);
483 Swap(&context_x86->dr3);
484 Swap(&context_x86->dr6);
485 Swap(&context_x86->dr7);
486 Swap(&context_x86->float_save.control_word);
487 Swap(&context_x86->float_save.status_word);
488 Swap(&context_x86->float_save.tag_word);
489 Swap(&context_x86->float_save.error_offset);
490 Swap(&context_x86->float_save.error_selector);
491 Swap(&context_x86->float_save.data_offset);
492 Swap(&context_x86->float_save.data_selector);
493 // context_x86->float_save.register_area[] contains 8-bit quantities
494 // and does not need to be swapped.
495 Swap(&context_x86->float_save.cr0_npx_state);
496 Swap(&context_x86->gs);
497 Swap(&context_x86->fs);
498 Swap(&context_x86->es);
499 Swap(&context_x86->ds);
500 Swap(&context_x86->edi);
501 Swap(&context_x86->esi);
502 Swap(&context_x86->ebx);
503 Swap(&context_x86->edx);
504 Swap(&context_x86->ecx);
505 Swap(&context_x86->eax);
506 Swap(&context_x86->ebp);
507 Swap(&context_x86->eip);
508 Swap(&context_x86->cs);
509 Swap(&context_x86->eflags);
510 Swap(&context_x86->esp);
511 Swap(&context_x86->ss);
512 // context_x86->extended_registers[] contains 8-bit quantities and
513 // does not need to be swapped.
514 }
516 context_.x86 = context_x86.release();
518 break;
519 }
521 case MD_CONTEXT_PPC: {
522 if (expected_size != sizeof(MDRawContextPPC)) {
523 BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
524 expected_size << " != " << sizeof(MDRawContextPPC);
525 return false;
526 }
528 scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
530 // Set the context_flags member, which has already been read, and
531 // read the rest of the structure beginning with the first member
532 // after context_flags.
533 context_ppc->context_flags = context_flags;
535 size_t flags_size = sizeof(context_ppc->context_flags);
536 uint8_t* context_after_flags =
537 reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
538 if (!minidump_->ReadBytes(context_after_flags,
539 sizeof(MDRawContextPPC) - flags_size)) {
540 BPLOG(ERROR) << "MinidumpContext could not read ppc context";
541 return false;
542 }
544 // Do this after reading the entire MDRawContext structure because
545 // GetSystemInfo may seek minidump to a new position.
546 if (!CheckAgainstSystemInfo(cpu_type)) {
547 BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
548 return false;
549 }
551 // Normalize the 128-bit types in the dump.
552 // Since this is PowerPC, by definition, the values are big-endian.
553 for (unsigned int vr_index = 0;
554 vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
555 ++vr_index) {
556 Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
557 }
559 if (minidump_->swap()) {
560 // context_ppc->context_flags was already swapped.
561 Swap(&context_ppc->srr0);
562 Swap(&context_ppc->srr1);
563 for (unsigned int gpr_index = 0;
564 gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
565 ++gpr_index) {
566 Swap(&context_ppc->gpr[gpr_index]);
567 }
568 Swap(&context_ppc->cr);
569 Swap(&context_ppc->xer);
570 Swap(&context_ppc->lr);
571 Swap(&context_ppc->ctr);
572 Swap(&context_ppc->mq);
573 Swap(&context_ppc->vrsave);
574 for (unsigned int fpr_index = 0;
575 fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
576 ++fpr_index) {
577 Swap(&context_ppc->float_save.fpregs[fpr_index]);
578 }
579 // Don't swap context_ppc->float_save.fpscr_pad because it is only
580 // used for padding.
581 Swap(&context_ppc->float_save.fpscr);
582 for (unsigned int vr_index = 0;
583 vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
584 ++vr_index) {
585 Swap(&context_ppc->vector_save.save_vr[vr_index]);
586 }
587 Swap(&context_ppc->vector_save.save_vscr);
588 // Don't swap the padding fields in vector_save.
589 Swap(&context_ppc->vector_save.save_vrvalid);
590 }
592 context_.ppc = context_ppc.release();
594 break;
595 }
597 case MD_CONTEXT_SPARC: {
598 if (expected_size != sizeof(MDRawContextSPARC)) {
599 BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
600 expected_size << " != " << sizeof(MDRawContextSPARC);
601 return false;
602 }
604 scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
606 // Set the context_flags member, which has already been read, and
607 // read the rest of the structure beginning with the first member
608 // after context_flags.
609 context_sparc->context_flags = context_flags;
611 size_t flags_size = sizeof(context_sparc->context_flags);
612 uint8_t* context_after_flags =
613 reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
614 if (!minidump_->ReadBytes(context_after_flags,
615 sizeof(MDRawContextSPARC) - flags_size)) {
616 BPLOG(ERROR) << "MinidumpContext could not read sparc context";
617 return false;
618 }
620 // Do this after reading the entire MDRawContext structure because
621 // GetSystemInfo may seek minidump to a new position.
622 if (!CheckAgainstSystemInfo(cpu_type)) {
623 BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
624 return false;
625 }
627 if (minidump_->swap()) {
628 // context_sparc->context_flags was already swapped.
629 for (unsigned int gpr_index = 0;
630 gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
631 ++gpr_index) {
632 Swap(&context_sparc->g_r[gpr_index]);
633 }
634 Swap(&context_sparc->ccr);
635 Swap(&context_sparc->pc);
636 Swap(&context_sparc->npc);
637 Swap(&context_sparc->y);
638 Swap(&context_sparc->asi);
639 Swap(&context_sparc->fprs);
640 for (unsigned int fpr_index = 0;
641 fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
642 ++fpr_index) {
643 Swap(&context_sparc->float_save.regs[fpr_index]);
644 }
645 Swap(&context_sparc->float_save.filler);
646 Swap(&context_sparc->float_save.fsr);
647 }
648 context_.ctx_sparc = context_sparc.release();
650 break;
651 }
653 case MD_CONTEXT_ARM: {
654 if (expected_size != sizeof(MDRawContextARM)) {
655 BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
656 expected_size << " != " << sizeof(MDRawContextARM);
657 return false;
658 }
660 scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
662 // Set the context_flags member, which has already been read, and
663 // read the rest of the structure beginning with the first member
664 // after context_flags.
665 context_arm->context_flags = context_flags;
667 size_t flags_size = sizeof(context_arm->context_flags);
668 uint8_t* context_after_flags =
669 reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
670 if (!minidump_->ReadBytes(context_after_flags,
671 sizeof(MDRawContextARM) - flags_size)) {
672 BPLOG(ERROR) << "MinidumpContext could not read arm context";
673 return false;
674 }
676 // Do this after reading the entire MDRawContext structure because
677 // GetSystemInfo may seek minidump to a new position.
678 if (!CheckAgainstSystemInfo(cpu_type)) {
679 BPLOG(ERROR) << "MinidumpContext arm does not match system info";
680 return false;
681 }
683 if (minidump_->swap()) {
684 // context_arm->context_flags was already swapped.
685 for (unsigned int ireg_index = 0;
686 ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
687 ++ireg_index) {
688 Swap(&context_arm->iregs[ireg_index]);
689 }
690 Swap(&context_arm->cpsr);
691 Swap(&context_arm->float_save.fpscr);
692 for (unsigned int fpr_index = 0;
693 fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
694 ++fpr_index) {
695 Swap(&context_arm->float_save.regs[fpr_index]);
696 }
697 for (unsigned int fpe_index = 0;
698 fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
699 ++fpe_index) {
700 Swap(&context_arm->float_save.extra[fpe_index]);
701 }
702 }
703 context_.arm = context_arm.release();
705 break;
706 }
708 default: {
709 // Unknown context type - Don't log as an error yet. Let the
710 // caller work that out.
711 BPLOG(INFO) << "MinidumpContext unknown context type " <<
712 HexString(cpu_type);
713 return false;
714 break;
715 }
716 }
717 context_flags_ = context_flags;
718 }
720 valid_ = true;
721 return true;
722 }
725 uint32_t MinidumpContext::GetContextCPU() const {
726 if (!valid_) {
727 // Don't log a message, GetContextCPU can be legitimately called with
728 // valid_ false by FreeContext, which is called by Read.
729 return 0;
730 }
732 return context_flags_ & MD_CONTEXT_CPU_MASK;
733 }
735 bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const {
736 BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer "
737 "requires |ip|";
738 assert(ip);
739 *ip = 0;
741 if (!valid_) {
742 BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer";
743 return false;
744 }
746 switch (context_flags_ & MD_CONTEXT_CPU_MASK) {
747 case MD_CONTEXT_AMD64:
748 *ip = context_.amd64->rip;
749 break;
750 case MD_CONTEXT_ARM:
751 *ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC];
752 break;
753 case MD_CONTEXT_PPC:
754 *ip = context_.ppc->srr0;
755 break;
756 case MD_CONTEXT_SPARC:
757 *ip = context_.ctx_sparc->pc;
758 break;
759 case MD_CONTEXT_X86:
760 *ip = context_.x86->eip;
761 break;
762 default:
763 // This should never happen.
764 BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer";
765 return false;
766 }
767 return true;
768 }
771 const MDRawContextX86* MinidumpContext::GetContextX86() const {
772 if (GetContextCPU() != MD_CONTEXT_X86) {
773 BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
774 return NULL;
775 }
777 return context_.x86;
778 }
781 const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
782 if (GetContextCPU() != MD_CONTEXT_PPC) {
783 BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
784 return NULL;
785 }
787 return context_.ppc;
788 }
790 const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
791 if (GetContextCPU() != MD_CONTEXT_AMD64) {
792 BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
793 return NULL;
794 }
796 return context_.amd64;
797 }
799 const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
800 if (GetContextCPU() != MD_CONTEXT_SPARC) {
801 BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
802 return NULL;
803 }
805 return context_.ctx_sparc;
806 }
808 const MDRawContextARM* MinidumpContext::GetContextARM() const {
809 if (GetContextCPU() != MD_CONTEXT_ARM) {
810 BPLOG(ERROR) << "MinidumpContext cannot get arm context";
811 return NULL;
812 }
814 return context_.arm;
815 }
817 void MinidumpContext::FreeContext() {
818 switch (GetContextCPU()) {
819 case MD_CONTEXT_X86:
820 delete context_.x86;
821 break;
823 case MD_CONTEXT_PPC:
824 delete context_.ppc;
825 break;
827 case MD_CONTEXT_AMD64:
828 delete context_.amd64;
829 break;
831 case MD_CONTEXT_SPARC:
832 delete context_.ctx_sparc;
833 break;
835 case MD_CONTEXT_ARM:
836 delete context_.arm;
837 break;
839 default:
840 // There is no context record (valid_ is false) or there's a
841 // context record for an unknown CPU (shouldn't happen, only known
842 // records are stored by Read).
843 break;
844 }
846 context_flags_ = 0;
847 context_.base = NULL;
848 }
851 bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
852 // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
853 // as this function just implements a sanity check.
854 MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
855 if (!system_info) {
856 BPLOG(INFO) << "MinidumpContext could not be compared against "
857 "MinidumpSystemInfo";
858 return true;
859 }
861 // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
862 const MDRawSystemInfo* raw_system_info = system_info->system_info();
863 if (!raw_system_info) {
864 BPLOG(INFO) << "MinidumpContext could not be compared against "
865 "MDRawSystemInfo";
866 return false;
867 }
869 MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
870 raw_system_info->processor_architecture);
872 // Compare the CPU type of the context record to the CPU type in the
873 // minidump's system info stream.
874 bool return_value = false;
875 switch (context_cpu_type) {
876 case MD_CONTEXT_X86:
877 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
878 system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
879 system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
880 return_value = true;
881 }
882 break;
884 case MD_CONTEXT_PPC:
885 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
886 return_value = true;
887 break;
889 case MD_CONTEXT_AMD64:
890 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
891 return_value = true;
892 break;
894 case MD_CONTEXT_SPARC:
895 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
896 return_value = true;
897 break;
899 case MD_CONTEXT_ARM:
900 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
901 return_value = true;
902 break;
903 }
905 BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
906 HexString(context_cpu_type) <<
907 " wrong for MinidumpSystemInfo CPU " <<
908 HexString(system_info_cpu_type);
910 return return_value;
911 }
914 void MinidumpContext::Print() {
915 if (!valid_) {
916 BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
917 return;
918 }
920 switch (GetContextCPU()) {
921 case MD_CONTEXT_X86: {
922 const MDRawContextX86* context_x86 = GetContextX86();
923 printf("MDRawContextX86\n");
924 printf(" context_flags = 0x%x\n",
925 context_x86->context_flags);
926 printf(" dr0 = 0x%x\n", context_x86->dr0);
927 printf(" dr1 = 0x%x\n", context_x86->dr1);
928 printf(" dr2 = 0x%x\n", context_x86->dr2);
929 printf(" dr3 = 0x%x\n", context_x86->dr3);
930 printf(" dr6 = 0x%x\n", context_x86->dr6);
931 printf(" dr7 = 0x%x\n", context_x86->dr7);
932 printf(" float_save.control_word = 0x%x\n",
933 context_x86->float_save.control_word);
934 printf(" float_save.status_word = 0x%x\n",
935 context_x86->float_save.status_word);
936 printf(" float_save.tag_word = 0x%x\n",
937 context_x86->float_save.tag_word);
938 printf(" float_save.error_offset = 0x%x\n",
939 context_x86->float_save.error_offset);
940 printf(" float_save.error_selector = 0x%x\n",
941 context_x86->float_save.error_selector);
942 printf(" float_save.data_offset = 0x%x\n",
943 context_x86->float_save.data_offset);
944 printf(" float_save.data_selector = 0x%x\n",
945 context_x86->float_save.data_selector);
946 printf(" float_save.register_area[%2d] = 0x",
947 MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
948 for (unsigned int register_index = 0;
949 register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
950 ++register_index) {
951 printf("%02x", context_x86->float_save.register_area[register_index]);
952 }
953 printf("\n");
954 printf(" float_save.cr0_npx_state = 0x%x\n",
955 context_x86->float_save.cr0_npx_state);
956 printf(" gs = 0x%x\n", context_x86->gs);
957 printf(" fs = 0x%x\n", context_x86->fs);
958 printf(" es = 0x%x\n", context_x86->es);
959 printf(" ds = 0x%x\n", context_x86->ds);
960 printf(" edi = 0x%x\n", context_x86->edi);
961 printf(" esi = 0x%x\n", context_x86->esi);
962 printf(" ebx = 0x%x\n", context_x86->ebx);
963 printf(" edx = 0x%x\n", context_x86->edx);
964 printf(" ecx = 0x%x\n", context_x86->ecx);
965 printf(" eax = 0x%x\n", context_x86->eax);
966 printf(" ebp = 0x%x\n", context_x86->ebp);
967 printf(" eip = 0x%x\n", context_x86->eip);
968 printf(" cs = 0x%x\n", context_x86->cs);
969 printf(" eflags = 0x%x\n", context_x86->eflags);
970 printf(" esp = 0x%x\n", context_x86->esp);
971 printf(" ss = 0x%x\n", context_x86->ss);
972 printf(" extended_registers[%3d] = 0x",
973 MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
974 for (unsigned int register_index = 0;
975 register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
976 ++register_index) {
977 printf("%02x", context_x86->extended_registers[register_index]);
978 }
979 printf("\n\n");
981 break;
982 }
984 case MD_CONTEXT_PPC: {
985 const MDRawContextPPC* context_ppc = GetContextPPC();
986 printf("MDRawContextPPC\n");
987 printf(" context_flags = 0x%x\n",
988 context_ppc->context_flags);
989 printf(" srr0 = 0x%x\n", context_ppc->srr0);
990 printf(" srr1 = 0x%x\n", context_ppc->srr1);
991 for (unsigned int gpr_index = 0;
992 gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
993 ++gpr_index) {
994 printf(" gpr[%2d] = 0x%x\n",
995 gpr_index, context_ppc->gpr[gpr_index]);
996 }
997 printf(" cr = 0x%x\n", context_ppc->cr);
998 printf(" xer = 0x%x\n", context_ppc->xer);
999 printf(" lr = 0x%x\n", context_ppc->lr);
1000 printf(" ctr = 0x%x\n", context_ppc->ctr);
1001 printf(" mq = 0x%x\n", context_ppc->mq);
1002 printf(" vrsave = 0x%x\n", context_ppc->vrsave);
1003 for (unsigned int fpr_index = 0;
1004 fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
1005 ++fpr_index) {
1006 printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
1007 fpr_index, context_ppc->float_save.fpregs[fpr_index]);
1008 }
1009 printf(" float_save.fpscr = 0x%x\n",
1010 context_ppc->float_save.fpscr);
1011 // TODO(mmentovai): print the 128-bit quantities in
1012 // context_ppc->vector_save. This isn't done yet because printf
1013 // doesn't support 128-bit quantities, and printing them using
1014 // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
1015 // byte ordering.
1016 printf(" vector_save.save_vrvalid = 0x%x\n",
1017 context_ppc->vector_save.save_vrvalid);
1018 printf("\n");
1020 break;
1021 }
1023 case MD_CONTEXT_AMD64: {
1024 const MDRawContextAMD64* context_amd64 = GetContextAMD64();
1025 printf("MDRawContextAMD64\n");
1026 printf(" p1_home = 0x%" PRIx64 "\n",
1027 context_amd64->p1_home);
1028 printf(" p2_home = 0x%" PRIx64 "\n",
1029 context_amd64->p2_home);
1030 printf(" p3_home = 0x%" PRIx64 "\n",
1031 context_amd64->p3_home);
1032 printf(" p4_home = 0x%" PRIx64 "\n",
1033 context_amd64->p4_home);
1034 printf(" p5_home = 0x%" PRIx64 "\n",
1035 context_amd64->p5_home);
1036 printf(" p6_home = 0x%" PRIx64 "\n",
1037 context_amd64->p6_home);
1038 printf(" context_flags = 0x%x\n",
1039 context_amd64->context_flags);
1040 printf(" mx_csr = 0x%x\n",
1041 context_amd64->mx_csr);
1042 printf(" cs = 0x%x\n", context_amd64->cs);
1043 printf(" ds = 0x%x\n", context_amd64->ds);
1044 printf(" es = 0x%x\n", context_amd64->es);
1045 printf(" fs = 0x%x\n", context_amd64->fs);
1046 printf(" gs = 0x%x\n", context_amd64->gs);
1047 printf(" ss = 0x%x\n", context_amd64->ss);
1048 printf(" eflags = 0x%x\n", context_amd64->eflags);
1049 printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0);
1050 printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1);
1051 printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2);
1052 printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3);
1053 printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6);
1054 printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7);
1055 printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax);
1056 printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx);
1057 printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx);
1058 printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx);
1059 printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp);
1060 printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp);
1061 printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi);
1062 printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi);
1063 printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8);
1064 printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9);
1065 printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10);
1066 printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11);
1067 printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12);
1068 printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13);
1069 printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14);
1070 printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15);
1071 printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip);
1072 //TODO: print xmm, vector, debug registers
1073 printf("\n");
1074 break;
1075 }
1077 case MD_CONTEXT_SPARC: {
1078 const MDRawContextSPARC* context_sparc = GetContextSPARC();
1079 printf("MDRawContextSPARC\n");
1080 printf(" context_flags = 0x%x\n",
1081 context_sparc->context_flags);
1082 for (unsigned int g_r_index = 0;
1083 g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
1084 ++g_r_index) {
1085 printf(" g_r[%2d] = 0x%" PRIx64 "\n",
1086 g_r_index, context_sparc->g_r[g_r_index]);
1087 }
1088 printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr);
1089 printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc);
1090 printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc);
1091 printf(" y = 0x%" PRIx64 "\n", context_sparc->y);
1092 printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi);
1093 printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs);
1095 for (unsigned int fpr_index = 0;
1096 fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
1097 ++fpr_index) {
1098 printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
1099 fpr_index, context_sparc->float_save.regs[fpr_index]);
1100 }
1101 printf(" float_save.filler = 0x%" PRIx64 "\n",
1102 context_sparc->float_save.filler);
1103 printf(" float_save.fsr = 0x%" PRIx64 "\n",
1104 context_sparc->float_save.fsr);
1105 break;
1106 }
1108 case MD_CONTEXT_ARM: {
1109 const MDRawContextARM* context_arm = GetContextARM();
1110 printf("MDRawContextARM\n");
1111 printf(" context_flags = 0x%x\n",
1112 context_arm->context_flags);
1113 for (unsigned int ireg_index = 0;
1114 ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
1115 ++ireg_index) {
1116 printf(" iregs[%2d] = 0x%x\n",
1117 ireg_index, context_arm->iregs[ireg_index]);
1118 }
1119 printf(" cpsr = 0x%x\n", context_arm->cpsr);
1120 printf(" float_save.fpscr = 0x%" PRIx64 "\n",
1121 context_arm->float_save.fpscr);
1122 for (unsigned int fpr_index = 0;
1123 fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
1124 ++fpr_index) {
1125 printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
1126 fpr_index, context_arm->float_save.regs[fpr_index]);
1127 }
1128 for (unsigned int fpe_index = 0;
1129 fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
1130 ++fpe_index) {
1131 printf(" float_save.extra[%2d] = 0x%" PRIx32 "\n",
1132 fpe_index, context_arm->float_save.extra[fpe_index]);
1133 }
1135 break;
1136 }
1138 default: {
1139 break;
1140 }
1141 }
1142 }
1145 //
1146 // MinidumpMemoryRegion
1147 //
1150 uint32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB
1153 MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
1154 : MinidumpObject(minidump),
1155 descriptor_(NULL),
1156 memory_(NULL) {
1157 }
1160 MinidumpMemoryRegion::~MinidumpMemoryRegion() {
1161 delete memory_;
1162 }
1165 void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
1166 descriptor_ = descriptor;
1167 valid_ = descriptor &&
1168 descriptor_->memory.data_size <=
1169 numeric_limits<uint64_t>::max() -
1170 descriptor_->start_of_memory_range;
1171 }
1174 const uint8_t* MinidumpMemoryRegion::GetMemory() const {
1175 if (!valid_) {
1176 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
1177 return NULL;
1178 }
1180 if (!memory_) {
1181 if (descriptor_->memory.data_size == 0) {
1182 BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
1183 return NULL;
1184 }
1186 if (!minidump_->SeekSet(descriptor_->memory.rva)) {
1187 BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
1188 return NULL;
1189 }
1191 if (descriptor_->memory.data_size > max_bytes_) {
1192 BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
1193 descriptor_->memory.data_size << " exceeds maximum " <<
1194 max_bytes_;
1195 return NULL;
1196 }
1198 scoped_ptr< vector<uint8_t> > memory(
1199 new vector<uint8_t>(descriptor_->memory.data_size));
1201 if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
1202 BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
1203 return NULL;
1204 }
1206 memory_ = memory.release();
1207 }
1209 return &(*memory_)[0];
1210 }
1213 uint64_t MinidumpMemoryRegion::GetBase() const {
1214 if (!valid_) {
1215 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
1216 return static_cast<uint64_t>(-1);
1217 }
1219 return descriptor_->start_of_memory_range;
1220 }
1223 uint32_t MinidumpMemoryRegion::GetSize() const {
1224 if (!valid_) {
1225 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
1226 return 0;
1227 }
1229 return descriptor_->memory.data_size;
1230 }
1233 void MinidumpMemoryRegion::FreeMemory() {
1234 delete memory_;
1235 memory_ = NULL;
1236 }
1239 template<typename T>
1240 bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
1241 T* value) const {
1242 BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
1243 "requires |value|";
1244 assert(value);
1245 *value = 0;
1247 if (!valid_) {
1248 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
1249 "GetMemoryAtAddressInternal";
1250 return false;
1251 }
1253 // Common failure case
1254 if (address < descriptor_->start_of_memory_range ||
1255 sizeof(T) > numeric_limits<uint64_t>::max() - address ||
1256 address + sizeof(T) > descriptor_->start_of_memory_range +
1257 descriptor_->memory.data_size) {
1258 BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
1259 HexString(address) << "+" << sizeof(T) << "/" <<
1260 HexString(descriptor_->start_of_memory_range) << "+" <<
1261 HexString(descriptor_->memory.data_size);
1262 return false;
1263 }
1265 const uint8_t* memory = GetMemory();
1266 if (!memory) {
1267 // GetMemory already logged a perfectly good message.
1268 return false;
1269 }
1271 // If the CPU requires memory accesses to be aligned, this can crash.
1272 // x86 and ppc are able to cope, though.
1273 *value = *reinterpret_cast<const T*>(
1274 &memory[address - descriptor_->start_of_memory_range]);
1276 if (minidump_->swap())
1277 Swap(value);
1279 return true;
1280 }
1283 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
1284 uint8_t* value) const {
1285 return GetMemoryAtAddressInternal(address, value);
1286 }
1289 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
1290 uint16_t* value) const {
1291 return GetMemoryAtAddressInternal(address, value);
1292 }
1295 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
1296 uint32_t* value) const {
1297 return GetMemoryAtAddressInternal(address, value);
1298 }
1301 bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
1302 uint64_t* value) const {
1303 return GetMemoryAtAddressInternal(address, value);
1304 }
1307 void MinidumpMemoryRegion::Print() {
1308 if (!valid_) {
1309 BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
1310 return;
1311 }
1313 const uint8_t* memory = GetMemory();
1314 if (memory) {
1315 printf("0x");
1316 for (unsigned int byte_index = 0;
1317 byte_index < descriptor_->memory.data_size;
1318 byte_index++) {
1319 printf("%02x", memory[byte_index]);
1320 }
1321 printf("\n");
1322 } else {
1323 printf("No memory\n");
1324 }
1325 }
1328 //
1329 // MinidumpThread
1330 //
1333 MinidumpThread::MinidumpThread(Minidump* minidump)
1334 : MinidumpObject(minidump),
1335 thread_(),
1336 memory_(NULL),
1337 context_(NULL) {
1338 }
1341 MinidumpThread::~MinidumpThread() {
1342 delete memory_;
1343 delete context_;
1344 }
1347 bool MinidumpThread::Read() {
1348 // Invalidate cached data.
1349 delete memory_;
1350 memory_ = NULL;
1351 delete context_;
1352 context_ = NULL;
1354 valid_ = false;
1356 if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
1357 BPLOG(ERROR) << "MinidumpThread cannot read thread";
1358 return false;
1359 }
1361 if (minidump_->swap()) {
1362 Swap(&thread_.thread_id);
1363 Swap(&thread_.suspend_count);
1364 Swap(&thread_.priority_class);
1365 Swap(&thread_.priority);
1366 Swap(&thread_.teb);
1367 Swap(&thread_.stack);
1368 Swap(&thread_.thread_context);
1369 }
1371 // Check for base + size overflow or undersize.
1372 if (thread_.stack.memory.data_size == 0 ||
1373 thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
1374 thread_.stack.start_of_memory_range) {
1375 // This is ok, but log an error anyway.
1376 BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
1377 HexString(thread_.stack.start_of_memory_range) << "+" <<
1378 HexString(thread_.stack.memory.data_size);
1379 } else {
1380 memory_ = new MinidumpMemoryRegion(minidump_);
1381 memory_->SetDescriptor(&thread_.stack);
1382 }
1384 valid_ = true;
1385 return true;
1386 }
1389 MinidumpMemoryRegion* MinidumpThread::GetMemory() {
1390 if (!valid_) {
1391 BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
1392 return NULL;
1393 }
1395 return memory_;
1396 }
1399 MinidumpContext* MinidumpThread::GetContext() {
1400 if (!valid_) {
1401 BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
1402 return NULL;
1403 }
1405 if (!context_) {
1406 if (!minidump_->SeekSet(thread_.thread_context.rva)) {
1407 BPLOG(ERROR) << "MinidumpThread cannot seek to context";
1408 return NULL;
1409 }
1411 scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
1413 if (!context->Read(thread_.thread_context.data_size)) {
1414 BPLOG(ERROR) << "MinidumpThread cannot read context";
1415 return NULL;
1416 }
1418 context_ = context.release();
1419 }
1421 return context_;
1422 }
1425 bool MinidumpThread::GetThreadID(uint32_t *thread_id) const {
1426 BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
1427 "|thread_id|";
1428 assert(thread_id);
1429 *thread_id = 0;
1431 if (!valid_) {
1432 BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
1433 return false;
1434 }
1436 *thread_id = thread_.thread_id;
1437 return true;
1438 }
1441 void MinidumpThread::Print() {
1442 if (!valid_) {
1443 BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
1444 return;
1445 }
1447 printf("MDRawThread\n");
1448 printf(" thread_id = 0x%x\n", thread_.thread_id);
1449 printf(" suspend_count = %d\n", thread_.suspend_count);
1450 printf(" priority_class = 0x%x\n", thread_.priority_class);
1451 printf(" priority = 0x%x\n", thread_.priority);
1452 printf(" teb = 0x%" PRIx64 "\n", thread_.teb);
1453 printf(" stack.start_of_memory_range = 0x%" PRIx64 "\n",
1454 thread_.stack.start_of_memory_range);
1455 printf(" stack.memory.data_size = 0x%x\n",
1456 thread_.stack.memory.data_size);
1457 printf(" stack.memory.rva = 0x%x\n", thread_.stack.memory.rva);
1458 printf(" thread_context.data_size = 0x%x\n",
1459 thread_.thread_context.data_size);
1460 printf(" thread_context.rva = 0x%x\n",
1461 thread_.thread_context.rva);
1463 MinidumpContext* context = GetContext();
1464 if (context) {
1465 printf("\n");
1466 context->Print();
1467 } else {
1468 printf(" (no context)\n");
1469 printf("\n");
1470 }
1472 MinidumpMemoryRegion* memory = GetMemory();
1473 if (memory) {
1474 printf("Stack\n");
1475 memory->Print();
1476 } else {
1477 printf("No stack\n");
1478 }
1479 printf("\n");
1480 }
1483 //
1484 // MinidumpThreadList
1485 //
1488 uint32_t MinidumpThreadList::max_threads_ = 4096;
1491 MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
1492 : MinidumpStream(minidump),
1493 id_to_thread_map_(),
1494 threads_(NULL),
1495 thread_count_(0) {
1496 }
1499 MinidumpThreadList::~MinidumpThreadList() {
1500 delete threads_;
1501 }
1504 bool MinidumpThreadList::Read(uint32_t expected_size) {
1505 // Invalidate cached data.
1506 id_to_thread_map_.clear();
1507 delete threads_;
1508 threads_ = NULL;
1509 thread_count_ = 0;
1511 valid_ = false;
1513 uint32_t thread_count;
1514 if (expected_size < sizeof(thread_count)) {
1515 BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
1516 expected_size << " < " << sizeof(thread_count);
1517 return false;
1518 }
1519 if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
1520 BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
1521 return false;
1522 }
1524 if (minidump_->swap())
1525 Swap(&thread_count);
1527 if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
1528 BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
1529 " would cause multiplication overflow";
1530 return false;
1531 }
1533 if (expected_size != sizeof(thread_count) +
1534 thread_count * sizeof(MDRawThread)) {
1535 // may be padded with 4 bytes on 64bit ABIs for alignment
1536 if (expected_size == sizeof(thread_count) + 4 +
1537 thread_count * sizeof(MDRawThread)) {
1538 uint32_t useless;
1539 if (!minidump_->ReadBytes(&useless, 4)) {
1540 BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes";
1541 return false;
1542 }
1543 } else {
1544 BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
1545 " != " << sizeof(thread_count) +
1546 thread_count * sizeof(MDRawThread);
1547 return false;
1548 }
1549 }
1552 if (thread_count > max_threads_) {
1553 BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
1554 " exceeds maximum " << max_threads_;
1555 return false;
1556 }
1558 if (thread_count != 0) {
1559 scoped_ptr<MinidumpThreads> threads(
1560 new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
1562 for (unsigned int thread_index = 0;
1563 thread_index < thread_count;
1564 ++thread_index) {
1565 MinidumpThread* thread = &(*threads)[thread_index];
1567 // Assume that the file offset is correct after the last read.
1568 if (!thread->Read()) {
1569 BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
1570 thread_index << "/" << thread_count;
1571 return false;
1572 }
1574 uint32_t thread_id;
1575 if (!thread->GetThreadID(&thread_id)) {
1576 BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
1577 thread_index << "/" << thread_count;
1578 return false;
1579 }
1581 if (GetThreadByID(thread_id)) {
1582 // Another thread with this ID is already in the list. Data error.
1583 BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
1584 HexString(thread_id) << " at thread " <<
1585 thread_index << "/" << thread_count;
1586 return false;
1587 }
1588 id_to_thread_map_[thread_id] = thread;
1589 }
1591 threads_ = threads.release();
1592 }
1594 thread_count_ = thread_count;
1596 valid_ = true;
1597 return true;
1598 }
1601 MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
1602 const {
1603 if (!valid_) {
1604 BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
1605 return NULL;
1606 }
1608 if (index >= thread_count_) {
1609 BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
1610 index << "/" << thread_count_;
1611 return NULL;
1612 }
1614 return &(*threads_)[index];
1615 }
1618 MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
1619 // Don't check valid_. Read calls this method before everything is
1620 // validated. It is safe to not check valid_ here.
1621 return id_to_thread_map_[thread_id];
1622 }
1625 void MinidumpThreadList::Print() {
1626 if (!valid_) {
1627 BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
1628 return;
1629 }
1631 printf("MinidumpThreadList\n");
1632 printf(" thread_count = %d\n", thread_count_);
1633 printf("\n");
1635 for (unsigned int thread_index = 0;
1636 thread_index < thread_count_;
1637 ++thread_index) {
1638 printf("thread[%d]\n", thread_index);
1640 (*threads_)[thread_index].Print();
1641 }
1642 }
1645 //
1646 // MinidumpModule
1647 //
1650 uint32_t MinidumpModule::max_cv_bytes_ = 32768;
1651 uint32_t MinidumpModule::max_misc_bytes_ = 32768;
1654 MinidumpModule::MinidumpModule(Minidump* minidump)
1655 : MinidumpObject(minidump),
1656 module_valid_(false),
1657 has_debug_info_(false),
1658 module_(),
1659 name_(NULL),
1660 cv_record_(NULL),
1661 cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
1662 misc_record_(NULL) {
1663 }
1666 MinidumpModule::~MinidumpModule() {
1667 delete name_;
1668 delete cv_record_;
1669 delete misc_record_;
1670 }
1673 bool MinidumpModule::Read() {
1674 // Invalidate cached data.
1675 delete name_;
1676 name_ = NULL;
1677 delete cv_record_;
1678 cv_record_ = NULL;
1679 cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
1680 delete misc_record_;
1681 misc_record_ = NULL;
1683 module_valid_ = false;
1684 has_debug_info_ = false;
1685 valid_ = false;
1687 if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
1688 BPLOG(ERROR) << "MinidumpModule cannot read module";
1689 return false;
1690 }
1692 if (minidump_->swap()) {
1693 Swap(&module_.base_of_image);
1694 Swap(&module_.size_of_image);
1695 Swap(&module_.checksum);
1696 Swap(&module_.time_date_stamp);
1697 Swap(&module_.module_name_rva);
1698 Swap(&module_.version_info.signature);
1699 Swap(&module_.version_info.struct_version);
1700 Swap(&module_.version_info.file_version_hi);
1701 Swap(&module_.version_info.file_version_lo);
1702 Swap(&module_.version_info.product_version_hi);
1703 Swap(&module_.version_info.product_version_lo);
1704 Swap(&module_.version_info.file_flags_mask);
1705 Swap(&module_.version_info.file_flags);
1706 Swap(&module_.version_info.file_os);
1707 Swap(&module_.version_info.file_type);
1708 Swap(&module_.version_info.file_subtype);
1709 Swap(&module_.version_info.file_date_hi);
1710 Swap(&module_.version_info.file_date_lo);
1711 Swap(&module_.cv_record);
1712 Swap(&module_.misc_record);
1713 // Don't swap reserved fields because their contents are unknown (as
1714 // are their proper widths).
1715 }
1717 // Check for base + size overflow or undersize.
1718 if (module_.size_of_image == 0 ||
1719 module_.size_of_image >
1720 numeric_limits<uint64_t>::max() - module_.base_of_image) {
1721 BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
1722 HexString(module_.base_of_image) << "+" <<
1723 HexString(module_.size_of_image);
1724 return false;
1725 }
1727 module_valid_ = true;
1728 return true;
1729 }
1732 bool MinidumpModule::ReadAuxiliaryData() {
1733 if (!module_valid_) {
1734 BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
1735 return false;
1736 }
1738 // Each module must have a name.
1739 name_ = minidump_->ReadString(module_.module_name_rva);
1740 if (!name_) {
1741 BPLOG(ERROR) << "MinidumpModule could not read name";
1742 return false;
1743 }
1745 // At this point, we have enough info for the module to be valid.
1746 valid_ = true;
1748 // CodeView and miscellaneous debug records are only required if the
1749 // module indicates that they exist.
1750 if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
1751 BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
1752 "but one was expected";
1753 return false;
1754 }
1756 if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
1757 BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
1758 "but one was expected";
1759 return false;
1760 }
1762 has_debug_info_ = true;
1763 return true;
1764 }
1767 string MinidumpModule::code_file() const {
1768 if (!valid_) {
1769 BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
1770 return "";
1771 }
1773 return *name_;
1774 }
1777 string MinidumpModule::code_identifier() const {
1778 if (!valid_) {
1779 BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
1780 return "";
1781 }
1783 if (!has_debug_info_)
1784 return "";
1786 MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
1787 if (!minidump_system_info) {
1788 BPLOG(ERROR) << "MinidumpModule code_identifier requires "
1789 "MinidumpSystemInfo";
1790 return "";
1791 }
1793 const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
1794 if (!raw_system_info) {
1795 BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
1796 return "";
1797 }
1799 string identifier;
1801 switch (raw_system_info->platform_id) {
1802 case MD_OS_WIN32_NT:
1803 case MD_OS_WIN32_WINDOWS: {
1804 // Use the same format that the MS symbol server uses in filesystem
1805 // hierarchies.
1806 char identifier_string[17];
1807 snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
1808 module_.time_date_stamp, module_.size_of_image);
1809 identifier = identifier_string;
1810 break;
1811 }
1813 case MD_OS_MAC_OS_X:
1814 case MD_OS_IOS:
1815 case MD_OS_SOLARIS:
1816 case MD_OS_ANDROID:
1817 case MD_OS_LINUX: {
1818 // TODO(mmentovai): support uuid extension if present, otherwise fall
1819 // back to version (from LC_ID_DYLIB?), otherwise fall back to something
1820 // else.
1821 identifier = "id";
1822 break;
1823 }
1825 default: {
1826 // Without knowing what OS generated the dump, we can't generate a good
1827 // identifier. Return an empty string, signalling failure.
1828 BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
1829 "found " << HexString(raw_system_info->platform_id);
1830 break;
1831 }
1832 }
1834 return identifier;
1835 }
1838 string MinidumpModule::debug_file() const {
1839 if (!valid_) {
1840 BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
1841 return "";
1842 }
1844 if (!has_debug_info_)
1845 return "";
1847 string file;
1848 // Prefer the CodeView record if present.
1849 if (cv_record_) {
1850 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
1851 // It's actually an MDCVInfoPDB70 structure.
1852 const MDCVInfoPDB70* cv_record_70 =
1853 reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
1854 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
1856 // GetCVRecord guarantees pdb_file_name is null-terminated.
1857 file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
1858 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
1859 // It's actually an MDCVInfoPDB20 structure.
1860 const MDCVInfoPDB20* cv_record_20 =
1861 reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
1862 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
1864 // GetCVRecord guarantees pdb_file_name is null-terminated.
1865 file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
1866 }
1868 // If there's a CodeView record but it doesn't match a known signature,
1869 // try the miscellaneous record.
1870 }
1872 if (file.empty()) {
1873 // No usable CodeView record. Try the miscellaneous debug record.
1874 if (misc_record_) {
1875 const MDImageDebugMisc* misc_record =
1876 reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
1877 if (!misc_record->unicode) {
1878 // If it's not Unicode, just stuff it into the string. It's unclear
1879 // if misc_record->data is 0-terminated, so use an explicit size.
1880 file = string(
1881 reinterpret_cast<const char*>(misc_record->data),
1882 module_.misc_record.data_size - MDImageDebugMisc_minsize);
1883 } else {
1884 // There's a misc_record but it encodes the debug filename in UTF-16.
1885 // (Actually, because miscellaneous records are so old, it's probably
1886 // UCS-2.) Convert it to UTF-8 for congruity with the other strings
1887 // that this method (and all other methods in the Minidump family)
1888 // return.
1890 unsigned int bytes =
1891 module_.misc_record.data_size - MDImageDebugMisc_minsize;
1892 if (bytes % 2 == 0) {
1893 unsigned int utf16_words = bytes / 2;
1895 // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
1896 // and copy the UTF-16 data into it.
1897 vector<uint16_t> string_utf16(utf16_words);
1898 if (utf16_words)
1899 memcpy(&string_utf16[0], &misc_record->data, bytes);
1901 // GetMiscRecord already byte-swapped the data[] field if it contains
1902 // UTF-16, so pass false as the swap argument.
1903 scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
1904 file = *new_file;
1905 }
1906 }
1907 }
1908 }
1910 // Relatively common case
1911 BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
1912 "debug_file for " << *name_;
1914 return file;
1915 }
1918 string MinidumpModule::debug_identifier() const {
1919 if (!valid_) {
1920 BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
1921 return "";
1922 }
1924 if (!has_debug_info_)
1925 return "";
1927 string identifier;
1929 // Use the CodeView record if present.
1930 if (cv_record_) {
1931 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
1932 // It's actually an MDCVInfoPDB70 structure.
1933 const MDCVInfoPDB70* cv_record_70 =
1934 reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
1935 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
1937 // Use the same format that the MS symbol server uses in filesystem
1938 // hierarchies.
1939 char identifier_string[41];
1940 snprintf(identifier_string, sizeof(identifier_string),
1941 "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
1942 cv_record_70->signature.data1,
1943 cv_record_70->signature.data2,
1944 cv_record_70->signature.data3,
1945 cv_record_70->signature.data4[0],
1946 cv_record_70->signature.data4[1],
1947 cv_record_70->signature.data4[2],
1948 cv_record_70->signature.data4[3],
1949 cv_record_70->signature.data4[4],
1950 cv_record_70->signature.data4[5],
1951 cv_record_70->signature.data4[6],
1952 cv_record_70->signature.data4[7],
1953 cv_record_70->age);
1954 identifier = identifier_string;
1955 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
1956 // It's actually an MDCVInfoPDB20 structure.
1957 const MDCVInfoPDB20* cv_record_20 =
1958 reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
1959 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
1961 // Use the same format that the MS symbol server uses in filesystem
1962 // hierarchies.
1963 char identifier_string[17];
1964 snprintf(identifier_string, sizeof(identifier_string),
1965 "%08X%x", cv_record_20->signature, cv_record_20->age);
1966 identifier = identifier_string;
1967 }
1968 }
1970 // TODO(mmentovai): if there's no usable CodeView record, there might be a
1971 // miscellaneous debug record. It only carries a filename, though, and no
1972 // identifier. I'm not sure what the right thing to do for the identifier
1973 // is in that case, but I don't expect to find many modules without a
1974 // CodeView record (or some other Breakpad extension structure in place of
1975 // a CodeView record). Treat it as an error (empty identifier) for now.
1977 // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
1979 // Relatively common case
1980 BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
1981 "debug_identifier for " << *name_;
1983 return identifier;
1984 }
1987 string MinidumpModule::version() const {
1988 if (!valid_) {
1989 BPLOG(ERROR) << "Invalid MinidumpModule for version";
1990 return "";
1991 }
1993 string version;
1995 if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
1996 module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
1997 char version_string[24];
1998 snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
1999 module_.version_info.file_version_hi >> 16,
2000 module_.version_info.file_version_hi & 0xffff,
2001 module_.version_info.file_version_lo >> 16,
2002 module_.version_info.file_version_lo & 0xffff);
2003 version = version_string;
2004 }
2006 // TODO(mmentovai): possibly support other struct types in place of
2007 // the one used with MD_VSFIXEDFILEINFO_SIGNATURE. We can possibly use
2008 // a different structure that better represents versioning facilities on
2009 // Mac OS X and Linux, instead of forcing them to adhere to the dotted
2010 // quad of 16-bit ints that Windows uses.
2012 BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
2013 "version for " << *name_;
2015 return version;
2016 }
2019 const CodeModule* MinidumpModule::Copy() const {
2020 return new BasicCodeModule(this);
2021 }
2024 const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
2025 if (!module_valid_) {
2026 BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
2027 return NULL;
2028 }
2030 if (!cv_record_) {
2031 // This just guards against 0-sized CodeView records; more specific checks
2032 // are used when the signature is checked against various structure types.
2033 if (module_.cv_record.data_size == 0) {
2034 return NULL;
2035 }
2037 if (!minidump_->SeekSet(module_.cv_record.rva)) {
2038 BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
2039 return NULL;
2040 }
2042 if (module_.cv_record.data_size > max_cv_bytes_) {
2043 BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
2044 module_.cv_record.data_size << " exceeds maximum " <<
2045 max_cv_bytes_;
2046 return NULL;
2047 }
2049 // Allocating something that will be accessed as MDCVInfoPDB70 or
2050 // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
2051 // problems. x86 and ppc are able to cope, though. This allocation
2052 // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
2053 // variable-sized due to their pdb_file_name fields; these structures
2054 // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
2055 // them as such would result in incomplete structures or overruns.
2056 scoped_ptr< vector<uint8_t> > cv_record(
2057 new vector<uint8_t>(module_.cv_record.data_size));
2059 if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
2060 BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
2061 return NULL;
2062 }
2064 uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
2065 if (module_.cv_record.data_size > sizeof(signature)) {
2066 MDCVInfoPDB70* cv_record_signature =
2067 reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2068 signature = cv_record_signature->cv_signature;
2069 if (minidump_->swap())
2070 Swap(&signature);
2071 }
2073 if (signature == MD_CVINFOPDB70_SIGNATURE) {
2074 // Now that the structure type is known, recheck the size.
2075 if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
2076 BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
2077 MDCVInfoPDB70_minsize << " > " <<
2078 module_.cv_record.data_size;
2079 return NULL;
2080 }
2082 if (minidump_->swap()) {
2083 MDCVInfoPDB70* cv_record_70 =
2084 reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2085 Swap(&cv_record_70->cv_signature);
2086 Swap(&cv_record_70->signature);
2087 Swap(&cv_record_70->age);
2088 // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
2089 // quantities. (It's a path, is it UTF-8?)
2090 }
2092 // The last field of either structure is null-terminated 8-bit character
2093 // data. Ensure that it's null-terminated.
2094 if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2095 BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
2096 "0-terminated";
2097 return NULL;
2098 }
2099 } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
2100 // Now that the structure type is known, recheck the size.
2101 if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
2102 BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
2103 MDCVInfoPDB20_minsize << " > " <<
2104 module_.cv_record.data_size;
2105 return NULL;
2106 }
2107 if (minidump_->swap()) {
2108 MDCVInfoPDB20* cv_record_20 =
2109 reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
2110 Swap(&cv_record_20->cv_header.signature);
2111 Swap(&cv_record_20->cv_header.offset);
2112 Swap(&cv_record_20->signature);
2113 Swap(&cv_record_20->age);
2114 // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
2115 // quantities. (It's a path, is it UTF-8?)
2116 }
2118 // The last field of either structure is null-terminated 8-bit character
2119 // data. Ensure that it's null-terminated.
2120 if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2121 BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
2122 "0-terminated";
2123 return NULL;
2124 }
2125 }
2127 // If the signature doesn't match something above, it's not something
2128 // that Breakpad can presently handle directly. Because some modules in
2129 // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
2130 // don't bail out here - allow the data to be returned to the user,
2131 // although byte-swapping can't be done.
2133 // Store the vector type because that's how storage was allocated, but
2134 // return it casted to uint8_t*.
2135 cv_record_ = cv_record.release();
2136 cv_record_signature_ = signature;
2137 }
2139 if (size)
2140 *size = module_.cv_record.data_size;
2142 return &(*cv_record_)[0];
2143 }
2146 const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
2147 if (!module_valid_) {
2148 BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
2149 return NULL;
2150 }
2152 if (!misc_record_) {
2153 if (module_.misc_record.data_size == 0) {
2154 return NULL;
2155 }
2157 if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
2158 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
2159 "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
2160 module_.misc_record.data_size;
2161 return NULL;
2162 }
2164 if (!minidump_->SeekSet(module_.misc_record.rva)) {
2165 BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
2166 "debugging record";
2167 return NULL;
2168 }
2170 if (module_.misc_record.data_size > max_misc_bytes_) {
2171 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
2172 module_.misc_record.data_size << " exceeds maximum " <<
2173 max_misc_bytes_;
2174 return NULL;
2175 }
2177 // Allocating something that will be accessed as MDImageDebugMisc but
2178 // is allocated as uint8_t[] can cause alignment problems. x86 and
2179 // ppc are able to cope, though. This allocation style is needed
2180 // because the MDImageDebugMisc is variable-sized due to its data field;
2181 // this structure is not MDImageDebugMisc_minsize and treating it as such
2182 // would result in an incomplete structure or an overrun.
2183 scoped_ptr< vector<uint8_t> > misc_record_mem(
2184 new vector<uint8_t>(module_.misc_record.data_size));
2185 MDImageDebugMisc* misc_record =
2186 reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
2188 if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
2189 BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
2190 "record";
2191 return NULL;
2192 }
2194 if (minidump_->swap()) {
2195 Swap(&misc_record->data_type);
2196 Swap(&misc_record->length);
2197 // Don't swap misc_record.unicode because it's an 8-bit quantity.
2198 // Don't swap the reserved fields for the same reason, and because
2199 // they don't contain any valid data.
2200 if (misc_record->unicode) {
2201 // There is a potential alignment problem, but shouldn't be a problem
2202 // in practice due to the layout of MDImageDebugMisc.
2203 uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
2204 unsigned int dataBytes = module_.misc_record.data_size -
2205 MDImageDebugMisc_minsize;
2206 unsigned int dataLength = dataBytes / 2;
2207 for (unsigned int characterIndex = 0;
2208 characterIndex < dataLength;
2209 ++characterIndex) {
2210 Swap(&data16[characterIndex]);
2211 }
2212 }
2213 }
2215 if (module_.misc_record.data_size != misc_record->length) {
2216 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
2217 "size mismatch, " << module_.misc_record.data_size <<
2218 " != " << misc_record->length;
2219 return NULL;
2220 }
2222 // Store the vector type because that's how storage was allocated, but
2223 // return it casted to MDImageDebugMisc*.
2224 misc_record_ = misc_record_mem.release();
2225 }
2227 if (size)
2228 *size = module_.misc_record.data_size;
2230 return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
2231 }
2234 void MinidumpModule::Print() {
2235 if (!valid_) {
2236 BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
2237 return;
2238 }
2240 printf("MDRawModule\n");
2241 printf(" base_of_image = 0x%" PRIx64 "\n",
2242 module_.base_of_image);
2243 printf(" size_of_image = 0x%x\n",
2244 module_.size_of_image);
2245 printf(" checksum = 0x%x\n",
2246 module_.checksum);
2247 printf(" time_date_stamp = 0x%x\n",
2248 module_.time_date_stamp);
2249 printf(" module_name_rva = 0x%x\n",
2250 module_.module_name_rva);
2251 printf(" version_info.signature = 0x%x\n",
2252 module_.version_info.signature);
2253 printf(" version_info.struct_version = 0x%x\n",
2254 module_.version_info.struct_version);
2255 printf(" version_info.file_version = 0x%x:0x%x\n",
2256 module_.version_info.file_version_hi,
2257 module_.version_info.file_version_lo);
2258 printf(" version_info.product_version = 0x%x:0x%x\n",
2259 module_.version_info.product_version_hi,
2260 module_.version_info.product_version_lo);
2261 printf(" version_info.file_flags_mask = 0x%x\n",
2262 module_.version_info.file_flags_mask);
2263 printf(" version_info.file_flags = 0x%x\n",
2264 module_.version_info.file_flags);
2265 printf(" version_info.file_os = 0x%x\n",
2266 module_.version_info.file_os);
2267 printf(" version_info.file_type = 0x%x\n",
2268 module_.version_info.file_type);
2269 printf(" version_info.file_subtype = 0x%x\n",
2270 module_.version_info.file_subtype);
2271 printf(" version_info.file_date = 0x%x:0x%x\n",
2272 module_.version_info.file_date_hi,
2273 module_.version_info.file_date_lo);
2274 printf(" cv_record.data_size = %d\n",
2275 module_.cv_record.data_size);
2276 printf(" cv_record.rva = 0x%x\n",
2277 module_.cv_record.rva);
2278 printf(" misc_record.data_size = %d\n",
2279 module_.misc_record.data_size);
2280 printf(" misc_record.rva = 0x%x\n",
2281 module_.misc_record.rva);
2283 printf(" (code_file) = \"%s\"\n", code_file().c_str());
2284 printf(" (code_identifier) = \"%s\"\n",
2285 code_identifier().c_str());
2287 uint32_t cv_record_size;
2288 const uint8_t *cv_record = GetCVRecord(&cv_record_size);
2289 if (cv_record) {
2290 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2291 const MDCVInfoPDB70* cv_record_70 =
2292 reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
2293 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2295 printf(" (cv_record).cv_signature = 0x%x\n",
2296 cv_record_70->cv_signature);
2297 printf(" (cv_record).signature = %08x-%04x-%04x-%02x%02x-",
2298 cv_record_70->signature.data1,
2299 cv_record_70->signature.data2,
2300 cv_record_70->signature.data3,
2301 cv_record_70->signature.data4[0],
2302 cv_record_70->signature.data4[1]);
2303 for (unsigned int guidIndex = 2;
2304 guidIndex < 8;
2305 ++guidIndex) {
2306 printf("%02x", cv_record_70->signature.data4[guidIndex]);
2307 }
2308 printf("\n");
2309 printf(" (cv_record).age = %d\n",
2310 cv_record_70->age);
2311 printf(" (cv_record).pdb_file_name = \"%s\"\n",
2312 cv_record_70->pdb_file_name);
2313 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2314 const MDCVInfoPDB20* cv_record_20 =
2315 reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
2316 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2318 printf(" (cv_record).cv_header.signature = 0x%x\n",
2319 cv_record_20->cv_header.signature);
2320 printf(" (cv_record).cv_header.offset = 0x%x\n",
2321 cv_record_20->cv_header.offset);
2322 printf(" (cv_record).signature = 0x%x\n",
2323 cv_record_20->signature);
2324 printf(" (cv_record).age = %d\n",
2325 cv_record_20->age);
2326 printf(" (cv_record).pdb_file_name = \"%s\"\n",
2327 cv_record_20->pdb_file_name);
2328 } else {
2329 printf(" (cv_record) = ");
2330 for (unsigned int cv_byte_index = 0;
2331 cv_byte_index < cv_record_size;
2332 ++cv_byte_index) {
2333 printf("%02x", cv_record[cv_byte_index]);
2334 }
2335 printf("\n");
2336 }
2337 } else {
2338 printf(" (cv_record) = (null)\n");
2339 }
2341 const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
2342 if (misc_record) {
2343 printf(" (misc_record).data_type = 0x%x\n",
2344 misc_record->data_type);
2345 printf(" (misc_record).length = 0x%x\n",
2346 misc_record->length);
2347 printf(" (misc_record).unicode = %d\n",
2348 misc_record->unicode);
2349 // Don't bother printing the UTF-16, we don't really even expect to ever
2350 // see this misc_record anyway.
2351 if (misc_record->unicode)
2352 printf(" (misc_record).data = \"%s\"\n",
2353 misc_record->data);
2354 else
2355 printf(" (misc_record).data = (UTF-16)\n");
2356 } else {
2357 printf(" (misc_record) = (null)\n");
2358 }
2360 printf(" (debug_file) = \"%s\"\n", debug_file().c_str());
2361 printf(" (debug_identifier) = \"%s\"\n",
2362 debug_identifier().c_str());
2363 printf(" (version) = \"%s\"\n", version().c_str());
2364 printf("\n");
2365 }
2368 //
2369 // MinidumpModuleList
2370 //
2373 uint32_t MinidumpModuleList::max_modules_ = 1024;
2376 MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
2377 : MinidumpStream(minidump),
2378 range_map_(new RangeMap<uint64_t, unsigned int>()),
2379 modules_(NULL),
2380 module_count_(0) {
2381 }
2384 MinidumpModuleList::~MinidumpModuleList() {
2385 delete range_map_;
2386 delete modules_;
2387 }
2390 bool MinidumpModuleList::Read(uint32_t expected_size) {
2391 // Invalidate cached data.
2392 range_map_->Clear();
2393 delete modules_;
2394 modules_ = NULL;
2395 module_count_ = 0;
2397 valid_ = false;
2399 uint32_t module_count;
2400 if (expected_size < sizeof(module_count)) {
2401 BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
2402 expected_size << " < " << sizeof(module_count);
2403 return false;
2404 }
2405 if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
2406 BPLOG(ERROR) << "MinidumpModuleList could not read module count";
2407 return false;
2408 }
2410 if (minidump_->swap())
2411 Swap(&module_count);
2413 if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
2414 BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
2415 " would cause multiplication overflow";
2416 return false;
2417 }
2419 if (expected_size != sizeof(module_count) +
2420 module_count * MD_MODULE_SIZE) {
2421 // may be padded with 4 bytes on 64bit ABIs for alignment
2422 if (expected_size == sizeof(module_count) + 4 +
2423 module_count * MD_MODULE_SIZE) {
2424 uint32_t useless;
2425 if (!minidump_->ReadBytes(&useless, 4)) {
2426 BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes";
2427 return false;
2428 }
2429 } else {
2430 BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
2431 " != " << sizeof(module_count) +
2432 module_count * MD_MODULE_SIZE;
2433 return false;
2434 }
2435 }
2437 if (module_count > max_modules_) {
2438 BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
2439 " exceeds maximum " << max_modules_;
2440 return false;
2441 }
2443 if (module_count != 0) {
2444 scoped_ptr<MinidumpModules> modules(
2445 new MinidumpModules(module_count, MinidumpModule(minidump_)));
2447 for (unsigned int module_index = 0;
2448 module_index < module_count;
2449 ++module_index) {
2450 MinidumpModule* module = &(*modules)[module_index];
2452 // Assume that the file offset is correct after the last read.
2453 if (!module->Read()) {
2454 BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
2455 module_index << "/" << module_count;
2456 return false;
2457 }
2458 }
2460 // Loop through the module list once more to read additional data and
2461 // build the range map. This is done in a second pass because
2462 // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
2463 // included in the loop above, additional seeks would be needed where
2464 // none are now to read contiguous data.
2465 for (unsigned int module_index = 0;
2466 module_index < module_count;
2467 ++module_index) {
2468 MinidumpModule* module = &(*modules)[module_index];
2470 // ReadAuxiliaryData fails if any data that the module indicates should
2471 // exist is missing, but we treat some such cases as valid anyway. See
2472 // issue #222: if a debugging record is of a format that's too large to
2473 // handle, it shouldn't render the entire dump invalid. Check module
2474 // validity before giving up.
2475 if (!module->ReadAuxiliaryData() && !module->valid()) {
2476 BPLOG(ERROR) << "MinidumpModuleList could not read required module "
2477 "auxiliary data for module " <<
2478 module_index << "/" << module_count;
2479 return false;
2480 }
2482 // It is safe to use module->code_file() after successfully calling
2483 // module->ReadAuxiliaryData or noting that the module is valid.
2485 uint64_t base_address = module->base_address();
2486 uint64_t module_size = module->size();
2487 if (base_address == static_cast<uint64_t>(-1)) {
2488 BPLOG(ERROR) << "MinidumpModuleList found bad base address "
2489 "for module " << module_index << "/" << module_count <<
2490 ", " << module->code_file();
2491 return false;
2492 }
2494 if (!range_map_->StoreRange(base_address, module_size, module_index)) {
2495 BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
2496 module_index << "/" << module_count << ", " <<
2497 module->code_file() << ", " <<
2498 HexString(base_address) << "+" <<
2499 HexString(module_size);
2500 return false;
2501 }
2502 }
2504 modules_ = modules.release();
2505 }
2507 module_count_ = module_count;
2509 valid_ = true;
2510 return true;
2511 }
2514 const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
2515 uint64_t address) const {
2516 if (!valid_) {
2517 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
2518 return NULL;
2519 }
2521 unsigned int module_index;
2522 if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) {
2523 BPLOG(INFO) << "MinidumpModuleList has no module at " <<
2524 HexString(address);
2525 return NULL;
2526 }
2528 return GetModuleAtIndex(module_index);
2529 }
2532 const MinidumpModule* MinidumpModuleList::GetMainModule() const {
2533 if (!valid_) {
2534 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
2535 return NULL;
2536 }
2538 // The main code module is the first one present in a minidump file's
2539 // MDRawModuleList.
2540 return GetModuleAtIndex(0);
2541 }
2544 const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
2545 unsigned int sequence) const {
2546 if (!valid_) {
2547 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
2548 return NULL;
2549 }
2551 if (sequence >= module_count_) {
2552 BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
2553 sequence << "/" << module_count_;
2554 return NULL;
2555 }
2557 unsigned int module_index;
2558 if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) {
2559 BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
2560 return NULL;
2561 }
2563 return GetModuleAtIndex(module_index);
2564 }
2567 const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
2568 unsigned int index) const {
2569 if (!valid_) {
2570 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
2571 return NULL;
2572 }
2574 if (index >= module_count_) {
2575 BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
2576 index << "/" << module_count_;
2577 return NULL;
2578 }
2580 return &(*modules_)[index];
2581 }
2584 const CodeModules* MinidumpModuleList::Copy() const {
2585 return new BasicCodeModules(this);
2586 }
2589 void MinidumpModuleList::Print() {
2590 if (!valid_) {
2591 BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
2592 return;
2593 }
2595 printf("MinidumpModuleList\n");
2596 printf(" module_count = %d\n", module_count_);
2597 printf("\n");
2599 for (unsigned int module_index = 0;
2600 module_index < module_count_;
2601 ++module_index) {
2602 printf("module[%d]\n", module_index);
2604 (*modules_)[module_index].Print();
2605 }
2606 }
2609 //
2610 // MinidumpMemoryList
2611 //
2614 uint32_t MinidumpMemoryList::max_regions_ = 4096;
2617 MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
2618 : MinidumpStream(minidump),
2619 range_map_(new RangeMap<uint64_t, unsigned int>()),
2620 descriptors_(NULL),
2621 regions_(NULL),
2622 region_count_(0) {
2623 }
2626 MinidumpMemoryList::~MinidumpMemoryList() {
2627 delete range_map_;
2628 delete descriptors_;
2629 delete regions_;
2630 }
2633 bool MinidumpMemoryList::Read(uint32_t expected_size) {
2634 // Invalidate cached data.
2635 delete descriptors_;
2636 descriptors_ = NULL;
2637 delete regions_;
2638 regions_ = NULL;
2639 range_map_->Clear();
2640 region_count_ = 0;
2642 valid_ = false;
2644 uint32_t region_count;
2645 if (expected_size < sizeof(region_count)) {
2646 BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
2647 expected_size << " < " << sizeof(region_count);
2648 return false;
2649 }
2650 if (!minidump_->ReadBytes(®ion_count, sizeof(region_count))) {
2651 BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
2652 return false;
2653 }
2655 if (minidump_->swap())
2656 Swap(®ion_count);
2658 if (region_count >
2659 numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
2660 BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
2661 " would cause multiplication overflow";
2662 return false;
2663 }
2665 if (expected_size != sizeof(region_count) +
2666 region_count * sizeof(MDMemoryDescriptor)) {
2667 // may be padded with 4 bytes on 64bit ABIs for alignment
2668 if (expected_size == sizeof(region_count) + 4 +
2669 region_count * sizeof(MDMemoryDescriptor)) {
2670 uint32_t useless;
2671 if (!minidump_->ReadBytes(&useless, 4)) {
2672 BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes";
2673 return false;
2674 }
2675 } else {
2676 BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
2677 " != " << sizeof(region_count) +
2678 region_count * sizeof(MDMemoryDescriptor);
2679 return false;
2680 }
2681 }
2683 if (region_count > max_regions_) {
2684 BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
2685 " exceeds maximum " << max_regions_;
2686 return false;
2687 }
2689 if (region_count != 0) {
2690 scoped_ptr<MemoryDescriptors> descriptors(
2691 new MemoryDescriptors(region_count));
2693 // Read the entire array in one fell swoop, instead of reading one entry
2694 // at a time in the loop.
2695 if (!minidump_->ReadBytes(&(*descriptors)[0],
2696 sizeof(MDMemoryDescriptor) * region_count)) {
2697 BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
2698 return false;
2699 }
2701 scoped_ptr<MemoryRegions> regions(
2702 new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
2704 for (unsigned int region_index = 0;
2705 region_index < region_count;
2706 ++region_index) {
2707 MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
2709 if (minidump_->swap())
2710 Swap(descriptor);
2712 uint64_t base_address = descriptor->start_of_memory_range;
2713 uint32_t region_size = descriptor->memory.data_size;
2715 // Check for base + size overflow or undersize.
2716 if (region_size == 0 ||
2717 region_size > numeric_limits<uint64_t>::max() - base_address) {
2718 BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
2719 " region " << region_index << "/" << region_count <<
2720 ", " << HexString(base_address) << "+" <<
2721 HexString(region_size);
2722 return false;
2723 }
2725 if (!range_map_->StoreRange(base_address, region_size, region_index)) {
2726 BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
2727 region_index << "/" << region_count << ", " <<
2728 HexString(base_address) << "+" <<
2729 HexString(region_size);
2730 return false;
2731 }
2733 (*regions)[region_index].SetDescriptor(descriptor);
2734 }
2736 descriptors_ = descriptors.release();
2737 regions_ = regions.release();
2738 }
2740 region_count_ = region_count;
2742 valid_ = true;
2743 return true;
2744 }
2747 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
2748 unsigned int index) {
2749 if (!valid_) {
2750 BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
2751 return NULL;
2752 }
2754 if (index >= region_count_) {
2755 BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
2756 index << "/" << region_count_;
2757 return NULL;
2758 }
2760 return &(*regions_)[index];
2761 }
2764 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
2765 uint64_t address) {
2766 if (!valid_) {
2767 BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
2768 return NULL;
2769 }
2771 unsigned int region_index;
2772 if (!range_map_->RetrieveRange(address, ®ion_index, NULL, NULL)) {
2773 BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
2774 HexString(address);
2775 return NULL;
2776 }
2778 return GetMemoryRegionAtIndex(region_index);
2779 }
2782 void MinidumpMemoryList::Print() {
2783 if (!valid_) {
2784 BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
2785 return;
2786 }
2788 printf("MinidumpMemoryList\n");
2789 printf(" region_count = %d\n", region_count_);
2790 printf("\n");
2792 for (unsigned int region_index = 0;
2793 region_index < region_count_;
2794 ++region_index) {
2795 MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
2796 printf("region[%d]\n", region_index);
2797 printf("MDMemoryDescriptor\n");
2798 printf(" start_of_memory_range = 0x%" PRIx64 "\n",
2799 descriptor->start_of_memory_range);
2800 printf(" memory.data_size = 0x%x\n", descriptor->memory.data_size);
2801 printf(" memory.rva = 0x%x\n", descriptor->memory.rva);
2802 MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
2803 if (region) {
2804 printf("Memory\n");
2805 region->Print();
2806 } else {
2807 printf("No memory\n");
2808 }
2809 printf("\n");
2810 }
2811 }
2814 //
2815 // MinidumpException
2816 //
2819 MinidumpException::MinidumpException(Minidump* minidump)
2820 : MinidumpStream(minidump),
2821 exception_(),
2822 context_(NULL) {
2823 }
2826 MinidumpException::~MinidumpException() {
2827 delete context_;
2828 }
2831 bool MinidumpException::Read(uint32_t expected_size) {
2832 // Invalidate cached data.
2833 delete context_;
2834 context_ = NULL;
2836 valid_ = false;
2838 if (expected_size != sizeof(exception_)) {
2839 BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
2840 " != " << sizeof(exception_);
2841 return false;
2842 }
2844 if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
2845 BPLOG(ERROR) << "MinidumpException cannot read exception";
2846 return false;
2847 }
2849 if (minidump_->swap()) {
2850 Swap(&exception_.thread_id);
2851 // exception_.__align is for alignment only and does not need to be
2852 // swapped.
2853 Swap(&exception_.exception_record.exception_code);
2854 Swap(&exception_.exception_record.exception_flags);
2855 Swap(&exception_.exception_record.exception_record);
2856 Swap(&exception_.exception_record.exception_address);
2857 Swap(&exception_.exception_record.number_parameters);
2858 // exception_.exception_record.__align is for alignment only and does not
2859 // need to be swapped.
2860 for (unsigned int parameter_index = 0;
2861 parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
2862 ++parameter_index) {
2863 Swap(&exception_.exception_record.exception_information[parameter_index]);
2864 }
2865 Swap(&exception_.thread_context);
2866 }
2868 valid_ = true;
2869 return true;
2870 }
2873 bool MinidumpException::GetThreadID(uint32_t *thread_id) const {
2874 BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
2875 "|thread_id|";
2876 assert(thread_id);
2877 *thread_id = 0;
2879 if (!valid_) {
2880 BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
2881 return false;
2882 }
2884 *thread_id = exception_.thread_id;
2885 return true;
2886 }
2889 MinidumpContext* MinidumpException::GetContext() {
2890 if (!valid_) {
2891 BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
2892 return NULL;
2893 }
2895 if (!context_) {
2896 if (!minidump_->SeekSet(exception_.thread_context.rva)) {
2897 BPLOG(ERROR) << "MinidumpException cannot seek to context";
2898 return NULL;
2899 }
2901 scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
2903 // Don't log as an error if we can still fall back on the thread's context
2904 // (which must be possible if we got this far.)
2905 if (!context->Read(exception_.thread_context.data_size)) {
2906 BPLOG(INFO) << "MinidumpException cannot read context";
2907 return NULL;
2908 }
2910 context_ = context.release();
2911 }
2913 return context_;
2914 }
2917 void MinidumpException::Print() {
2918 if (!valid_) {
2919 BPLOG(ERROR) << "MinidumpException cannot print invalid data";
2920 return;
2921 }
2923 printf("MDException\n");
2924 printf(" thread_id = 0x%x\n",
2925 exception_.thread_id);
2926 printf(" exception_record.exception_code = 0x%x\n",
2927 exception_.exception_record.exception_code);
2928 printf(" exception_record.exception_flags = 0x%x\n",
2929 exception_.exception_record.exception_flags);
2930 printf(" exception_record.exception_record = 0x%" PRIx64 "\n",
2931 exception_.exception_record.exception_record);
2932 printf(" exception_record.exception_address = 0x%" PRIx64 "\n",
2933 exception_.exception_record.exception_address);
2934 printf(" exception_record.number_parameters = %d\n",
2935 exception_.exception_record.number_parameters);
2936 for (unsigned int parameterIndex = 0;
2937 parameterIndex < exception_.exception_record.number_parameters;
2938 ++parameterIndex) {
2939 printf(" exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
2940 parameterIndex,
2941 exception_.exception_record.exception_information[parameterIndex]);
2942 }
2943 printf(" thread_context.data_size = %d\n",
2944 exception_.thread_context.data_size);
2945 printf(" thread_context.rva = 0x%x\n",
2946 exception_.thread_context.rva);
2947 MinidumpContext* context = GetContext();
2948 if (context) {
2949 printf("\n");
2950 context->Print();
2951 } else {
2952 printf(" (no context)\n");
2953 printf("\n");
2954 }
2955 }
2957 //
2958 // MinidumpAssertion
2959 //
2962 MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
2963 : MinidumpStream(minidump),
2964 assertion_(),
2965 expression_(),
2966 function_(),
2967 file_() {
2968 }
2971 MinidumpAssertion::~MinidumpAssertion() {
2972 }
2975 bool MinidumpAssertion::Read(uint32_t expected_size) {
2976 // Invalidate cached data.
2977 valid_ = false;
2979 if (expected_size != sizeof(assertion_)) {
2980 BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
2981 " != " << sizeof(assertion_);
2982 return false;
2983 }
2985 if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
2986 BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
2987 return false;
2988 }
2990 // Each of {expression, function, file} is a UTF-16 string,
2991 // we'll convert them to UTF-8 for ease of use.
2992 // expression
2993 // Since we don't have an explicit byte length for each string,
2994 // we use UTF16codeunits to calculate word length, then derive byte
2995 // length from that.
2996 uint32_t word_length = UTF16codeunits(assertion_.expression,
2997 sizeof(assertion_.expression));
2998 if (word_length > 0) {
2999 uint32_t byte_length = word_length * 2;
3000 vector<uint16_t> expression_utf16(word_length);
3001 memcpy(&expression_utf16[0], &assertion_.expression[0], byte_length);
3003 scoped_ptr<string> new_expression(UTF16ToUTF8(expression_utf16,
3004 minidump_->swap()));
3005 if (new_expression.get())
3006 expression_ = *new_expression;
3007 }
3009 // assertion
3010 word_length = UTF16codeunits(assertion_.function,
3011 sizeof(assertion_.function));
3012 if (word_length) {
3013 uint32_t byte_length = word_length * 2;
3014 vector<uint16_t> function_utf16(word_length);
3015 memcpy(&function_utf16[0], &assertion_.function[0], byte_length);
3016 scoped_ptr<string> new_function(UTF16ToUTF8(function_utf16,
3017 minidump_->swap()));
3018 if (new_function.get())
3019 function_ = *new_function;
3020 }
3022 // file
3023 word_length = UTF16codeunits(assertion_.file,
3024 sizeof(assertion_.file));
3025 if (word_length > 0) {
3026 uint32_t byte_length = word_length * 2;
3027 vector<uint16_t> file_utf16(word_length);
3028 memcpy(&file_utf16[0], &assertion_.file[0], byte_length);
3029 scoped_ptr<string> new_file(UTF16ToUTF8(file_utf16,
3030 minidump_->swap()));
3031 if (new_file.get())
3032 file_ = *new_file;
3033 }
3035 if (minidump_->swap()) {
3036 Swap(&assertion_.line);
3037 Swap(&assertion_.type);
3038 }
3040 valid_ = true;
3041 return true;
3042 }
3044 void MinidumpAssertion::Print() {
3045 if (!valid_) {
3046 BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
3047 return;
3048 }
3050 printf("MDAssertion\n");
3051 printf(" expression = %s\n",
3052 expression_.c_str());
3053 printf(" function = %s\n",
3054 function_.c_str());
3055 printf(" file = %s\n",
3056 file_.c_str());
3057 printf(" line = %u\n",
3058 assertion_.line);
3059 printf(" type = %u\n",
3060 assertion_.type);
3061 printf("\n");
3062 }
3064 //
3065 // MinidumpSystemInfo
3066 //
3069 MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
3070 : MinidumpStream(minidump),
3071 system_info_(),
3072 csd_version_(NULL),
3073 cpu_vendor_(NULL) {
3074 }
3077 MinidumpSystemInfo::~MinidumpSystemInfo() {
3078 delete csd_version_;
3079 delete cpu_vendor_;
3080 }
3083 bool MinidumpSystemInfo::Read(uint32_t expected_size) {
3084 // Invalidate cached data.
3085 delete csd_version_;
3086 csd_version_ = NULL;
3087 delete cpu_vendor_;
3088 cpu_vendor_ = NULL;
3090 valid_ = false;
3092 if (expected_size != sizeof(system_info_)) {
3093 BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
3094 " != " << sizeof(system_info_);
3095 return false;
3096 }
3098 if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
3099 BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
3100 return false;
3101 }
3103 if (minidump_->swap()) {
3104 Swap(&system_info_.processor_architecture);
3105 Swap(&system_info_.processor_level);
3106 Swap(&system_info_.processor_revision);
3107 // number_of_processors and product_type are 8-bit quantities and need no
3108 // swapping.
3109 Swap(&system_info_.major_version);
3110 Swap(&system_info_.minor_version);
3111 Swap(&system_info_.build_number);
3112 Swap(&system_info_.platform_id);
3113 Swap(&system_info_.csd_version_rva);
3114 Swap(&system_info_.suite_mask);
3115 // Don't swap the reserved2 field because its contents are unknown.
3117 if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3118 system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
3119 for (unsigned int i = 0; i < 3; ++i)
3120 Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
3121 Swap(&system_info_.cpu.x86_cpu_info.version_information);
3122 Swap(&system_info_.cpu.x86_cpu_info.feature_information);
3123 Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3124 } else {
3125 for (unsigned int i = 0; i < 2; ++i)
3126 Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
3127 }
3128 }
3130 valid_ = true;
3131 return true;
3132 }
3135 string MinidumpSystemInfo::GetOS() {
3136 string os;
3138 if (!valid_) {
3139 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
3140 return os;
3141 }
3143 switch (system_info_.platform_id) {
3144 case MD_OS_WIN32_NT:
3145 case MD_OS_WIN32_WINDOWS:
3146 os = "windows";
3147 break;
3149 case MD_OS_MAC_OS_X:
3150 os = "mac";
3151 break;
3153 case MD_OS_IOS:
3154 os = "ios";
3155 break;
3157 case MD_OS_LINUX:
3158 os = "linux";
3159 break;
3161 case MD_OS_SOLARIS:
3162 os = "solaris";
3163 break;
3165 case MD_OS_ANDROID:
3166 os = "android";
3167 break;
3169 default:
3170 BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
3171 HexString(system_info_.platform_id);
3172 break;
3173 }
3175 return os;
3176 }
3179 string MinidumpSystemInfo::GetCPU() {
3180 if (!valid_) {
3181 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
3182 return "";
3183 }
3185 string cpu;
3187 switch (system_info_.processor_architecture) {
3188 case MD_CPU_ARCHITECTURE_X86:
3189 case MD_CPU_ARCHITECTURE_X86_WIN64:
3190 cpu = "x86";
3191 break;
3193 case MD_CPU_ARCHITECTURE_AMD64:
3194 cpu = "x86-64";
3195 break;
3197 case MD_CPU_ARCHITECTURE_PPC:
3198 cpu = "ppc";
3199 break;
3201 case MD_CPU_ARCHITECTURE_SPARC:
3202 cpu = "sparc";
3203 break;
3205 case MD_CPU_ARCHITECTURE_ARM:
3206 cpu = "arm";
3207 break;
3209 default:
3210 BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
3211 HexString(system_info_.processor_architecture);
3212 break;
3213 }
3215 return cpu;
3216 }
3219 const string* MinidumpSystemInfo::GetCSDVersion() {
3220 if (!valid_) {
3221 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
3222 return NULL;
3223 }
3225 if (!csd_version_)
3226 csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
3228 BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
3229 "CSD version";
3231 return csd_version_;
3232 }
3235 const string* MinidumpSystemInfo::GetCPUVendor() {
3236 if (!valid_) {
3237 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
3238 return NULL;
3239 }
3241 // CPU vendor information can only be determined from x86 minidumps.
3242 if (!cpu_vendor_ &&
3243 (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3244 system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
3245 char cpu_vendor_string[13];
3246 snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
3247 "%c%c%c%c%c%c%c%c%c%c%c%c",
3248 system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
3249 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
3250 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
3251 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
3252 system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
3253 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
3254 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
3255 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
3256 system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
3257 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
3258 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
3259 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
3260 cpu_vendor_ = new string(cpu_vendor_string);
3261 }
3263 return cpu_vendor_;
3264 }
3267 void MinidumpSystemInfo::Print() {
3268 if (!valid_) {
3269 BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
3270 return;
3271 }
3273 printf("MDRawSystemInfo\n");
3274 printf(" processor_architecture = %d\n",
3275 system_info_.processor_architecture);
3276 printf(" processor_level = %d\n",
3277 system_info_.processor_level);
3278 printf(" processor_revision = 0x%x\n",
3279 system_info_.processor_revision);
3280 printf(" number_of_processors = %d\n",
3281 system_info_.number_of_processors);
3282 printf(" product_type = %d\n",
3283 system_info_.product_type);
3284 printf(" major_version = %d\n",
3285 system_info_.major_version);
3286 printf(" minor_version = %d\n",
3287 system_info_.minor_version);
3288 printf(" build_number = %d\n",
3289 system_info_.build_number);
3290 printf(" platform_id = %d\n",
3291 system_info_.platform_id);
3292 printf(" csd_version_rva = 0x%x\n",
3293 system_info_.csd_version_rva);
3294 printf(" suite_mask = 0x%x\n",
3295 system_info_.suite_mask);
3296 for (unsigned int i = 0; i < 3; ++i) {
3297 printf(" cpu.x86_cpu_info.vendor_id[%d] = 0x%x\n",
3298 i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
3299 }
3300 printf(" cpu.x86_cpu_info.version_information = 0x%x\n",
3301 system_info_.cpu.x86_cpu_info.version_information);
3302 printf(" cpu.x86_cpu_info.feature_information = 0x%x\n",
3303 system_info_.cpu.x86_cpu_info.feature_information);
3304 printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
3305 system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3306 const string* csd_version = GetCSDVersion();
3307 if (csd_version) {
3308 printf(" (csd_version) = \"%s\"\n",
3309 csd_version->c_str());
3310 } else {
3311 printf(" (csd_version) = (null)\n");
3312 }
3313 const string* cpu_vendor = GetCPUVendor();
3314 if (cpu_vendor) {
3315 printf(" (cpu_vendor) = \"%s\"\n",
3316 cpu_vendor->c_str());
3317 } else {
3318 printf(" (cpu_vendor) = (null)\n");
3319 }
3320 printf("\n");
3321 }
3324 //
3325 // MinidumpMiscInfo
3326 //
3329 MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
3330 : MinidumpStream(minidump),
3331 misc_info_() {
3332 }
3335 bool MinidumpMiscInfo::Read(uint32_t expected_size) {
3336 valid_ = false;
3338 if (expected_size != MD_MISCINFO_SIZE &&
3339 expected_size != MD_MISCINFO2_SIZE) {
3340 BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size <<
3341 " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE <<
3342 ")";
3343 return false;
3344 }
3346 if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
3347 BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
3348 return false;
3349 }
3351 if (minidump_->swap()) {
3352 Swap(&misc_info_.size_of_info);
3353 Swap(&misc_info_.flags1);
3354 Swap(&misc_info_.process_id);
3355 Swap(&misc_info_.process_create_time);
3356 Swap(&misc_info_.process_user_time);
3357 Swap(&misc_info_.process_kernel_time);
3358 if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3359 Swap(&misc_info_.processor_max_mhz);
3360 Swap(&misc_info_.processor_current_mhz);
3361 Swap(&misc_info_.processor_mhz_limit);
3362 Swap(&misc_info_.processor_max_idle_state);
3363 Swap(&misc_info_.processor_current_idle_state);
3364 }
3365 }
3367 if (expected_size != misc_info_.size_of_info) {
3368 BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
3369 expected_size << " != " << misc_info_.size_of_info;
3370 return false;
3371 }
3373 valid_ = true;
3374 return true;
3375 }
3378 void MinidumpMiscInfo::Print() {
3379 if (!valid_) {
3380 BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
3381 return;
3382 }
3384 printf("MDRawMiscInfo\n");
3385 printf(" size_of_info = %d\n", misc_info_.size_of_info);
3386 printf(" flags1 = 0x%x\n", misc_info_.flags1);
3387 printf(" process_id = 0x%x\n", misc_info_.process_id);
3388 printf(" process_create_time = 0x%x\n",
3389 misc_info_.process_create_time);
3390 printf(" process_user_time = 0x%x\n",
3391 misc_info_.process_user_time);
3392 printf(" process_kernel_time = 0x%x\n",
3393 misc_info_.process_kernel_time);
3394 if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3395 printf(" processor_max_mhz = %d\n",
3396 misc_info_.processor_max_mhz);
3397 printf(" processor_current_mhz = %d\n",
3398 misc_info_.processor_current_mhz);
3399 printf(" processor_mhz_limit = %d\n",
3400 misc_info_.processor_mhz_limit);
3401 printf(" processor_max_idle_state = 0x%x\n",
3402 misc_info_.processor_max_idle_state);
3403 printf(" processor_current_idle_state = 0x%x\n",
3404 misc_info_.processor_current_idle_state);
3405 }
3406 printf("\n");
3407 }
3410 //
3411 // MinidumpBreakpadInfo
3412 //
3415 MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
3416 : MinidumpStream(minidump),
3417 breakpad_info_() {
3418 }
3421 bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
3422 valid_ = false;
3424 if (expected_size != sizeof(breakpad_info_)) {
3425 BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
3426 " != " << sizeof(breakpad_info_);
3427 return false;
3428 }
3430 if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
3431 BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
3432 return false;
3433 }
3435 if (minidump_->swap()) {
3436 Swap(&breakpad_info_.validity);
3437 Swap(&breakpad_info_.dump_thread_id);
3438 Swap(&breakpad_info_.requesting_thread_id);
3439 }
3441 valid_ = true;
3442 return true;
3443 }
3446 bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const {
3447 BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
3448 "requires |thread_id|";
3449 assert(thread_id);
3450 *thread_id = 0;
3452 if (!valid_) {
3453 BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
3454 return false;
3455 }
3457 if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
3458 BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
3459 return false;
3460 }
3462 *thread_id = breakpad_info_.dump_thread_id;
3463 return true;
3464 }
3467 bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id)
3468 const {
3469 BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
3470 "requires |thread_id|";
3471 assert(thread_id);
3472 *thread_id = 0;
3474 if (!thread_id || !valid_) {
3475 BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
3476 return false;
3477 }
3479 if (!(breakpad_info_.validity &
3480 MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
3481 BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
3482 return false;
3483 }
3485 *thread_id = breakpad_info_.requesting_thread_id;
3486 return true;
3487 }
3490 void MinidumpBreakpadInfo::Print() {
3491 if (!valid_) {
3492 BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
3493 return;
3494 }
3496 printf("MDRawBreakpadInfo\n");
3497 printf(" validity = 0x%x\n", breakpad_info_.validity);
3499 if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3500 printf(" dump_thread_id = 0x%x\n", breakpad_info_.dump_thread_id);
3501 } else {
3502 printf(" dump_thread_id = (invalid)\n");
3503 }
3505 if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3506 printf(" requesting_thread_id = 0x%x\n",
3507 breakpad_info_.requesting_thread_id);
3508 } else {
3509 printf(" requesting_thread_id = (invalid)\n");
3510 }
3512 printf("\n");
3513 }
3516 //
3517 // MinidumpMemoryInfo
3518 //
3521 MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
3522 : MinidumpObject(minidump),
3523 memory_info_() {
3524 }
3527 bool MinidumpMemoryInfo::IsExecutable() const {
3528 uint32_t protection =
3529 memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
3530 return protection == MD_MEMORY_PROTECT_EXECUTE ||
3531 protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
3532 protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
3533 }
3536 bool MinidumpMemoryInfo::IsWritable() const {
3537 uint32_t protection =
3538 memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
3539 return protection == MD_MEMORY_PROTECT_READWRITE ||
3540 protection == MD_MEMORY_PROTECT_WRITECOPY ||
3541 protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
3542 protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
3543 }
3546 bool MinidumpMemoryInfo::Read() {
3547 valid_ = false;
3549 if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
3550 BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
3551 return false;
3552 }
3554 if (minidump_->swap()) {
3555 Swap(&memory_info_.base_address);
3556 Swap(&memory_info_.allocation_base);
3557 Swap(&memory_info_.allocation_protection);
3558 Swap(&memory_info_.region_size);
3559 Swap(&memory_info_.state);
3560 Swap(&memory_info_.protection);
3561 Swap(&memory_info_.type);
3562 }
3564 // Check for base + size overflow or undersize.
3565 if (memory_info_.region_size == 0 ||
3566 memory_info_.region_size > numeric_limits<uint64_t>::max() -
3567 memory_info_.base_address) {
3568 BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
3569 HexString(memory_info_.base_address) << "+" <<
3570 HexString(memory_info_.region_size);
3571 return false;
3572 }
3574 valid_ = true;
3575 return true;
3576 }
3579 void MinidumpMemoryInfo::Print() {
3580 if (!valid_) {
3581 BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
3582 return;
3583 }
3585 printf("MDRawMemoryInfo\n");
3586 printf(" base_address = 0x%" PRIx64 "\n",
3587 memory_info_.base_address);
3588 printf(" allocation_base = 0x%" PRIx64 "\n",
3589 memory_info_.allocation_base);
3590 printf(" allocation_protection = 0x%x\n",
3591 memory_info_.allocation_protection);
3592 printf(" region_size = 0x%" PRIx64 "\n", memory_info_.region_size);
3593 printf(" state = 0x%x\n", memory_info_.state);
3594 printf(" protection = 0x%x\n", memory_info_.protection);
3595 printf(" type = 0x%x\n", memory_info_.type);
3596 }
3599 //
3600 // MinidumpMemoryInfoList
3601 //
3604 MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
3605 : MinidumpStream(minidump),
3606 range_map_(new RangeMap<uint64_t, unsigned int>()),
3607 infos_(NULL),
3608 info_count_(0) {
3609 }
3612 MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
3613 delete range_map_;
3614 delete infos_;
3615 }
3618 bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
3619 // Invalidate cached data.
3620 delete infos_;
3621 infos_ = NULL;
3622 range_map_->Clear();
3623 info_count_ = 0;
3625 valid_ = false;
3627 MDRawMemoryInfoList header;
3628 if (expected_size < sizeof(MDRawMemoryInfoList)) {
3629 BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
3630 expected_size << " < " << sizeof(MDRawMemoryInfoList);
3631 return false;
3632 }
3633 if (!minidump_->ReadBytes(&header, sizeof(header))) {
3634 BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
3635 return false;
3636 }
3638 if (minidump_->swap()) {
3639 Swap(&header.size_of_header);
3640 Swap(&header.size_of_entry);
3641 Swap(&header.number_of_entries);
3642 }
3644 // Sanity check that the header is the expected size.
3645 //TODO(ted): could possibly handle this more gracefully, assuming
3646 // that future versions of the structs would be backwards-compatible.
3647 if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
3648 BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
3649 header.size_of_header << " != " <<
3650 sizeof(MDRawMemoryInfoList);
3651 return false;
3652 }
3654 // Sanity check that the entries are the expected size.
3655 if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
3656 BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
3657 header.size_of_entry << " != " <<
3658 sizeof(MDRawMemoryInfo);
3659 return false;
3660 }
3662 if (header.number_of_entries >
3663 numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
3664 BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
3665 header.number_of_entries <<
3666 " would cause multiplication overflow";
3667 return false;
3668 }
3670 if (expected_size != sizeof(MDRawMemoryInfoList) +
3671 header.number_of_entries * sizeof(MDRawMemoryInfo)) {
3672 BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
3673 " != " << sizeof(MDRawMemoryInfoList) +
3674 header.number_of_entries * sizeof(MDRawMemoryInfo);
3675 return false;
3676 }
3678 if (header.number_of_entries != 0) {
3679 scoped_ptr<MinidumpMemoryInfos> infos(
3680 new MinidumpMemoryInfos(header.number_of_entries,
3681 MinidumpMemoryInfo(minidump_)));
3683 for (unsigned int index = 0;
3684 index < header.number_of_entries;
3685 ++index) {
3686 MinidumpMemoryInfo* info = &(*infos)[index];
3688 // Assume that the file offset is correct after the last read.
3689 if (!info->Read()) {
3690 BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
3691 index << "/" << header.number_of_entries;
3692 return false;
3693 }
3695 uint64_t base_address = info->GetBase();
3696 uint32_t region_size = info->GetSize();
3698 if (!range_map_->StoreRange(base_address, region_size, index)) {
3699 BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
3700 " memory region " <<
3701 index << "/" << header.number_of_entries << ", " <<
3702 HexString(base_address) << "+" <<
3703 HexString(region_size);
3704 return false;
3705 }
3706 }
3708 infos_ = infos.release();
3709 }
3711 info_count_ = header.number_of_entries;
3713 valid_ = true;
3714 return true;
3715 }
3718 const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
3719 unsigned int index) const {
3720 if (!valid_) {
3721 BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
3722 return NULL;
3723 }
3725 if (index >= info_count_) {
3726 BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
3727 index << "/" << info_count_;
3728 return NULL;
3729 }
3731 return &(*infos_)[index];
3732 }
3735 const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
3736 uint64_t address) const {
3737 if (!valid_) {
3738 BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
3739 " GetMemoryInfoForAddress";
3740 return NULL;
3741 }
3743 unsigned int info_index;
3744 if (!range_map_->RetrieveRange(address, &info_index, NULL, NULL)) {
3745 BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
3746 HexString(address);
3747 return NULL;
3748 }
3750 return GetMemoryInfoAtIndex(info_index);
3751 }
3754 void MinidumpMemoryInfoList::Print() {
3755 if (!valid_) {
3756 BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
3757 return;
3758 }
3760 printf("MinidumpMemoryInfoList\n");
3761 printf(" info_count = %d\n", info_count_);
3762 printf("\n");
3764 for (unsigned int info_index = 0;
3765 info_index < info_count_;
3766 ++info_index) {
3767 printf("info[%d]\n", info_index);
3768 (*infos_)[info_index].Print();
3769 printf("\n");
3770 }
3771 }
3774 //
3775 // Minidump
3776 //
3779 uint32_t Minidump::max_streams_ = 128;
3780 unsigned int Minidump::max_string_length_ = 1024;
3783 Minidump::Minidump(const string& path)
3784 : header_(),
3785 directory_(NULL),
3786 stream_map_(new MinidumpStreamMap()),
3787 path_(path),
3788 stream_(NULL),
3789 swap_(false),
3790 valid_(false) {
3791 }
3793 Minidump::Minidump(istream& stream)
3794 : header_(),
3795 directory_(NULL),
3796 stream_map_(new MinidumpStreamMap()),
3797 path_(),
3798 stream_(&stream),
3799 swap_(false),
3800 valid_(false) {
3801 }
3803 Minidump::~Minidump() {
3804 if (stream_) {
3805 BPLOG(INFO) << "Minidump closing minidump";
3806 }
3807 if (!path_.empty()) {
3808 delete stream_;
3809 }
3810 delete directory_;
3811 delete stream_map_;
3812 }
3815 bool Minidump::Open() {
3816 if (stream_ != NULL) {
3817 BPLOG(INFO) << "Minidump reopening minidump " << path_;
3819 // The file is already open. Seek to the beginning, which is the position
3820 // the file would be at if it were opened anew.
3821 return SeekSet(0);
3822 }
3824 stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
3825 if (!stream_ || !stream_->good()) {
3826 string error_string;
3827 int error_code = ErrnoString(&error_string);
3828 BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
3829 ", error " << error_code << ": " << error_string;
3830 return false;
3831 }
3833 BPLOG(INFO) << "Minidump opened minidump " << path_;
3834 return true;
3835 }
3837 bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) {
3838 // Initialize output parameters
3839 *context_cpu_flags = 0;
3841 // Save the current stream position
3842 off_t saved_position = Tell();
3843 if (saved_position == -1) {
3844 // Failed to save the current stream position.
3845 // Returns true because the current position of the stream is preserved.
3846 return true;
3847 }
3849 const MDRawSystemInfo* system_info =
3850 GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
3852 if (system_info != NULL) {
3853 switch (system_info->processor_architecture) {
3854 case MD_CPU_ARCHITECTURE_X86:
3855 *context_cpu_flags = MD_CONTEXT_X86;
3856 break;
3857 case MD_CPU_ARCHITECTURE_MIPS:
3858 *context_cpu_flags = MD_CONTEXT_MIPS;
3859 break;
3860 case MD_CPU_ARCHITECTURE_ALPHA:
3861 *context_cpu_flags = MD_CONTEXT_ALPHA;
3862 break;
3863 case MD_CPU_ARCHITECTURE_PPC:
3864 *context_cpu_flags = MD_CONTEXT_PPC;
3865 break;
3866 case MD_CPU_ARCHITECTURE_SHX:
3867 *context_cpu_flags = MD_CONTEXT_SHX;
3868 break;
3869 case MD_CPU_ARCHITECTURE_ARM:
3870 *context_cpu_flags = MD_CONTEXT_ARM;
3871 break;
3872 case MD_CPU_ARCHITECTURE_IA64:
3873 *context_cpu_flags = MD_CONTEXT_IA64;
3874 break;
3875 case MD_CPU_ARCHITECTURE_ALPHA64:
3876 *context_cpu_flags = 0;
3877 break;
3878 case MD_CPU_ARCHITECTURE_MSIL:
3879 *context_cpu_flags = 0;
3880 break;
3881 case MD_CPU_ARCHITECTURE_AMD64:
3882 *context_cpu_flags = MD_CONTEXT_AMD64;
3883 break;
3884 case MD_CPU_ARCHITECTURE_X86_WIN64:
3885 *context_cpu_flags = 0;
3886 break;
3887 case MD_CPU_ARCHITECTURE_SPARC:
3888 *context_cpu_flags = MD_CONTEXT_SPARC;
3889 break;
3890 case MD_CPU_ARCHITECTURE_UNKNOWN:
3891 *context_cpu_flags = 0;
3892 break;
3893 default:
3894 *context_cpu_flags = 0;
3895 break;
3896 }
3897 }
3899 // Restore position and return
3900 return SeekSet(saved_position);
3901 }
3904 bool Minidump::Read() {
3905 // Invalidate cached data.
3906 delete directory_;
3907 directory_ = NULL;
3908 stream_map_->clear();
3910 valid_ = false;
3912 if (!Open()) {
3913 BPLOG(ERROR) << "Minidump cannot open minidump";
3914 return false;
3915 }
3917 if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
3918 BPLOG(ERROR) << "Minidump cannot read header";
3919 return false;
3920 }
3922 if (header_.signature != MD_HEADER_SIGNATURE) {
3923 // The file may be byte-swapped. Under the present architecture, these
3924 // classes don't know or need to know what CPU (or endianness) the
3925 // minidump was produced on in order to parse it. Use the signature as
3926 // a byte order marker.
3927 uint32_t signature_swapped = header_.signature;
3928 Swap(&signature_swapped);
3929 if (signature_swapped != MD_HEADER_SIGNATURE) {
3930 // This isn't a minidump or a byte-swapped minidump.
3931 BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
3932 HexString(header_.signature) << ", " <<
3933 HexString(signature_swapped) << ") != " <<
3934 HexString(MD_HEADER_SIGNATURE);
3935 return false;
3936 }
3937 swap_ = true;
3938 } else {
3939 // The file is not byte-swapped. Set swap_ false (it may have been true
3940 // if the object is being reused?)
3941 swap_ = false;
3942 }
3944 BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
3945 "byte-swapping minidump";
3947 if (swap_) {
3948 Swap(&header_.signature);
3949 Swap(&header_.version);
3950 Swap(&header_.stream_count);
3951 Swap(&header_.stream_directory_rva);
3952 Swap(&header_.checksum);
3953 Swap(&header_.time_date_stamp);
3954 Swap(&header_.flags);
3955 }
3957 // Version check. The high 16 bits of header_.version contain something
3958 // else "implementation specific."
3959 if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
3960 BPLOG(ERROR) << "Minidump version mismatch: " <<
3961 HexString(header_.version & 0x0000ffff) << " != " <<
3962 HexString(MD_HEADER_VERSION);
3963 return false;
3964 }
3966 if (!SeekSet(header_.stream_directory_rva)) {
3967 BPLOG(ERROR) << "Minidump cannot seek to stream directory";
3968 return false;
3969 }
3971 if (header_.stream_count > max_streams_) {
3972 BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
3973 " exceeds maximum " << max_streams_;
3974 return false;
3975 }
3977 if (header_.stream_count != 0) {
3978 scoped_ptr<MinidumpDirectoryEntries> directory(
3979 new MinidumpDirectoryEntries(header_.stream_count));
3981 // Read the entire array in one fell swoop, instead of reading one entry
3982 // at a time in the loop.
3983 if (!ReadBytes(&(*directory)[0],
3984 sizeof(MDRawDirectory) * header_.stream_count)) {
3985 BPLOG(ERROR) << "Minidump cannot read stream directory";
3986 return false;
3987 }
3989 for (unsigned int stream_index = 0;
3990 stream_index < header_.stream_count;
3991 ++stream_index) {
3992 MDRawDirectory* directory_entry = &(*directory)[stream_index];
3994 if (swap_) {
3995 Swap(&directory_entry->stream_type);
3996 Swap(&directory_entry->location);
3997 }
3999 // Initialize the stream_map_ map, which speeds locating a stream by
4000 // type.
4001 unsigned int stream_type = directory_entry->stream_type;
4002 switch (stream_type) {
4003 case MD_THREAD_LIST_STREAM:
4004 case MD_MODULE_LIST_STREAM:
4005 case MD_MEMORY_LIST_STREAM:
4006 case MD_EXCEPTION_STREAM:
4007 case MD_SYSTEM_INFO_STREAM:
4008 case MD_MISC_INFO_STREAM:
4009 case MD_BREAKPAD_INFO_STREAM: {
4010 if (stream_map_->find(stream_type) != stream_map_->end()) {
4011 // Another stream with this type was already found. A minidump
4012 // file should contain at most one of each of these stream types.
4013 BPLOG(ERROR) << "Minidump found multiple streams of type " <<
4014 stream_type << ", but can only deal with one";
4015 return false;
4016 }
4017 // Fall through to default
4018 }
4020 default: {
4021 // Overwrites for stream types other than those above, but it's
4022 // expected to be the user's burden in that case.
4023 (*stream_map_)[stream_type].stream_index = stream_index;
4024 }
4025 }
4026 }
4028 directory_ = directory.release();
4029 }
4031 valid_ = true;
4032 return true;
4033 }
4036 MinidumpThreadList* Minidump::GetThreadList() {
4037 MinidumpThreadList* thread_list;
4038 return GetStream(&thread_list);
4039 }
4042 MinidumpModuleList* Minidump::GetModuleList() {
4043 MinidumpModuleList* module_list;
4044 return GetStream(&module_list);
4045 }
4048 MinidumpMemoryList* Minidump::GetMemoryList() {
4049 MinidumpMemoryList* memory_list;
4050 return GetStream(&memory_list);
4051 }
4054 MinidumpException* Minidump::GetException() {
4055 MinidumpException* exception;
4056 return GetStream(&exception);
4057 }
4059 MinidumpAssertion* Minidump::GetAssertion() {
4060 MinidumpAssertion* assertion;
4061 return GetStream(&assertion);
4062 }
4065 MinidumpSystemInfo* Minidump::GetSystemInfo() {
4066 MinidumpSystemInfo* system_info;
4067 return GetStream(&system_info);
4068 }
4071 MinidumpMiscInfo* Minidump::GetMiscInfo() {
4072 MinidumpMiscInfo* misc_info;
4073 return GetStream(&misc_info);
4074 }
4077 MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
4078 MinidumpBreakpadInfo* breakpad_info;
4079 return GetStream(&breakpad_info);
4080 }
4082 MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
4083 MinidumpMemoryInfoList* memory_info_list;
4084 return GetStream(&memory_info_list);
4085 }
4088 void Minidump::Print() {
4089 if (!valid_) {
4090 BPLOG(ERROR) << "Minidump cannot print invalid data";
4091 return;
4092 }
4094 printf("MDRawHeader\n");
4095 printf(" signature = 0x%x\n", header_.signature);
4096 printf(" version = 0x%x\n", header_.version);
4097 printf(" stream_count = %d\n", header_.stream_count);
4098 printf(" stream_directory_rva = 0x%x\n", header_.stream_directory_rva);
4099 printf(" checksum = 0x%x\n", header_.checksum);
4100 struct tm timestruct;
4101 #ifdef _WIN32
4102 gmtime_s(×truct, reinterpret_cast<time_t*>(&header_.time_date_stamp));
4103 #else
4104 gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), ×truct);
4105 #endif
4106 char timestr[20];
4107 strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
4108 printf(" time_date_stamp = 0x%x %s\n", header_.time_date_stamp,
4109 timestr);
4110 printf(" flags = 0x%" PRIx64 "\n", header_.flags);
4111 printf("\n");
4113 for (unsigned int stream_index = 0;
4114 stream_index < header_.stream_count;
4115 ++stream_index) {
4116 MDRawDirectory* directory_entry = &(*directory_)[stream_index];
4118 printf("mDirectory[%d]\n", stream_index);
4119 printf("MDRawDirectory\n");
4120 printf(" stream_type = %d\n", directory_entry->stream_type);
4121 printf(" location.data_size = %d\n",
4122 directory_entry->location.data_size);
4123 printf(" location.rva = 0x%x\n", directory_entry->location.rva);
4124 printf("\n");
4125 }
4127 printf("Streams:\n");
4128 for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
4129 iterator != stream_map_->end();
4130 ++iterator) {
4131 uint32_t stream_type = iterator->first;
4132 MinidumpStreamInfo info = iterator->second;
4133 printf(" stream type 0x%x at index %d\n", stream_type, info.stream_index);
4134 }
4135 printf("\n");
4136 }
4139 const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
4140 const {
4141 if (!valid_) {
4142 BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
4143 return NULL;
4144 }
4146 if (index >= header_.stream_count) {
4147 BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
4148 index << "/" << header_.stream_count;
4149 return NULL;
4150 }
4152 return &(*directory_)[index];
4153 }
4156 bool Minidump::ReadBytes(void* bytes, size_t count) {
4157 // Can't check valid_ because Read needs to call this method before
4158 // validity can be determined.
4159 if (!stream_) {
4160 return false;
4161 }
4162 stream_->read(static_cast<char*>(bytes), count);
4163 size_t bytes_read = stream_->gcount();
4164 if (bytes_read != count) {
4165 if (bytes_read == size_t(-1)) {
4166 string error_string;
4167 int error_code = ErrnoString(&error_string);
4168 BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
4169 } else {
4170 BPLOG(ERROR) << "ReadBytes: read " << bytes_read << "/" << count;
4171 }
4172 return false;
4173 }
4174 return true;
4175 }
4178 bool Minidump::SeekSet(off_t offset) {
4179 // Can't check valid_ because Read needs to call this method before
4180 // validity can be determined.
4181 if (!stream_) {
4182 return false;
4183 }
4184 stream_->seekg(offset, std::ios_base::beg);
4185 if (!stream_->good()) {
4186 string error_string;
4187 int error_code = ErrnoString(&error_string);
4188 BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
4189 return false;
4190 }
4191 return true;
4192 }
4194 off_t Minidump::Tell() {
4195 if (!valid_ || !stream_) {
4196 return (off_t)-1;
4197 }
4199 return stream_->tellg();
4200 }
4203 string* Minidump::ReadString(off_t offset) {
4204 if (!valid_) {
4205 BPLOG(ERROR) << "Invalid Minidump for ReadString";
4206 return NULL;
4207 }
4208 if (!SeekSet(offset)) {
4209 BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
4210 return NULL;
4211 }
4213 uint32_t bytes;
4214 if (!ReadBytes(&bytes, sizeof(bytes))) {
4215 BPLOG(ERROR) << "ReadString could not read string size at offset " <<
4216 offset;
4217 return NULL;
4218 }
4219 if (swap_)
4220 Swap(&bytes);
4222 if (bytes % 2 != 0) {
4223 BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
4224 "-byte string at offset " << offset;
4225 return NULL;
4226 }
4227 unsigned int utf16_words = bytes / 2;
4229 if (utf16_words > max_string_length_) {
4230 BPLOG(ERROR) << "ReadString string length " << utf16_words <<
4231 " exceeds maximum " << max_string_length_ <<
4232 " at offset " << offset;
4233 return NULL;
4234 }
4236 vector<uint16_t> string_utf16(utf16_words);
4238 if (utf16_words) {
4239 if (!ReadBytes(&string_utf16[0], bytes)) {
4240 BPLOG(ERROR) << "ReadString could not read " << bytes <<
4241 "-byte string at offset " << offset;
4242 return NULL;
4243 }
4244 }
4246 return UTF16ToUTF8(string_utf16, swap_);
4247 }
4250 bool Minidump::SeekToStreamType(uint32_t stream_type,
4251 uint32_t* stream_length) {
4252 BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
4253 "|stream_length|";
4254 assert(stream_length);
4255 *stream_length = 0;
4257 if (!valid_) {
4258 BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
4259 return false;
4260 }
4262 MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
4263 if (iterator == stream_map_->end()) {
4264 // This stream type didn't exist in the directory.
4265 BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
4266 return false;
4267 }
4269 MinidumpStreamInfo info = iterator->second;
4270 if (info.stream_index >= header_.stream_count) {
4271 BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
4272 " out of range: " <<
4273 info.stream_index << "/" << header_.stream_count;
4274 return false;
4275 }
4277 MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
4278 if (!SeekSet(directory_entry->location.rva)) {
4279 BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
4280 stream_type;
4281 return false;
4282 }
4284 *stream_length = directory_entry->location.data_size;
4286 return true;
4287 }
4290 template<typename T>
4291 T* Minidump::GetStream(T** stream) {
4292 // stream is a garbage parameter that's present only to account for C++'s
4293 // inability to overload a method based solely on its return type.
4295 const uint32_t stream_type = T::kStreamType;
4297 BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
4298 " requires |stream|";
4299 assert(stream);
4300 *stream = NULL;
4302 if (!valid_) {
4303 BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
4304 return NULL;
4305 }
4307 MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
4308 if (iterator == stream_map_->end()) {
4309 // This stream type didn't exist in the directory.
4310 BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
4311 return NULL;
4312 }
4314 // Get a pointer so that the stored stream field can be altered.
4315 MinidumpStreamInfo* info = &iterator->second;
4317 if (info->stream) {
4318 // This cast is safe because info.stream is only populated by this
4319 // method, and there is a direct correlation between T and stream_type.
4320 *stream = static_cast<T*>(info->stream);
4321 return *stream;
4322 }
4324 uint32_t stream_length;
4325 if (!SeekToStreamType(stream_type, &stream_length)) {
4326 BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
4327 return NULL;
4328 }
4330 scoped_ptr<T> new_stream(new T(this));
4332 if (!new_stream->Read(stream_length)) {
4333 BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
4334 return NULL;
4335 }
4337 *stream = new_stream.release();
4338 info->stream = *stream;
4339 return *stream;
4340 }
4343 } // namespace google_breakpad