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