1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // minidump.cc: A minidump reader.
31 //
32 // See minidump.h for documentation.
33 //
34 // Author: Mark Mentovai
35
36 #ifdef _WIN32
37 #define NOMINMAX
38 #endif
39
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <time.h>
44
45 #include <cassert>
46 #include <limits>
47 #include <map>
48 #include <vector>
49
50 #include "processor/range_map-inl.h"
51
52 #include "google_breakpad/processor/minidump.h"
53 #include "processor/basic_code_module.h"
54 #include "processor/basic_code_modules.h"
55 #include "processor/logging.h"
56 #include "processor/scoped_ptr.h"
57
58 #ifdef _WIN32
59 #include <io.h>
60 #include <stdint.h>
61 typedef SSIZE_T ssize_t;
62 #define open _open
63 #define read _read
64 #define lseek _lseek
65 #define snprintf _snprintf
66 #define gmtime_r(d, res) { struct tm* _t = gmtime(d); memcpy(res, _t, sizeof(tm)); }
67 #else // _WIN32
68 #include <unistd.h>
69 #define O_BINARY 0
70 #endif // _WIN32
71
72
73 namespace google_breakpad {
74
75
76 using std::numeric_limits;
77 using std::vector;
78
79
80 //
81 // Swapping routines
82 //
83 // Inlining these doesn't increase code size significantly, and it saves
84 // a whole lot of unnecessary jumping back and forth.
85 //
86
87
88 // Swapping an 8-bit quantity is a no-op. This function is only provided
89 // to account for certain templatized operations that require swapping for
90 // wider types but handle u_int8_t too
91 // (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
Swap(u_int8_t * value)92 static inline void Swap(u_int8_t* value) {
93 }
94
95
96 // Optimization: don't need to AND the furthest right shift, because we're
97 // shifting an unsigned quantity. The standard requires zero-filling in this
98 // case. If the quantities were signed, a bitmask whould be needed for this
99 // right shift to avoid an arithmetic shift (which retains the sign bit).
100 // The furthest left shift never needs to be ANDed bitmask.
101
102
Swap(u_int16_t * value)103 static inline void Swap(u_int16_t* value) {
104 *value = (*value >> 8) |
105 (*value << 8);
106 }
107
108
Swap(u_int32_t * value)109 static inline void Swap(u_int32_t* value) {
110 *value = (*value >> 24) |
111 ((*value >> 8) & 0x0000ff00) |
112 ((*value << 8) & 0x00ff0000) |
113 (*value << 24);
114 }
115
116
Swap(u_int64_t * value)117 static inline void Swap(u_int64_t* value) {
118 u_int32_t* value32 = reinterpret_cast<u_int32_t*>(value);
119 Swap(&value32[0]);
120 Swap(&value32[1]);
121 u_int32_t temp = value32[0];
122 value32[0] = value32[1];
123 value32[1] = temp;
124 }
125
126
127 // Given a pointer to a 128-bit int in the minidump data, set the "low"
128 // and "high" fields appropriately.
Normalize128(u_int128_t * value,bool is_big_endian)129 static void Normalize128(u_int128_t* value, bool is_big_endian) {
130 // The struct format is [high, low], so if the format is big-endian,
131 // the most significant bytes will already be in the high field.
132 if (!is_big_endian) {
133 u_int64_t temp = value->low;
134 value->low = value->high;
135 value->high = temp;
136 }
137 }
138
139 // This just swaps each int64 half of the 128-bit value.
140 // The value should also be normalized by calling Normalize128().
Swap(u_int128_t * value)141 static void Swap(u_int128_t* value) {
142 Swap(&value->low);
143 Swap(&value->high);
144 }
145
146
Swap(MDLocationDescriptor * location_descriptor)147 static inline void Swap(MDLocationDescriptor* location_descriptor) {
148 Swap(&location_descriptor->data_size);
149 Swap(&location_descriptor->rva);
150 }
151
152
Swap(MDMemoryDescriptor * memory_descriptor)153 static inline void Swap(MDMemoryDescriptor* memory_descriptor) {
154 Swap(&memory_descriptor->start_of_memory_range);
155 Swap(&memory_descriptor->memory);
156 }
157
158
Swap(MDGUID * guid)159 static inline void Swap(MDGUID* guid) {
160 Swap(&guid->data1);
161 Swap(&guid->data2);
162 Swap(&guid->data3);
163 // Don't swap guid->data4[] because it contains 8-bit quantities.
164 }
165
166
167 //
168 // Character conversion routines
169 //
170
171
172 // Standard wide-character conversion routines depend on the system's own
173 // idea of what width a wide character should be: some use 16 bits, and
174 // some use 32 bits. For the purposes of a minidump, wide strings are
175 // always represented with 16-bit UTF-16 chracters. iconv isn't available
176 // everywhere, and its interface varies where it is available. iconv also
177 // deals purely with char* pointers, so in addition to considering the swap
178 // parameter, a converter that uses iconv would also need to take the host
179 // CPU's endianness into consideration. It doesn't seems worth the trouble
180 // of making it a dependency when we don't care about anything but UTF-16.
UTF16ToUTF8(const vector<u_int16_t> & in,bool swap)181 static string* UTF16ToUTF8(const vector<u_int16_t>& in,
182 bool swap) {
183 scoped_ptr<string> out(new string());
184
185 // Set the string's initial capacity to the number of UTF-16 characters,
186 // because the UTF-8 representation will always be at least this long.
187 // If the UTF-8 representation is longer, the string will grow dynamically.
188 out->reserve(in.size());
189
190 for (vector<u_int16_t>::const_iterator iterator = in.begin();
191 iterator != in.end();
192 ++iterator) {
193 // Get a 16-bit value from the input
194 u_int16_t in_word = *iterator;
195 if (swap)
196 Swap(&in_word);
197
198 // Convert the input value (in_word) into a Unicode code point (unichar).
199 u_int32_t unichar;
200 if (in_word >= 0xdc00 && in_word <= 0xdcff) {
201 BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
202 HexString(in_word) << " without high";
203 return NULL;
204 } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
205 // High surrogate.
206 unichar = (in_word - 0xd7c0) << 10;
207 if (++iterator == in.end()) {
208 BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
209 HexString(in_word) << " at end of string";
210 return NULL;
211 }
212 u_int32_t high_word = in_word;
213 in_word = *iterator;
214 if (in_word < 0xdc00 || in_word > 0xdcff) {
215 BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
216 HexString(high_word) << " without low " <<
217 HexString(in_word);
218 return NULL;
219 }
220 unichar |= in_word & 0x03ff;
221 } else {
222 // The ordinary case, a single non-surrogate Unicode character encoded
223 // as a single 16-bit value.
224 unichar = in_word;
225 }
226
227 // Convert the Unicode code point (unichar) into its UTF-8 representation,
228 // appending it to the out string.
229 if (unichar < 0x80) {
230 (*out) += unichar;
231 } else if (unichar < 0x800) {
232 (*out) += 0xc0 | (unichar >> 6);
233 (*out) += 0x80 | (unichar & 0x3f);
234 } else if (unichar < 0x10000) {
235 (*out) += 0xe0 | (unichar >> 12);
236 (*out) += 0x80 | ((unichar >> 6) & 0x3f);
237 (*out) += 0x80 | (unichar & 0x3f);
238 } else if (unichar < 0x200000) {
239 (*out) += 0xf0 | (unichar >> 18);
240 (*out) += 0x80 | ((unichar >> 12) & 0x3f);
241 (*out) += 0x80 | ((unichar >> 6) & 0x3f);
242 (*out) += 0x80 | (unichar & 0x3f);
243 } else {
244 BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
245 HexString(unichar) << " in UTF-8";
246 return NULL;
247 }
248 }
249
250 return out.release();
251 }
252
253
254 //
255 // MinidumpObject
256 //
257
258
MinidumpObject(Minidump * minidump)259 MinidumpObject::MinidumpObject(Minidump* minidump)
260 : minidump_(minidump),
261 valid_(false) {
262 }
263
264
265 //
266 // MinidumpStream
267 //
268
269
MinidumpStream(Minidump * minidump)270 MinidumpStream::MinidumpStream(Minidump* minidump)
271 : MinidumpObject(minidump) {
272 }
273
274
275 //
276 // MinidumpContext
277 //
278
279
MinidumpContext(Minidump * minidump)280 MinidumpContext::MinidumpContext(Minidump* minidump)
281 : MinidumpStream(minidump),
282 context_flags_(0),
283 context_() {
284 }
285
286
~MinidumpContext()287 MinidumpContext::~MinidumpContext() {
288 FreeContext();
289 }
290
291
Read(u_int32_t expected_size)292 bool MinidumpContext::Read(u_int32_t expected_size) {
293 valid_ = false;
294
295 FreeContext();
296
297 // First, figure out what type of CPU this context structure is for.
298 // For some reason, the AMD64 Context doesn't have context_flags
299 // at the beginning of the structure, so special case it here.
300 if (expected_size == sizeof(MDRawContextAMD64)) {
301 BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
302
303 scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
304 if (!minidump_->ReadBytes(context_amd64.get(),
305 sizeof(MDRawContextAMD64))) {
306 BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
307 return false;
308 }
309
310 if (minidump_->swap())
311 Swap(&context_amd64->context_flags);
312
313 u_int32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
314
315 if (cpu_type != MD_CONTEXT_AMD64) {
316 //TODO: fall through to switch below?
317 // need a Tell method to be able to SeekSet back to beginning
318 // http://code.google.com/p/google-breakpad/issues/detail?id=224
319 BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
320 return false;
321 }
322
323 // Do this after reading the entire MDRawContext structure because
324 // GetSystemInfo may seek minidump to a new position.
325 if (!CheckAgainstSystemInfo(cpu_type)) {
326 BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
327 return false;
328 }
329
330 // Normalize the 128-bit types in the dump.
331 // Since this is AMD64, by definition, the values are little-endian.
332 for (unsigned int vr_index = 0;
333 vr_index < MD_CONTEXT_AMD64_VR_COUNT;
334 ++vr_index)
335 Normalize128(&context_amd64->vector_register[vr_index], false);
336
337 if (minidump_->swap()) {
338 Swap(&context_amd64->p1_home);
339 Swap(&context_amd64->p2_home);
340 Swap(&context_amd64->p3_home);
341 Swap(&context_amd64->p4_home);
342 Swap(&context_amd64->p5_home);
343 Swap(&context_amd64->p6_home);
344 // context_flags is already swapped
345 Swap(&context_amd64->mx_csr);
346 Swap(&context_amd64->cs);
347 Swap(&context_amd64->ds);
348 Swap(&context_amd64->es);
349 Swap(&context_amd64->fs);
350 Swap(&context_amd64->ss);
351 Swap(&context_amd64->eflags);
352 Swap(&context_amd64->dr0);
353 Swap(&context_amd64->dr1);
354 Swap(&context_amd64->dr2);
355 Swap(&context_amd64->dr3);
356 Swap(&context_amd64->dr6);
357 Swap(&context_amd64->dr7);
358 Swap(&context_amd64->rax);
359 Swap(&context_amd64->rcx);
360 Swap(&context_amd64->rdx);
361 Swap(&context_amd64->rbx);
362 Swap(&context_amd64->rsp);
363 Swap(&context_amd64->rbp);
364 Swap(&context_amd64->rsi);
365 Swap(&context_amd64->rdi);
366 Swap(&context_amd64->r8);
367 Swap(&context_amd64->r9);
368 Swap(&context_amd64->r10);
369 Swap(&context_amd64->r11);
370 Swap(&context_amd64->r12);
371 Swap(&context_amd64->r13);
372 Swap(&context_amd64->r14);
373 Swap(&context_amd64->r15);
374 Swap(&context_amd64->rip);
375 //FIXME: I'm not sure what actually determines
376 // which member of the union {flt_save, sse_registers}
377 // is valid. We're not currently using either,
378 // but it would be good to have them swapped properly.
379
380 for (unsigned int vr_index = 0;
381 vr_index < MD_CONTEXT_AMD64_VR_COUNT;
382 ++vr_index)
383 Swap(&context_amd64->vector_register[vr_index]);
384 Swap(&context_amd64->vector_control);
385 Swap(&context_amd64->debug_control);
386 Swap(&context_amd64->last_branch_to_rip);
387 Swap(&context_amd64->last_branch_from_rip);
388 Swap(&context_amd64->last_exception_to_rip);
389 Swap(&context_amd64->last_exception_from_rip);
390 }
391
392 context_flags_ = context_amd64->context_flags;
393
394 context_.amd64 = context_amd64.release();
395 }
396 else {
397 u_int32_t context_flags;
398 if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
399 BPLOG(ERROR) << "MinidumpContext could not read context flags";
400 return false;
401 }
402 if (minidump_->swap())
403 Swap(&context_flags);
404
405 u_int32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
406
407 // Allocate the context structure for the correct CPU and fill it. The
408 // casts are slightly unorthodox, but it seems better to do that than to
409 // maintain a separate pointer for each type of CPU context structure
410 // when only one of them will be used.
411 switch (cpu_type) {
412 case MD_CONTEXT_X86: {
413 if (expected_size != sizeof(MDRawContextX86)) {
414 BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
415 expected_size << " != " << sizeof(MDRawContextX86);
416 return false;
417 }
418
419 scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
420
421 // Set the context_flags member, which has already been read, and
422 // read the rest of the structure beginning with the first member
423 // after context_flags.
424 context_x86->context_flags = context_flags;
425
426 size_t flags_size = sizeof(context_x86->context_flags);
427 u_int8_t* context_after_flags =
428 reinterpret_cast<u_int8_t*>(context_x86.get()) + flags_size;
429 if (!minidump_->ReadBytes(context_after_flags,
430 sizeof(MDRawContextX86) - flags_size)) {
431 BPLOG(ERROR) << "MinidumpContext could not read x86 context";
432 return false;
433 }
434
435 // Do this after reading the entire MDRawContext structure because
436 // GetSystemInfo may seek minidump to a new position.
437 if (!CheckAgainstSystemInfo(cpu_type)) {
438 BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
439 return false;
440 }
441
442 if (minidump_->swap()) {
443 // context_x86->context_flags was already swapped.
444 Swap(&context_x86->dr0);
445 Swap(&context_x86->dr1);
446 Swap(&context_x86->dr2);
447 Swap(&context_x86->dr3);
448 Swap(&context_x86->dr6);
449 Swap(&context_x86->dr7);
450 Swap(&context_x86->float_save.control_word);
451 Swap(&context_x86->float_save.status_word);
452 Swap(&context_x86->float_save.tag_word);
453 Swap(&context_x86->float_save.error_offset);
454 Swap(&context_x86->float_save.error_selector);
455 Swap(&context_x86->float_save.data_offset);
456 Swap(&context_x86->float_save.data_selector);
457 // context_x86->float_save.register_area[] contains 8-bit quantities
458 // and does not need to be swapped.
459 Swap(&context_x86->float_save.cr0_npx_state);
460 Swap(&context_x86->gs);
461 Swap(&context_x86->fs);
462 Swap(&context_x86->es);
463 Swap(&context_x86->ds);
464 Swap(&context_x86->edi);
465 Swap(&context_x86->esi);
466 Swap(&context_x86->ebx);
467 Swap(&context_x86->edx);
468 Swap(&context_x86->ecx);
469 Swap(&context_x86->eax);
470 Swap(&context_x86->ebp);
471 Swap(&context_x86->eip);
472 Swap(&context_x86->cs);
473 Swap(&context_x86->eflags);
474 Swap(&context_x86->esp);
475 Swap(&context_x86->ss);
476 // context_x86->extended_registers[] contains 8-bit quantities and
477 // does not need to be swapped.
478 }
479
480 context_.x86 = context_x86.release();
481
482 break;
483 }
484
485 case MD_CONTEXT_PPC: {
486 if (expected_size != sizeof(MDRawContextPPC)) {
487 BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
488 expected_size << " != " << sizeof(MDRawContextPPC);
489 return false;
490 }
491
492 scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
493
494 // Set the context_flags member, which has already been read, and
495 // read the rest of the structure beginning with the first member
496 // after context_flags.
497 context_ppc->context_flags = context_flags;
498
499 size_t flags_size = sizeof(context_ppc->context_flags);
500 u_int8_t* context_after_flags =
501 reinterpret_cast<u_int8_t*>(context_ppc.get()) + flags_size;
502 if (!minidump_->ReadBytes(context_after_flags,
503 sizeof(MDRawContextPPC) - flags_size)) {
504 BPLOG(ERROR) << "MinidumpContext could not read ppc context";
505 return false;
506 }
507
508 // Do this after reading the entire MDRawContext structure because
509 // GetSystemInfo may seek minidump to a new position.
510 if (!CheckAgainstSystemInfo(cpu_type)) {
511 BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
512 return false;
513 }
514
515 // Normalize the 128-bit types in the dump.
516 // Since this is PowerPC, by definition, the values are big-endian.
517 for (unsigned int vr_index = 0;
518 vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
519 ++vr_index) {
520 Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
521 }
522
523 if (minidump_->swap()) {
524 // context_ppc->context_flags was already swapped.
525 Swap(&context_ppc->srr0);
526 Swap(&context_ppc->srr1);
527 for (unsigned int gpr_index = 0;
528 gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
529 ++gpr_index) {
530 Swap(&context_ppc->gpr[gpr_index]);
531 }
532 Swap(&context_ppc->cr);
533 Swap(&context_ppc->xer);
534 Swap(&context_ppc->lr);
535 Swap(&context_ppc->ctr);
536 Swap(&context_ppc->mq);
537 Swap(&context_ppc->vrsave);
538 for (unsigned int fpr_index = 0;
539 fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
540 ++fpr_index) {
541 Swap(&context_ppc->float_save.fpregs[fpr_index]);
542 }
543 // Don't swap context_ppc->float_save.fpscr_pad because it is only
544 // used for padding.
545 Swap(&context_ppc->float_save.fpscr);
546 for (unsigned int vr_index = 0;
547 vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
548 ++vr_index) {
549 Swap(&context_ppc->vector_save.save_vr[vr_index]);
550 }
551 Swap(&context_ppc->vector_save.save_vscr);
552 // Don't swap the padding fields in vector_save.
553 Swap(&context_ppc->vector_save.save_vrvalid);
554 }
555
556 context_.ppc = context_ppc.release();
557
558 break;
559 }
560
561 case MD_CONTEXT_SPARC: {
562 if (expected_size != sizeof(MDRawContextSPARC)) {
563 BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
564 expected_size << " != " << sizeof(MDRawContextSPARC);
565 return false;
566 }
567
568 scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
569
570 // Set the context_flags member, which has already been read, and
571 // read the rest of the structure beginning with the first member
572 // after context_flags.
573 context_sparc->context_flags = context_flags;
574
575 size_t flags_size = sizeof(context_sparc->context_flags);
576 u_int8_t* context_after_flags =
577 reinterpret_cast<u_int8_t*>(context_sparc.get()) + flags_size;
578 if (!minidump_->ReadBytes(context_after_flags,
579 sizeof(MDRawContextSPARC) - flags_size)) {
580 BPLOG(ERROR) << "MinidumpContext could not read sparc context";
581 return false;
582 }
583
584 // Do this after reading the entire MDRawContext structure because
585 // GetSystemInfo may seek minidump to a new position.
586 if (!CheckAgainstSystemInfo(cpu_type)) {
587 BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
588 return false;
589 }
590
591 if (minidump_->swap()) {
592 // context_sparc->context_flags was already swapped.
593 for (unsigned int gpr_index = 0;
594 gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
595 ++gpr_index) {
596 Swap(&context_sparc->g_r[gpr_index]);
597 }
598 Swap(&context_sparc->ccr);
599 Swap(&context_sparc->pc);
600 Swap(&context_sparc->npc);
601 Swap(&context_sparc->y);
602 Swap(&context_sparc->asi);
603 Swap(&context_sparc->fprs);
604 for (unsigned int fpr_index = 0;
605 fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
606 ++fpr_index) {
607 Swap(&context_sparc->float_save.regs[fpr_index]);
608 }
609 Swap(&context_sparc->float_save.filler);
610 Swap(&context_sparc->float_save.fsr);
611 }
612 context_.ctx_sparc = context_sparc.release();
613
614 break;
615 }
616
617 default: {
618 // Unknown context type
619 BPLOG(ERROR) << "MinidumpContext unknown context type " <<
620 HexString(cpu_type);
621 return false;
622 break;
623 }
624 }
625 context_flags_ = context_flags;
626 }
627
628 valid_ = true;
629 return true;
630 }
631
632
GetContextCPU() const633 u_int32_t MinidumpContext::GetContextCPU() const {
634 if (!valid_) {
635 // Don't log a message, GetContextCPU can be legitimately called with
636 // valid_ false by FreeContext, which is called by Read.
637 return 0;
638 }
639
640 return context_flags_ & MD_CONTEXT_CPU_MASK;
641 }
642
643
GetContextX86() const644 const MDRawContextX86* MinidumpContext::GetContextX86() const {
645 if (GetContextCPU() != MD_CONTEXT_X86) {
646 BPLOG(ERROR) << "MinidumpContext cannot get x86 context";
647 return NULL;
648 }
649
650 return context_.x86;
651 }
652
653
GetContextPPC() const654 const MDRawContextPPC* MinidumpContext::GetContextPPC() const {
655 if (GetContextCPU() != MD_CONTEXT_PPC) {
656 BPLOG(ERROR) << "MinidumpContext cannot get ppc context";
657 return NULL;
658 }
659
660 return context_.ppc;
661 }
662
GetContextAMD64() const663 const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const {
664 if (GetContextCPU() != MD_CONTEXT_AMD64) {
665 BPLOG(ERROR) << "MinidumpContext cannot get amd64 context";
666 return NULL;
667 }
668
669 return context_.amd64;
670 }
671
GetContextSPARC() const672 const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const {
673 if (GetContextCPU() != MD_CONTEXT_SPARC) {
674 BPLOG(ERROR) << "MinidumpContext cannot get sparc context";
675 return NULL;
676 }
677
678 return context_.ctx_sparc;
679 }
680
FreeContext()681 void MinidumpContext::FreeContext() {
682 switch (GetContextCPU()) {
683 case MD_CONTEXT_X86:
684 delete context_.x86;
685 break;
686
687 case MD_CONTEXT_PPC:
688 delete context_.ppc;
689 break;
690
691 case MD_CONTEXT_AMD64:
692 delete context_.amd64;
693 break;
694
695 case MD_CONTEXT_SPARC:
696 delete context_.ctx_sparc;
697 break;
698
699 default:
700 // There is no context record (valid_ is false) or there's a
701 // context record for an unknown CPU (shouldn't happen, only known
702 // records are stored by Read).
703 break;
704 }
705
706 context_flags_ = 0;
707 context_.base = NULL;
708 }
709
710
CheckAgainstSystemInfo(u_int32_t context_cpu_type)711 bool MinidumpContext::CheckAgainstSystemInfo(u_int32_t context_cpu_type) {
712 // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
713 // as this function just implements a sanity check.
714 MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
715 if (!system_info) {
716 BPLOG(INFO) << "MinidumpContext could not be compared against "
717 "MinidumpSystemInfo";
718 return true;
719 }
720
721 // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
722 const MDRawSystemInfo* raw_system_info = system_info->system_info();
723 if (!raw_system_info) {
724 BPLOG(INFO) << "MinidumpContext could not be compared against "
725 "MDRawSystemInfo";
726 return false;
727 }
728
729 MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
730 raw_system_info->processor_architecture);
731
732 // Compare the CPU type of the context record to the CPU type in the
733 // minidump's system info stream.
734 bool return_value = false;
735 switch (context_cpu_type) {
736 case MD_CONTEXT_X86:
737 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
738 system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
739 system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
740 return_value = true;
741 }
742 break;
743
744 case MD_CONTEXT_PPC:
745 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
746 return_value = true;
747 break;
748
749 case MD_CONTEXT_AMD64:
750 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
751 return_value = true;
752 break;
753
754 case MD_CONTEXT_SPARC:
755 if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
756 return_value = true;
757 break;
758 }
759
760 BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
761 HexString(context_cpu_type) <<
762 " wrong for MinidumpSysmtemInfo CPU " <<
763 HexString(system_info_cpu_type);
764
765 return return_value;
766 }
767
768
Print()769 void MinidumpContext::Print() {
770 if (!valid_) {
771 BPLOG(ERROR) << "MinidumpContext cannot print invalid data";
772 return;
773 }
774
775 switch (GetContextCPU()) {
776 case MD_CONTEXT_X86: {
777 const MDRawContextX86* context_x86 = GetContextX86();
778 printf("MDRawContextX86\n");
779 printf(" context_flags = 0x%x\n",
780 context_x86->context_flags);
781 printf(" dr0 = 0x%x\n", context_x86->dr0);
782 printf(" dr1 = 0x%x\n", context_x86->dr1);
783 printf(" dr2 = 0x%x\n", context_x86->dr2);
784 printf(" dr3 = 0x%x\n", context_x86->dr3);
785 printf(" dr6 = 0x%x\n", context_x86->dr6);
786 printf(" dr7 = 0x%x\n", context_x86->dr7);
787 printf(" float_save.control_word = 0x%x\n",
788 context_x86->float_save.control_word);
789 printf(" float_save.status_word = 0x%x\n",
790 context_x86->float_save.status_word);
791 printf(" float_save.tag_word = 0x%x\n",
792 context_x86->float_save.tag_word);
793 printf(" float_save.error_offset = 0x%x\n",
794 context_x86->float_save.error_offset);
795 printf(" float_save.error_selector = 0x%x\n",
796 context_x86->float_save.error_selector);
797 printf(" float_save.data_offset = 0x%x\n",
798 context_x86->float_save.data_offset);
799 printf(" float_save.data_selector = 0x%x\n",
800 context_x86->float_save.data_selector);
801 printf(" float_save.register_area[%2d] = 0x",
802 MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE);
803 for (unsigned int register_index = 0;
804 register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE;
805 ++register_index) {
806 printf("%02x", context_x86->float_save.register_area[register_index]);
807 }
808 printf("\n");
809 printf(" float_save.cr0_npx_state = 0x%x\n",
810 context_x86->float_save.cr0_npx_state);
811 printf(" gs = 0x%x\n", context_x86->gs);
812 printf(" fs = 0x%x\n", context_x86->fs);
813 printf(" es = 0x%x\n", context_x86->es);
814 printf(" ds = 0x%x\n", context_x86->ds);
815 printf(" edi = 0x%x\n", context_x86->edi);
816 printf(" esi = 0x%x\n", context_x86->esi);
817 printf(" ebx = 0x%x\n", context_x86->ebx);
818 printf(" edx = 0x%x\n", context_x86->edx);
819 printf(" ecx = 0x%x\n", context_x86->ecx);
820 printf(" eax = 0x%x\n", context_x86->eax);
821 printf(" ebp = 0x%x\n", context_x86->ebp);
822 printf(" eip = 0x%x\n", context_x86->eip);
823 printf(" cs = 0x%x\n", context_x86->cs);
824 printf(" eflags = 0x%x\n", context_x86->eflags);
825 printf(" esp = 0x%x\n", context_x86->esp);
826 printf(" ss = 0x%x\n", context_x86->ss);
827 printf(" extended_registers[%3d] = 0x",
828 MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE);
829 for (unsigned int register_index = 0;
830 register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE;
831 ++register_index) {
832 printf("%02x", context_x86->extended_registers[register_index]);
833 }
834 printf("\n\n");
835
836 break;
837 }
838
839 case MD_CONTEXT_PPC: {
840 const MDRawContextPPC* context_ppc = GetContextPPC();
841 printf("MDRawContextPPC\n");
842 printf(" context_flags = 0x%x\n",
843 context_ppc->context_flags);
844 printf(" srr0 = 0x%x\n", context_ppc->srr0);
845 printf(" srr1 = 0x%x\n", context_ppc->srr1);
846 for (unsigned int gpr_index = 0;
847 gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
848 ++gpr_index) {
849 printf(" gpr[%2d] = 0x%x\n",
850 gpr_index, context_ppc->gpr[gpr_index]);
851 }
852 printf(" cr = 0x%x\n", context_ppc->cr);
853 printf(" xer = 0x%x\n", context_ppc->xer);
854 printf(" lr = 0x%x\n", context_ppc->lr);
855 printf(" ctr = 0x%x\n", context_ppc->ctr);
856 printf(" mq = 0x%x\n", context_ppc->mq);
857 printf(" vrsave = 0x%x\n", context_ppc->vrsave);
858 for (unsigned int fpr_index = 0;
859 fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
860 ++fpr_index) {
861 printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n",
862 fpr_index, context_ppc->float_save.fpregs[fpr_index]);
863 }
864 printf(" float_save.fpscr = 0x%x\n",
865 context_ppc->float_save.fpscr);
866 // TODO(mmentovai): print the 128-bit quantities in
867 // context_ppc->vector_save. This isn't done yet because printf
868 // doesn't support 128-bit quantities, and printing them using
869 // PRIx64 as two 64-bit quantities requires knowledge of the CPU's
870 // byte ordering.
871 printf(" vector_save.save_vrvalid = 0x%x\n",
872 context_ppc->vector_save.save_vrvalid);
873 printf("\n");
874
875 break;
876 }
877
878 case MD_CONTEXT_AMD64: {
879 const MDRawContextAMD64* context_amd64 = GetContextAMD64();
880 printf("MDRawContextAMD64\n");
881 printf(" p1_home = 0x%" PRIx64 "\n",
882 context_amd64->p1_home);
883 printf(" p2_home = 0x%" PRIx64 "\n",
884 context_amd64->p2_home);
885 printf(" p3_home = 0x%" PRIx64 "\n",
886 context_amd64->p3_home);
887 printf(" p4_home = 0x%" PRIx64 "\n",
888 context_amd64->p4_home);
889 printf(" p5_home = 0x%" PRIx64 "\n",
890 context_amd64->p5_home);
891 printf(" p6_home = 0x%" PRIx64 "\n",
892 context_amd64->p6_home);
893 printf(" context_flags = 0x%x\n",
894 context_amd64->context_flags);
895 printf(" mx_csr = 0x%x\n",
896 context_amd64->mx_csr);
897 printf(" cs = 0x%x\n", context_amd64->cs);
898 printf(" ds = 0x%x\n", context_amd64->ds);
899 printf(" es = 0x%x\n", context_amd64->es);
900 printf(" fs = 0x%x\n", context_amd64->fs);
901 printf(" gs = 0x%x\n", context_amd64->gs);
902 printf(" ss = 0x%x\n", context_amd64->ss);
903 printf(" eflags = 0x%x\n", context_amd64->eflags);
904 printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0);
905 printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1);
906 printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2);
907 printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3);
908 printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6);
909 printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7);
910 printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax);
911 printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx);
912 printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx);
913 printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx);
914 printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp);
915 printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp);
916 printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi);
917 printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi);
918 printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8);
919 printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9);
920 printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10);
921 printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11);
922 printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12);
923 printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13);
924 printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14);
925 printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15);
926 printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip);
927 //TODO: print xmm, vector, debug registers
928 printf("\n");
929 break;
930 }
931
932 case MD_CONTEXT_SPARC: {
933 const MDRawContextSPARC* context_sparc = GetContextSPARC();
934 printf("MDRawContextSPARC\n");
935 printf(" context_flags = 0x%x\n",
936 context_sparc->context_flags);
937 for (unsigned int g_r_index = 0;
938 g_r_index < MD_CONTEXT_SPARC_GPR_COUNT;
939 ++g_r_index) {
940 printf(" g_r[%2d] = 0x%" PRIx64 "\n",
941 g_r_index, context_sparc->g_r[g_r_index]);
942 }
943 printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr);
944 printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc);
945 printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc);
946 printf(" y = 0x%" PRIx64 "\n", context_sparc->y);
947 printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi);
948 printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs);
949
950 for (unsigned int fpr_index = 0;
951 fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
952 ++fpr_index) {
953 printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n",
954 fpr_index, context_sparc->float_save.regs[fpr_index]);
955 }
956 printf(" float_save.filler = 0x%" PRIx64 "\n",
957 context_sparc->float_save.filler);
958 printf(" float_save.fsr = 0x%" PRIx64 "\n",
959 context_sparc->float_save.fsr);
960 break;
961 }
962
963 default: {
964 break;
965 }
966 }
967 }
968
969
970 //
971 // MinidumpMemoryRegion
972 //
973
974
975 u_int32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB
976
977
MinidumpMemoryRegion(Minidump * minidump)978 MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
979 : MinidumpObject(minidump),
980 descriptor_(NULL),
981 memory_(NULL) {
982 }
983
984
~MinidumpMemoryRegion()985 MinidumpMemoryRegion::~MinidumpMemoryRegion() {
986 delete memory_;
987 }
988
989
SetDescriptor(MDMemoryDescriptor * descriptor)990 void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
991 descriptor_ = descriptor;
992 valid_ = descriptor &&
993 descriptor_->memory.data_size <=
994 numeric_limits<uint64_t>::max() -
995 descriptor_->start_of_memory_range;
996 }
997
998
GetMemory()999 const u_int8_t* MinidumpMemoryRegion::GetMemory() {
1000 if (!valid_) {
1001 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
1002 return NULL;
1003 }
1004
1005 if (!memory_) {
1006 if (descriptor_->memory.data_size == 0) {
1007 BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
1008 return NULL;
1009 }
1010
1011 if (!minidump_->SeekSet(descriptor_->memory.rva)) {
1012 BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
1013 return NULL;
1014 }
1015
1016 if (descriptor_->memory.data_size > max_bytes_) {
1017 BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
1018 descriptor_->memory.data_size << " exceeds maximum " <<
1019 max_bytes_;
1020 return NULL;
1021 }
1022
1023 scoped_ptr< vector<u_int8_t> > memory(
1024 new vector<u_int8_t>(descriptor_->memory.data_size));
1025
1026 if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
1027 BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
1028 return NULL;
1029 }
1030
1031 memory_ = memory.release();
1032 }
1033
1034 return &(*memory_)[0];
1035 }
1036
1037
GetBase()1038 u_int64_t MinidumpMemoryRegion::GetBase() {
1039 if (!valid_) {
1040 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
1041 return static_cast<u_int64_t>(-1);
1042 }
1043
1044 return descriptor_->start_of_memory_range;
1045 }
1046
1047
GetSize()1048 u_int32_t MinidumpMemoryRegion::GetSize() {
1049 if (!valid_) {
1050 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
1051 return 0;
1052 }
1053
1054 return descriptor_->memory.data_size;
1055 }
1056
1057
FreeMemory()1058 void MinidumpMemoryRegion::FreeMemory() {
1059 delete memory_;
1060 memory_ = NULL;
1061 }
1062
1063
1064 template<typename T>
GetMemoryAtAddressInternal(u_int64_t address,T * value)1065 bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(u_int64_t address,
1066 T* value) {
1067 BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
1068 "requires |value|";
1069 assert(value);
1070 *value = 0;
1071
1072 if (!valid_) {
1073 BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
1074 "GetMemoryAtAddressInternal";
1075 return false;
1076 }
1077
1078 if (address < descriptor_->start_of_memory_range ||
1079 sizeof(T) > numeric_limits<u_int64_t>::max() - address ||
1080 address + sizeof(T) > descriptor_->start_of_memory_range +
1081 descriptor_->memory.data_size) {
1082 BPLOG(ERROR) << "MinidumpMemoryRegion request out of range: " <<
1083 HexString(address) << "+" << sizeof(T) << "/" <<
1084 HexString(descriptor_->start_of_memory_range) << "+" <<
1085 HexString(descriptor_->memory.data_size);
1086 return false;
1087 }
1088
1089 const u_int8_t* memory = GetMemory();
1090 if (!memory) {
1091 // GetMemory already logged a perfectly good message.
1092 return false;
1093 }
1094
1095 // If the CPU requires memory accesses to be aligned, this can crash.
1096 // x86 and ppc are able to cope, though.
1097 *value = *reinterpret_cast<const T*>(
1098 &memory[address - descriptor_->start_of_memory_range]);
1099
1100 if (minidump_->swap())
1101 Swap(value);
1102
1103 return true;
1104 }
1105
1106
GetMemoryAtAddress(u_int64_t address,u_int8_t * value)1107 bool MinidumpMemoryRegion::GetMemoryAtAddress(u_int64_t address,
1108 u_int8_t* value) {
1109 return GetMemoryAtAddressInternal(address, value);
1110 }
1111
1112
GetMemoryAtAddress(u_int64_t address,u_int16_t * value)1113 bool MinidumpMemoryRegion::GetMemoryAtAddress(u_int64_t address,
1114 u_int16_t* value) {
1115 return GetMemoryAtAddressInternal(address, value);
1116 }
1117
1118
GetMemoryAtAddress(u_int64_t address,u_int32_t * value)1119 bool MinidumpMemoryRegion::GetMemoryAtAddress(u_int64_t address,
1120 u_int32_t* value) {
1121 return GetMemoryAtAddressInternal(address, value);
1122 }
1123
1124
GetMemoryAtAddress(u_int64_t address,u_int64_t * value)1125 bool MinidumpMemoryRegion::GetMemoryAtAddress(u_int64_t address,
1126 u_int64_t* value) {
1127 return GetMemoryAtAddressInternal(address, value);
1128 }
1129
1130
Print()1131 void MinidumpMemoryRegion::Print() {
1132 if (!valid_) {
1133 BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
1134 return;
1135 }
1136
1137 const u_int8_t* memory = GetMemory();
1138 if (memory) {
1139 printf("0x");
1140 for (unsigned int byte_index = 0;
1141 byte_index < descriptor_->memory.data_size;
1142 byte_index++) {
1143 printf("%02x", memory[byte_index]);
1144 }
1145 printf("\n");
1146 } else {
1147 printf("No memory\n");
1148 }
1149 }
1150
1151
1152 //
1153 // MinidumpThread
1154 //
1155
1156
MinidumpThread(Minidump * minidump)1157 MinidumpThread::MinidumpThread(Minidump* minidump)
1158 : MinidumpObject(minidump),
1159 thread_(),
1160 memory_(NULL),
1161 context_(NULL) {
1162 }
1163
1164
~MinidumpThread()1165 MinidumpThread::~MinidumpThread() {
1166 delete memory_;
1167 delete context_;
1168 }
1169
1170
Read()1171 bool MinidumpThread::Read() {
1172 // Invalidate cached data.
1173 delete memory_;
1174 memory_ = NULL;
1175 delete context_;
1176 context_ = NULL;
1177
1178 valid_ = false;
1179
1180 if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
1181 BPLOG(ERROR) << "MinidumpThread cannot read thread";
1182 return false;
1183 }
1184
1185 if (minidump_->swap()) {
1186 Swap(&thread_.thread_id);
1187 Swap(&thread_.suspend_count);
1188 Swap(&thread_.priority_class);
1189 Swap(&thread_.priority);
1190 Swap(&thread_.teb);
1191 Swap(&thread_.stack);
1192 Swap(&thread_.thread_context);
1193 }
1194
1195 // Check for base + size overflow or undersize.
1196 if (thread_.stack.memory.data_size == 0 ||
1197 thread_.stack.memory.data_size > numeric_limits<u_int64_t>::max() -
1198 thread_.stack.start_of_memory_range) {
1199 BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
1200 HexString(thread_.stack.start_of_memory_range) << "+" <<
1201 HexString(thread_.stack.memory.data_size);
1202 return false;
1203 }
1204
1205 memory_ = new MinidumpMemoryRegion(minidump_);
1206 memory_->SetDescriptor(&thread_.stack);
1207
1208 valid_ = true;
1209 return true;
1210 }
1211
1212
GetMemory()1213 MinidumpMemoryRegion* MinidumpThread::GetMemory() {
1214 if (!valid_) {
1215 BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
1216 return NULL;
1217 }
1218
1219 return memory_;
1220 }
1221
1222
GetContext()1223 MinidumpContext* MinidumpThread::GetContext() {
1224 if (!valid_) {
1225 BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
1226 return NULL;
1227 }
1228
1229 if (!context_) {
1230 if (!minidump_->SeekSet(thread_.thread_context.rva)) {
1231 BPLOG(ERROR) << "MinidumpThread cannot seek to context";
1232 return NULL;
1233 }
1234
1235 scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
1236
1237 if (!context->Read(thread_.thread_context.data_size)) {
1238 BPLOG(ERROR) << "MinidumpThread cannot read context";
1239 return NULL;
1240 }
1241
1242 context_ = context.release();
1243 }
1244
1245 return context_;
1246 }
1247
1248
GetThreadID(u_int32_t * thread_id) const1249 bool MinidumpThread::GetThreadID(u_int32_t *thread_id) const {
1250 BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
1251 "|thread_id|";
1252 assert(thread_id);
1253 *thread_id = 0;
1254
1255 if (!valid_) {
1256 BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
1257 return false;
1258 }
1259
1260 *thread_id = thread_.thread_id;
1261 return true;
1262 }
1263
1264
Print()1265 void MinidumpThread::Print() {
1266 if (!valid_) {
1267 BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
1268 return;
1269 }
1270
1271 printf("MDRawThread\n");
1272 printf(" thread_id = 0x%x\n", thread_.thread_id);
1273 printf(" suspend_count = %d\n", thread_.suspend_count);
1274 printf(" priority_class = 0x%x\n", thread_.priority_class);
1275 printf(" priority = 0x%x\n", thread_.priority);
1276 printf(" teb = 0x%" PRIx64 "\n", thread_.teb);
1277 printf(" stack.start_of_memory_range = 0x%" PRIx64 "\n",
1278 thread_.stack.start_of_memory_range);
1279 printf(" stack.memory.data_size = 0x%x\n",
1280 thread_.stack.memory.data_size);
1281 printf(" stack.memory.rva = 0x%x\n", thread_.stack.memory.rva);
1282 printf(" thread_context.data_size = 0x%x\n",
1283 thread_.thread_context.data_size);
1284 printf(" thread_context.rva = 0x%x\n",
1285 thread_.thread_context.rva);
1286
1287 MinidumpContext* context = GetContext();
1288 if (context) {
1289 printf("\n");
1290 context->Print();
1291 } else {
1292 printf(" (no context)\n");
1293 printf("\n");
1294 }
1295
1296 MinidumpMemoryRegion* memory = GetMemory();
1297 if (memory) {
1298 printf("Stack\n");
1299 memory->Print();
1300 } else {
1301 printf("No stack\n");
1302 }
1303 printf("\n");
1304 }
1305
1306
1307 //
1308 // MinidumpThreadList
1309 //
1310
1311
1312 u_int32_t MinidumpThreadList::max_threads_ = 4096;
1313
1314
MinidumpThreadList(Minidump * minidump)1315 MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
1316 : MinidumpStream(minidump),
1317 id_to_thread_map_(),
1318 threads_(NULL),
1319 thread_count_(0) {
1320 }
1321
1322
~MinidumpThreadList()1323 MinidumpThreadList::~MinidumpThreadList() {
1324 delete threads_;
1325 }
1326
1327
Read(u_int32_t expected_size)1328 bool MinidumpThreadList::Read(u_int32_t expected_size) {
1329 // Invalidate cached data.
1330 id_to_thread_map_.clear();
1331 delete threads_;
1332 threads_ = NULL;
1333 thread_count_ = 0;
1334
1335 valid_ = false;
1336
1337 u_int32_t thread_count;
1338 if (expected_size < sizeof(thread_count)) {
1339 BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
1340 expected_size << " < " << sizeof(thread_count);
1341 return false;
1342 }
1343 if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
1344 BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
1345 return false;
1346 }
1347
1348 if (minidump_->swap())
1349 Swap(&thread_count);
1350
1351 if (thread_count > numeric_limits<u_int32_t>::max() / sizeof(MDRawThread)) {
1352 BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
1353 " would cause multiplication overflow";
1354 return false;
1355 }
1356
1357 if (expected_size != sizeof(thread_count) +
1358 thread_count * sizeof(MDRawThread)) {
1359 // may be padded with 4 bytes on 64bit ABIs for alignment
1360 if (expected_size == sizeof(thread_count) + 4 +
1361 thread_count * sizeof(MDRawThread)) {
1362 u_int32_t useless;
1363 if (!minidump_->ReadBytes(&useless, 4)) {
1364 BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes";
1365 return false;
1366 }
1367 } else {
1368 BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
1369 " != " << sizeof(thread_count) +
1370 thread_count * sizeof(MDRawThread);
1371 return false;
1372 }
1373 }
1374
1375
1376 if (thread_count > max_threads_) {
1377 BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
1378 " exceeds maximum " << max_threads_;
1379 return false;
1380 }
1381
1382 if (thread_count != 0) {
1383 scoped_ptr<MinidumpThreads> threads(
1384 new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
1385
1386 for (unsigned int thread_index = 0;
1387 thread_index < thread_count;
1388 ++thread_index) {
1389 MinidumpThread* thread = &(*threads)[thread_index];
1390
1391 // Assume that the file offset is correct after the last read.
1392 if (!thread->Read()) {
1393 BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
1394 thread_index << "/" << thread_count;
1395 return false;
1396 }
1397
1398 u_int32_t thread_id;
1399 if (!thread->GetThreadID(&thread_id)) {
1400 BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
1401 thread_index << "/" << thread_count;
1402 return false;
1403 }
1404
1405 if (GetThreadByID(thread_id)) {
1406 // Another thread with this ID is already in the list. Data error.
1407 BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
1408 HexString(thread_id) << " at thread " <<
1409 thread_index << "/" << thread_count;
1410 return false;
1411 }
1412 id_to_thread_map_[thread_id] = thread;
1413 }
1414
1415 threads_ = threads.release();
1416 }
1417
1418 thread_count_ = thread_count;
1419
1420 valid_ = true;
1421 return true;
1422 }
1423
1424
GetThreadAtIndex(unsigned int index) const1425 MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
1426 const {
1427 if (!valid_) {
1428 BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
1429 return NULL;
1430 }
1431
1432 if (index >= thread_count_) {
1433 BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
1434 index << "/" << thread_count_;
1435 return NULL;
1436 }
1437
1438 return &(*threads_)[index];
1439 }
1440
1441
GetThreadByID(u_int32_t thread_id)1442 MinidumpThread* MinidumpThreadList::GetThreadByID(u_int32_t thread_id) {
1443 // Don't check valid_. Read calls this method before everything is
1444 // validated. It is safe to not check valid_ here.
1445 return id_to_thread_map_[thread_id];
1446 }
1447
1448
Print()1449 void MinidumpThreadList::Print() {
1450 if (!valid_) {
1451 BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
1452 return;
1453 }
1454
1455 printf("MinidumpThreadList\n");
1456 printf(" thread_count = %d\n", thread_count_);
1457 printf("\n");
1458
1459 for (unsigned int thread_index = 0;
1460 thread_index < thread_count_;
1461 ++thread_index) {
1462 printf("thread[%d]\n", thread_index);
1463
1464 (*threads_)[thread_index].Print();
1465 }
1466 }
1467
1468
1469 //
1470 // MinidumpModule
1471 //
1472
1473
1474 u_int32_t MinidumpModule::max_cv_bytes_ = 32768;
1475 u_int32_t MinidumpModule::max_misc_bytes_ = 32768;
1476
1477
MinidumpModule(Minidump * minidump)1478 MinidumpModule::MinidumpModule(Minidump* minidump)
1479 : MinidumpObject(minidump),
1480 module_valid_(false),
1481 has_debug_info_(false),
1482 module_(),
1483 name_(NULL),
1484 cv_record_(NULL),
1485 cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
1486 misc_record_(NULL) {
1487 }
1488
1489
~MinidumpModule()1490 MinidumpModule::~MinidumpModule() {
1491 delete name_;
1492 delete cv_record_;
1493 delete misc_record_;
1494 }
1495
1496
Read()1497 bool MinidumpModule::Read() {
1498 // Invalidate cached data.
1499 delete name_;
1500 name_ = NULL;
1501 delete cv_record_;
1502 cv_record_ = NULL;
1503 cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
1504 delete misc_record_;
1505 misc_record_ = NULL;
1506
1507 module_valid_ = false;
1508 has_debug_info_ = false;
1509 valid_ = false;
1510
1511 if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
1512 BPLOG(ERROR) << "MinidumpModule cannot read module";
1513 return false;
1514 }
1515
1516 if (minidump_->swap()) {
1517 Swap(&module_.base_of_image);
1518 Swap(&module_.size_of_image);
1519 Swap(&module_.checksum);
1520 Swap(&module_.time_date_stamp);
1521 Swap(&module_.module_name_rva);
1522 Swap(&module_.version_info.signature);
1523 Swap(&module_.version_info.struct_version);
1524 Swap(&module_.version_info.file_version_hi);
1525 Swap(&module_.version_info.file_version_lo);
1526 Swap(&module_.version_info.product_version_hi);
1527 Swap(&module_.version_info.product_version_lo);
1528 Swap(&module_.version_info.file_flags_mask);
1529 Swap(&module_.version_info.file_flags);
1530 Swap(&module_.version_info.file_os);
1531 Swap(&module_.version_info.file_type);
1532 Swap(&module_.version_info.file_subtype);
1533 Swap(&module_.version_info.file_date_hi);
1534 Swap(&module_.version_info.file_date_lo);
1535 Swap(&module_.cv_record);
1536 Swap(&module_.misc_record);
1537 // Don't swap reserved fields because their contents are unknown (as
1538 // are their proper widths).
1539 }
1540
1541 // Check for base + size overflow or undersize.
1542 if (module_.size_of_image == 0 ||
1543 module_.size_of_image >
1544 numeric_limits<u_int64_t>::max() - module_.base_of_image) {
1545 BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
1546 HexString(module_.base_of_image) << "+" <<
1547 HexString(module_.size_of_image);
1548 return false;
1549 }
1550
1551 module_valid_ = true;
1552 return true;
1553 }
1554
1555
ReadAuxiliaryData()1556 bool MinidumpModule::ReadAuxiliaryData() {
1557 if (!module_valid_) {
1558 BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
1559 return false;
1560 }
1561
1562 // Each module must have a name.
1563 name_ = minidump_->ReadString(module_.module_name_rva);
1564 if (!name_) {
1565 BPLOG(ERROR) << "MinidumpModule could not read name";
1566 return false;
1567 }
1568
1569 // At this point, we have enough info for the module to be valid.
1570 valid_ = true;
1571
1572 // CodeView and miscellaneous debug records are only required if the
1573 // module indicates that they exist.
1574 if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
1575 BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
1576 "but one was expected";
1577 return false;
1578 }
1579
1580 if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
1581 BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
1582 "but one was expected";
1583 return false;
1584 }
1585
1586 has_debug_info_ = true;
1587 return true;
1588 }
1589
1590
code_file() const1591 string MinidumpModule::code_file() const {
1592 if (!valid_) {
1593 BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
1594 return "";
1595 }
1596
1597 return *name_;
1598 }
1599
1600
code_identifier() const1601 string MinidumpModule::code_identifier() const {
1602 if (!valid_) {
1603 BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
1604 return "";
1605 }
1606
1607 if (!has_debug_info_)
1608 return "";
1609
1610 MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
1611 if (!minidump_system_info) {
1612 BPLOG(ERROR) << "MinidumpModule code_identifier requires "
1613 "MinidumpSystemInfo";
1614 return "";
1615 }
1616
1617 const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
1618 if (!raw_system_info) {
1619 BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
1620 return "";
1621 }
1622
1623 string identifier;
1624
1625 switch (raw_system_info->platform_id) {
1626 case MD_OS_WIN32_NT:
1627 case MD_OS_WIN32_WINDOWS: {
1628 // Use the same format that the MS symbol server uses in filesystem
1629 // hierarchies.
1630 char identifier_string[17];
1631 snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
1632 module_.time_date_stamp, module_.size_of_image);
1633 identifier = identifier_string;
1634 break;
1635 }
1636
1637 case MD_OS_MAC_OS_X:
1638 case MD_OS_SOLARIS:
1639 case MD_OS_LINUX: {
1640 // TODO(mmentovai): support uuid extension if present, otherwise fall
1641 // back to version (from LC_ID_DYLIB?), otherwise fall back to something
1642 // else.
1643 identifier = "id";
1644 break;
1645 }
1646
1647 default: {
1648 // Without knowing what OS generated the dump, we can't generate a good
1649 // identifier. Return an empty string, signalling failure.
1650 BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
1651 "found " << HexString(raw_system_info->platform_id);
1652 break;
1653 }
1654 }
1655
1656 return identifier;
1657 }
1658
1659
debug_file() const1660 string MinidumpModule::debug_file() const {
1661 if (!valid_) {
1662 BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
1663 return "";
1664 }
1665
1666 if (!has_debug_info_)
1667 return "";
1668
1669 string file;
1670 // Prefer the CodeView record if present.
1671 if (cv_record_) {
1672 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
1673 // It's actually an MDCVInfoPDB70 structure.
1674 const MDCVInfoPDB70* cv_record_70 =
1675 reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
1676 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
1677
1678 // GetCVRecord guarantees pdb_file_name is null-terminated.
1679 file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
1680 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
1681 // It's actually an MDCVInfoPDB20 structure.
1682 const MDCVInfoPDB20* cv_record_20 =
1683 reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
1684 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
1685
1686 // GetCVRecord guarantees pdb_file_name is null-terminated.
1687 file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
1688 }
1689
1690 // If there's a CodeView record but it doesn't match a known signature,
1691 // try the miscellaneous record.
1692 }
1693
1694 if (file.empty()) {
1695 // No usable CodeView record. Try the miscellaneous debug record.
1696 if (misc_record_) {
1697 const MDImageDebugMisc* misc_record =
1698 reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]);
1699 if (!misc_record->unicode) {
1700 // If it's not Unicode, just stuff it into the string. It's unclear
1701 // if misc_record->data is 0-terminated, so use an explicit size.
1702 file = string(
1703 reinterpret_cast<const char*>(misc_record->data),
1704 module_.misc_record.data_size - MDImageDebugMisc_minsize);
1705 } else {
1706 // There's a misc_record but it encodes the debug filename in UTF-16.
1707 // (Actually, because miscellaneous records are so old, it's probably
1708 // UCS-2.) Convert it to UTF-8 for congruity with the other strings
1709 // that this method (and all other methods in the Minidump family)
1710 // return.
1711
1712 unsigned int bytes =
1713 module_.misc_record.data_size - MDImageDebugMisc_minsize;
1714 if (bytes % 2 == 0) {
1715 unsigned int utf16_words = bytes / 2;
1716
1717 // UTF16ToUTF8 expects a vector<u_int16_t>, so create a temporary one
1718 // and copy the UTF-16 data into it.
1719 vector<u_int16_t> string_utf16(utf16_words);
1720 if (utf16_words)
1721 memcpy(&string_utf16[0], &misc_record->data, bytes);
1722
1723 // GetMiscRecord already byte-swapped the data[] field if it contains
1724 // UTF-16, so pass false as the swap argument.
1725 scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
1726 file = *new_file;
1727 }
1728 }
1729 }
1730 }
1731
1732 BPLOG_IF(ERROR, file.empty()) << "MinidumpModule could not determine "
1733 "debug_file for " << *name_;
1734
1735 return file;
1736 }
1737
1738
debug_identifier() const1739 string MinidumpModule::debug_identifier() const {
1740 if (!valid_) {
1741 BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
1742 return "";
1743 }
1744
1745 if (!has_debug_info_)
1746 return "";
1747
1748 string identifier;
1749
1750 // Use the CodeView record if present.
1751 if (cv_record_) {
1752 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
1753 // It's actually an MDCVInfoPDB70 structure.
1754 const MDCVInfoPDB70* cv_record_70 =
1755 reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
1756 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
1757
1758 // Use the same format that the MS symbol server uses in filesystem
1759 // hierarchies.
1760 char identifier_string[41];
1761 snprintf(identifier_string, sizeof(identifier_string),
1762 "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
1763 cv_record_70->signature.data1,
1764 cv_record_70->signature.data2,
1765 cv_record_70->signature.data3,
1766 cv_record_70->signature.data4[0],
1767 cv_record_70->signature.data4[1],
1768 cv_record_70->signature.data4[2],
1769 cv_record_70->signature.data4[3],
1770 cv_record_70->signature.data4[4],
1771 cv_record_70->signature.data4[5],
1772 cv_record_70->signature.data4[6],
1773 cv_record_70->signature.data4[7],
1774 cv_record_70->age);
1775 identifier = identifier_string;
1776 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
1777 // It's actually an MDCVInfoPDB20 structure.
1778 const MDCVInfoPDB20* cv_record_20 =
1779 reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
1780 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
1781
1782 // Use the same format that the MS symbol server uses in filesystem
1783 // hierarchies.
1784 char identifier_string[17];
1785 snprintf(identifier_string, sizeof(identifier_string),
1786 "%08X%x", cv_record_20->signature, cv_record_20->age);
1787 identifier = identifier_string;
1788 }
1789 }
1790
1791 // TODO(mmentovai): if there's no usable CodeView record, there might be a
1792 // miscellaneous debug record. It only carries a filename, though, and no
1793 // identifier. I'm not sure what the right thing to do for the identifier
1794 // is in that case, but I don't expect to find many modules without a
1795 // CodeView record (or some other Breakpad extension structure in place of
1796 // a CodeView record). Treat it as an error (empty identifier) for now.
1797
1798 // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
1799
1800 BPLOG_IF(ERROR, identifier.empty()) << "MinidumpModule could not determine "
1801 "debug_identifier for " << *name_;
1802
1803 return identifier;
1804 }
1805
1806
version() const1807 string MinidumpModule::version() const {
1808 if (!valid_) {
1809 BPLOG(ERROR) << "Invalid MinidumpModule for version";
1810 return "";
1811 }
1812
1813 string version;
1814
1815 if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
1816 module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
1817 char version_string[24];
1818 snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
1819 module_.version_info.file_version_hi >> 16,
1820 module_.version_info.file_version_hi & 0xffff,
1821 module_.version_info.file_version_lo >> 16,
1822 module_.version_info.file_version_lo & 0xffff);
1823 version = version_string;
1824 }
1825
1826 // TODO(mmentovai): possibly support other struct types in place of
1827 // the one used with MD_VSFIXEDFILEINFO_SIGNATURE. We can possibly use
1828 // a different structure that better represents versioning facilities on
1829 // Mac OS X and Linux, instead of forcing them to adhere to the dotted
1830 // quad of 16-bit ints that Windows uses.
1831
1832 BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
1833 "version for " << *name_;
1834
1835 return version;
1836 }
1837
1838
Copy() const1839 const CodeModule* MinidumpModule::Copy() const {
1840 return new BasicCodeModule(this);
1841 }
1842
1843
GetCVRecord(u_int32_t * size)1844 const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) {
1845 if (!module_valid_) {
1846 BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
1847 return NULL;
1848 }
1849
1850 if (!cv_record_) {
1851 // This just guards against 0-sized CodeView records; more specific checks
1852 // are used when the signature is checked against various structure types.
1853 if (module_.cv_record.data_size == 0) {
1854 return NULL;
1855 }
1856
1857 if (!minidump_->SeekSet(module_.cv_record.rva)) {
1858 BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
1859 return NULL;
1860 }
1861
1862 if (module_.cv_record.data_size > max_cv_bytes_) {
1863 BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
1864 module_.cv_record.data_size << " exceeds maximum " <<
1865 max_cv_bytes_;
1866 return NULL;
1867 }
1868
1869 // Allocating something that will be accessed as MDCVInfoPDB70 or
1870 // MDCVInfoPDB20 but is allocated as u_int8_t[] can cause alignment
1871 // problems. x86 and ppc are able to cope, though. This allocation
1872 // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
1873 // variable-sized due to their pdb_file_name fields; these structures
1874 // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
1875 // them as such would result in incomplete structures or overruns.
1876 scoped_ptr< vector<u_int8_t> > cv_record(
1877 new vector<u_int8_t>(module_.cv_record.data_size));
1878
1879 if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
1880 BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
1881 return NULL;
1882 }
1883
1884 u_int32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
1885 if (module_.cv_record.data_size > sizeof(signature)) {
1886 MDCVInfoPDB70* cv_record_signature =
1887 reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
1888 signature = cv_record_signature->cv_signature;
1889 if (minidump_->swap())
1890 Swap(&signature);
1891 }
1892
1893 if (signature == MD_CVINFOPDB70_SIGNATURE) {
1894 // Now that the structure type is known, recheck the size.
1895 if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) {
1896 BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
1897 MDCVInfoPDB70_minsize << " > " <<
1898 module_.cv_record.data_size;
1899 return NULL;
1900 }
1901
1902 if (minidump_->swap()) {
1903 MDCVInfoPDB70* cv_record_70 =
1904 reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
1905 Swap(&cv_record_70->cv_signature);
1906 Swap(&cv_record_70->signature);
1907 Swap(&cv_record_70->age);
1908 // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
1909 // quantities. (It's a path, is it UTF-8?)
1910 }
1911
1912 // The last field of either structure is null-terminated 8-bit character
1913 // data. Ensure that it's null-terminated.
1914 if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
1915 BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
1916 "0-terminated";
1917 return NULL;
1918 }
1919 } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
1920 // Now that the structure type is known, recheck the size.
1921 if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) {
1922 BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
1923 MDCVInfoPDB20_minsize << " > " <<
1924 module_.cv_record.data_size;
1925 return NULL;
1926 }
1927 if (minidump_->swap()) {
1928 MDCVInfoPDB20* cv_record_20 =
1929 reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
1930 Swap(&cv_record_20->cv_header.signature);
1931 Swap(&cv_record_20->cv_header.offset);
1932 Swap(&cv_record_20->signature);
1933 Swap(&cv_record_20->age);
1934 // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
1935 // quantities. (It's a path, is it UTF-8?)
1936 }
1937
1938 // The last field of either structure is null-terminated 8-bit character
1939 // data. Ensure that it's null-terminated.
1940 if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
1941 BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
1942 "0-terminated";
1943 return NULL;
1944 }
1945 }
1946
1947 // If the signature doesn't match something above, it's not something
1948 // that Breakpad can presently handle directly. Because some modules in
1949 // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
1950 // don't bail out here - allow the data to be returned to the user,
1951 // although byte-swapping can't be done.
1952
1953 // Store the vector type because that's how storage was allocated, but
1954 // return it casted to u_int8_t*.
1955 cv_record_ = cv_record.release();
1956 cv_record_signature_ = signature;
1957 }
1958
1959 if (size)
1960 *size = module_.cv_record.data_size;
1961
1962 return &(*cv_record_)[0];
1963 }
1964
1965
GetMiscRecord(u_int32_t * size)1966 const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) {
1967 if (!module_valid_) {
1968 BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
1969 return NULL;
1970 }
1971
1972 if (!misc_record_) {
1973 if (module_.misc_record.data_size == 0) {
1974 return NULL;
1975 }
1976
1977 if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
1978 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
1979 "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
1980 module_.misc_record.data_size;
1981 return NULL;
1982 }
1983
1984 if (!minidump_->SeekSet(module_.misc_record.rva)) {
1985 BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
1986 "debugging record";
1987 return NULL;
1988 }
1989
1990 if (module_.misc_record.data_size > max_misc_bytes_) {
1991 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
1992 module_.misc_record.data_size << " exceeds maximum " <<
1993 max_misc_bytes_;
1994 return NULL;
1995 }
1996
1997 // Allocating something that will be accessed as MDImageDebugMisc but
1998 // is allocated as u_int8_t[] can cause alignment problems. x86 and
1999 // ppc are able to cope, though. This allocation style is needed
2000 // because the MDImageDebugMisc is variable-sized due to its data field;
2001 // this structure is not MDImageDebugMisc_minsize and treating it as such
2002 // would result in an incomplete structure or an overrun.
2003 scoped_ptr< vector<u_int8_t> > misc_record_mem(
2004 new vector<u_int8_t>(module_.misc_record.data_size));
2005 MDImageDebugMisc* misc_record =
2006 reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
2007
2008 if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
2009 BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
2010 "record";
2011 return NULL;
2012 }
2013
2014 if (minidump_->swap()) {
2015 Swap(&misc_record->data_type);
2016 Swap(&misc_record->length);
2017 // Don't swap misc_record.unicode because it's an 8-bit quantity.
2018 // Don't swap the reserved fields for the same reason, and because
2019 // they don't contain any valid data.
2020 if (misc_record->unicode) {
2021 // There is a potential alignment problem, but shouldn't be a problem
2022 // in practice due to the layout of MDImageDebugMisc.
2023 u_int16_t* data16 = reinterpret_cast<u_int16_t*>(&(misc_record->data));
2024 unsigned int dataBytes = module_.misc_record.data_size -
2025 MDImageDebugMisc_minsize;
2026 unsigned int dataLength = dataBytes / 2;
2027 for (unsigned int characterIndex = 0;
2028 characterIndex < dataLength;
2029 ++characterIndex) {
2030 Swap(&data16[characterIndex]);
2031 }
2032 }
2033 }
2034
2035 if (module_.misc_record.data_size != misc_record->length) {
2036 BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
2037 "size mismatch, " << module_.misc_record.data_size <<
2038 " != " << misc_record->length;
2039 return NULL;
2040 }
2041
2042 // Store the vector type because that's how storage was allocated, but
2043 // return it casted to MDImageDebugMisc*.
2044 misc_record_ = misc_record_mem.release();
2045 }
2046
2047 if (size)
2048 *size = module_.misc_record.data_size;
2049
2050 return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
2051 }
2052
2053
Print()2054 void MinidumpModule::Print() {
2055 if (!valid_) {
2056 BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
2057 return;
2058 }
2059
2060 printf("MDRawModule\n");
2061 printf(" base_of_image = 0x%" PRIx64 "\n",
2062 module_.base_of_image);
2063 printf(" size_of_image = 0x%x\n",
2064 module_.size_of_image);
2065 printf(" checksum = 0x%x\n",
2066 module_.checksum);
2067 printf(" time_date_stamp = 0x%x\n",
2068 module_.time_date_stamp);
2069 printf(" module_name_rva = 0x%x\n",
2070 module_.module_name_rva);
2071 printf(" version_info.signature = 0x%x\n",
2072 module_.version_info.signature);
2073 printf(" version_info.struct_version = 0x%x\n",
2074 module_.version_info.struct_version);
2075 printf(" version_info.file_version = 0x%x:0x%x\n",
2076 module_.version_info.file_version_hi,
2077 module_.version_info.file_version_lo);
2078 printf(" version_info.product_version = 0x%x:0x%x\n",
2079 module_.version_info.product_version_hi,
2080 module_.version_info.product_version_lo);
2081 printf(" version_info.file_flags_mask = 0x%x\n",
2082 module_.version_info.file_flags_mask);
2083 printf(" version_info.file_flags = 0x%x\n",
2084 module_.version_info.file_flags);
2085 printf(" version_info.file_os = 0x%x\n",
2086 module_.version_info.file_os);
2087 printf(" version_info.file_type = 0x%x\n",
2088 module_.version_info.file_type);
2089 printf(" version_info.file_subtype = 0x%x\n",
2090 module_.version_info.file_subtype);
2091 printf(" version_info.file_date = 0x%x:0x%x\n",
2092 module_.version_info.file_date_hi,
2093 module_.version_info.file_date_lo);
2094 printf(" cv_record.data_size = %d\n",
2095 module_.cv_record.data_size);
2096 printf(" cv_record.rva = 0x%x\n",
2097 module_.cv_record.rva);
2098 printf(" misc_record.data_size = %d\n",
2099 module_.misc_record.data_size);
2100 printf(" misc_record.rva = 0x%x\n",
2101 module_.misc_record.rva);
2102
2103 printf(" (code_file) = \"%s\"\n", code_file().c_str());
2104 printf(" (code_identifier) = \"%s\"\n",
2105 code_identifier().c_str());
2106
2107 u_int32_t cv_record_size;
2108 const u_int8_t *cv_record = GetCVRecord(&cv_record_size);
2109 if (cv_record) {
2110 if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2111 const MDCVInfoPDB70* cv_record_70 =
2112 reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
2113 assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2114
2115 printf(" (cv_record).cv_signature = 0x%x\n",
2116 cv_record_70->cv_signature);
2117 printf(" (cv_record).signature = %08x-%04x-%04x-%02x%02x-",
2118 cv_record_70->signature.data1,
2119 cv_record_70->signature.data2,
2120 cv_record_70->signature.data3,
2121 cv_record_70->signature.data4[0],
2122 cv_record_70->signature.data4[1]);
2123 for (unsigned int guidIndex = 2;
2124 guidIndex < 8;
2125 ++guidIndex) {
2126 printf("%02x", cv_record_70->signature.data4[guidIndex]);
2127 }
2128 printf("\n");
2129 printf(" (cv_record).age = %d\n",
2130 cv_record_70->age);
2131 printf(" (cv_record).pdb_file_name = \"%s\"\n",
2132 cv_record_70->pdb_file_name);
2133 } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2134 const MDCVInfoPDB20* cv_record_20 =
2135 reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
2136 assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2137
2138 printf(" (cv_record).cv_header.signature = 0x%x\n",
2139 cv_record_20->cv_header.signature);
2140 printf(" (cv_record).cv_header.offset = 0x%x\n",
2141 cv_record_20->cv_header.offset);
2142 printf(" (cv_record).signature = 0x%x\n",
2143 cv_record_20->signature);
2144 printf(" (cv_record).age = %d\n",
2145 cv_record_20->age);
2146 printf(" (cv_record).pdb_file_name = \"%s\"\n",
2147 cv_record_20->pdb_file_name);
2148 } else {
2149 printf(" (cv_record) = ");
2150 for (unsigned int cv_byte_index = 0;
2151 cv_byte_index < cv_record_size;
2152 ++cv_byte_index) {
2153 printf("%02x", cv_record[cv_byte_index]);
2154 }
2155 printf("\n");
2156 }
2157 } else {
2158 printf(" (cv_record) = (null)\n");
2159 }
2160
2161 const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
2162 if (misc_record) {
2163 printf(" (misc_record).data_type = 0x%x\n",
2164 misc_record->data_type);
2165 printf(" (misc_record).length = 0x%x\n",
2166 misc_record->length);
2167 printf(" (misc_record).unicode = %d\n",
2168 misc_record->unicode);
2169 // Don't bother printing the UTF-16, we don't really even expect to ever
2170 // see this misc_record anyway.
2171 if (misc_record->unicode)
2172 printf(" (misc_record).data = \"%s\"\n",
2173 misc_record->data);
2174 else
2175 printf(" (misc_record).data = (UTF-16)\n");
2176 } else {
2177 printf(" (misc_record) = (null)\n");
2178 }
2179
2180 printf(" (debug_file) = \"%s\"\n", debug_file().c_str());
2181 printf(" (debug_identifier) = \"%s\"\n",
2182 debug_identifier().c_str());
2183 printf(" (version) = \"%s\"\n", version().c_str());
2184 printf("\n");
2185 }
2186
2187
2188 //
2189 // MinidumpModuleList
2190 //
2191
2192
2193 u_int32_t MinidumpModuleList::max_modules_ = 1024;
2194
2195
MinidumpModuleList(Minidump * minidump)2196 MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
2197 : MinidumpStream(minidump),
2198 range_map_(new RangeMap<u_int64_t, unsigned int>()),
2199 modules_(NULL),
2200 module_count_(0) {
2201 }
2202
2203
~MinidumpModuleList()2204 MinidumpModuleList::~MinidumpModuleList() {
2205 delete range_map_;
2206 delete modules_;
2207 }
2208
2209
Read(u_int32_t expected_size)2210 bool MinidumpModuleList::Read(u_int32_t expected_size) {
2211 // Invalidate cached data.
2212 range_map_->Clear();
2213 delete modules_;
2214 modules_ = NULL;
2215 module_count_ = 0;
2216
2217 valid_ = false;
2218
2219 u_int32_t module_count;
2220 if (expected_size < sizeof(module_count)) {
2221 BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
2222 expected_size << " < " << sizeof(module_count);
2223 return false;
2224 }
2225 if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
2226 BPLOG(ERROR) << "MinidumpModuleList could not read module count";
2227 return false;
2228 }
2229
2230 if (minidump_->swap())
2231 Swap(&module_count);
2232
2233 if (module_count > numeric_limits<u_int32_t>::max() / MD_MODULE_SIZE) {
2234 BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
2235 " would cause multiplication overflow";
2236 return false;
2237 }
2238
2239 if (expected_size != sizeof(module_count) +
2240 module_count * MD_MODULE_SIZE) {
2241 // may be padded with 4 bytes on 64bit ABIs for alignment
2242 if (expected_size == sizeof(module_count) + 4 +
2243 module_count * MD_MODULE_SIZE) {
2244 u_int32_t useless;
2245 if (!minidump_->ReadBytes(&useless, 4)) {
2246 BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes";
2247 return false;
2248 }
2249 } else {
2250 BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
2251 " != " << sizeof(module_count) +
2252 module_count * MD_MODULE_SIZE;
2253 return false;
2254 }
2255 }
2256
2257 if (module_count > max_modules_) {
2258 BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ <<
2259 " exceeds maximum " << max_modules_;
2260 return false;
2261 }
2262
2263 if (module_count != 0) {
2264 scoped_ptr<MinidumpModules> modules(
2265 new MinidumpModules(module_count, MinidumpModule(minidump_)));
2266
2267 for (unsigned int module_index = 0;
2268 module_index < module_count;
2269 ++module_index) {
2270 MinidumpModule* module = &(*modules)[module_index];
2271
2272 // Assume that the file offset is correct after the last read.
2273 if (!module->Read()) {
2274 BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
2275 module_index << "/" << module_count;
2276 return false;
2277 }
2278 }
2279
2280 // Loop through the module list once more to read additional data and
2281 // build the range map. This is done in a second pass because
2282 // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
2283 // included in the loop above, additional seeks would be needed where
2284 // none are now to read contiguous data.
2285 for (unsigned int module_index = 0;
2286 module_index < module_count;
2287 ++module_index) {
2288 MinidumpModule* module = &(*modules)[module_index];
2289
2290 // ReadAuxiliaryData fails if any data that the module indicates should
2291 // exist is missing, but we treat some such cases as valid anyway. See
2292 // issue #222: if a debugging record is of a format that's too large to
2293 // handle, it shouldn't render the entire dump invalid. Check module
2294 // validity before giving up.
2295 if (!module->ReadAuxiliaryData() && !module->valid()) {
2296 BPLOG(ERROR) << "MinidumpModuleList could not read required module "
2297 "auxiliary data for module " <<
2298 module_index << "/" << module_count;
2299 return false;
2300 }
2301
2302 // It is safe to use module->code_file() after successfully calling
2303 // module->ReadAuxiliaryData or noting that the module is valid.
2304
2305 u_int64_t base_address = module->base_address();
2306 u_int64_t module_size = module->size();
2307 if (base_address == static_cast<u_int64_t>(-1)) {
2308 BPLOG(ERROR) << "MinidumpModuleList found bad base address "
2309 "for module " << module_index << "/" << module_count <<
2310 ", " << module->code_file();
2311 return false;
2312 }
2313
2314 if (!range_map_->StoreRange(base_address, module_size, module_index)) {
2315 BPLOG(ERROR) << "MinidumpModuleList could not store module " <<
2316 module_index << "/" << module_count << ", " <<
2317 module->code_file() << ", " <<
2318 HexString(base_address) << "+" <<
2319 HexString(module_size);
2320 return false;
2321 }
2322 }
2323
2324 modules_ = modules.release();
2325 }
2326
2327 module_count_ = module_count;
2328
2329 valid_ = true;
2330 return true;
2331 }
2332
2333
GetModuleForAddress(u_int64_t address) const2334 const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
2335 u_int64_t address) const {
2336 if (!valid_) {
2337 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
2338 return NULL;
2339 }
2340
2341 unsigned int module_index;
2342 if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) {
2343 BPLOG(INFO) << "MinidumpModuleList has no module at " <<
2344 HexString(address);
2345 return NULL;
2346 }
2347
2348 return GetModuleAtIndex(module_index);
2349 }
2350
2351
GetMainModule() const2352 const MinidumpModule* MinidumpModuleList::GetMainModule() const {
2353 if (!valid_) {
2354 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
2355 return NULL;
2356 }
2357
2358 // The main code module is the first one present in a minidump file's
2359 // MDRawModuleList.
2360 return GetModuleAtSequence(0);
2361 }
2362
2363
GetModuleAtSequence(unsigned int sequence) const2364 const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
2365 unsigned int sequence) const {
2366 if (!valid_) {
2367 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
2368 return NULL;
2369 }
2370
2371 if (sequence >= module_count_) {
2372 BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
2373 sequence << "/" << module_count_;
2374 return NULL;
2375 }
2376
2377 unsigned int module_index;
2378 if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) {
2379 BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
2380 return NULL;
2381 }
2382
2383 return GetModuleAtIndex(module_index);
2384 }
2385
2386
GetModuleAtIndex(unsigned int index) const2387 const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
2388 unsigned int index) const {
2389 if (!valid_) {
2390 BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
2391 return NULL;
2392 }
2393
2394 if (index >= module_count_) {
2395 BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
2396 index << "/" << module_count_;
2397 return NULL;
2398 }
2399
2400 return &(*modules_)[index];
2401 }
2402
2403
Copy() const2404 const CodeModules* MinidumpModuleList::Copy() const {
2405 return new BasicCodeModules(this);
2406 }
2407
2408
Print()2409 void MinidumpModuleList::Print() {
2410 if (!valid_) {
2411 BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
2412 return;
2413 }
2414
2415 printf("MinidumpModuleList\n");
2416 printf(" module_count = %d\n", module_count_);
2417 printf("\n");
2418
2419 for (unsigned int module_index = 0;
2420 module_index < module_count_;
2421 ++module_index) {
2422 printf("module[%d]\n", module_index);
2423
2424 (*modules_)[module_index].Print();
2425 }
2426 }
2427
2428
2429 //
2430 // MinidumpMemoryList
2431 //
2432
2433
2434 u_int32_t MinidumpMemoryList::max_regions_ = 4096;
2435
2436
MinidumpMemoryList(Minidump * minidump)2437 MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
2438 : MinidumpStream(minidump),
2439 range_map_(new RangeMap<u_int64_t, unsigned int>()),
2440 descriptors_(NULL),
2441 regions_(NULL),
2442 region_count_(0) {
2443 }
2444
2445
~MinidumpMemoryList()2446 MinidumpMemoryList::~MinidumpMemoryList() {
2447 delete range_map_;
2448 delete descriptors_;
2449 delete regions_;
2450 }
2451
2452
Read(u_int32_t expected_size)2453 bool MinidumpMemoryList::Read(u_int32_t expected_size) {
2454 // Invalidate cached data.
2455 delete descriptors_;
2456 descriptors_ = NULL;
2457 delete regions_;
2458 regions_ = NULL;
2459 range_map_->Clear();
2460 region_count_ = 0;
2461
2462 valid_ = false;
2463
2464 u_int32_t region_count;
2465 if (expected_size < sizeof(region_count)) {
2466 BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
2467 expected_size << " < " << sizeof(region_count);
2468 return false;
2469 }
2470 if (!minidump_->ReadBytes(®ion_count, sizeof(region_count))) {
2471 BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
2472 return false;
2473 }
2474
2475 if (minidump_->swap())
2476 Swap(®ion_count);
2477
2478 if (region_count >
2479 numeric_limits<u_int32_t>::max() / sizeof(MDMemoryDescriptor)) {
2480 BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
2481 " would cause multiplication overflow";
2482 return false;
2483 }
2484
2485 if (expected_size != sizeof(region_count) +
2486 region_count * sizeof(MDMemoryDescriptor)) {
2487 // may be padded with 4 bytes on 64bit ABIs for alignment
2488 if (expected_size == sizeof(region_count) + 4 +
2489 region_count * sizeof(MDMemoryDescriptor)) {
2490 u_int32_t useless;
2491 if (!minidump_->ReadBytes(&useless, 4)) {
2492 BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes";
2493 return false;
2494 }
2495 } else {
2496 BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
2497 " != " << sizeof(region_count) +
2498 region_count * sizeof(MDMemoryDescriptor);
2499 return false;
2500 }
2501 }
2502
2503 if (region_count > max_regions_) {
2504 BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
2505 " exceeds maximum " << max_regions_;
2506 return false;
2507 }
2508
2509 if (region_count != 0) {
2510 scoped_ptr<MemoryDescriptors> descriptors(
2511 new MemoryDescriptors(region_count));
2512
2513 // Read the entire array in one fell swoop, instead of reading one entry
2514 // at a time in the loop.
2515 if (!minidump_->ReadBytes(&(*descriptors)[0],
2516 sizeof(MDMemoryDescriptor) * region_count)) {
2517 BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
2518 return false;
2519 }
2520
2521 scoped_ptr<MemoryRegions> regions(
2522 new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
2523
2524 for (unsigned int region_index = 0;
2525 region_index < region_count;
2526 ++region_index) {
2527 MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
2528
2529 if (minidump_->swap())
2530 Swap(descriptor);
2531
2532 u_int64_t base_address = descriptor->start_of_memory_range;
2533 u_int32_t region_size = descriptor->memory.data_size;
2534
2535 // Check for base + size overflow or undersize.
2536 if (region_size == 0 ||
2537 region_size > numeric_limits<u_int64_t>::max() - base_address) {
2538 BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
2539 " region " << region_index << "/" << region_count <<
2540 ", " << HexString(base_address) << "+" <<
2541 HexString(region_size);
2542 return false;
2543 }
2544
2545 if (!range_map_->StoreRange(base_address, region_size, region_index)) {
2546 BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
2547 region_index << "/" << region_count << ", " <<
2548 HexString(base_address) << "+" <<
2549 HexString(region_size);
2550 return false;
2551 }
2552
2553 (*regions)[region_index].SetDescriptor(descriptor);
2554 }
2555
2556 descriptors_ = descriptors.release();
2557 regions_ = regions.release();
2558 }
2559
2560 region_count_ = region_count;
2561
2562 valid_ = true;
2563 return true;
2564 }
2565
2566
GetMemoryRegionAtIndex(unsigned int index)2567 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
2568 unsigned int index) {
2569 if (!valid_) {
2570 BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
2571 return NULL;
2572 }
2573
2574 if (index >= region_count_) {
2575 BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
2576 index << "/" << region_count_;
2577 return NULL;
2578 }
2579
2580 return &(*regions_)[index];
2581 }
2582
2583
GetMemoryRegionForAddress(u_int64_t address)2584 MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
2585 u_int64_t address) {
2586 if (!valid_) {
2587 BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
2588 return NULL;
2589 }
2590
2591 unsigned int region_index;
2592 if (!range_map_->RetrieveRange(address, ®ion_index, NULL, NULL)) {
2593 BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
2594 HexString(address);
2595 return NULL;
2596 }
2597
2598 return GetMemoryRegionAtIndex(region_index);
2599 }
2600
2601
Print()2602 void MinidumpMemoryList::Print() {
2603 if (!valid_) {
2604 BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
2605 return;
2606 }
2607
2608 printf("MinidumpMemoryList\n");
2609 printf(" region_count = %d\n", region_count_);
2610 printf("\n");
2611
2612 for (unsigned int region_index = 0;
2613 region_index < region_count_;
2614 ++region_index) {
2615 MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
2616 printf("region[%d]\n", region_index);
2617 printf("MDMemoryDescriptor\n");
2618 printf(" start_of_memory_range = 0x%" PRIx64 "\n",
2619 descriptor->start_of_memory_range);
2620 printf(" memory.data_size = 0x%x\n", descriptor->memory.data_size);
2621 printf(" memory.rva = 0x%x\n", descriptor->memory.rva);
2622 MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
2623 if (region) {
2624 printf("Memory\n");
2625 region->Print();
2626 } else {
2627 printf("No memory\n");
2628 }
2629 printf("\n");
2630 }
2631 }
2632
2633
2634 //
2635 // MinidumpException
2636 //
2637
2638
MinidumpException(Minidump * minidump)2639 MinidumpException::MinidumpException(Minidump* minidump)
2640 : MinidumpStream(minidump),
2641 exception_(),
2642 context_(NULL) {
2643 }
2644
2645
~MinidumpException()2646 MinidumpException::~MinidumpException() {
2647 delete context_;
2648 }
2649
2650
Read(u_int32_t expected_size)2651 bool MinidumpException::Read(u_int32_t expected_size) {
2652 // Invalidate cached data.
2653 delete context_;
2654 context_ = NULL;
2655
2656 valid_ = false;
2657
2658 if (expected_size != sizeof(exception_)) {
2659 BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
2660 " != " << sizeof(exception_);
2661 return false;
2662 }
2663
2664 if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
2665 BPLOG(ERROR) << "MinidumpException cannot read exception";
2666 return false;
2667 }
2668
2669 if (minidump_->swap()) {
2670 Swap(&exception_.thread_id);
2671 // exception_.__align is for alignment only and does not need to be
2672 // swapped.
2673 Swap(&exception_.exception_record.exception_code);
2674 Swap(&exception_.exception_record.exception_flags);
2675 Swap(&exception_.exception_record.exception_record);
2676 Swap(&exception_.exception_record.exception_address);
2677 Swap(&exception_.exception_record.number_parameters);
2678 // exception_.exception_record.__align is for alignment only and does not
2679 // need to be swapped.
2680 for (unsigned int parameter_index = 0;
2681 parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
2682 ++parameter_index) {
2683 Swap(&exception_.exception_record.exception_information[parameter_index]);
2684 }
2685 Swap(&exception_.thread_context);
2686 }
2687
2688 valid_ = true;
2689 return true;
2690 }
2691
2692
GetThreadID(u_int32_t * thread_id) const2693 bool MinidumpException::GetThreadID(u_int32_t *thread_id) const {
2694 BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
2695 "|thread_id|";
2696 assert(thread_id);
2697 *thread_id = 0;
2698
2699 if (!valid_) {
2700 BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
2701 return false;
2702 }
2703
2704 *thread_id = exception_.thread_id;
2705 return true;
2706 }
2707
2708
GetContext()2709 MinidumpContext* MinidumpException::GetContext() {
2710 if (!valid_) {
2711 BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
2712 return NULL;
2713 }
2714
2715 if (!context_) {
2716 if (!minidump_->SeekSet(exception_.thread_context.rva)) {
2717 BPLOG(ERROR) << "MinidumpException cannot seek to context";
2718 return NULL;
2719 }
2720
2721 scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
2722
2723 if (!context->Read(exception_.thread_context.data_size)) {
2724 BPLOG(ERROR) << "MinidumpException cannot read context";
2725 return NULL;
2726 }
2727
2728 context_ = context.release();
2729 }
2730
2731 return context_;
2732 }
2733
2734
Print()2735 void MinidumpException::Print() {
2736 if (!valid_) {
2737 BPLOG(ERROR) << "MinidumpException cannot print invalid data";
2738 return;
2739 }
2740
2741 printf("MDException\n");
2742 printf(" thread_id = 0x%x\n",
2743 exception_.thread_id);
2744 printf(" exception_record.exception_code = 0x%x\n",
2745 exception_.exception_record.exception_code);
2746 printf(" exception_record.exception_flags = 0x%x\n",
2747 exception_.exception_record.exception_flags);
2748 printf(" exception_record.exception_record = 0x%" PRIx64 "\n",
2749 exception_.exception_record.exception_record);
2750 printf(" exception_record.exception_address = 0x%" PRIx64 "\n",
2751 exception_.exception_record.exception_address);
2752 printf(" exception_record.number_parameters = %d\n",
2753 exception_.exception_record.number_parameters);
2754 for (unsigned int parameterIndex = 0;
2755 parameterIndex < exception_.exception_record.number_parameters;
2756 ++parameterIndex) {
2757 printf(" exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
2758 parameterIndex,
2759 exception_.exception_record.exception_information[parameterIndex]);
2760 }
2761 printf(" thread_context.data_size = %d\n",
2762 exception_.thread_context.data_size);
2763 printf(" thread_context.rva = 0x%x\n",
2764 exception_.thread_context.rva);
2765 MinidumpContext* context = GetContext();
2766 if (context) {
2767 printf("\n");
2768 context->Print();
2769 } else {
2770 printf(" (no context)\n");
2771 printf("\n");
2772 }
2773 }
2774
2775
2776 //
2777 // MinidumpSystemInfo
2778 //
2779
2780
MinidumpSystemInfo(Minidump * minidump)2781 MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
2782 : MinidumpStream(minidump),
2783 system_info_(),
2784 csd_version_(NULL),
2785 cpu_vendor_(NULL) {
2786 }
2787
2788
~MinidumpSystemInfo()2789 MinidumpSystemInfo::~MinidumpSystemInfo() {
2790 delete csd_version_;
2791 delete cpu_vendor_;
2792 }
2793
2794
Read(u_int32_t expected_size)2795 bool MinidumpSystemInfo::Read(u_int32_t expected_size) {
2796 // Invalidate cached data.
2797 delete csd_version_;
2798 csd_version_ = NULL;
2799 delete cpu_vendor_;
2800 cpu_vendor_ = NULL;
2801
2802 valid_ = false;
2803
2804 if (expected_size != sizeof(system_info_)) {
2805 BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
2806 " != " << sizeof(system_info_);
2807 return false;
2808 }
2809
2810 if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
2811 BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
2812 return false;
2813 }
2814
2815 if (minidump_->swap()) {
2816 Swap(&system_info_.processor_architecture);
2817 Swap(&system_info_.processor_level);
2818 Swap(&system_info_.processor_revision);
2819 // number_of_processors and product_type are 8-bit quantities and need no
2820 // swapping.
2821 Swap(&system_info_.major_version);
2822 Swap(&system_info_.minor_version);
2823 Swap(&system_info_.build_number);
2824 Swap(&system_info_.platform_id);
2825 Swap(&system_info_.csd_version_rva);
2826 Swap(&system_info_.suite_mask);
2827 // Don't swap the reserved2 field because its contents are unknown.
2828
2829 if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
2830 system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
2831 for (unsigned int i = 0; i < 3; ++i)
2832 Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
2833 Swap(&system_info_.cpu.x86_cpu_info.version_information);
2834 Swap(&system_info_.cpu.x86_cpu_info.feature_information);
2835 Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
2836 } else {
2837 for (unsigned int i = 0; i < 2; ++i)
2838 Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
2839 }
2840 }
2841
2842 valid_ = true;
2843 return true;
2844 }
2845
2846
GetOS()2847 string MinidumpSystemInfo::GetOS() {
2848 if (!valid_) {
2849 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
2850 return NULL;
2851 }
2852
2853 string os;
2854
2855 switch (system_info_.platform_id) {
2856 case MD_OS_WIN32_NT:
2857 case MD_OS_WIN32_WINDOWS:
2858 os = "windows";
2859 break;
2860
2861 case MD_OS_MAC_OS_X:
2862 os = "mac";
2863 break;
2864
2865 case MD_OS_LINUX:
2866 os = "linux";
2867 break;
2868
2869 case MD_OS_SOLARIS:
2870 os = "solaris";
2871 break;
2872
2873 default:
2874 BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
2875 HexString(system_info_.platform_id);
2876 break;
2877 }
2878
2879 return os;
2880 }
2881
2882
GetCPU()2883 string MinidumpSystemInfo::GetCPU() {
2884 if (!valid_) {
2885 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
2886 return "";
2887 }
2888
2889 string cpu;
2890
2891 switch (system_info_.processor_architecture) {
2892 case MD_CPU_ARCHITECTURE_X86:
2893 case MD_CPU_ARCHITECTURE_X86_WIN64:
2894 cpu = "x86";
2895 break;
2896
2897 case MD_CPU_ARCHITECTURE_PPC:
2898 cpu = "ppc";
2899 break;
2900
2901 case MD_CPU_ARCHITECTURE_SPARC:
2902 cpu = "sparc";
2903 break;
2904
2905 default:
2906 BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
2907 HexString(system_info_.processor_architecture);
2908 break;
2909 }
2910
2911 return cpu;
2912 }
2913
2914
GetCSDVersion()2915 const string* MinidumpSystemInfo::GetCSDVersion() {
2916 if (!valid_) {
2917 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
2918 return NULL;
2919 }
2920
2921 if (!csd_version_)
2922 csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
2923
2924 BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
2925 "CSD version";
2926
2927 return csd_version_;
2928 }
2929
2930
GetCPUVendor()2931 const string* MinidumpSystemInfo::GetCPUVendor() {
2932 if (!valid_) {
2933 BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
2934 return NULL;
2935 }
2936
2937 // CPU vendor information can only be determined from x86 minidumps.
2938 if (!cpu_vendor_ &&
2939 (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
2940 system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
2941 char cpu_vendor_string[13];
2942 snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
2943 "%c%c%c%c%c%c%c%c%c%c%c%c",
2944 system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
2945 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
2946 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
2947 (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
2948 system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
2949 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
2950 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
2951 (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
2952 system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
2953 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
2954 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
2955 (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
2956 cpu_vendor_ = new string(cpu_vendor_string);
2957 }
2958
2959 return cpu_vendor_;
2960 }
2961
2962
Print()2963 void MinidumpSystemInfo::Print() {
2964 if (!valid_) {
2965 BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
2966 return;
2967 }
2968
2969 printf("MDRawSystemInfo\n");
2970 printf(" processor_architecture = %d\n",
2971 system_info_.processor_architecture);
2972 printf(" processor_level = %d\n",
2973 system_info_.processor_level);
2974 printf(" processor_revision = 0x%x\n",
2975 system_info_.processor_revision);
2976 printf(" number_of_processors = %d\n",
2977 system_info_.number_of_processors);
2978 printf(" product_type = %d\n",
2979 system_info_.product_type);
2980 printf(" major_version = %d\n",
2981 system_info_.major_version);
2982 printf(" minor_version = %d\n",
2983 system_info_.minor_version);
2984 printf(" build_number = %d\n",
2985 system_info_.build_number);
2986 printf(" platform_id = %d\n",
2987 system_info_.platform_id);
2988 printf(" csd_version_rva = 0x%x\n",
2989 system_info_.csd_version_rva);
2990 printf(" suite_mask = 0x%x\n",
2991 system_info_.suite_mask);
2992 for (unsigned int i = 0; i < 3; ++i) {
2993 printf(" cpu.x86_cpu_info.vendor_id[%d] = 0x%x\n",
2994 i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
2995 }
2996 printf(" cpu.x86_cpu_info.version_information = 0x%x\n",
2997 system_info_.cpu.x86_cpu_info.version_information);
2998 printf(" cpu.x86_cpu_info.feature_information = 0x%x\n",
2999 system_info_.cpu.x86_cpu_info.feature_information);
3000 printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
3001 system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3002 const string* csd_version = GetCSDVersion();
3003 if (csd_version) {
3004 printf(" (csd_version) = \"%s\"\n",
3005 csd_version->c_str());
3006 } else {
3007 printf(" (csd_version) = (null)\n");
3008 }
3009 const string* cpu_vendor = GetCPUVendor();
3010 if (cpu_vendor) {
3011 printf(" (cpu_vendor) = \"%s\"\n",
3012 cpu_vendor->c_str());
3013 } else {
3014 printf(" (cpu_vendor) = (null)\n");
3015 }
3016 printf("\n");
3017 }
3018
3019
3020 //
3021 // MinidumpMiscInfo
3022 //
3023
3024
MinidumpMiscInfo(Minidump * minidump)3025 MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
3026 : MinidumpStream(minidump),
3027 misc_info_() {
3028 }
3029
3030
Read(u_int32_t expected_size)3031 bool MinidumpMiscInfo::Read(u_int32_t expected_size) {
3032 valid_ = false;
3033
3034 if (expected_size != MD_MISCINFO_SIZE &&
3035 expected_size != MD_MISCINFO2_SIZE) {
3036 BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size <<
3037 " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE <<
3038 ")";
3039 return false;
3040 }
3041
3042 if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
3043 BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
3044 return false;
3045 }
3046
3047 if (minidump_->swap()) {
3048 Swap(&misc_info_.size_of_info);
3049 Swap(&misc_info_.flags1);
3050 Swap(&misc_info_.process_id);
3051 Swap(&misc_info_.process_create_time);
3052 Swap(&misc_info_.process_user_time);
3053 Swap(&misc_info_.process_kernel_time);
3054 if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3055 Swap(&misc_info_.processor_max_mhz);
3056 Swap(&misc_info_.processor_current_mhz);
3057 Swap(&misc_info_.processor_mhz_limit);
3058 Swap(&misc_info_.processor_max_idle_state);
3059 Swap(&misc_info_.processor_current_idle_state);
3060 }
3061 }
3062
3063 if (expected_size != misc_info_.size_of_info) {
3064 BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
3065 expected_size << " != " << misc_info_.size_of_info;
3066 return false;
3067 }
3068
3069 valid_ = true;
3070 return true;
3071 }
3072
3073
Print()3074 void MinidumpMiscInfo::Print() {
3075 if (!valid_) {
3076 BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
3077 return;
3078 }
3079
3080 printf("MDRawMiscInfo\n");
3081 printf(" size_of_info = %d\n", misc_info_.size_of_info);
3082 printf(" flags1 = 0x%x\n", misc_info_.flags1);
3083 printf(" process_id = 0x%x\n", misc_info_.process_id);
3084 printf(" process_create_time = 0x%x\n",
3085 misc_info_.process_create_time);
3086 printf(" process_user_time = 0x%x\n",
3087 misc_info_.process_user_time);
3088 printf(" process_kernel_time = 0x%x\n",
3089 misc_info_.process_kernel_time);
3090 if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
3091 printf(" processor_max_mhz = %d\n",
3092 misc_info_.processor_max_mhz);
3093 printf(" processor_current_mhz = %d\n",
3094 misc_info_.processor_current_mhz);
3095 printf(" processor_mhz_limit = %d\n",
3096 misc_info_.processor_mhz_limit);
3097 printf(" processor_max_idle_state = 0x%x\n",
3098 misc_info_.processor_max_idle_state);
3099 printf(" processor_current_idle_state = 0x%x\n",
3100 misc_info_.processor_current_idle_state);
3101 }
3102 printf("\n");
3103 }
3104
3105
3106 //
3107 // MinidumpBreakpadInfo
3108 //
3109
3110
MinidumpBreakpadInfo(Minidump * minidump)3111 MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
3112 : MinidumpStream(minidump),
3113 breakpad_info_() {
3114 }
3115
3116
Read(u_int32_t expected_size)3117 bool MinidumpBreakpadInfo::Read(u_int32_t expected_size) {
3118 valid_ = false;
3119
3120 if (expected_size != sizeof(breakpad_info_)) {
3121 BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
3122 " != " << sizeof(breakpad_info_);
3123 return false;
3124 }
3125
3126 if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
3127 BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
3128 return false;
3129 }
3130
3131 if (minidump_->swap()) {
3132 Swap(&breakpad_info_.validity);
3133 Swap(&breakpad_info_.dump_thread_id);
3134 Swap(&breakpad_info_.requesting_thread_id);
3135 }
3136
3137 valid_ = true;
3138 return true;
3139 }
3140
3141
GetDumpThreadID(u_int32_t * thread_id) const3142 bool MinidumpBreakpadInfo::GetDumpThreadID(u_int32_t *thread_id) const {
3143 BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
3144 "requires |thread_id|";
3145 assert(thread_id);
3146 *thread_id = 0;
3147
3148 if (!valid_) {
3149 BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
3150 return false;
3151 }
3152
3153 if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
3154 BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
3155 return false;
3156 }
3157
3158 *thread_id = breakpad_info_.dump_thread_id;
3159 return true;
3160 }
3161
3162
GetRequestingThreadID(u_int32_t * thread_id) const3163 bool MinidumpBreakpadInfo::GetRequestingThreadID(u_int32_t *thread_id)
3164 const {
3165 BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
3166 "requires |thread_id|";
3167 assert(thread_id);
3168 *thread_id = 0;
3169
3170 if (!thread_id || !valid_) {
3171 BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
3172 return false;
3173 }
3174
3175 if (!(breakpad_info_.validity &
3176 MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
3177 BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
3178 return false;
3179 }
3180
3181 *thread_id = breakpad_info_.requesting_thread_id;
3182 return true;
3183 }
3184
3185
Print()3186 void MinidumpBreakpadInfo::Print() {
3187 if (!valid_) {
3188 BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
3189 return;
3190 }
3191
3192 printf("MDRawBreakpadInfo\n");
3193 printf(" validity = 0x%x\n", breakpad_info_.validity);
3194
3195 if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3196 printf(" dump_thread_id = 0x%x\n", breakpad_info_.dump_thread_id);
3197 } else {
3198 printf(" dump_thread_id = (invalid)\n");
3199 }
3200
3201 if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) {
3202 printf(" requesting_thread_id = 0x%x\n",
3203 breakpad_info_.requesting_thread_id);
3204 } else {
3205 printf(" requesting_thread_id = (invalid)\n");
3206 }
3207
3208 printf("\n");
3209 }
3210
3211
3212 //
3213 // Minidump
3214 //
3215
3216
3217 u_int32_t Minidump::max_streams_ = 128;
3218 unsigned int Minidump::max_string_length_ = 1024;
3219
3220
Minidump(const string & path)3221 Minidump::Minidump(const string& path)
3222 : header_(),
3223 directory_(NULL),
3224 stream_map_(new MinidumpStreamMap()),
3225 path_(path),
3226 fd_(-1),
3227 swap_(false),
3228 valid_(false) {
3229 }
3230
3231
~Minidump()3232 Minidump::~Minidump() {
3233 delete directory_;
3234 delete stream_map_;
3235 if (fd_ != -1) {
3236 BPLOG(INFO) << "Minidump closing minidump on fd " << fd_;
3237 close(fd_);
3238 }
3239 }
3240
3241
Open()3242 bool Minidump::Open() {
3243 if (fd_ != -1) {
3244 BPLOG(INFO) << "Minidump reopening minidump " << path_ << " on fd " << fd_;
3245
3246 // The file is already open. Seek to the beginning, which is the position
3247 // the file would be at if it were opened anew.
3248 return SeekSet(0);
3249 }
3250
3251 // O_BINARY is useful (and defined) on Windows. On other platforms, it's
3252 // useless, and because it's defined as 0 above, harmless.
3253 fd_ = open(path_.c_str(), O_RDONLY | O_BINARY);
3254 if (fd_ == -1) {
3255 string error_string;
3256 int error_code = ErrnoString(&error_string);
3257 BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
3258 ", error " << error_code << ": " << error_string;
3259 return false;
3260 }
3261
3262 BPLOG(INFO) << "Minidump opened minidump " << path_ << " on fd " << fd_;
3263 return true;
3264 }
3265
3266
Read()3267 bool Minidump::Read() {
3268 // Invalidate cached data.
3269 delete directory_;
3270 directory_ = NULL;
3271 stream_map_->clear();
3272
3273 valid_ = false;
3274
3275 if (!Open()) {
3276 BPLOG(ERROR) << "Minidump cannot open minidump";
3277 return false;
3278 }
3279
3280 if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
3281 BPLOG(ERROR) << "Minidump cannot read header";
3282 return false;
3283 }
3284
3285 if (header_.signature != MD_HEADER_SIGNATURE) {
3286 // The file may be byte-swapped. Under the present architecture, these
3287 // classes don't know or need to know what CPU (or endianness) the
3288 // minidump was produced on in order to parse it. Use the signature as
3289 // a byte order marker.
3290 u_int32_t signature_swapped = header_.signature;
3291 Swap(&signature_swapped);
3292 if (signature_swapped != MD_HEADER_SIGNATURE) {
3293 // This isn't a minidump or a byte-swapped minidump.
3294 BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
3295 HexString(header_.signature) << ", " <<
3296 HexString(signature_swapped) << ") != " <<
3297 HexString(MD_HEADER_SIGNATURE);
3298 return false;
3299 }
3300 swap_ = true;
3301 } else {
3302 // The file is not byte-swapped. Set swap_ false (it may have been true
3303 // if the object is being reused?)
3304 swap_ = false;
3305 }
3306
3307 BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
3308 "byte-swapping minidump";
3309
3310 if (swap_) {
3311 Swap(&header_.signature);
3312 Swap(&header_.version);
3313 Swap(&header_.stream_count);
3314 Swap(&header_.stream_directory_rva);
3315 Swap(&header_.checksum);
3316 Swap(&header_.time_date_stamp);
3317 Swap(&header_.flags);
3318 }
3319
3320 // Version check. The high 16 bits of header_.version contain something
3321 // else "implementation specific."
3322 if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
3323 BPLOG(ERROR) << "Minidump version mismatch: " <<
3324 HexString(header_.version & 0x0000ffff) << " != " <<
3325 HexString(MD_HEADER_VERSION);
3326 return false;
3327 }
3328
3329 if (!SeekSet(header_.stream_directory_rva)) {
3330 BPLOG(ERROR) << "Minidump cannot seek to stream directory";
3331 return false;
3332 }
3333
3334 if (header_.stream_count > max_streams_) {
3335 BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
3336 " exceeds maximum " << max_streams_;
3337 return false;
3338 }
3339
3340 if (header_.stream_count != 0) {
3341 scoped_ptr<MinidumpDirectoryEntries> directory(
3342 new MinidumpDirectoryEntries(header_.stream_count));
3343
3344 // Read the entire array in one fell swoop, instead of reading one entry
3345 // at a time in the loop.
3346 if (!ReadBytes(&(*directory)[0],
3347 sizeof(MDRawDirectory) * header_.stream_count)) {
3348 BPLOG(ERROR) << "Minidump cannot read stream directory";
3349 return false;
3350 }
3351
3352 for (unsigned int stream_index = 0;
3353 stream_index < header_.stream_count;
3354 ++stream_index) {
3355 MDRawDirectory* directory_entry = &(*directory)[stream_index];
3356
3357 if (swap_) {
3358 Swap(&directory_entry->stream_type);
3359 Swap(&directory_entry->location);
3360 }
3361
3362 // Initialize the stream_map_ map, which speeds locating a stream by
3363 // type.
3364 unsigned int stream_type = directory_entry->stream_type;
3365 switch (stream_type) {
3366 case MD_THREAD_LIST_STREAM:
3367 case MD_MODULE_LIST_STREAM:
3368 case MD_MEMORY_LIST_STREAM:
3369 case MD_EXCEPTION_STREAM:
3370 case MD_SYSTEM_INFO_STREAM:
3371 case MD_MISC_INFO_STREAM:
3372 case MD_BREAKPAD_INFO_STREAM: {
3373 if (stream_map_->find(stream_type) != stream_map_->end()) {
3374 // Another stream with this type was already found. A minidump
3375 // file should contain at most one of each of these stream types.
3376 BPLOG(ERROR) << "Minidump found multiple streams of type " <<
3377 stream_type << ", but can only deal with one";
3378 return false;
3379 }
3380 // Fall through to default
3381 }
3382
3383 default: {
3384 // Overwrites for stream types other than those above, but it's
3385 // expected to be the user's burden in that case.
3386 (*stream_map_)[stream_type].stream_index = stream_index;
3387 }
3388 }
3389 }
3390
3391 directory_ = directory.release();
3392 }
3393
3394 valid_ = true;
3395 return true;
3396 }
3397
3398
GetThreadList()3399 MinidumpThreadList* Minidump::GetThreadList() {
3400 MinidumpThreadList* thread_list;
3401 return GetStream(&thread_list);
3402 }
3403
3404
GetModuleList()3405 MinidumpModuleList* Minidump::GetModuleList() {
3406 MinidumpModuleList* module_list;
3407 return GetStream(&module_list);
3408 }
3409
3410
GetMemoryList()3411 MinidumpMemoryList* Minidump::GetMemoryList() {
3412 MinidumpMemoryList* memory_list;
3413 return GetStream(&memory_list);
3414 }
3415
3416
GetException()3417 MinidumpException* Minidump::GetException() {
3418 MinidumpException* exception;
3419 return GetStream(&exception);
3420 }
3421
3422
GetSystemInfo()3423 MinidumpSystemInfo* Minidump::GetSystemInfo() {
3424 MinidumpSystemInfo* system_info;
3425 return GetStream(&system_info);
3426 }
3427
3428
GetMiscInfo()3429 MinidumpMiscInfo* Minidump::GetMiscInfo() {
3430 MinidumpMiscInfo* misc_info;
3431 return GetStream(&misc_info);
3432 }
3433
3434
GetBreakpadInfo()3435 MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
3436 MinidumpBreakpadInfo* breakpad_info;
3437 return GetStream(&breakpad_info);
3438 }
3439
3440
Print()3441 void Minidump::Print() {
3442 if (!valid_) {
3443 BPLOG(ERROR) << "Minidump cannot print invalid data";
3444 return;
3445 }
3446
3447 printf("MDRawHeader\n");
3448 printf(" signature = 0x%x\n", header_.signature);
3449 printf(" version = 0x%x\n", header_.version);
3450 printf(" stream_count = %d\n", header_.stream_count);
3451 printf(" stream_directory_rva = 0x%x\n", header_.stream_directory_rva);
3452 printf(" checksum = 0x%x\n", header_.checksum);
3453 struct tm timestruct;
3454 gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), ×truct);
3455 char timestr[20];
3456 strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct);
3457 printf(" time_date_stamp = 0x%x %s\n", header_.time_date_stamp,
3458 timestr);
3459 printf(" flags = 0x%" PRIx64 "\n", header_.flags);
3460 printf("\n");
3461
3462 for (unsigned int stream_index = 0;
3463 stream_index < header_.stream_count;
3464 ++stream_index) {
3465 MDRawDirectory* directory_entry = &(*directory_)[stream_index];
3466
3467 printf("mDirectory[%d]\n", stream_index);
3468 printf("MDRawDirectory\n");
3469 printf(" stream_type = %d\n", directory_entry->stream_type);
3470 printf(" location.data_size = %d\n",
3471 directory_entry->location.data_size);
3472 printf(" location.rva = 0x%x\n", directory_entry->location.rva);
3473 printf("\n");
3474 }
3475
3476 printf("Streams:\n");
3477 for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
3478 iterator != stream_map_->end();
3479 ++iterator) {
3480 u_int32_t stream_type = iterator->first;
3481 MinidumpStreamInfo info = iterator->second;
3482 printf(" stream type 0x%x at index %d\n", stream_type, info.stream_index);
3483 }
3484 printf("\n");
3485 }
3486
3487
GetDirectoryEntryAtIndex(unsigned int index) const3488 const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
3489 const {
3490 if (!valid_) {
3491 BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
3492 return NULL;
3493 }
3494
3495 if (index >= header_.stream_count) {
3496 BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
3497 index << "/" << header_.stream_count;
3498 return NULL;
3499 }
3500
3501 return &(*directory_)[index];
3502 }
3503
3504
ReadBytes(void * bytes,size_t count)3505 bool Minidump::ReadBytes(void* bytes, size_t count) {
3506 // Can't check valid_ because Read needs to call this method before
3507 // validity can be determined. The only member that this method
3508 // depends on is mFD, and an unset or invalid fd may generate an
3509 // error but should not cause a crash.
3510 ssize_t bytes_read = read(fd_, bytes, count);
3511 if (static_cast<size_t>(bytes_read) != count) {
3512 if (bytes_read == -1) {
3513 string error_string;
3514 int error_code = ErrnoString(&error_string);
3515 BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
3516 } else {
3517 BPLOG(ERROR) << "ReadBytes: read " << bytes_read << "/" << count;
3518 }
3519 return false;
3520 }
3521 return true;
3522 }
3523
3524
SeekSet(off_t offset)3525 bool Minidump::SeekSet(off_t offset) {
3526 // Can't check valid_ because Read needs to call this method before
3527 // validity can be determined. The only member that this method
3528 // depends on is mFD, and an unset or invalid fd may generate an
3529 // error but should not cause a crash.
3530 off_t sought = lseek(fd_, offset, SEEK_SET);
3531 if (sought != offset) {
3532 if (sought == -1) {
3533 string error_string;
3534 int error_code = ErrnoString(&error_string);
3535 BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
3536 } else {
3537 BPLOG(ERROR) << "SeekSet: sought " << sought << "/" << offset;
3538 }
3539 return false;
3540 }
3541 return true;
3542 }
3543
3544
ReadString(off_t offset)3545 string* Minidump::ReadString(off_t offset) {
3546 if (!valid_) {
3547 BPLOG(ERROR) << "Invalid Minidump for ReadString";
3548 return NULL;
3549 }
3550 if (!SeekSet(offset)) {
3551 BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
3552 return NULL;
3553 }
3554
3555 u_int32_t bytes;
3556 if (!ReadBytes(&bytes, sizeof(bytes))) {
3557 BPLOG(ERROR) << "ReadString could not read string size at offset " <<
3558 offset;
3559 return NULL;
3560 }
3561 if (swap_)
3562 Swap(&bytes);
3563
3564 if (bytes % 2 != 0) {
3565 BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
3566 "-byte string at offset " << offset;
3567 return NULL;
3568 }
3569 unsigned int utf16_words = bytes / 2;
3570
3571 if (utf16_words > max_string_length_) {
3572 BPLOG(ERROR) << "ReadString string length " << utf16_words <<
3573 " exceeds maximum " << max_string_length_ <<
3574 " at offset " << offset;
3575 return NULL;
3576 }
3577
3578 vector<u_int16_t> string_utf16(utf16_words);
3579
3580 if (utf16_words) {
3581 if (!ReadBytes(&string_utf16[0], bytes)) {
3582 BPLOG(ERROR) << "ReadString could not read " << bytes <<
3583 "-byte string at offset " << offset;
3584 return NULL;
3585 }
3586 }
3587
3588 return UTF16ToUTF8(string_utf16, swap_);
3589 }
3590
3591
SeekToStreamType(u_int32_t stream_type,u_int32_t * stream_length)3592 bool Minidump::SeekToStreamType(u_int32_t stream_type,
3593 u_int32_t* stream_length) {
3594 BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
3595 "|stream_length|";
3596 assert(stream_length);
3597 *stream_length = 0;
3598
3599 if (!valid_) {
3600 BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
3601 return false;
3602 }
3603
3604 MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
3605 if (iterator == stream_map_->end()) {
3606 // This stream type didn't exist in the directory.
3607 BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
3608 return false;
3609 }
3610
3611 MinidumpStreamInfo info = iterator->second;
3612 if (info.stream_index >= header_.stream_count) {
3613 BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
3614 " out of range: " <<
3615 info.stream_index << "/" << header_.stream_count;
3616 return false;
3617 }
3618
3619 MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
3620 if (!SeekSet(directory_entry->location.rva)) {
3621 BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
3622 stream_type;
3623 return false;
3624 }
3625
3626 *stream_length = directory_entry->location.data_size;
3627
3628 return true;
3629 }
3630
3631
3632 template<typename T>
GetStream(T ** stream)3633 T* Minidump::GetStream(T** stream) {
3634 // stream is a garbage parameter that's present only to account for C++'s
3635 // inability to overload a method based solely on its return type.
3636
3637 const u_int32_t stream_type = T::kStreamType;
3638
3639 BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
3640 " requires |stream|";
3641 assert(stream);
3642 *stream = NULL;
3643
3644 if (!valid_) {
3645 BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
3646 return NULL;
3647 }
3648
3649 MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
3650 if (iterator == stream_map_->end()) {
3651 // This stream type didn't exist in the directory.
3652 BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
3653 return NULL;
3654 }
3655
3656 // Get a pointer so that the stored stream field can be altered.
3657 MinidumpStreamInfo* info = &iterator->second;
3658
3659 if (info->stream) {
3660 // This cast is safe because info.stream is only populated by this
3661 // method, and there is a direct correlation between T and stream_type.
3662 *stream = static_cast<T*>(info->stream);
3663 return *stream;
3664 }
3665
3666 u_int32_t stream_length;
3667 if (!SeekToStreamType(stream_type, &stream_length)) {
3668 BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
3669 return NULL;
3670 }
3671
3672 scoped_ptr<T> new_stream(new T(this));
3673
3674 if (!new_stream->Read(stream_length)) {
3675 BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
3676 return NULL;
3677 }
3678
3679 *stream = new_stream.release();
3680 info->stream = *stream;
3681 return *stream;
3682 }
3683
3684
3685 } // namespace google_breakpad
3686