minidump_generator.cc revision a157c99f9fdfc5f5072db05a5075ae23fce43c88
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 60using MacStringUtils::ConvertToString; 61using MacStringUtils::IntegerValueAtIndex; 62 63namespace google_breakpad { 64 65#if __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 72MinidumpGenerator::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 89MinidumpGenerator::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 113MinidumpGenerator::~MinidumpGenerator() { 114 delete dynamic_images_; 115} 116 117char MinidumpGenerator::build_string_[16]; 118int MinidumpGenerator::os_major_version_ = 0; 119int MinidumpGenerator::os_minor_version_ = 0; 120int MinidumpGenerator::os_build_number_ = 0; 121 122// static 123void 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 174void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { 175 task_context_ = task_context; 176} 177 178string 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 203bool 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 258size_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 316bool 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 365bool 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 393bool 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 421uint64_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 451bool 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 459uint64_t 460MinidumpGenerator::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 467bool 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 508bool 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 516uint64_t 517MinidumpGenerator::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 524bool 525MinidumpGenerator::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 584bool 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 592bool 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 600uint64_t 601MinidumpGenerator::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 608uint64_t 609MinidumpGenerator::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 616bool 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 = REGISTER_FROM_THREADSTATE(machine_state, a) 631#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a) 632 633 AddReg(srr0); 634 AddReg(cr); 635 AddReg(xer); 636 AddReg(ctr); 637 AddReg(lr); 638 AddReg(vrsave); 639 640 AddGPR(0); 641 AddGPR(1); 642 AddGPR(2); 643 AddGPR(3); 644 AddGPR(4); 645 AddGPR(5); 646 AddGPR(6); 647 AddGPR(7); 648 AddGPR(8); 649 AddGPR(9); 650 AddGPR(10); 651 AddGPR(11); 652 AddGPR(12); 653 AddGPR(13); 654 AddGPR(14); 655 AddGPR(15); 656 AddGPR(16); 657 AddGPR(17); 658 AddGPR(18); 659 AddGPR(19); 660 AddGPR(20); 661 AddGPR(21); 662 AddGPR(22); 663 AddGPR(23); 664 AddGPR(24); 665 AddGPR(25); 666 AddGPR(26); 667 AddGPR(27); 668 AddGPR(28); 669 AddGPR(29); 670 AddGPR(30); 671 AddGPR(31); 672 AddReg(mq); 673#undef AddReg 674#undef AddGPR 675 676 return true; 677} 678 679bool MinidumpGenerator::WriteContextPPC64( 680 breakpad_thread_state_data_t state, 681 MDLocationDescriptor *register_location) { 682 TypedMDRVA<MDRawContextPPC64> context(&writer_); 683 ppc_thread_state64_t *machine_state = 684 reinterpret_cast<ppc_thread_state64_t *>(state); 685 686 if (!context.Allocate()) 687 return false; 688 689 *register_location = context.location(); 690 MDRawContextPPC64 *context_ptr = context.get(); 691 context_ptr->context_flags = MD_CONTEXT_PPC_BASE; 692 693#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) 694#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a) 695 696 AddReg(srr0); 697 AddReg(cr); 698 AddReg(xer); 699 AddReg(ctr); 700 AddReg(lr); 701 AddReg(vrsave); 702 703 AddGPR(0); 704 AddGPR(1); 705 AddGPR(2); 706 AddGPR(3); 707 AddGPR(4); 708 AddGPR(5); 709 AddGPR(6); 710 AddGPR(7); 711 AddGPR(8); 712 AddGPR(9); 713 AddGPR(10); 714 AddGPR(11); 715 AddGPR(12); 716 AddGPR(13); 717 AddGPR(14); 718 AddGPR(15); 719 AddGPR(16); 720 AddGPR(17); 721 AddGPR(18); 722 AddGPR(19); 723 AddGPR(20); 724 AddGPR(21); 725 AddGPR(22); 726 AddGPR(23); 727 AddGPR(24); 728 AddGPR(25); 729 AddGPR(26); 730 AddGPR(27); 731 AddGPR(28); 732 AddGPR(29); 733 AddGPR(30); 734 AddGPR(31); 735#undef AddReg 736#undef AddGPR 737 738 return true; 739} 740 741#endif 742 743#ifdef HAS_X86_SUPPORT 744bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, 745 MDMemoryDescriptor *stack_location) { 746 i386_thread_state_t *machine_state = 747 reinterpret_cast<i386_thread_state_t *>(state); 748 749 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); 750 return WriteStackFromStartAddress(start_addr, stack_location); 751} 752 753bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state, 754 MDMemoryDescriptor *stack_location) { 755 x86_thread_state64_t *machine_state = 756 reinterpret_cast<x86_thread_state64_t *>(state); 757 758 mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp); 759 return WriteStackFromStartAddress(start_addr, stack_location); 760} 761 762uint64_t 763MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { 764 i386_thread_state_t *machine_state = 765 reinterpret_cast<i386_thread_state_t *>(state); 766 767 return REGISTER_FROM_THREADSTATE(machine_state, eip); 768} 769 770uint64_t 771MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) { 772 x86_thread_state64_t *machine_state = 773 reinterpret_cast<x86_thread_state64_t *>(state); 774 775 return REGISTER_FROM_THREADSTATE(machine_state, rip); 776} 777 778bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state, 779 MDLocationDescriptor *register_location) 780{ 781 TypedMDRVA<MDRawContextX86> context(&writer_); 782 i386_thread_state_t *machine_state = 783 reinterpret_cast<i386_thread_state_t *>(state); 784 785 if (!context.Allocate()) 786 return false; 787 788 *register_location = context.location(); 789 MDRawContextX86 *context_ptr = context.get(); 790 791#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) 792 793 context_ptr->context_flags = MD_CONTEXT_X86; 794 AddReg(eax); 795 AddReg(ebx); 796 AddReg(ecx); 797 AddReg(edx); 798 AddReg(esi); 799 AddReg(edi); 800 AddReg(ebp); 801 AddReg(esp); 802 803 AddReg(cs); 804 AddReg(ds); 805 AddReg(ss); 806 AddReg(es); 807 AddReg(fs); 808 AddReg(gs); 809 AddReg(eflags); 810 811 AddReg(eip); 812#undef AddReg 813 814 return true; 815} 816 817bool MinidumpGenerator::WriteContextX86_64( 818 breakpad_thread_state_data_t state, 819 MDLocationDescriptor *register_location) { 820 TypedMDRVA<MDRawContextAMD64> context(&writer_); 821 x86_thread_state64_t *machine_state = 822 reinterpret_cast<x86_thread_state64_t *>(state); 823 824 if (!context.Allocate()) 825 return false; 826 827 *register_location = context.location(); 828 MDRawContextAMD64 *context_ptr = context.get(); 829 830#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) 831 832 context_ptr->context_flags = MD_CONTEXT_AMD64; 833 AddReg(rax); 834 AddReg(rbx); 835 AddReg(rcx); 836 AddReg(rdx); 837 AddReg(rdi); 838 AddReg(rsi); 839 AddReg(rbp); 840 AddReg(rsp); 841 AddReg(r8); 842 AddReg(r9); 843 AddReg(r10); 844 AddReg(r11); 845 AddReg(r12); 846 AddReg(r13); 847 AddReg(r14); 848 AddReg(r15); 849 AddReg(rip); 850 // according to AMD's software developer guide, bits above 18 are 851 // not used in the flags register. Since the minidump format 852 // specifies 32 bits for the flags register, we can truncate safely 853 // with no loss. 854 context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags)); 855 AddReg(cs); 856 AddReg(fs); 857 AddReg(gs); 858#undef AddReg 859 860 return true; 861} 862#endif 863 864bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, 865 thread_state_t state, 866 mach_msg_type_number_t *count) { 867 if (task_context_ && target_thread == mach_thread_self()) { 868 switch (cpu_type_) { 869#ifdef HAS_ARM_SUPPORT 870 case CPU_TYPE_ARM: 871 size_t final_size = 872 std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t)); 873 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 874 *count = final_size; 875 return true; 876#endif 877#ifdef HAS_ARM64_SUPPORT 878 case CPU_TYPE_ARM64: { 879 size_t final_size = 880 std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t)); 881 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 882 *count = final_size; 883 return true; 884 } 885#endif 886#ifdef HAS_X86_SUPPORT 887 case CPU_TYPE_I386: 888 case CPU_TYPE_X86_64: { 889 size_t state_size = cpu_type_ == CPU_TYPE_I386 ? 890 sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); 891 size_t final_size = 892 std::min(static_cast<size_t>(*count), state_size); 893 memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); 894 *count = final_size; 895 return true; 896 } 897#endif 898 } 899 } 900 901 thread_state_flavor_t flavor; 902 switch (cpu_type_) { 903#ifdef HAS_ARM_SUPPORT 904 case CPU_TYPE_ARM: 905 flavor = ARM_THREAD_STATE; 906 break; 907#endif 908#ifdef HAS_ARM64_SUPPORT 909 case CPU_TYPE_ARM64: 910 flavor = ARM_THREAD_STATE64; 911 break; 912#endif 913#ifdef HAS_PPC_SUPPORT 914 case CPU_TYPE_POWERPC: 915 flavor = PPC_THREAD_STATE; 916 break; 917 case CPU_TYPE_POWERPC64: 918 flavor = PPC_THREAD_STATE64; 919 break; 920#endif 921#ifdef HAS_X86_SUPPORT 922 case CPU_TYPE_I386: 923 flavor = i386_THREAD_STATE; 924 break; 925 case CPU_TYPE_X86_64: 926 flavor = x86_THREAD_STATE64; 927 break; 928#endif 929 default: 930 return false; 931 } 932 return thread_get_state(target_thread, flavor, 933 state, count) == KERN_SUCCESS; 934} 935 936bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, 937 MDRawThread *thread) { 938 breakpad_thread_state_data_t state; 939 mach_msg_type_number_t state_count 940 = static_cast<mach_msg_type_number_t>(sizeof(state)); 941 942 if (GetThreadState(thread_id, state, &state_count)) { 943 if (!WriteStack(state, &thread->stack)) 944 return false; 945 946 memory_blocks_.push_back(thread->stack); 947 948 if (!WriteContext(state, &thread->thread_context)) 949 return false; 950 951 thread->thread_id = thread_id; 952 } else { 953 return false; 954 } 955 956 return true; 957} 958 959bool MinidumpGenerator::WriteThreadListStream( 960 MDRawDirectory *thread_list_stream) { 961 TypedMDRVA<MDRawThreadList> list(&writer_); 962 thread_act_port_array_t threads_for_task; 963 mach_msg_type_number_t thread_count; 964 int non_generator_thread_count; 965 966 if (task_threads(crashing_task_, &threads_for_task, &thread_count)) 967 return false; 968 969 // Don't include the generator thread 970 if (handler_thread_ != MACH_PORT_NULL) 971 non_generator_thread_count = thread_count - 1; 972 else 973 non_generator_thread_count = thread_count; 974 if (!list.AllocateObjectAndArray(non_generator_thread_count, 975 sizeof(MDRawThread))) 976 return false; 977 978 thread_list_stream->stream_type = MD_THREAD_LIST_STREAM; 979 thread_list_stream->location = list.location(); 980 981 list.get()->number_of_threads = non_generator_thread_count; 982 983 MDRawThread thread; 984 int thread_idx = 0; 985 986 for (unsigned int i = 0; i < thread_count; ++i) { 987 memset(&thread, 0, sizeof(MDRawThread)); 988 989 if (threads_for_task[i] != handler_thread_) { 990 if (!WriteThreadStream(threads_for_task[i], &thread)) 991 return false; 992 993 list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread)); 994 } 995 } 996 997 return true; 998} 999 1000bool MinidumpGenerator::WriteMemoryListStream( 1001 MDRawDirectory *memory_list_stream) { 1002 TypedMDRVA<MDRawMemoryList> list(&writer_); 1003 1004 // If the dump has an exception, include some memory around the 1005 // instruction pointer. 1006 const size_t kIPMemorySize = 256; // bytes 1007 bool have_ip_memory = false; 1008 MDMemoryDescriptor ip_memory_d; 1009 if (exception_thread_ && exception_type_) { 1010 breakpad_thread_state_data_t state; 1011 mach_msg_type_number_t stateCount 1012 = static_cast<mach_msg_type_number_t>(sizeof(state)); 1013 1014 if (GetThreadState(exception_thread_, state, &stateCount)) { 1015 uint64_t ip = CurrentPCForStack(state); 1016 // Bound it to the upper and lower bounds of the region 1017 // it's contained within. If it's not in a known memory region, 1018 // don't bother trying to write it. 1019 mach_vm_address_t addr = static_cast<vm_address_t>(ip); 1020 mach_vm_size_t size; 1021 natural_t nesting_level = 0; 1022 vm_region_submap_info_64 info; 1023 mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; 1024 vm_region_recurse_info_t recurse_info; 1025 recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info); 1026 1027 kern_return_t ret = 1028 mach_vm_region_recurse(crashing_task_, 1029 &addr, 1030 &size, 1031 &nesting_level, 1032 recurse_info, 1033 &info_count); 1034 if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) { 1035 // Try to get 128 bytes before and after the IP, but 1036 // settle for whatever's available. 1037 ip_memory_d.start_of_memory_range = 1038 std::max(uintptr_t(addr), 1039 uintptr_t(ip - (kIPMemorySize / 2))); 1040 uintptr_t end_of_range = 1041 std::min(uintptr_t(ip + (kIPMemorySize / 2)), 1042 uintptr_t(addr + size)); 1043 ip_memory_d.memory.data_size = 1044 end_of_range - 1045 static_cast<uintptr_t>(ip_memory_d.start_of_memory_range); 1046 have_ip_memory = true; 1047 // This needs to get appended to the list even though 1048 // the memory bytes aren't filled in yet so the entire 1049 // list can be written first. The memory bytes will get filled 1050 // in after the memory list is written. 1051 memory_blocks_.push_back(ip_memory_d); 1052 } 1053 } 1054 } 1055 1056 // Now fill in the memory list and write it. 1057 unsigned memory_count = memory_blocks_.size(); 1058 if (!list.AllocateObjectAndArray(memory_count, 1059 sizeof(MDMemoryDescriptor))) 1060 return false; 1061 1062 memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM; 1063 memory_list_stream->location = list.location(); 1064 1065 list.get()->number_of_memory_ranges = memory_count; 1066 1067 unsigned int i; 1068 for (i = 0; i < memory_count; ++i) { 1069 list.CopyIndexAfterObject(i, &memory_blocks_[i], 1070 sizeof(MDMemoryDescriptor)); 1071 } 1072 1073 if (have_ip_memory) { 1074 // Now read the memory around the instruction pointer. 1075 UntypedMDRVA ip_memory(&writer_); 1076 if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) 1077 return false; 1078 1079 if (dynamic_images_) { 1080 // Out-of-process. 1081 vector<uint8_t> memory; 1082 if (ReadTaskMemory(crashing_task_, 1083 ip_memory_d.start_of_memory_range, 1084 ip_memory_d.memory.data_size, 1085 memory) != KERN_SUCCESS) { 1086 return false; 1087 } 1088 1089 ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size); 1090 } else { 1091 // In-process, just copy from local memory. 1092 ip_memory.Copy( 1093 reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range), 1094 ip_memory_d.memory.data_size); 1095 } 1096 1097 ip_memory_d.memory = ip_memory.location(); 1098 // Write this again now that the data location is filled in. 1099 list.CopyIndexAfterObject(i - 1, &ip_memory_d, 1100 sizeof(MDMemoryDescriptor)); 1101 } 1102 1103 return true; 1104} 1105 1106bool 1107MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) { 1108 TypedMDRVA<MDRawExceptionStream> exception(&writer_); 1109 1110 if (!exception.Allocate()) 1111 return false; 1112 1113 exception_stream->stream_type = MD_EXCEPTION_STREAM; 1114 exception_stream->location = exception.location(); 1115 MDRawExceptionStream *exception_ptr = exception.get(); 1116 exception_ptr->thread_id = exception_thread_; 1117 1118 // This naming is confusing, but it is the proper translation from 1119 // mach naming to minidump naming. 1120 exception_ptr->exception_record.exception_code = exception_type_; 1121 exception_ptr->exception_record.exception_flags = exception_code_; 1122 1123 breakpad_thread_state_data_t state; 1124 mach_msg_type_number_t state_count 1125 = static_cast<mach_msg_type_number_t>(sizeof(state)); 1126 1127 if (!GetThreadState(exception_thread_, state, &state_count)) 1128 return false; 1129 1130 if (!WriteContext(state, &exception_ptr->thread_context)) 1131 return false; 1132 1133 if (exception_type_ == EXC_BAD_ACCESS) 1134 exception_ptr->exception_record.exception_address = exception_subcode_; 1135 else 1136 exception_ptr->exception_record.exception_address = CurrentPCForStack(state); 1137 1138 return true; 1139} 1140 1141bool MinidumpGenerator::WriteSystemInfoStream( 1142 MDRawDirectory *system_info_stream) { 1143 TypedMDRVA<MDRawSystemInfo> info(&writer_); 1144 1145 if (!info.Allocate()) 1146 return false; 1147 1148 system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM; 1149 system_info_stream->location = info.location(); 1150 1151 // CPU Information 1152 uint32_t number_of_processors; 1153 size_t len = sizeof(number_of_processors); 1154 sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0); 1155 MDRawSystemInfo *info_ptr = info.get(); 1156 1157 switch (cpu_type_) { 1158#ifdef HAS_ARM_SUPPORT 1159 case CPU_TYPE_ARM: 1160 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM; 1161 break; 1162#endif 1163#ifdef HAS_ARM64_SUPPORT 1164 case CPU_TYPE_ARM64: 1165 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64; 1166 break; 1167#endif 1168#ifdef HAS_PPC_SUPPORT 1169 case CPU_TYPE_POWERPC: 1170 case CPU_TYPE_POWERPC64: 1171 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; 1172 break; 1173#endif 1174#ifdef HAS_X86_SUPPORT 1175 case CPU_TYPE_I386: 1176 case CPU_TYPE_X86_64: 1177 if (cpu_type_ == CPU_TYPE_I386) 1178 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; 1179 else 1180 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64; 1181#ifdef __i386__ 1182 // ebx is used for PIC code, so we need 1183 // to preserve it. 1184#define cpuid(op,eax,ebx,ecx,edx) \ 1185 asm ("pushl %%ebx \n\t" \ 1186 "cpuid \n\t" \ 1187 "movl %%ebx,%1 \n\t" \ 1188 "popl %%ebx" \ 1189 : "=a" (eax), \ 1190 "=g" (ebx), \ 1191 "=c" (ecx), \ 1192 "=d" (edx) \ 1193 : "0" (op)) 1194#elif defined(__x86_64__) 1195 1196#define cpuid(op,eax,ebx,ecx,edx) \ 1197 asm ("cpuid \n\t" \ 1198 : "=a" (eax), \ 1199 "=b" (ebx), \ 1200 "=c" (ecx), \ 1201 "=d" (edx) \ 1202 : "0" (op)) 1203#endif 1204 1205#if defined(__i386__) || defined(__x86_64__) 1206 int unused, unused2; 1207 // get vendor id 1208 cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0], 1209 info_ptr->cpu.x86_cpu_info.vendor_id[2], 1210 info_ptr->cpu.x86_cpu_info.vendor_id[1]); 1211 // get version and feature info 1212 cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2, 1213 info_ptr->cpu.x86_cpu_info.feature_information); 1214 1215 // family 1216 info_ptr->processor_level = 1217 (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8; 1218 // 0xMMSS (Model, Stepping) 1219 info_ptr->processor_revision = 1220 (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | 1221 ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4); 1222 1223 // decode extended model info 1224 if (info_ptr->processor_level == 0xF || 1225 info_ptr->processor_level == 0x6) { 1226 info_ptr->processor_revision |= 1227 ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4); 1228 } 1229 1230 // decode extended family info 1231 if (info_ptr->processor_level == 0xF) { 1232 info_ptr->processor_level += 1233 ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20); 1234 } 1235 1236#endif // __i386__ || __x86_64_ 1237 break; 1238#endif // HAS_X86_SUPPORT 1239 default: 1240 info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN; 1241 break; 1242 } 1243 1244 info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors); 1245#if TARGET_OS_IPHONE 1246 info_ptr->platform_id = MD_OS_IOS; 1247#else 1248 info_ptr->platform_id = MD_OS_MAC_OS_X; 1249#endif // TARGET_OS_IPHONE 1250 1251 MDLocationDescriptor build_string_loc; 1252 1253 if (!writer_.WriteString(build_string_, 0, 1254 &build_string_loc)) 1255 return false; 1256 1257 info_ptr->csd_version_rva = build_string_loc.rva; 1258 info_ptr->major_version = os_major_version_; 1259 info_ptr->minor_version = os_minor_version_; 1260 info_ptr->build_number = os_build_number_; 1261 1262 return true; 1263} 1264 1265bool MinidumpGenerator::WriteModuleStream(unsigned int index, 1266 MDRawModule *module) { 1267 if (dynamic_images_) { 1268 // we're in a different process than the crashed process 1269 DynamicImage *image = dynamic_images_->GetImage(index); 1270 1271 if (!image) 1272 return false; 1273 1274 memset(module, 0, sizeof(MDRawModule)); 1275 1276 MDLocationDescriptor string_location; 1277 1278 string name = image->GetFilePath(); 1279 if (!writer_.WriteString(name.c_str(), 0, &string_location)) 1280 return false; 1281 1282 module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); 1283 module->size_of_image = static_cast<uint32_t>(image->GetVMSize()); 1284 module->module_name_rva = string_location.rva; 1285 1286 // We'll skip the executable module, because they don't have 1287 // LC_ID_DYLIB load commands, and the crash processing server gets 1288 // version information from the Plist file, anyway. 1289 if (index != static_cast<uint32_t>(FindExecutableModule())) { 1290 module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE; 1291 module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION; 1292 // Convert MAC dylib version format, which is a 32 bit number, to the 1293 // format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits> 1294 // so it fits nicely into the windows version with some massaging 1295 // The mapping is: 1296 // 1) upper 16 bits of MAC version go to lower 16 bits of product HI 1297 // 2) Next most significant 8 bits go to upper 16 bits of product LO 1298 // 3) Least significant 8 bits go to lower 16 bits of product LO 1299 uint32_t modVersion = image->GetVersion(); 1300 module->version_info.file_version_hi = 0; 1301 module->version_info.file_version_hi = modVersion >> 16; 1302 module->version_info.file_version_lo |= (modVersion & 0xff00) << 8; 1303 module->version_info.file_version_lo |= (modVersion & 0xff); 1304 } 1305 1306 if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) { 1307 return false; 1308 } 1309 } else { 1310 // Getting module info in the crashed process 1311 const breakpad_mach_header *header; 1312 header = (breakpad_mach_header*)_dyld_get_image_header(index); 1313 if (!header) 1314 return false; 1315 1316#ifdef __LP64__ 1317 assert(header->magic == MH_MAGIC_64); 1318 1319 if(header->magic != MH_MAGIC_64) 1320 return false; 1321#else 1322 assert(header->magic == MH_MAGIC); 1323 1324 if(header->magic != MH_MAGIC) 1325 return false; 1326#endif 1327 1328 int cpu_type = header->cputype; 1329 unsigned long slide = _dyld_get_image_vmaddr_slide(index); 1330 const char* name = _dyld_get_image_name(index); 1331 const struct load_command *cmd = 1332 reinterpret_cast<const struct load_command *>(header + 1); 1333 1334 memset(module, 0, sizeof(MDRawModule)); 1335 1336 for (unsigned int i = 0; cmd && (i < header->ncmds); i++) { 1337 if (cmd->cmd == LC_SEGMENT_ARCH) { 1338 1339 const breakpad_mach_segment_command *seg = 1340 reinterpret_cast<const breakpad_mach_segment_command *>(cmd); 1341 1342 if (!strcmp(seg->segname, "__TEXT")) { 1343 MDLocationDescriptor string_location; 1344 1345 if (!writer_.WriteString(name, 0, &string_location)) 1346 return false; 1347 1348 module->base_of_image = seg->vmaddr + slide; 1349 module->size_of_image = static_cast<uint32_t>(seg->vmsize); 1350 module->module_name_rva = string_location.rva; 1351 1352 bool in_memory = false; 1353#if TARGET_OS_IPHONE 1354 in_memory = true; 1355#endif 1356 if (!WriteCVRecord(module, cpu_type, name, in_memory)) 1357 return false; 1358 1359 return true; 1360 } 1361 } 1362 1363 cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize); 1364 } 1365 } 1366 1367 return true; 1368} 1369 1370int MinidumpGenerator::FindExecutableModule() { 1371 if (dynamic_images_) { 1372 int index = dynamic_images_->GetExecutableImageIndex(); 1373 1374 if (index >= 0) { 1375 return index; 1376 } 1377 } else { 1378 int image_count = _dyld_image_count(); 1379 const struct mach_header *header; 1380 1381 for (int index = 0; index < image_count; ++index) { 1382 header = _dyld_get_image_header(index); 1383 1384 if (header->filetype == MH_EXECUTE) 1385 return index; 1386 } 1387 } 1388 1389 // failed - just use the first image 1390 return 0; 1391} 1392 1393bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type, 1394 const char *module_path, bool in_memory) { 1395 TypedMDRVA<MDCVInfoPDB70> cv(&writer_); 1396 1397 // Only return the last path component of the full module path 1398 const char *module_name = strrchr(module_path, '/'); 1399 1400 // Increment past the slash 1401 if (module_name) 1402 ++module_name; 1403 else 1404 module_name = "<Unknown>"; 1405 1406 size_t module_name_length = strlen(module_name); 1407 1408 if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t))) 1409 return false; 1410 1411 if (!cv.CopyIndexAfterObject(0, module_name, module_name_length)) 1412 return false; 1413 1414 module->cv_record = cv.location(); 1415 MDCVInfoPDB70 *cv_ptr = cv.get(); 1416 cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE; 1417 cv_ptr->age = 0; 1418 1419 // Get the module identifier 1420 unsigned char identifier[16]; 1421 bool result = false; 1422 if (in_memory) { 1423 MacFileUtilities::MachoID macho(module_path, 1424 reinterpret_cast<void *>(module->base_of_image), 1425 static_cast<size_t>(module->size_of_image)); 1426 result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); 1427 if (!result) 1428 result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier); 1429 } 1430 1431 if (!result) { 1432 FileID file_id(module_path); 1433 result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE, 1434 identifier); 1435 } 1436 1437 if (result) { 1438 cv_ptr->signature.data1 = 1439 static_cast<uint32_t>(identifier[0]) << 24 | 1440 static_cast<uint32_t>(identifier[1]) << 16 | 1441 static_cast<uint32_t>(identifier[2]) << 8 | 1442 static_cast<uint32_t>(identifier[3]); 1443 cv_ptr->signature.data2 = 1444 static_cast<uint16_t>(identifier[4] << 8) | identifier[5]; 1445 cv_ptr->signature.data3 = 1446 static_cast<uint16_t>(identifier[6] << 8) | identifier[7]; 1447 cv_ptr->signature.data4[0] = identifier[8]; 1448 cv_ptr->signature.data4[1] = identifier[9]; 1449 cv_ptr->signature.data4[2] = identifier[10]; 1450 cv_ptr->signature.data4[3] = identifier[11]; 1451 cv_ptr->signature.data4[4] = identifier[12]; 1452 cv_ptr->signature.data4[5] = identifier[13]; 1453 cv_ptr->signature.data4[6] = identifier[14]; 1454 cv_ptr->signature.data4[7] = identifier[15]; 1455 } 1456 1457 return true; 1458} 1459 1460bool MinidumpGenerator::WriteModuleListStream( 1461 MDRawDirectory *module_list_stream) { 1462 TypedMDRVA<MDRawModuleList> list(&writer_); 1463 1464 size_t image_count = dynamic_images_ ? 1465 static_cast<size_t>(dynamic_images_->GetImageCount()) : 1466 _dyld_image_count(); 1467 1468 if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE)) 1469 return false; 1470 1471 module_list_stream->stream_type = MD_MODULE_LIST_STREAM; 1472 module_list_stream->location = list.location(); 1473 list.get()->number_of_modules = image_count; 1474 1475 // Write out the executable module as the first one 1476 MDRawModule module; 1477 size_t executableIndex = FindExecutableModule(); 1478 1479 if (!WriteModuleStream(executableIndex, &module)) { 1480 return false; 1481 } 1482 1483 list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE); 1484 int destinationIndex = 1; // Write all other modules after this one 1485 1486 for (size_t i = 0; i < image_count; ++i) { 1487 if (i != executableIndex) { 1488 if (!WriteModuleStream(i, &module)) { 1489 return false; 1490 } 1491 1492 list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE); 1493 } 1494 } 1495 1496 return true; 1497} 1498 1499bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) { 1500 TypedMDRVA<MDRawMiscInfo> info(&writer_); 1501 1502 if (!info.Allocate()) 1503 return false; 1504 1505 misc_info_stream->stream_type = MD_MISC_INFO_STREAM; 1506 misc_info_stream->location = info.location(); 1507 1508 MDRawMiscInfo *info_ptr = info.get(); 1509 info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo)); 1510 info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID | 1511 MD_MISCINFO_FLAGS1_PROCESS_TIMES | 1512 MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO; 1513 1514 // Process ID 1515 info_ptr->process_id = getpid(); 1516 1517 // Times 1518 struct rusage usage; 1519 if (getrusage(RUSAGE_SELF, &usage) != -1) { 1520 // Omit the fractional time since the MDRawMiscInfo only wants seconds 1521 info_ptr->process_user_time = 1522 static_cast<uint32_t>(usage.ru_utime.tv_sec); 1523 info_ptr->process_kernel_time = 1524 static_cast<uint32_t>(usage.ru_stime.tv_sec); 1525 } 1526 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 1527 static_cast<int>(info_ptr->process_id) }; 1528 uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0])); 1529 struct kinfo_proc proc; 1530 size_t size = sizeof(proc); 1531 if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) { 1532 info_ptr->process_create_time = 1533 static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec); 1534 } 1535 1536 // Speed 1537 uint64_t speed; 1538 const uint64_t kOneMillion = 1000 * 1000; 1539 size = sizeof(speed); 1540 sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); 1541 info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion); 1542 info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion); 1543 size = sizeof(speed); 1544 sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); 1545 info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion); 1546 1547 return true; 1548} 1549 1550bool MinidumpGenerator::WriteBreakpadInfoStream( 1551 MDRawDirectory *breakpad_info_stream) { 1552 TypedMDRVA<MDRawBreakpadInfo> info(&writer_); 1553 1554 if (!info.Allocate()) 1555 return false; 1556 1557 breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM; 1558 breakpad_info_stream->location = info.location(); 1559 MDRawBreakpadInfo *info_ptr = info.get(); 1560 1561 if (exception_thread_ && exception_type_) { 1562 info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | 1563 MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; 1564 info_ptr->dump_thread_id = handler_thread_; 1565 info_ptr->requesting_thread_id = exception_thread_; 1566 } else { 1567 info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID; 1568 info_ptr->dump_thread_id = handler_thread_; 1569 info_ptr->requesting_thread_id = 0; 1570 } 1571 1572 return true; 1573} 1574 1575} // namespace google_breakpad 1576