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