1 // Copyright (c) 2006, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30 #include <algorithm> 31 #include <cstdio> 32 33 #include <mach/host_info.h> 34 #include <mach/machine.h> 35 #include <mach/vm_statistics.h> 36 #include <mach-o/dyld.h> 37 #include <mach-o/loader.h> 38 #include <sys/sysctl.h> 39 #include <sys/resource.h> 40 41 #include <CoreFoundation/CoreFoundation.h> 42 43 #include "client/mac/handler/minidump_generator.h" 44 45 #if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) 46 #include <mach/arm/thread_status.h> 47 #endif 48 #ifdef HAS_PPC_SUPPORT 49 #include <mach/ppc/thread_status.h> 50 #endif 51 #ifdef HAS_X86_SUPPORT 52 #include <mach/i386/thread_status.h> 53 #endif 54 55 #include "client/minidump_file_writer-inl.h" 56 #include "common/mac/file_id.h" 57 #include "common/mac/macho_id.h" 58 #include "common/mac/string_utilities.h" 59 60 using MacStringUtils::ConvertToString; 61 using MacStringUtils::IntegerValueAtIndex; 62 63 namespace google_breakpad { 64 65 #if defined(__LP64__) && __LP64__ 66 #define LC_SEGMENT_ARCH LC_SEGMENT_64 67 #else 68 #define LC_SEGMENT_ARCH LC_SEGMENT 69 #endif 70 71 // constructor when generating from within the crashed process 72 MinidumpGenerator::MinidumpGenerator() 73 : writer_(), 74 exception_type_(0), 75 exception_code_(0), 76 exception_subcode_(0), 77 exception_thread_(0), 78 crashing_task_(mach_task_self()), 79 handler_thread_(mach_thread_self()), 80 cpu_type_(DynamicImages::GetNativeCPUType()), 81 task_context_(NULL), 82 dynamic_images_(NULL), 83 memory_blocks_(&allocator_) { 84 GatherSystemInformation(); 85 } 86 87 // constructor when generating from a different process than the 88 // crashed process 89 MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, 90 mach_port_t handler_thread) 91 : writer_(), 92 exception_type_(0), 93 exception_code_(0), 94 exception_subcode_(0), 95 exception_thread_(0), 96 crashing_task_(crashing_task), 97 handler_thread_(handler_thread), 98 cpu_type_(DynamicImages::GetNativeCPUType()), 99 task_context_(NULL), 100 dynamic_images_(NULL), 101 memory_blocks_(&allocator_) { 102 if (crashing_task != mach_task_self()) { 103 dynamic_images_ = new DynamicImages(crashing_task_); 104 cpu_type_ = dynamic_images_->GetCPUType(); 105 } else { 106 dynamic_images_ = NULL; 107 cpu_type_ = DynamicImages::GetNativeCPUType(); 108 } 109 110 GatherSystemInformation(); 111 } 112 113 MinidumpGenerator::~MinidumpGenerator() { 114 delete dynamic_images_; 115 } 116 117 char MinidumpGenerator::build_string_[16]; 118 int MinidumpGenerator::os_major_version_ = 0; 119 int MinidumpGenerator::os_minor_version_ = 0; 120 int MinidumpGenerator::os_build_number_ = 0; 121 122 // static 123 void MinidumpGenerator::GatherSystemInformation() { 124 // If this is non-zero, then we've already gathered the information 125 if (os_major_version_) 126 return; 127 128 // This code extracts the version and build information from the OS 129 CFStringRef vers_path = 130 CFSTR("/System/Library/CoreServices/SystemVersion.plist"); 131 CFURLRef sys_vers = 132 CFURLCreateWithFileSystemPath(NULL, 133 vers_path, 134 kCFURLPOSIXPathStyle, 135 false); 136 CFDataRef data; 137 SInt32 error; 138 CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL, 139 &error); 140 141 if (!data) { 142 CFRelease(sys_vers); 143 return; 144 } 145 146 CFDictionaryRef list = static_cast<CFDictionaryRef> 147 (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, 148 NULL)); 149 if (!list) { 150 CFRelease(sys_vers); 151 CFRelease(data); 152 return; 153 } 154 155 CFStringRef build_version = static_cast<CFStringRef> 156 (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion"))); 157 CFStringRef product_version = static_cast<CFStringRef> 158 (CFDictionaryGetValue(list, CFSTR("ProductVersion"))); 159 string build_str = ConvertToString(build_version); 160 string product_str = ConvertToString(product_version); 161 162 CFRelease(list); 163 CFRelease(sys_vers); 164 CFRelease(data); 165 166 strlcpy(build_string_, build_str.c_str(), sizeof(build_string_)); 167 168 // Parse the string that looks like "10.4.8" 169 os_major_version_ = IntegerValueAtIndex(product_str, 0); 170 os_minor_version_ = IntegerValueAtIndex(product_str, 1); 171 os_build_number_ = IntegerValueAtIndex(product_str, 2); 172 } 173 174 void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { 175 task_context_ = task_context; 176 } 177 178 string MinidumpGenerator::UniqueNameInDirectory(const string &dir, 179 string *unique_name) { 180 CFUUIDRef uuid = CFUUIDCreate(NULL); 181 CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid); 182 CFRelease(uuid); 183 string file_name(ConvertToString(uuid_cfstr)); 184 CFRelease(uuid_cfstr); 185 string path(dir); 186 187 // Ensure that the directory (if non-empty) has a trailing slash so that 188 // we can append the file name and have a valid pathname. 189 if (!dir.empty()) { 190 if (dir.at(dir.size() - 1) != '/') 191 path.append(1, '/'); 192 } 193 194 path.append(file_name); 195 path.append(".dmp"); 196 197 if (unique_name) 198 *unique_name = file_name; 199 200 return path; 201 } 202 203 bool MinidumpGenerator::Write(const char *path) { 204 WriteStreamFN writers[] = { 205 &MinidumpGenerator::WriteThreadListStream, 206 &MinidumpGenerator::WriteMemoryListStream, 207 &MinidumpGenerator::WriteSystemInfoStream, 208 &MinidumpGenerator::WriteModuleListStream, 209 &MinidumpGenerator::WriteMiscInfoStream, 210 &MinidumpGenerator::WriteBreakpadInfoStream, 211 // Exception stream needs to be the last entry in this array as it may 212 // be omitted in the case where the minidump is written without an 213 // exception. 214 &MinidumpGenerator::WriteExceptionStream, 215 }; 216 bool result = false; 217 218 // If opening was successful, create the header, directory, and call each 219 // writer. The destructor for the TypedMDRVAs will cause the data to be 220 // flushed. The destructor for the MinidumpFileWriter will close the file. 221 if (writer_.Open(path)) { 222 TypedMDRVA<MDRawHeader> header(&writer_); 223 TypedMDRVA<MDRawDirectory> dir(&writer_); 224 225 if (!header.Allocate()) 226 return false; 227 228 int writer_count = static_cast<int>(sizeof(writers) / sizeof(writers[0])); 229 230 // If we don't have exception information, don't write out the 231 // exception stream 232 if (!exception_thread_ && !exception_type_) 233 --writer_count; 234 235 // Add space for all writers 236 if (!dir.AllocateArray(writer_count)) 237 return false; 238 239 MDRawHeader *header_ptr = header.get(); 240 header_ptr->signature = MD_HEADER_SIGNATURE; 241 header_ptr->version = MD_HEADER_VERSION; 242 time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp))); 243 header_ptr->stream_count = writer_count; 244 header_ptr->stream_directory_rva = dir.position(); 245 246 MDRawDirectory local_dir; 247 result = true; 248 for (int i = 0; (result) && (i < writer_count); ++i) { 249 result = (this->*writers[i])(&local_dir); 250 251 if (result) 252 dir.CopyIndex(i, &local_dir); 253 } 254 } 255 return result; 256 } 257 258 size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { 259 mach_vm_address_t stack_region_base = start_addr; 260 mach_vm_size_t stack_region_size; 261 natural_t nesting_level = 0; 262 vm_region_submap_info_64 submap_info; 263 mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 264 265 vm_region_recurse_info_t region_info; 266 region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info); 267 268 if (start_addr == 0) { 269 return 0; 270 } 271 272 kern_return_t result = 273 mach_vm_region_recurse(crashing_task_, &stack_region_base, 274 &stack_region_size, &nesting_level, 275 region_info, &info_count); 276 277 if (result != KERN_SUCCESS || start_addr < stack_region_base) { 278 // Failure or stack corruption, since mach_vm_region had to go 279 // higher in the process address space to find a valid region. 280 return 0; 281 } 282 283 unsigned int tag = submap_info.user_tag; 284 285 // If the user tag is VM_MEMORY_STACK, look for more readable regions with 286 // the same tag placed immediately above the computed stack region. Under 287 // some circumstances, the stack for thread 0 winds up broken up into 288 // multiple distinct abutting regions. This can happen for several reasons, 289 // including user code that calls setrlimit(RLIMIT_STACK, ...) or changes 290 // the access on stack pages by calling mprotect. 291 if (tag == VM_MEMORY_STACK) { 292 while (true) { 293 mach_vm_address_t next_region_base = stack_region_base + 294 stack_region_size; 295 mach_vm_address_t proposed_next_region_base = next_region_base; 296 mach_vm_size_t next_region_size; 297 nesting_level = 0; 298 info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 299 result = mach_vm_region_recurse(crashing_task_, &next_region_base, 300 &next_region_size, &nesting_level, 301 region_info, &info_count); 302 if (result != KERN_SUCCESS || 303 next_region_base != proposed_next_region_base || 304 submap_info.user_tag != tag || 305 (submap_info.protection & VM_PROT_READ) == 0) { 306 break; 307 } 308 309 stack_region_size += next_region_size; 310 } 311 } 312 313 return stack_region_base + stack_region_size - start_addr; 314 } 315 316 bool MinidumpGenerator::WriteStackFromStartAddress( 317 mach_vm_address_t start_addr, 318 MDMemoryDescriptor *stack_location) { 319 UntypedMDRVA memory(&writer_); 320 321 bool result = false; 322 size_t size = CalculateStackSize(start_addr); 323 324 if (size == 0) { 325 // In some situations the stack address for the thread can come back 0. 326 // In these cases we skip over the threads in question and stuff the 327 // stack with a clearly borked value. 328 start_addr = 0xDEADBEEF; 329 size = 16; 330 if (!memory.Allocate(size)) 331 return false; 332 333 unsigned long long dummy_stack[2]; // Fill dummy stack with 16 bytes of 334 // junk. 335 dummy_stack[0] = 0xDEADBEEF; 336 dummy_stack[1] = 0xDEADBEEF; 337 338 result = memory.Copy(dummy_stack, size); 339 } else { 340 341 if (!memory.Allocate(size)) 342 return false; 343 344 if (dynamic_images_) { 345 vector<uint8_t> stack_memory; 346 if (ReadTaskMemory(crashing_task_, 347 start_addr, 348 size, 349 stack_memory) != KERN_SUCCESS) { 350 return false; 351 } 352 353 result = memory.Copy(&stack_memory[0], size); 354 } else { 355 result = memory.Copy(reinterpret_cast<const void *>(start_addr), size); 356 } 357 } 358 359 stack_location->start_of_memory_range = start_addr; 360 stack_location->memory = memory.location(); 361 362 return result; 363 } 364 365 bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, 366 MDMemoryDescriptor *stack_location) { 367 switch (cpu_type_) { 368 #ifdef HAS_ARM_SUPPORT 369 case CPU_TYPE_ARM: 370 return WriteStackARM(state, stack_location); 371 #endif 372 #ifdef HAS_ARM64_SUPPORT 373 case CPU_TYPE_ARM64: 374 return WriteStackARM64(state, stack_location); 375 #endif 376 #ifdef HAS_PPC_SUPPORT 377 case CPU_TYPE_POWERPC: 378 return WriteStackPPC(state, stack_location); 379 case CPU_TYPE_POWERPC64: 380 return WriteStackPPC64(state, stack_location); 381 #endif 382 #ifdef HAS_X86_SUPPORT 383 case CPU_TYPE_I386: 384 return WriteStackX86(state, stack_location); 385 case CPU_TYPE_X86_64: 386 return WriteStackX86_64(state, stack_location); 387 #endif 388 default: 389 return false; 390 } 391 } 392 393 bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, 394 MDLocationDescriptor *register_location) { 395 switch (cpu_type_) { 396 #ifdef HAS_ARM_SUPPORT 397 case CPU_TYPE_ARM: 398 return WriteContextARM(state, register_location); 399 #endif 400 #ifdef HAS_ARM64_SUPPORT 401 case CPU_TYPE_ARM64: 402 return WriteContextARM64(state, register_location); 403 #endif 404 #ifdef HAS_PPC_SUPPORT 405 case CPU_TYPE_POWERPC: 406 return WriteContextPPC(state, register_location); 407 case CPU_TYPE_POWERPC64: 408 return WriteContextPPC64(state, register_location); 409 #endif 410 #ifdef HAS_X86_SUPPORT 411 case CPU_TYPE_I386: 412 return WriteContextX86(state, register_location); 413 case CPU_TYPE_X86_64: 414 return WriteContextX86_64(state, register_location); 415 #endif 416 default: 417 return false; 418 } 419 } 420 421 uint64_t MinidumpGenerator::CurrentPCForStack( 422 breakpad_thread_state_data_t state) { 423 switch (cpu_type_) { 424 #ifdef HAS_ARM_SUPPORT 425 case CPU_TYPE_ARM: 426 return CurrentPCForStackARM(state); 427 #endif 428 #ifdef HAS_ARM64_SUPPORT 429 case CPU_TYPE_ARM64: 430 return CurrentPCForStackARM64(state); 431 #endif 432 #ifdef HAS_PPC_SUPPORT 433 case CPU_TYPE_POWERPC: 434 return CurrentPCForStackPPC(state); 435 case CPU_TYPE_POWERPC64: 436 return CurrentPCForStackPPC64(state); 437 #endif 438 #ifdef HAS_X86_SUPPORT 439 case CPU_TYPE_I386: 440 return CurrentPCForStackX86(state); 441 case CPU_TYPE_X86_64: 442 return CurrentPCForStackX86_64(state); 443 #endif 444 default: 445 assert(0 && "Unknown CPU type!"); 446 return 0; 447 } 448 } 449 450 #ifdef HAS_ARM_SUPPORT 451 bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state, 452 MDMemoryDescriptor *stack_location) { 453 arm_thread_state_t *machine_state = 454 reinterpret_cast<arm_thread_state_t *>(state); 455 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); 456 return WriteStackFromStartAddress(start_addr, stack_location); 457 } 458 459 uint64_t 460 MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) { 461 arm_thread_state_t *machine_state = 462 reinterpret_cast<arm_thread_state_t *>(state); 463 464 return REGISTER_FROM_THREADSTATE(machine_state, pc); 465 } 466 467 bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, 468 MDLocationDescriptor *register_location) 469 { 470 TypedMDRVA<MDRawContextARM> context(&writer_); 471 arm_thread_state_t *machine_state = 472 reinterpret_cast<arm_thread_state_t *>(state); 473 474 if (!context.Allocate()) 475 return false; 476 477 *register_location = context.location(); 478 MDRawContextARM *context_ptr = context.get(); 479 context_ptr->context_flags = MD_CONTEXT_ARM_FULL; 480 481 #define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a]) 482 483 context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp); 484 context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr); 485 context_ptr->iregs[15] = REGISTER_FROM_THREADSTATE(machine_state, pc); 486 context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); 487 488 AddGPR(0); 489 AddGPR(1); 490 AddGPR(2); 491 AddGPR(3); 492 AddGPR(4); 493 AddGPR(5); 494 AddGPR(6); 495 AddGPR(7); 496 AddGPR(8); 497 AddGPR(9); 498 AddGPR(10); 499 AddGPR(11); 500 AddGPR(12); 501 #undef AddGPR 502 503 return true; 504 } 505 #endif 506 507 #ifdef HAS_ARM64_SUPPORT 508 bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state, 509 MDMemoryDescriptor *stack_location) { 510 arm_thread_state64_t *machine_state = 511 reinterpret_cast<arm_thread_state64_t *>(state); 512 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); 513 return WriteStackFromStartAddress(start_addr, stack_location); 514 } 515 516 uint64_t 517 MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) { 518 arm_thread_state64_t *machine_state = 519 reinterpret_cast<arm_thread_state64_t *>(state); 520 521 return REGISTER_FROM_THREADSTATE(machine_state, pc); 522 } 523 524 bool 525 MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, 526 MDLocationDescriptor *register_location) 527 { 528 TypedMDRVA<MDRawContextARM64> context(&writer_); 529 arm_thread_state64_t *machine_state = 530 reinterpret_cast<arm_thread_state64_t *>(state); 531 532 if (!context.Allocate()) 533 return false; 534 535 *register_location = context.location(); 536 MDRawContextARM64 *context_ptr = context.get(); 537 context_ptr->context_flags = MD_CONTEXT_ARM64_FULL; 538 539 #define AddGPR(a) context_ptr->iregs[a] = \ 540 REGISTER_FROM_THREADSTATE(machine_state, x[a]) 541 542 context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp); 543 context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr); 544 context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp); 545 context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc); 546 context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); 547 548 AddGPR(0); 549 AddGPR(1); 550 AddGPR(2); 551 AddGPR(3); 552 AddGPR(4); 553 AddGPR(5); 554 AddGPR(6); 555 AddGPR(7); 556 AddGPR(8); 557 AddGPR(9); 558 AddGPR(10); 559 AddGPR(11); 560 AddGPR(12); 561 AddGPR(13); 562 AddGPR(14); 563 AddGPR(15); 564 AddGPR(16); 565 AddGPR(17); 566 AddGPR(18); 567 AddGPR(19); 568 AddGPR(20); 569 AddGPR(21); 570 AddGPR(22); 571 AddGPR(23); 572 AddGPR(24); 573 AddGPR(25); 574 AddGPR(26); 575 AddGPR(27); 576 AddGPR(28); 577 #undef AddGPR 578 579 return true; 580 } 581 #endif 582 583 #ifdef HAS_PCC_SUPPORT 584 bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state, 585 MDMemoryDescriptor *stack_location) { 586 ppc_thread_state_t *machine_state = 587 reinterpret_cast<ppc_thread_state_t *>(state); 588 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); 589 return WriteStackFromStartAddress(start_addr, stack_location); 590 } 591 592 bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state, 593 MDMemoryDescriptor *stack_location) { 594 ppc_thread_state64_t *machine_state = 595 reinterpret_cast<ppc_thread_state64_t *>(state); 596 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1); 597 return WriteStackFromStartAddress(start_addr, stack_location); 598 } 599 600 uint64_t 601 MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) { 602 ppc_thread_state_t *machine_state = 603 reinterpret_cast<ppc_thread_state_t *>(state); 604 605 return REGISTER_FROM_THREADSTATE(machine_state, srr0); 606 } 607 608 uint64_t 609 MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) { 610 ppc_thread_state64_t *machine_state = 611 reinterpret_cast<ppc_thread_state64_t *>(state); 612 613 return REGISTER_FROM_THREADSTATE(machine_state, srr0); 614 } 615 616 bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state, 617 MDLocationDescriptor *register_location) 618 { 619 TypedMDRVA<MDRawContextPPC> context(&writer_); 620 ppc_thread_state_t *machine_state = 621 reinterpret_cast<ppc_thread_state_t *>(state); 622 623 if (!context.Allocate()) 624 return false; 625 626 *register_location = context.location(); 627 MDRawContextPPC *context_ptr = context.get(); 628 context_ptr->context_flags = MD_CONTEXT_PPC_BASE; 629 630 #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ 631 REGISTER_FROM_THREADSTATE(machine_state, a)) 632 #define AddGPR(a) context_ptr->gpr[a] = \ 633 static_cast<__typeof__(context_ptr->a)>( \ 634 REGISTER_FROM_THREADSTATE(machine_state, r ## a) 635 636 AddReg(srr0); 637 AddReg(cr); 638 AddReg(xer); 639 AddReg(ctr); 640 AddReg(lr); 641 AddReg(vrsave); 642 643 AddGPR(0); 644 AddGPR(1); 645 AddGPR(2); 646 AddGPR(3); 647 AddGPR(4); 648 AddGPR(5); 649 AddGPR(6); 650 AddGPR(7); 651 AddGPR(8); 652 AddGPR(9); 653 AddGPR(10); 654 AddGPR(11); 655 AddGPR(12); 656 AddGPR(13); 657 AddGPR(14); 658 AddGPR(15); 659 AddGPR(16); 660 AddGPR(17); 661 AddGPR(18); 662 AddGPR(19); 663 AddGPR(20); 664 AddGPR(21); 665 AddGPR(22); 666 AddGPR(23); 667 AddGPR(24); 668 AddGPR(25); 669 AddGPR(26); 670 AddGPR(27); 671 AddGPR(28); 672 AddGPR(29); 673 AddGPR(30); 674 AddGPR(31); 675 AddReg(mq); 676 #undef AddReg 677 #undef AddGPR 678 679 return true; 680 } 681 682 bool MinidumpGenerator::WriteContextPPC64( 683 breakpad_thread_state_data_t state, 684 MDLocationDescriptor *register_location) { 685 TypedMDRVA<MDRawContextPPC64> context(&writer_); 686 ppc_thread_state64_t *machine_state = 687 reinterpret_cast<ppc_thread_state64_t *>(state); 688 689 if (!context.Allocate()) 690 return false; 691 692 *register_location = context.location(); 693 MDRawContextPPC64 *context_ptr = context.get(); 694 context_ptr->context_flags = MD_CONTEXT_PPC_BASE; 695 696 #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ 697 REGISTER_FROM_THREADSTATE(machine_state, a)) 698 #define AddGPR(a) context_ptr->gpr[a] = \ 699 static_cast<__typeof__(context_ptr->a)>( \ 700 REGISTER_FROM_THREADSTATE(machine_state, r ## a) 701 702 AddReg(srr0); 703 AddReg(cr); 704 AddReg(xer); 705 AddReg(ctr); 706 AddReg(lr); 707 AddReg(vrsave); 708 709 AddGPR(0); 710 AddGPR(1); 711 AddGPR(2); 712 AddGPR(3); 713 AddGPR(4); 714 AddGPR(5); 715 AddGPR(6); 716 AddGPR(7); 717 AddGPR(8); 718 AddGPR(9); 719 AddGPR(10); 720 AddGPR(11); 721 AddGPR(12); 722 AddGPR(13); 723 AddGPR(14); 724 AddGPR(15); 725 AddGPR(16); 726 AddGPR(17); 727 AddGPR(18); 728 AddGPR(19); 729 AddGPR(20); 730 AddGPR(21); 731 AddGPR(22); 732 AddGPR(23); 733 AddGPR(24); 734 AddGPR(25); 735 AddGPR(26); 736 AddGPR(27); 737 AddGPR(28); 738 AddGPR(29); 739 AddGPR(30); 740 AddGPR(31); 741 #undef AddReg 742 #undef AddGPR 743 744 return true; 745 } 746 747 #endif 748 749 #ifdef HAS_X86_SUPPORT 750 bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, 751 MDMemoryDescriptor *stack_location) { 752 i386_thread_state_t *machine_state = 753 reinterpret_cast<i386_thread_state_t *>(state); 754 755 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); 756 return WriteStackFromStartAddress(start_addr, stack_location); 757 } 758 759 bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, 760 MDMemoryDescriptor *stack_location) { 761 x86_thread_state64_t *machine_state = 762 reinterpret_cast<x86_thread_state64_t *>(state); 763 764 mach_vm_address_t start_addr = static_cast<mach_vm_address_t>( 765 REGISTER_FROM_THREADSTATE(machine_state, rsp)); 766 return WriteStackFromStartAddress(start_addr, stack_location); 767 } 768 769 uint64_t 770 MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { 771 i386_thread_state_t *machine_state = 772 reinterpret_cast<i386_thread_state_t *>(state); 773 774 return REGISTER_FROM_THREADSTATE(machine_state, eip); 775 } 776 777 uint64_t 778 MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) { 779 x86_thread_state64_t *machine_state = 780 reinterpret_cast<x86_thread_state64_t *>(state); 781 782 return REGISTER_FROM_THREADSTATE(machine_state, rip); 783 } 784 785 bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, 786 MDLocationDescriptor *register_location) 787 { 788 TypedMDRVA<MDRawContextX86> context(&writer_); 789 i386_thread_state_t *machine_state = 790 reinterpret_cast<i386_thread_state_t *>(state); 791 792 if (!context.Allocate()) 793 return false; 794 795 *register_location = context.location(); 796 MDRawContextX86 *context_ptr = context.get(); 797 798 #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ 799 REGISTER_FROM_THREADSTATE(machine_state, a)) 800 801 context_ptr->context_flags = MD_CONTEXT_X86; 802 AddReg(eax); 803 AddReg(ebx); 804 AddReg(ecx); 805 AddReg(edx); 806 AddReg(esi); 807 AddReg(edi); 808 AddReg(ebp); 809 AddReg(esp); 810 811 AddReg(cs); 812 AddReg(ds); 813 AddReg(ss); 814 AddReg(es); 815 AddReg(fs); 816 AddReg(gs); 817 AddReg(eflags); 818 819 AddReg(eip); 820 #undef AddReg 821 822 return true; 823 } 824 825 bool MinidumpGenerator::WriteContextX86_64( 826 breakpad_thread_state_data_t state, 827 MDLocationDescriptor *register_location) { 828 TypedMDRVA<MDRawContextAMD64> context(&writer_); 829 x86_thread_state64_t *machine_state = 830 reinterpret_cast<x86_thread_state64_t *>(state); 831 832 if (!context.Allocate()) 833 return false; 834 835 *register_location = context.location(); 836 MDRawContextAMD64 *context_ptr = context.get(); 837 838 #define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ 839 REGISTER_FROM_THREADSTATE(machine_state, a)) 840 841 context_ptr->context_flags = MD_CONTEXT_AMD64; 842 AddReg(rax); 843 AddReg(rbx); 844 AddReg(rcx); 845 AddReg(rdx); 846 AddReg(rdi); 847 AddReg(rsi); 848 AddReg(rbp); 849 AddReg(rsp); 850 AddReg(r8); 851 AddReg(r9); 852 AddReg(r10); 853 AddReg(r11); 854 AddReg(r12); 855 AddReg(r13); 856 AddReg(r14); 857 AddReg(r15); 858 AddReg(rip); 859 // according to AMD's software developer guide, bits above 18 are 860 // not used in the flags register. Since the minidump format 861 // specifies 32 bits for the flags register, we can truncate safely 862 // with no loss. 863 context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags)); 864 AddReg(cs); 865 AddReg(fs); 866 AddReg(gs); 867 #undef AddReg 868 869 return true; 870 } 871 #endif 872 873 bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, 874 thread_state_t state, 875 mach_msg_type_number_t *count) { 876 if (task_context_ && target_thread == mach_thread_self()) { 877 switch (cpu_type_) { 878 #ifdef HAS_ARM_SUPPORT 879 case CPU_TYPE_ARM: 880 size_t final_size = 881 std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t)); 882 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 883 *count = static_cast<mach_msg_type_number_t>(final_size); 884 return true; 885 #endif 886 #ifdef HAS_ARM64_SUPPORT 887 case CPU_TYPE_ARM64: { 888 size_t final_size = 889 std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t)); 890 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 891 *count = static_cast<mach_msg_type_number_t>(final_size); 892 return true; 893 } 894 #endif 895 #ifdef HAS_X86_SUPPORT 896 case CPU_TYPE_I386: 897 case CPU_TYPE_X86_64: { 898 size_t state_size = cpu_type_ == CPU_TYPE_I386 ? 899 sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); 900 size_t final_size = 901 std::min(static_cast<size_t>(*count), state_size); 902 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 903 *count = static_cast<mach_msg_type_number_t>(final_size); 904 return true; 905 } 906 #endif 907 } 908 } 909 910 thread_state_flavor_t flavor; 911 switch (cpu_type_) { 912 #ifdef HAS_ARM_SUPPORT 913 case CPU_TYPE_ARM: 914 flavor = ARM_THREAD_STATE; 915 break; 916 #endif 917 #ifdef HAS_ARM64_SUPPORT 918 case CPU_TYPE_ARM64: 919 flavor = ARM_THREAD_STATE64; 920 break; 921 #endif 922 #ifdef HAS_PPC_SUPPORT 923 case CPU_TYPE_POWERPC: 924 flavor = PPC_THREAD_STATE; 925 break; 926 case CPU_TYPE_POWERPC64: 927 flavor = PPC_THREAD_STATE64; 928 break; 929 #endif 930 #ifdef HAS_X86_SUPPORT 931 case CPU_TYPE_I386: 932 flavor = i386_THREAD_STATE; 933 break; 934 case CPU_TYPE_X86_64: 935 flavor = x86_THREAD_STATE64; 936 break; 937 #endif 938 default: 939 return false; 940 } 941 return thread_get_state(target_thread, flavor, 942 state, count) == KERN_SUCCESS; 943 } 944 945 bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, 946 MDRawThread *thread) { 947 breakpad_thread_state_data_t state; 948 mach_msg_type_number_t state_count 949 = static_cast<mach_msg_type_number_t>(sizeof(state)); 950 951 if (GetThreadState(thread_id, state, &state_count)) { 952 if (!WriteStack(state, &thread->stack)) 953 return false; 954 955 memory_blocks_.push_back(thread->stack); 956 957 if (!WriteContext(state, &thread->thread_context)) 958 return false; 959 960 thread->thread_id = thread_id; 961 } else { 962 return false; 963 } 964 965 return true; 966 } 967 968 bool MinidumpGenerator::WriteThreadListStream( 969 MDRawDirectory *thread_list_stream) { 970 TypedMDRVA<MDRawThreadList> list(&writer_); 971 thread_act_port_array_t threads_for_task; 972 mach_msg_type_number_t thread_count; 973 int non_generator_thread_count; 974 975 if (task_threads(crashing_task_, &threads_for_task, &thread_count)) 976 return false; 977 978 // Don't include the generator thread 979 if (handler_thread_ != MACH_PORT_NULL) 980 non_generator_thread_count = thread_count - 1; 981 else 982 non_generator_thread_count = thread_count; 983 if (!list.AllocateObjectAndArray(non_generator_thread_count, 984 sizeof(MDRawThread))) 985 return false; 986 987 thread_list_stream->stream_type = MD_THREAD_LIST_STREAM; 988 thread_list_stream->location = list.location(); 989 990 list.get()->number_of_threads = non_generator_thread_count; 991 992 MDRawThread thread; 993 int thread_idx = 0; 994 995 for (unsigned int i = 0; i < thread_count; ++i) { 996 memset(&thread, 0, sizeof(MDRawThread)); 997 998 if (threads_for_task[i] != handler_thread_) { 999 if (!WriteThreadStream(threads_for_task[i], &thread)) 1000 return false; 1001 1002 list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread)); 1003 } 1004 } 1005 1006 return true; 1007 } 1008 1009 bool MinidumpGenerator::WriteMemoryListStream( 1010 MDRawDirectory *memory_list_stream) { 1011 TypedMDRVA<MDRawMemoryList> list(&writer_); 1012 1013 // If the dump has an exception, include some memory around the 1014 // instruction pointer. 1015 const size_t kIPMemorySize = 256; // bytes 1016 bool have_ip_memory = false; 1017 MDMemoryDescriptor ip_memory_d; 1018 if (exception_thread_ && exception_type_) { 1019 breakpad_thread_state_data_t state; 1020 mach_msg_type_number_t stateCount 1021 = static_cast<mach_msg_type_number_t>(sizeof(state)); 1022 1023 if (GetThreadState(exception_thread_, state, &stateCount)) { 1024 uint64_t ip = CurrentPCForStack(state); 1025 // Bound it to the upper and lower bounds of the region 1026 // it's contained within. If it's not in a known memory region, 1027 // don't bother trying to write it. 1028 mach_vm_address_t addr = static_cast<vm_address_t>(ip); 1029 mach_vm_size_t size; 1030 natural_t nesting_level = 0; 1031 vm_region_submap_info_64 info; 1032 mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 1033 vm_region_recurse_info_t recurse_info; 1034 recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info); 1035 1036 kern_return_t ret = 1037 mach_vm_region_recurse(crashing_task_, 1038 &addr, 1039 &size, 1040 &nesting_level, 1041 recurse_info, 1042 &info_count); 1043 if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) { 1044 // Try to get 128 bytes before and after the IP, but 1045 // settle for whatever's available. 1046 ip_memory_d.start_of_memory_range = 1047 std::max(uintptr_t(addr), 1048 uintptr_t(ip - (kIPMemorySize / 2))); 1049 uintptr_t end_of_range = 1050 std::min(uintptr_t(ip + (kIPMemorySize / 2)), 1051 uintptr_t(addr + size)); 1052 uintptr_t range_diff = end_of_range - 1053 static_cast<uintptr_t>(ip_memory_d.start_of_memory_range); 1054 ip_memory_d.memory.data_size = static_cast<uint32_t>(range_diff); 1055 have_ip_memory = true; 1056 // This needs to get appended to the list even though 1057 // the memory bytes aren't filled in yet so the entire 1058 // list can be written first. The memory bytes will get filled 1059 // in after the memory list is written. 1060 memory_blocks_.push_back(ip_memory_d); 1061 } 1062 } 1063 } 1064 1065 // Now fill in the memory list and write it. 1066 size_t memory_count = memory_blocks_.size(); 1067 if (!list.AllocateObjectAndArray(memory_count, 1068 sizeof(MDMemoryDescriptor))) 1069 return false; 1070 1071 memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM; 1072 memory_list_stream->location = list.location(); 1073 1074 list.get()->number_of_memory_ranges = static_cast<uint32_t>(memory_count); 1075 1076 unsigned int i; 1077 for (i = 0; i < memory_count; ++i) { 1078 list.CopyIndexAfterObject(i, &memory_blocks_[i], 1079 sizeof(MDMemoryDescriptor)); 1080 } 1081 1082 if (have_ip_memory) { 1083 // Now read the memory around the instruction pointer. 1084 UntypedMDRVA ip_memory(&writer_); 1085 if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) 1086 return false; 1087 1088 if (dynamic_images_) { 1089 // Out-of-process. 1090 vector<uint8_t> memory; 1091 if (ReadTaskMemory(crashing_task_, 1092 ip_memory_d.start_of_memory_range, 1093 ip_memory_d.memory.data_size, 1094 memory) != KERN_SUCCESS) { 1095 return false; 1096 } 1097 1098 ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size); 1099 } else { 1100 // In-process, just copy from local memory. 1101 ip_memory.Copy( 1102 reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range), 1103 ip_memory_d.memory.data_size); 1104 } 1105 1106 ip_memory_d.memory = ip_memory.location(); 1107 // Write this again now that the data location is filled in. 1108 list.CopyIndexAfterObject(i - 1, &ip_memory_d, 1109 sizeof(MDMemoryDescriptor)); 1110 } 1111 1112 return true; 1113 } 1114 1115 bool 1116 MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { 1117 TypedMDRVA<MDRawExceptionStream> exception(&writer_); 1118 1119 if (!exception.Allocate()) 1120 return false; 1121 1122 exception_stream->stream_type = MD_EXCEPTION_STREAM; 1123 exception_stream->location = exception.location(); 1124 MDRawExceptionStream *exception_ptr = exception.get(); 1125 exception_ptr->thread_id = exception_thread_; 1126 1127 // This naming is confusing, but it is the proper translation from 1128 // mach naming to minidump naming. 1129 exception_ptr->exception_record.exception_code = exception_type_; 1130 exception_ptr->exception_record.exception_flags = exception_code_; 1131 1132 breakpad_thread_state_data_t state; 1133 mach_msg_type_number_t state_count 1134 = static_cast<mach_msg_type_number_t>(sizeof(state)); 1135 1136 if (!GetThreadState(exception_thread_, state, &state_count)) 1137 return false; 1138 1139 if (!WriteContext(state, &exception_ptr->thread_context)) 1140 return false; 1141 1142 if (exception_type_ == EXC_BAD_ACCESS) 1143 exception_ptr->exception_record.exception_address = exception_subcode_; 1144 else 1145 exception_ptr->exception_record.exception_address = CurrentPCForStack(state); 1146 1147 return true; 1148 } 1149 1150 bool MinidumpGenerator::WriteSystemInfoStream( 1151 MDRawDirectory *system_info_stream) { 1152 TypedMDRVA<MDRawSystemInfo> info(&writer_); 1153 1154 if (!info.Allocate()) 1155 return false; 1156 1157 system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM; 1158 system_info_stream->location = info.location(); 1159 1160 // CPU Information 1161 uint32_t number_of_processors; 1162 size_t len = sizeof(number_of_processors); 1163 sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); 1164 MDRawSystemInfo *info_ptr = info.get(); 1165 1166 switch (cpu_type_) { 1167 #ifdef HAS_ARM_SUPPORT 1168 case CPU_TYPE_ARM: 1169 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM; 1170 break; 1171 #endif 1172 #ifdef HAS_ARM64_SUPPORT 1173 case CPU_TYPE_ARM64: 1174 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64; 1175 break; 1176 #endif 1177 #ifdef HAS_PPC_SUPPORT 1178 case CPU_TYPE_POWERPC: 1179 case CPU_TYPE_POWERPC64: 1180 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; 1181 break; 1182 #endif 1183 #ifdef HAS_X86_SUPPORT 1184 case CPU_TYPE_I386: 1185 case CPU_TYPE_X86_64: 1186 if (cpu_type_ == CPU_TYPE_I386) 1187 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; 1188 else 1189 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64; 1190 #ifdef __i386__ 1191 // ebx is used for PIC code, so we need 1192 // to preserve it. 1193 #define cpuid(op,eax,ebx,ecx,edx) \ 1194 asm ("pushl %%ebx \n\t" \ 1195 "cpuid \n\t" \ 1196 "movl %%ebx,%1 \n\t" \ 1197 "popl %%ebx" \ 1198 : "=a" (eax), \ 1199 "=g" (ebx), \ 1200 "=c" (ecx), \ 1201 "=d" (edx) \ 1202 : "0" (op)) 1203 #elif defined(__x86_64__) 1204 1205 #define cpuid(op,eax,ebx,ecx,edx) \ 1206 asm ("cpuid \n\t" \ 1207 : "=a" (eax), \ 1208 "=b" (ebx), \ 1209 "=c" (ecx), \ 1210 "=d" (edx) \ 1211 : "0" (op)) 1212 #endif 1213 1214 #if defined(__i386__) || defined(__x86_64__) 1215 int unused, unused2; 1216 // get vendor id 1217 cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0], 1218 info_ptr->cpu.x86_cpu_info.vendor_id[2], 1219 info_ptr->cpu.x86_cpu_info.vendor_id[1]); 1220 // get version and feature info 1221 cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2, 1222 info_ptr->cpu.x86_cpu_info.feature_information); 1223 1224 // family 1225 info_ptr->processor_level = 1226 (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8; 1227 // 0xMMSS (Model, Stepping) 1228 info_ptr->processor_revision = static_cast<uint16_t>( 1229 (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | 1230 ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4)); 1231 1232 // decode extended model info 1233 if (info_ptr->processor_level == 0xF || 1234 info_ptr->processor_level == 0x6) { 1235 info_ptr->processor_revision |= 1236 ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4); 1237 } 1238 1239 // decode extended family info 1240 if (info_ptr->processor_level == 0xF) { 1241 info_ptr->processor_level += 1242 ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20); 1243 } 1244 1245 #endif // __i386__ || __x86_64_ 1246 break; 1247 #endif // HAS_X86_SUPPORT 1248 default: 1249 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; 1250 break; 1251 } 1252 1253 info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors); 1254 #if TARGET_OS_IPHONE 1255 info_ptr->platform_id = MD_OS_IOS; 1256 #else 1257 info_ptr->platform_id = MD_OS_MAC_OS_X; 1258 #endif // TARGET_OS_IPHONE 1259 1260 MDLocationDescriptor build_string_loc; 1261 1262 if (!writer_.WriteString(build_string_, 0, 1263 &build_string_loc)) 1264 return false; 1265 1266 info_ptr->csd_version_rva = build_string_loc.rva; 1267 info_ptr->major_version = os_major_version_; 1268 info_ptr->minor_version = os_minor_version_; 1269 info_ptr->build_number = os_build_number_; 1270 1271 return true; 1272 } 1273 1274 bool MinidumpGenerator::WriteModuleStream(unsigned int index, 1275 MDRawModule *module) { 1276 if (dynamic_images_) { 1277 // we're in a different process than the crashed process 1278 DynamicImage *image = dynamic_images_->GetImage(index); 1279 1280 if (!image) 1281 return false; 1282 1283 memset(module, 0, sizeof(MDRawModule)); 1284 1285 MDLocationDescriptor string_location; 1286 1287 string name = image->GetFilePath(); 1288 if (!writer_.WriteString(name.c_str(), 0, &string_location)) 1289 return false; 1290 1291 module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); 1292 module->size_of_image = static_cast<uint32_t>(image->GetVMSize()); 1293 module->module_name_rva = string_location.rva; 1294 1295 // We'll skip the executable module, because they don't have 1296 // LC_ID_DYLIB load commands, and the crash processing server gets 1297 // version information from the Plist file, anyway. 1298 if (index != static_cast<uint32_t>(FindExecutableModule())) { 1299 module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE; 1300 module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION; 1301 // Convert MAC dylib version format, which is a 32 bit number, to the 1302 // format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits> 1303 // so it fits nicely into the windows version with some massaging 1304 // The mapping is: 1305 // 1) upper 16 bits of MAC version go to lower 16 bits of product HI 1306 // 2) Next most significant 8 bits go to upper 16 bits of product LO 1307 // 3) Least significant 8 bits go to lower 16 bits of product LO 1308 uint32_t modVersion = image->GetVersion(); 1309 module->version_info.file_version_hi = 0; 1310 module->version_info.file_version_hi = modVersion >> 16; 1311 module->version_info.file_version_lo |= (modVersion & 0xff00) << 8; 1312 module->version_info.file_version_lo |= (modVersion & 0xff); 1313 } 1314 1315 if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) { 1316 return false; 1317 } 1318 } else { 1319 // Getting module info in the crashed process 1320 const breakpad_mach_header *header; 1321 header = (breakpad_mach_header*)_dyld_get_image_header(index); 1322 if (!header) 1323 return false; 1324 1325 #ifdef __LP64__ 1326 assert(header->magic == MH_MAGIC_64); 1327 1328 if(header->magic != MH_MAGIC_64) 1329 return false; 1330 #else 1331 assert(header->magic == MH_MAGIC); 1332 1333 if(header->magic != MH_MAGIC) 1334 return false; 1335 #endif 1336 1337 int cpu_type = header->cputype; 1338 unsigned long slide = _dyld_get_image_vmaddr_slide(index); 1339 const char* name = _dyld_get_image_name(index); 1340 const struct load_command *cmd = 1341 reinterpret_cast<const struct load_command *>(header + 1); 1342 1343 memset(module, 0, sizeof(MDRawModule)); 1344 1345 for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { 1346 if (cmd->cmd == LC_SEGMENT_ARCH) { 1347 1348 const breakpad_mach_segment_command *seg = 1349 reinterpret_cast<const breakpad_mach_segment_command *>(cmd); 1350 1351 if (!strcmp(seg->segname, "__TEXT")) { 1352 MDLocationDescriptor string_location; 1353 1354 if (!writer_.WriteString(name, 0, &string_location)) 1355 return false; 1356 1357 module->base_of_image = seg->vmaddr + slide; 1358 module->size_of_image = static_cast<uint32_t>(seg->vmsize); 1359 module->module_name_rva = string_location.rva; 1360 1361 bool in_memory = false; 1362 #if TARGET_OS_IPHONE 1363 in_memory = true; 1364 #endif 1365 if (!WriteCVRecord(module, cpu_type, name, in_memory)) 1366 return false; 1367 1368 return true; 1369 } 1370 } 1371 1372 cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize); 1373 } 1374 } 1375 1376 return true; 1377 } 1378 1379 int MinidumpGenerator::FindExecutableModule() { 1380 if (dynamic_images_) { 1381 int index = dynamic_images_->GetExecutableImageIndex(); 1382 1383 if (index >= 0) { 1384 return index; 1385 } 1386 } else { 1387 int image_count = _dyld_image_count(); 1388 const struct mach_header *header; 1389 1390 for (int index = 0; index < image_count; ++index) { 1391 header = _dyld_get_image_header(index); 1392 1393 if (header->filetype == MH_EXECUTE) 1394 return index; 1395 } 1396 } 1397 1398 // failed - just use the first image 1399 return 0; 1400 } 1401 1402 bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, 1403 const char *module_path, bool in_memory) { 1404 TypedMDRVA<MDCVInfoPDB70> cv(&writer_); 1405 1406 // Only return the last path component of the full module path 1407 const char *module_name = strrchr(module_path, '/'); 1408 1409 // Increment past the slash 1410 if (module_name) 1411 ++module_name; 1412 else 1413 module_name = "<Unknown>"; 1414 1415 size_t module_name_length = strlen(module_name); 1416 1417 if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t))) 1418 return false; 1419 1420 if (!cv.CopyIndexAfterObject(0, module_name, module_name_length)) 1421 return false; 1422 1423 module->cv_record = cv.location(); 1424 MDCVInfoPDB70 *cv_ptr = cv.get(); 1425 cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; 1426 cv_ptr->age = 0; 1427 1428 // Get the module identifier 1429 unsigned char identifier[16]; 1430 bool result = false; 1431 if (in_memory) { 1432 MacFileUtilities::MachoID macho(module_path, 1433 reinterpret_cast<void *>(module->base_of_image), 1434 static_cast<size_t>(module->size_of_image)); 1435 result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); 1436 if (!result) 1437 result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); 1438 } 1439 1440 if (!result) { 1441 FileID file_id(module_path); 1442 result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE, 1443 identifier); 1444 } 1445 1446 if (result) { 1447 cv_ptr->signature.data1 = 1448 static_cast<uint32_t>(identifier[0]) << 24 | 1449 static_cast<uint32_t>(identifier[1]) << 16 | 1450 static_cast<uint32_t>(identifier[2]) << 8 | 1451 static_cast<uint32_t>(identifier[3]); 1452 cv_ptr->signature.data2 = 1453 static_cast<uint16_t>(identifier[4] << 8) | identifier[5]; 1454 cv_ptr->signature.data3 = 1455 static_cast<uint16_t>(identifier[6] << 8) | identifier[7]; 1456 cv_ptr->signature.data4[0] = identifier[8]; 1457 cv_ptr->signature.data4[1] = identifier[9]; 1458 cv_ptr->signature.data4[2] = identifier[10]; 1459 cv_ptr->signature.data4[3] = identifier[11]; 1460 cv_ptr->signature.data4[4] = identifier[12]; 1461 cv_ptr->signature.data4[5] = identifier[13]; 1462 cv_ptr->signature.data4[6] = identifier[14]; 1463 cv_ptr->signature.data4[7] = identifier[15]; 1464 } 1465 1466 return true; 1467 } 1468 1469 bool MinidumpGenerator::WriteModuleListStream( 1470 MDRawDirectory *module_list_stream) { 1471 TypedMDRVA<MDRawModuleList> list(&writer_); 1472 1473 uint32_t image_count = dynamic_images_ ? 1474 dynamic_images_->GetImageCount() : 1475 _dyld_image_count(); 1476 1477 if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE)) 1478 return false; 1479 1480 module_list_stream->stream_type = MD_MODULE_LIST_STREAM; 1481 module_list_stream->location = list.location(); 1482 list.get()->number_of_modules = static_cast<uint32_t>(image_count); 1483 1484 // Write out the executable module as the first one 1485 MDRawModule module; 1486 uint32_t executableIndex = FindExecutableModule(); 1487 1488 if (!WriteModuleStream(static_cast<unsigned>(executableIndex), &module)) { 1489 return false; 1490 } 1491 1492 list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE); 1493 int destinationIndex = 1; // Write all other modules after this one 1494 1495 for (uint32_t i = 0; i < image_count; ++i) { 1496 if (i != executableIndex) { 1497 if (!WriteModuleStream(static_cast<unsigned>(i), &module)) { 1498 return false; 1499 } 1500 1501 list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); 1502 } 1503 } 1504 1505 return true; 1506 } 1507 1508 bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { 1509 TypedMDRVA<MDRawMiscInfo> info(&writer_); 1510 1511 if (!info.Allocate()) 1512 return false; 1513 1514 misc_info_stream->stream_type = MD_MISC_INFO_STREAM; 1515 misc_info_stream->location = info.location(); 1516 1517 MDRawMiscInfo *info_ptr = info.get(); 1518 info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo)); 1519 info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID | 1520 MD_MISCINFO_FLAGS1_PROCESS_TIMES | 1521 MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO; 1522 1523 // Process ID 1524 info_ptr->process_id = getpid(); 1525 1526 // Times 1527 struct rusage usage; 1528 if (getrusage(RUSAGE_SELF, &usage) != -1) { 1529 // Omit the fractional time since the MDRawMiscInfo only wants seconds 1530 info_ptr->process_user_time = 1531 static_cast<uint32_t>(usage.ru_utime.tv_sec); 1532 info_ptr->process_kernel_time = 1533 static_cast<uint32_t>(usage.ru_stime.tv_sec); 1534 } 1535 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 1536 static_cast<int>(info_ptr->process_id) }; 1537 uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0])); 1538 struct kinfo_proc proc; 1539 size_t size = sizeof(proc); 1540 if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) { 1541 info_ptr->process_create_time = 1542 static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec); 1543 } 1544 1545 // Speed 1546 uint64_t speed; 1547 const uint64_t kOneMillion = 1000 * 1000; 1548 size = sizeof(speed); 1549 sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); 1550 info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion); 1551 info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion); 1552 size = sizeof(speed); 1553 sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); 1554 info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion); 1555 1556 return true; 1557 } 1558 1559 bool MinidumpGenerator::WriteBreakpadInfoStream( 1560 MDRawDirectory *breakpad_info_stream) { 1561 TypedMDRVA<MDRawBreakpadInfo> info(&writer_); 1562 1563 if (!info.Allocate()) 1564 return false; 1565 1566 breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM; 1567 breakpad_info_stream->location = info.location(); 1568 MDRawBreakpadInfo *info_ptr = info.get(); 1569 1570 if (exception_thread_ && exception_type_) { 1571 info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | 1572 MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; 1573 info_ptr->dump_thread_id = handler_thread_; 1574 info_ptr->requesting_thread_id = exception_thread_; 1575 } else { 1576 info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID; 1577 info_ptr->dump_thread_id = handler_thread_; 1578 info_ptr->requesting_thread_id = 0; 1579 } 1580 1581 return true; 1582 } 1583 1584 } // namespace google_breakpad 1585