summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc1604
1 files changed, 0 insertions, 1604 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc
deleted file mode 100644
index 48cd2e99b..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc
+++ /dev/null
@@ -1,1604 +0,0 @@
-// Copyright (c) 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <algorithm>
-#include <cstdio>
-
-#include <mach/host_info.h>
-#include <mach/machine.h>
-#include <mach/vm_statistics.h>
-#include <mach-o/dyld.h>
-#include <mach-o/loader.h>
-#include <sys/sysctl.h>
-#include <sys/resource.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "client/mac/handler/minidump_generator.h"
-
-#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)
-#include <mach/arm/thread_status.h>
-#endif
-#ifdef HAS_PPC_SUPPORT
-#include <mach/ppc/thread_status.h>
-#endif
-#ifdef HAS_X86_SUPPORT
-#include <mach/i386/thread_status.h>
-#endif
-
-#include "client/minidump_file_writer-inl.h"
-#include "common/mac/file_id.h"
-#include "common/mac/macho_id.h"
-#include "common/mac/string_utilities.h"
-
-using MacStringUtils::ConvertToString;
-using MacStringUtils::IntegerValueAtIndex;
-
-namespace google_breakpad {
-
-#if defined(__LP64__) && __LP64__
-#define LC_SEGMENT_ARCH LC_SEGMENT_64
-#else
-#define LC_SEGMENT_ARCH LC_SEGMENT
-#endif
-
-// constructor when generating from within the crashed process
-MinidumpGenerator::MinidumpGenerator()
- : writer_(),
- exception_type_(0),
- exception_code_(0),
- exception_subcode_(0),
- exception_thread_(0),
- crashing_task_(mach_task_self()),
- handler_thread_(mach_thread_self()),
- cpu_type_(DynamicImages::GetNativeCPUType()),
- task_context_(NULL),
- dynamic_images_(NULL),
- memory_blocks_(&allocator_) {
- GatherSystemInformation();
-}
-
-// constructor when generating from a different process than the
-// crashed process
-MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
- mach_port_t handler_thread)
- : writer_(),
- exception_type_(0),
- exception_code_(0),
- exception_subcode_(0),
- exception_thread_(0),
- crashing_task_(crashing_task),
- handler_thread_(handler_thread),
- cpu_type_(DynamicImages::GetNativeCPUType()),
- task_context_(NULL),
- dynamic_images_(NULL),
- memory_blocks_(&allocator_) {
- if (crashing_task != mach_task_self()) {
- dynamic_images_ = new DynamicImages(crashing_task_);
- cpu_type_ = dynamic_images_->GetCPUType();
- } else {
- dynamic_images_ = NULL;
- cpu_type_ = DynamicImages::GetNativeCPUType();
- }
-
- GatherSystemInformation();
-}
-
-MinidumpGenerator::~MinidumpGenerator() {
- delete dynamic_images_;
-}
-
-char MinidumpGenerator::build_string_[16];
-int MinidumpGenerator::os_major_version_ = 0;
-int MinidumpGenerator::os_minor_version_ = 0;
-int MinidumpGenerator::os_build_number_ = 0;
-
-// static
-void MinidumpGenerator::GatherSystemInformation() {
- // If this is non-zero, then we've already gathered the information
- if (os_major_version_)
- return;
-
- // This code extracts the version and build information from the OS
- CFStringRef vers_path =
- CFSTR("/System/Library/CoreServices/SystemVersion.plist");
- CFURLRef sys_vers =
- CFURLCreateWithFileSystemPath(NULL,
- vers_path,
- kCFURLPOSIXPathStyle,
- false);
- CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers);
- CFRelease(sys_vers);
- if (!read_stream) {
- return;
- }
- if (!CFReadStreamOpen(read_stream)) {
- CFRelease(read_stream);
- return;
- }
- CFMutableDataRef data = NULL;
- while (true) {
- // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes.
- const CFIndex kMaxBufferLength = 1024;
- UInt8 data_bytes[kMaxBufferLength];
- CFIndex num_bytes_read =
- CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength);
- if (num_bytes_read < 0) {
- if (data) {
- CFRelease(data);
- data = NULL;
- }
- break;
- } else if (num_bytes_read == 0) {
- break;
- } else if (!data) {
- data = CFDataCreateMutable(NULL, 0);
- }
- CFDataAppendBytes(data, data_bytes, num_bytes_read);
- }
- CFReadStreamClose(read_stream);
- CFRelease(read_stream);
- if (!data) {
- return;
- }
- CFDictionaryRef list =
- static_cast<CFDictionaryRef>(CFPropertyListCreateWithData(
- NULL, data, kCFPropertyListImmutable, NULL, NULL));
- CFRelease(data);
- if (!list) {
- return;
- }
- CFStringRef build_version = static_cast<CFStringRef>
- (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
- CFStringRef product_version = static_cast<CFStringRef>
- (CFDictionaryGetValue(list, CFSTR("ProductVersion")));
- string build_str = ConvertToString(build_version);
- string product_str = ConvertToString(product_version);
-
- CFRelease(list);
-
- strlcpy(build_string_, build_str.c_str(), sizeof(build_string_));
-
- // Parse the string that looks like "10.4.8"
- os_major_version_ = IntegerValueAtIndex(product_str, 0);
- os_minor_version_ = IntegerValueAtIndex(product_str, 1);
- os_build_number_ = IntegerValueAtIndex(product_str, 2);
-}
-
-void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) {
- task_context_ = task_context;
-}
-
-string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
- string *unique_name) {
- CFUUIDRef uuid = CFUUIDCreate(NULL);
- CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid);
- CFRelease(uuid);
- string file_name(ConvertToString(uuid_cfstr));
- CFRelease(uuid_cfstr);
- string path(dir);
-
- // Ensure that the directory (if non-empty) has a trailing slash so that
- // we can append the file name and have a valid pathname.
- if (!dir.empty()) {
- if (dir.at(dir.size() - 1) != '/')
- path.append(1, '/');
- }
-
- path.append(file_name);
- path.append(".dmp");
-
- if (unique_name)
- *unique_name = file_name;
-
- return path;
-}
-
-bool MinidumpGenerator::Write(const char *path) {
- WriteStreamFN writers[] = {
- &MinidumpGenerator::WriteThreadListStream,
- &MinidumpGenerator::WriteMemoryListStream,
- &MinidumpGenerator::WriteSystemInfoStream,
- &MinidumpGenerator::WriteModuleListStream,
- &MinidumpGenerator::WriteMiscInfoStream,
- &MinidumpGenerator::WriteBreakpadInfoStream,
- // Exception stream needs to be the last entry in this array as it may
- // be omitted in the case where the minidump is written without an
- // exception.
- &MinidumpGenerator::WriteExceptionStream,
- };
- bool result = false;
-
- // If opening was successful, create the header, directory, and call each
- // writer. The destructor for the TypedMDRVAs will cause the data to be
- // flushed. The destructor for the MinidumpFileWriter will close the file.
- if (writer_.Open(path)) {
- TypedMDRVA<MDRawHeader> header(&writer_);
- TypedMDRVA<MDRawDirectory> dir(&writer_);
-
- if (!header.Allocate())
- return false;
-
- int writer_count = static_cast<int>(sizeof(writers) / sizeof(writers[0]));
-
- // If we don't have exception information, don't write out the
- // exception stream
- if (!exception_thread_ && !exception_type_)
- --writer_count;
-
- // Add space for all writers
- if (!dir.AllocateArray(writer_count))
- return false;
-
- MDRawHeader *header_ptr = header.get();
- header_ptr->signature = MD_HEADER_SIGNATURE;
- header_ptr->version = MD_HEADER_VERSION;
- time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp)));
- header_ptr->stream_count = writer_count;
- header_ptr->stream_directory_rva = dir.position();
-
- MDRawDirectory local_dir;
- result = true;
- for (int i = 0; (result) && (i < writer_count); ++i) {
- result = (this->*writers[i])(&local_dir);
-
- if (result)
- dir.CopyIndex(i, &local_dir);
- }
- }
- return result;
-}
-
-size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
- mach_vm_address_t stack_region_base = start_addr;
- mach_vm_size_t stack_region_size;
- natural_t nesting_level = 0;
- vm_region_submap_info_64 submap_info;
- mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
-
- vm_region_recurse_info_t region_info;
- region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
-
- if (start_addr == 0) {
- return 0;
- }
-
- kern_return_t result =
- mach_vm_region_recurse(crashing_task_, &stack_region_base,
- &stack_region_size, &nesting_level,
- region_info, &info_count);
-
- if (result != KERN_SUCCESS || start_addr < stack_region_base) {
- // Failure or stack corruption, since mach_vm_region had to go
- // higher in the process address space to find a valid region.
- return 0;
- }
-
- unsigned int tag = submap_info.user_tag;
-
- // If the user tag is VM_MEMORY_STACK, look for more readable regions with
- // the same tag placed immediately above the computed stack region. Under
- // some circumstances, the stack for thread 0 winds up broken up into
- // multiple distinct abutting regions. This can happen for several reasons,
- // including user code that calls setrlimit(RLIMIT_STACK, ...) or changes
- // the access on stack pages by calling mprotect.
- if (tag == VM_MEMORY_STACK) {
- while (true) {
- mach_vm_address_t next_region_base = stack_region_base +
- stack_region_size;
- mach_vm_address_t proposed_next_region_base = next_region_base;
- mach_vm_size_t next_region_size;
- nesting_level = 0;
- info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
- result = mach_vm_region_recurse(crashing_task_, &next_region_base,
- &next_region_size, &nesting_level,
- region_info, &info_count);
- if (result != KERN_SUCCESS ||
- next_region_base != proposed_next_region_base ||
- submap_info.user_tag != tag ||
- (submap_info.protection & VM_PROT_READ) == 0) {
- break;
- }
-
- stack_region_size += next_region_size;
- }
- }
-
- return stack_region_base + stack_region_size - start_addr;
-}
-
-bool MinidumpGenerator::WriteStackFromStartAddress(
- mach_vm_address_t start_addr,
- MDMemoryDescriptor *stack_location) {
- UntypedMDRVA memory(&writer_);
-
- bool result = false;
- size_t size = CalculateStackSize(start_addr);
-
- if (size == 0) {
- // In some situations the stack address for the thread can come back 0.
- // In these cases we skip over the threads in question and stuff the
- // stack with a clearly borked value.
- start_addr = 0xDEADBEEF;
- size = 16;
- if (!memory.Allocate(size))
- return false;
-
- unsigned long long dummy_stack[2]; // Fill dummy stack with 16 bytes of
- // junk.
- dummy_stack[0] = 0xDEADBEEF;
- dummy_stack[1] = 0xDEADBEEF;
-
- result = memory.Copy(dummy_stack, size);
- } else {
-
- if (!memory.Allocate(size))
- return false;
-
- if (dynamic_images_) {
- vector<uint8_t> stack_memory;
- if (ReadTaskMemory(crashing_task_,
- start_addr,
- size,
- stack_memory) != KERN_SUCCESS) {
- return false;
- }
-
- result = memory.Copy(&stack_memory[0], size);
- } else {
- result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
- }
- }
-
- stack_location->start_of_memory_range = start_addr;
- stack_location->memory = memory.location();
-
- return result;
-}
-
-bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- return WriteStackARM(state, stack_location);
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64:
- return WriteStackARM64(state, stack_location);
-#endif
-#ifdef HAS_PPC_SUPPORT
- case CPU_TYPE_POWERPC:
- return WriteStackPPC(state, stack_location);
- case CPU_TYPE_POWERPC64:
- return WriteStackPPC64(state, stack_location);
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- return WriteStackX86(state, stack_location);
- case CPU_TYPE_X86_64:
- return WriteStackX86_64(state, stack_location);
-#endif
- default:
- return false;
- }
-}
-
-bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- return WriteContextARM(state, register_location);
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64:
- return WriteContextARM64(state, register_location);
-#endif
-#ifdef HAS_PPC_SUPPORT
- case CPU_TYPE_POWERPC:
- return WriteContextPPC(state, register_location);
- case CPU_TYPE_POWERPC64:
- return WriteContextPPC64(state, register_location);
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- return WriteContextX86(state, register_location);
- case CPU_TYPE_X86_64:
- return WriteContextX86_64(state, register_location);
-#endif
- default:
- return false;
- }
-}
-
-uint64_t MinidumpGenerator::CurrentPCForStack(
- breakpad_thread_state_data_t state) {
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- return CurrentPCForStackARM(state);
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64:
- return CurrentPCForStackARM64(state);
-#endif
-#ifdef HAS_PPC_SUPPORT
- case CPU_TYPE_POWERPC:
- return CurrentPCForStackPPC(state);
- case CPU_TYPE_POWERPC64:
- return CurrentPCForStackPPC64(state);
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- return CurrentPCForStackX86(state);
- case CPU_TYPE_X86_64:
- return CurrentPCForStackX86_64(state);
-#endif
- default:
- assert(0 && "Unknown CPU type!");
- return 0;
- }
-}
-
-#ifdef HAS_ARM_SUPPORT
-bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, pc);
-}
-
-bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
-{
- TypedMDRVA<MDRawContextARM> context(&writer_);
- arm_thread_state_t *machine_state =
- reinterpret_cast<arm_thread_state_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextARM *context_ptr = context.get();
- context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
-
-#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a])
-
- context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp);
- context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr);
- context_ptr->iregs[15] = REGISTER_FROM_THREADSTATE(machine_state, pc);
- context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr);
-
- AddGPR(0);
- AddGPR(1);
- AddGPR(2);
- AddGPR(3);
- AddGPR(4);
- AddGPR(5);
- AddGPR(6);
- AddGPR(7);
- AddGPR(8);
- AddGPR(9);
- AddGPR(10);
- AddGPR(11);
- AddGPR(12);
-#undef AddGPR
-
- return true;
-}
-#endif
-
-#ifdef HAS_ARM64_SUPPORT
-bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) {
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, pc);
-}
-
-bool
-MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
-{
- TypedMDRVA<MDRawContextARM64> context(&writer_);
- arm_thread_state64_t *machine_state =
- reinterpret_cast<arm_thread_state64_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextARM64 *context_ptr = context.get();
- context_ptr->context_flags = MD_CONTEXT_ARM64_FULL;
-
-#define AddGPR(a) context_ptr->iregs[a] = \
- REGISTER_FROM_THREADSTATE(machine_state, x[a])
-
- context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp);
- context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr);
- context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp);
- context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc);
- context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr);
-
- AddGPR(0);
- AddGPR(1);
- AddGPR(2);
- AddGPR(3);
- AddGPR(4);
- AddGPR(5);
- AddGPR(6);
- AddGPR(7);
- AddGPR(8);
- AddGPR(9);
- AddGPR(10);
- AddGPR(11);
- AddGPR(12);
- AddGPR(13);
- AddGPR(14);
- AddGPR(15);
- AddGPR(16);
- AddGPR(17);
- AddGPR(18);
- AddGPR(19);
- AddGPR(20);
- AddGPR(21);
- AddGPR(22);
- AddGPR(23);
- AddGPR(24);
- AddGPR(25);
- AddGPR(26);
- AddGPR(27);
- AddGPR(28);
-#undef AddGPR
-
- return true;
-}
-#endif
-
-#ifdef HAS_PCC_SUPPORT
-bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, srr0);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, srr0);
-}
-
-bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
-{
- TypedMDRVA<MDRawContextPPC> context(&writer_);
- ppc_thread_state_t *machine_state =
- reinterpret_cast<ppc_thread_state_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextPPC *context_ptr = context.get();
- context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-
-#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, a))
-#define AddGPR(a) context_ptr->gpr[a] = \
- static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, r ## a)
-
- AddReg(srr0);
- AddReg(cr);
- AddReg(xer);
- AddReg(ctr);
- AddReg(lr);
- AddReg(vrsave);
-
- AddGPR(0);
- AddGPR(1);
- AddGPR(2);
- AddGPR(3);
- AddGPR(4);
- AddGPR(5);
- AddGPR(6);
- AddGPR(7);
- AddGPR(8);
- AddGPR(9);
- AddGPR(10);
- AddGPR(11);
- AddGPR(12);
- AddGPR(13);
- AddGPR(14);
- AddGPR(15);
- AddGPR(16);
- AddGPR(17);
- AddGPR(18);
- AddGPR(19);
- AddGPR(20);
- AddGPR(21);
- AddGPR(22);
- AddGPR(23);
- AddGPR(24);
- AddGPR(25);
- AddGPR(26);
- AddGPR(27);
- AddGPR(28);
- AddGPR(29);
- AddGPR(30);
- AddGPR(31);
- AddReg(mq);
-#undef AddReg
-#undef AddGPR
-
- return true;
-}
-
-bool MinidumpGenerator::WriteContextPPC64(
- breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
- TypedMDRVA<MDRawContextPPC64> context(&writer_);
- ppc_thread_state64_t *machine_state =
- reinterpret_cast<ppc_thread_state64_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextPPC64 *context_ptr = context.get();
- context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
-
-#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, a))
-#define AddGPR(a) context_ptr->gpr[a] = \
- static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, r ## a)
-
- AddReg(srr0);
- AddReg(cr);
- AddReg(xer);
- AddReg(ctr);
- AddReg(lr);
- AddReg(vrsave);
-
- AddGPR(0);
- AddGPR(1);
- AddGPR(2);
- AddGPR(3);
- AddGPR(4);
- AddGPR(5);
- AddGPR(6);
- AddGPR(7);
- AddGPR(8);
- AddGPR(9);
- AddGPR(10);
- AddGPR(11);
- AddGPR(12);
- AddGPR(13);
- AddGPR(14);
- AddGPR(15);
- AddGPR(16);
- AddGPR(17);
- AddGPR(18);
- AddGPR(19);
- AddGPR(20);
- AddGPR(21);
- AddGPR(22);
- AddGPR(23);
- AddGPR(24);
- AddGPR(25);
- AddGPR(26);
- AddGPR(27);
- AddGPR(28);
- AddGPR(29);
- AddGPR(30);
- AddGPR(31);
-#undef AddReg
-#undef AddGPR
-
- return true;
-}
-
-#endif
-
-#ifdef HAS_X86_SUPPORT
-bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
-
- mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp);
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
- MDMemoryDescriptor *stack_location) {
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
-
- mach_vm_address_t start_addr = static_cast<mach_vm_address_t>(
- REGISTER_FROM_THREADSTATE(machine_state, rsp));
- return WriteStackFromStartAddress(start_addr, stack_location);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, eip);
-}
-
-uint64_t
-MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
-
- return REGISTER_FROM_THREADSTATE(machine_state, rip);
-}
-
-bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location)
-{
- TypedMDRVA<MDRawContextX86> context(&writer_);
- i386_thread_state_t *machine_state =
- reinterpret_cast<i386_thread_state_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextX86 *context_ptr = context.get();
-
-#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, a))
-
- context_ptr->context_flags = MD_CONTEXT_X86;
- AddReg(eax);
- AddReg(ebx);
- AddReg(ecx);
- AddReg(edx);
- AddReg(esi);
- AddReg(edi);
- AddReg(ebp);
- AddReg(esp);
-
- AddReg(cs);
- AddReg(ds);
- AddReg(ss);
- AddReg(es);
- AddReg(fs);
- AddReg(gs);
- AddReg(eflags);
-
- AddReg(eip);
-#undef AddReg
-
- return true;
-}
-
-bool MinidumpGenerator::WriteContextX86_64(
- breakpad_thread_state_data_t state,
- MDLocationDescriptor *register_location) {
- TypedMDRVA<MDRawContextAMD64> context(&writer_);
- x86_thread_state64_t *machine_state =
- reinterpret_cast<x86_thread_state64_t *>(state);
-
- if (!context.Allocate())
- return false;
-
- *register_location = context.location();
- MDRawContextAMD64 *context_ptr = context.get();
-
-#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \
- REGISTER_FROM_THREADSTATE(machine_state, a))
-
- context_ptr->context_flags = MD_CONTEXT_AMD64;
- AddReg(rax);
- AddReg(rbx);
- AddReg(rcx);
- AddReg(rdx);
- AddReg(rdi);
- AddReg(rsi);
- AddReg(rbp);
- AddReg(rsp);
- AddReg(r8);
- AddReg(r9);
- AddReg(r10);
- AddReg(r11);
- AddReg(r12);
- AddReg(r13);
- AddReg(r14);
- AddReg(r15);
- AddReg(rip);
- // according to AMD's software developer guide, bits above 18 are
- // not used in the flags register. Since the minidump format
- // specifies 32 bits for the flags register, we can truncate safely
- // with no loss.
- context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
- AddReg(cs);
- AddReg(fs);
- AddReg(gs);
-#undef AddReg
-
- return true;
-}
-#endif
-
-bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
- thread_state_t state,
- mach_msg_type_number_t *count) {
- if (task_context_ && target_thread == mach_thread_self()) {
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- size_t final_size =
- std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t));
- memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
- *count = static_cast<mach_msg_type_number_t>(final_size);
- return true;
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64: {
- size_t final_size =
- std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t));
- memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
- *count = static_cast<mach_msg_type_number_t>(final_size);
- return true;
- }
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- case CPU_TYPE_X86_64: {
- size_t state_size = cpu_type_ == CPU_TYPE_I386 ?
- sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t);
- size_t final_size =
- std::min(static_cast<size_t>(*count), state_size);
- memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size);
- *count = static_cast<mach_msg_type_number_t>(final_size);
- return true;
- }
-#endif
- }
- }
-
- thread_state_flavor_t flavor;
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- flavor = ARM_THREAD_STATE;
- break;
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64:
- flavor = ARM_THREAD_STATE64;
- break;
-#endif
-#ifdef HAS_PPC_SUPPORT
- case CPU_TYPE_POWERPC:
- flavor = PPC_THREAD_STATE;
- break;
- case CPU_TYPE_POWERPC64:
- flavor = PPC_THREAD_STATE64;
- break;
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- flavor = i386_THREAD_STATE;
- break;
- case CPU_TYPE_X86_64:
- flavor = x86_THREAD_STATE64;
- break;
-#endif
- default:
- return false;
- }
- return thread_get_state(target_thread, flavor,
- state, count) == KERN_SUCCESS;
-}
-
-bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
- MDRawThread *thread) {
- breakpad_thread_state_data_t state;
- mach_msg_type_number_t state_count
- = static_cast<mach_msg_type_number_t>(sizeof(state));
-
- if (GetThreadState(thread_id, state, &state_count)) {
- if (!WriteStack(state, &thread->stack))
- return false;
-
- memory_blocks_.push_back(thread->stack);
-
- if (!WriteContext(state, &thread->thread_context))
- return false;
-
- thread->thread_id = thread_id;
- } else {
- return false;
- }
-
- return true;
-}
-
-bool MinidumpGenerator::WriteThreadListStream(
- MDRawDirectory *thread_list_stream) {
- TypedMDRVA<MDRawThreadList> list(&writer_);
- thread_act_port_array_t threads_for_task;
- mach_msg_type_number_t thread_count;
- int non_generator_thread_count;
-
- if (task_threads(crashing_task_, &threads_for_task, &thread_count))
- return false;
-
- // Don't include the generator thread
- if (handler_thread_ != MACH_PORT_NULL)
- non_generator_thread_count = thread_count - 1;
- else
- non_generator_thread_count = thread_count;
- if (!list.AllocateObjectAndArray(non_generator_thread_count,
- sizeof(MDRawThread)))
- return false;
-
- thread_list_stream->stream_type = MD_THREAD_LIST_STREAM;
- thread_list_stream->location = list.location();
-
- list.get()->number_of_threads = non_generator_thread_count;
-
- MDRawThread thread;
- int thread_idx = 0;
-
- for (unsigned int i = 0; i < thread_count; ++i) {
- memset(&thread, 0, sizeof(MDRawThread));
-
- if (threads_for_task[i] != handler_thread_) {
- if (!WriteThreadStream(threads_for_task[i], &thread))
- return false;
-
- list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread));
- }
- }
-
- return true;
-}
-
-bool MinidumpGenerator::WriteMemoryListStream(
- MDRawDirectory *memory_list_stream) {
- TypedMDRVA<MDRawMemoryList> list(&writer_);
-
- // If the dump has an exception, include some memory around the
- // instruction pointer.
- const size_t kIPMemorySize = 256; // bytes
- bool have_ip_memory = false;
- MDMemoryDescriptor ip_memory_d;
- if (exception_thread_ && exception_type_) {
- breakpad_thread_state_data_t state;
- mach_msg_type_number_t stateCount
- = static_cast<mach_msg_type_number_t>(sizeof(state));
-
- if (GetThreadState(exception_thread_, state, &stateCount)) {
- uint64_t ip = CurrentPCForStack(state);
- // Bound it to the upper and lower bounds of the region
- // it's contained within. If it's not in a known memory region,
- // don't bother trying to write it.
- mach_vm_address_t addr = static_cast<vm_address_t>(ip);
- mach_vm_size_t size;
- natural_t nesting_level = 0;
- vm_region_submap_info_64 info;
- mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
- vm_region_recurse_info_t recurse_info;
- recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info);
-
- kern_return_t ret =
- mach_vm_region_recurse(crashing_task_,
- &addr,
- &size,
- &nesting_level,
- recurse_info,
- &info_count);
- if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
- // Try to get 128 bytes before and after the IP, but
- // settle for whatever's available.
- ip_memory_d.start_of_memory_range =
- std::max(uintptr_t(addr),
- uintptr_t(ip - (kIPMemorySize / 2)));
- uintptr_t end_of_range =
- std::min(uintptr_t(ip + (kIPMemorySize / 2)),
- uintptr_t(addr + size));
- uintptr_t range_diff = end_of_range -
- static_cast<uintptr_t>(ip_memory_d.start_of_memory_range);
- ip_memory_d.memory.data_size = static_cast<uint32_t>(range_diff);
- have_ip_memory = true;
- // This needs to get appended to the list even though
- // the memory bytes aren't filled in yet so the entire
- // list can be written first. The memory bytes will get filled
- // in after the memory list is written.
- memory_blocks_.push_back(ip_memory_d);
- }
- }
- }
-
- // Now fill in the memory list and write it.
- size_t memory_count = memory_blocks_.size();
- if (!list.AllocateObjectAndArray(memory_count,
- sizeof(MDMemoryDescriptor)))
- return false;
-
- memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
- memory_list_stream->location = list.location();
-
- list.get()->number_of_memory_ranges = static_cast<uint32_t>(memory_count);
-
- unsigned int i;
- for (i = 0; i < memory_count; ++i) {
- list.CopyIndexAfterObject(i, &memory_blocks_[i],
- sizeof(MDMemoryDescriptor));
- }
-
- if (have_ip_memory) {
- // Now read the memory around the instruction pointer.
- UntypedMDRVA ip_memory(&writer_);
- if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
- return false;
-
- if (dynamic_images_) {
- // Out-of-process.
- vector<uint8_t> memory;
- if (ReadTaskMemory(crashing_task_,
- ip_memory_d.start_of_memory_range,
- ip_memory_d.memory.data_size,
- memory) != KERN_SUCCESS) {
- return false;
- }
-
- ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size);
- } else {
- // In-process, just copy from local memory.
- ip_memory.Copy(
- reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
- ip_memory_d.memory.data_size);
- }
-
- ip_memory_d.memory = ip_memory.location();
- // Write this again now that the data location is filled in.
- list.CopyIndexAfterObject(i - 1, &ip_memory_d,
- sizeof(MDMemoryDescriptor));
- }
-
- return true;
-}
-
-bool
-MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
- TypedMDRVA<MDRawExceptionStream> exception(&writer_);
-
- if (!exception.Allocate())
- return false;
-
- exception_stream->stream_type = MD_EXCEPTION_STREAM;
- exception_stream->location = exception.location();
- MDRawExceptionStream *exception_ptr = exception.get();
- exception_ptr->thread_id = exception_thread_;
-
- // This naming is confusing, but it is the proper translation from
- // mach naming to minidump naming.
- exception_ptr->exception_record.exception_code = exception_type_;
- exception_ptr->exception_record.exception_flags = exception_code_;
-
- breakpad_thread_state_data_t state;
- mach_msg_type_number_t state_count
- = static_cast<mach_msg_type_number_t>(sizeof(state));
-
- if (!GetThreadState(exception_thread_, state, &state_count))
- return false;
-
- if (!WriteContext(state, &exception_ptr->thread_context))
- return false;
-
- if (exception_type_ == EXC_BAD_ACCESS)
- exception_ptr->exception_record.exception_address = exception_subcode_;
- else
- exception_ptr->exception_record.exception_address = CurrentPCForStack(state);
-
- return true;
-}
-
-bool MinidumpGenerator::WriteSystemInfoStream(
- MDRawDirectory *system_info_stream) {
- TypedMDRVA<MDRawSystemInfo> info(&writer_);
-
- if (!info.Allocate())
- return false;
-
- system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM;
- system_info_stream->location = info.location();
-
- // CPU Information
- uint32_t number_of_processors;
- size_t len = sizeof(number_of_processors);
- sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0);
- MDRawSystemInfo *info_ptr = info.get();
-
- switch (cpu_type_) {
-#ifdef HAS_ARM_SUPPORT
- case CPU_TYPE_ARM:
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
- break;
-#endif
-#ifdef HAS_ARM64_SUPPORT
- case CPU_TYPE_ARM64:
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64;
- break;
-#endif
-#ifdef HAS_PPC_SUPPORT
- case CPU_TYPE_POWERPC:
- case CPU_TYPE_POWERPC64:
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
- break;
-#endif
-#ifdef HAS_X86_SUPPORT
- case CPU_TYPE_I386:
- case CPU_TYPE_X86_64:
- if (cpu_type_ == CPU_TYPE_I386)
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
- else
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
-#ifdef __i386__
- // ebx is used for PIC code, so we need
- // to preserve it.
-#define cpuid(op,eax,ebx,ecx,edx) \
- asm ("pushl %%ebx \n\t" \
- "cpuid \n\t" \
- "movl %%ebx,%1 \n\t" \
- "popl %%ebx" \
- : "=a" (eax), \
- "=g" (ebx), \
- "=c" (ecx), \
- "=d" (edx) \
- : "0" (op))
-#elif defined(__x86_64__)
-
-#define cpuid(op,eax,ebx,ecx,edx) \
- asm ("cpuid \n\t" \
- : "=a" (eax), \
- "=b" (ebx), \
- "=c" (ecx), \
- "=d" (edx) \
- : "0" (op))
-#endif
-
-#if defined(__i386__) || defined(__x86_64__)
- int unused, unused2;
- // get vendor id
- cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0],
- info_ptr->cpu.x86_cpu_info.vendor_id[2],
- info_ptr->cpu.x86_cpu_info.vendor_id[1]);
- // get version and feature info
- cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2,
- info_ptr->cpu.x86_cpu_info.feature_information);
-
- // family
- info_ptr->processor_level =
- (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
- // 0xMMSS (Model, Stepping)
- info_ptr->processor_revision = static_cast<uint16_t>(
- (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
- ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4));
-
- // decode extended model info
- if (info_ptr->processor_level == 0xF ||
- info_ptr->processor_level == 0x6) {
- info_ptr->processor_revision |=
- ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4);
- }
-
- // decode extended family info
- if (info_ptr->processor_level == 0xF) {
- info_ptr->processor_level +=
- ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20);
- }
-
-#endif // __i386__ || __x86_64_
- break;
-#endif // HAS_X86_SUPPORT
- default:
- info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
- break;
- }
-
- info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors);
-#if TARGET_OS_IPHONE
- info_ptr->platform_id = MD_OS_IOS;
-#else
- info_ptr->platform_id = MD_OS_MAC_OS_X;
-#endif // TARGET_OS_IPHONE
-
- MDLocationDescriptor build_string_loc;
-
- if (!writer_.WriteString(build_string_, 0,
- &build_string_loc))
- return false;
-
- info_ptr->csd_version_rva = build_string_loc.rva;
- info_ptr->major_version = os_major_version_;
- info_ptr->minor_version = os_minor_version_;
- info_ptr->build_number = os_build_number_;
-
- return true;
-}
-
-bool MinidumpGenerator::WriteModuleStream(unsigned int index,
- MDRawModule *module) {
- if (dynamic_images_) {
- // we're in a different process than the crashed process
- DynamicImage *image = dynamic_images_->GetImage(index);
-
- if (!image)
- return false;
-
- memset(module, 0, sizeof(MDRawModule));
-
- MDLocationDescriptor string_location;
-
- string name = image->GetFilePath();
- if (!writer_.WriteString(name.c_str(), 0, &string_location))
- return false;
-
- module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
- module->size_of_image = static_cast<uint32_t>(image->GetVMSize());
- module->module_name_rva = string_location.rva;
-
- // We'll skip the executable module, because they don't have
- // LC_ID_DYLIB load commands, and the crash processing server gets
- // version information from the Plist file, anyway.
- if (index != static_cast<uint32_t>(FindExecutableModule())) {
- module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
- module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
- // Convert MAC dylib version format, which is a 32 bit number, to the
- // format used by minidump. The mac format is <16 bits>.<8 bits>.<8 bits>
- // so it fits nicely into the windows version with some massaging
- // The mapping is:
- // 1) upper 16 bits of MAC version go to lower 16 bits of product HI
- // 2) Next most significant 8 bits go to upper 16 bits of product LO
- // 3) Least significant 8 bits go to lower 16 bits of product LO
- uint32_t modVersion = image->GetVersion();
- module->version_info.file_version_hi = 0;
- module->version_info.file_version_hi = modVersion >> 16;
- module->version_info.file_version_lo |= (modVersion & 0xff00) << 8;
- module->version_info.file_version_lo |= (modVersion & 0xff);
- }
-
- if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) {
- return false;
- }
- } else {
- // Getting module info in the crashed process
- const breakpad_mach_header *header;
- header = (breakpad_mach_header*)_dyld_get_image_header(index);
- if (!header)
- return false;
-
-#ifdef __LP64__
- assert(header->magic == MH_MAGIC_64);
-
- if(header->magic != MH_MAGIC_64)
- return false;
-#else
- assert(header->magic == MH_MAGIC);
-
- if(header->magic != MH_MAGIC)
- return false;
-#endif
-
- int cpu_type = header->cputype;
- unsigned long slide = _dyld_get_image_vmaddr_slide(index);
- const char* name = _dyld_get_image_name(index);
- const struct load_command *cmd =
- reinterpret_cast<const struct load_command *>(header + 1);
-
- memset(module, 0, sizeof(MDRawModule));
-
- for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
- if (cmd->cmd == LC_SEGMENT_ARCH) {
-
- const breakpad_mach_segment_command *seg =
- reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
-
- if (!strcmp(seg->segname, "__TEXT")) {
- MDLocationDescriptor string_location;
-
- if (!writer_.WriteString(name, 0, &string_location))
- return false;
-
- module->base_of_image = seg->vmaddr + slide;
- module->size_of_image = static_cast<uint32_t>(seg->vmsize);
- module->module_name_rva = string_location.rva;
-
- bool in_memory = false;
-#if TARGET_OS_IPHONE
- in_memory = true;
-#endif
- if (!WriteCVRecord(module, cpu_type, name, in_memory))
- return false;
-
- return true;
- }
- }
-
- cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize);
- }
- }
-
- return true;
-}
-
-int MinidumpGenerator::FindExecutableModule() {
- if (dynamic_images_) {
- int index = dynamic_images_->GetExecutableImageIndex();
-
- if (index >= 0) {
- return index;
- }
- } else {
- int image_count = _dyld_image_count();
- const struct mach_header *header;
-
- for (int index = 0; index < image_count; ++index) {
- header = _dyld_get_image_header(index);
-
- if (header->filetype == MH_EXECUTE)
- return index;
- }
- }
-
- // failed - just use the first image
- return 0;
-}
-
-bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
- const char *module_path, bool in_memory) {
- TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
-
- // Only return the last path component of the full module path
- const char *module_name = strrchr(module_path, '/');
-
- // Increment past the slash
- if (module_name)
- ++module_name;
- else
- module_name = "<Unknown>";
-
- size_t module_name_length = strlen(module_name);
-
- if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t)))
- return false;
-
- if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
- return false;
-
- module->cv_record = cv.location();
- MDCVInfoPDB70 *cv_ptr = cv.get();
- cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
- cv_ptr->age = 0;
-
- // Get the module identifier
- unsigned char identifier[16];
- bool result = false;
- if (in_memory) {
- MacFileUtilities::MachoID macho(module_path,
- reinterpret_cast<void *>(module->base_of_image),
- static_cast<size_t>(module->size_of_image));
- result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
- if (!result)
- result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
- }
-
- if (!result) {
- FileID file_id(module_path);
- result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE,
- identifier);
- }
-
- if (result) {
- cv_ptr->signature.data1 =
- static_cast<uint32_t>(identifier[0]) << 24 |
- static_cast<uint32_t>(identifier[1]) << 16 |
- static_cast<uint32_t>(identifier[2]) << 8 |
- static_cast<uint32_t>(identifier[3]);
- cv_ptr->signature.data2 =
- static_cast<uint16_t>(identifier[4] << 8) | identifier[5];
- cv_ptr->signature.data3 =
- static_cast<uint16_t>(identifier[6] << 8) | identifier[7];
- cv_ptr->signature.data4[0] = identifier[8];
- cv_ptr->signature.data4[1] = identifier[9];
- cv_ptr->signature.data4[2] = identifier[10];
- cv_ptr->signature.data4[3] = identifier[11];
- cv_ptr->signature.data4[4] = identifier[12];
- cv_ptr->signature.data4[5] = identifier[13];
- cv_ptr->signature.data4[6] = identifier[14];
- cv_ptr->signature.data4[7] = identifier[15];
- }
-
- return true;
-}
-
-bool MinidumpGenerator::WriteModuleListStream(
- MDRawDirectory *module_list_stream) {
- TypedMDRVA<MDRawModuleList> list(&writer_);
-
- uint32_t image_count = dynamic_images_ ?
- dynamic_images_->GetImageCount() :
- _dyld_image_count();
-
- if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
- return false;
-
- module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
- module_list_stream->location = list.location();
- list.get()->number_of_modules = static_cast<uint32_t>(image_count);
-
- // Write out the executable module as the first one
- MDRawModule module;
- uint32_t executableIndex = FindExecutableModule();
-
- if (!WriteModuleStream(static_cast<unsigned>(executableIndex), &module)) {
- return false;
- }
-
- list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
- int destinationIndex = 1; // Write all other modules after this one
-
- for (uint32_t i = 0; i < image_count; ++i) {
- if (i != executableIndex) {
- if (!WriteModuleStream(static_cast<unsigned>(i), &module)) {
- return false;
- }
-
- list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE);
- }
- }
-
- return true;
-}
-
-bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
- TypedMDRVA<MDRawMiscInfo> info(&writer_);
-
- if (!info.Allocate())
- return false;
-
- misc_info_stream->stream_type = MD_MISC_INFO_STREAM;
- misc_info_stream->location = info.location();
-
- MDRawMiscInfo *info_ptr = info.get();
- info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo));
- info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
- MD_MISCINFO_FLAGS1_PROCESS_TIMES |
- MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO;
-
- // Process ID
- info_ptr->process_id = getpid();
-
- // Times
- struct rusage usage;
- if (getrusage(RUSAGE_SELF, &usage) != -1) {
- // Omit the fractional time since the MDRawMiscInfo only wants seconds
- info_ptr->process_user_time =
- static_cast<uint32_t>(usage.ru_utime.tv_sec);
- info_ptr->process_kernel_time =
- static_cast<uint32_t>(usage.ru_stime.tv_sec);
- }
- int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
- static_cast<int>(info_ptr->process_id) };
- uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0]));
- struct kinfo_proc proc;
- size_t size = sizeof(proc);
- if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {
- info_ptr->process_create_time =
- static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec);
- }
-
- // Speed
- uint64_t speed;
- const uint64_t kOneMillion = 1000 * 1000;
- size = sizeof(speed);
- sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0);
- info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion);
- info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion);
- size = sizeof(speed);
- sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0);
- info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion);
-
- return true;
-}
-
-bool MinidumpGenerator::WriteBreakpadInfoStream(
- MDRawDirectory *breakpad_info_stream) {
- TypedMDRVA<MDRawBreakpadInfo> info(&writer_);
-
- if (!info.Allocate())
- return false;
-
- breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM;
- breakpad_info_stream->location = info.location();
- MDRawBreakpadInfo *info_ptr = info.get();
-
- if (exception_thread_ && exception_type_) {
- info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
- MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
- info_ptr->dump_thread_id = handler_thread_;
- info_ptr->requesting_thread_id = exception_thread_;
- } else {
- info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID;
- info_ptr->dump_thread_id = handler_thread_;
- info_ptr->requesting_thread_id = 0;
- }
-
- return true;
-}
-
-} // namespace google_breakpad