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