diff options
Diffstat (limited to 'src/client/mac/handler/minidump_generator.cc')
-rw-r--r-- | src/client/mac/handler/minidump_generator.cc | 346 |
1 files changed, 253 insertions, 93 deletions
diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index 8e3faf27..2e9765ad 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -31,7 +31,9 @@ #include <cstdio> #include <mach/host_info.h> +#include <mach/i386/thread_status.h> #include <mach/mach_vm.h> +#include <mach/ppc/thread_status.h> #include <mach/vm_statistics.h> #include <mach-o/dyld.h> #include <mach-o/loader.h> @@ -65,6 +67,7 @@ MinidumpGenerator::MinidumpGenerator() exception_thread_(0), crashing_task_(mach_task_self()), handler_thread_(mach_thread_self()), + cpu_type_(DynamicImages::GetNativeCPUType()), dynamic_images_(NULL), memory_blocks_(&allocator_) { GatherSystemInformation(); @@ -81,12 +84,15 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, exception_thread_(0), crashing_task_(crashing_task), handler_thread_(handler_thread), + cpu_type_(DynamicImages::GetNativeCPUType()), 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(); @@ -254,8 +260,10 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) { return 0; } - - if ((stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK) { + if (((cpu_type_ & CPU_ARCH_ABI64) && + (stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK_64BIT) || + (!(cpu_type_ & CPU_ARCH_ABI64) && + (stack_region_base + stack_region_size) == TOP_OF_THREAD0_STACK_32BIT)) { // The stack for thread 0 needs to extend all the way to // 0xc0000000 on 32 bit and 00007fff5fc00000 on 64bit. HOWEVER, // for many processes, the stack is first created in one page @@ -305,20 +313,15 @@ bool MinidumpGenerator::WriteStackFromStartAddress( return false; if (dynamic_images_) { - - kern_return_t kr; - - void *stack_memory = ReadTaskMemory(crashing_task_, - (void*)start_addr, - size, - &kr); - - if (stack_memory == NULL) { + vector<uint8_t> stack_memory; + if (ReadTaskMemory(crashing_task_, + start_addr, + size, + stack_memory) != KERN_SUCCESS) { return false; } - result = memory.Copy(stack_memory, size); - free(stack_memory); + result = memory.Copy(&stack_memory[0], size); } else { result = memory.Copy(reinterpret_cast<const void *>(start_addr), size); } @@ -330,34 +333,99 @@ bool MinidumpGenerator::WriteStackFromStartAddress( return result; } -#if TARGET_CPU_PPC || TARGET_CPU_PPC64 bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location) { - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); + switch (cpu_type_) { + case CPU_TYPE_POWERPC: + return WriteStackPPC(state, stack_location); + case CPU_TYPE_POWERPC64: + return WriteStackPPC64(state, stack_location); + case CPU_TYPE_I386: + return WriteStackX86(state, stack_location); + case CPU_TYPE_X86_64: + return WriteStackX86_64(state, stack_location); + default: + return false; + } +} + +bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) { + switch (cpu_type_) { + case CPU_TYPE_POWERPC: + return WriteContextPPC(state, register_location); + case CPU_TYPE_POWERPC64: + return WriteContextPPC64(state, register_location); + case CPU_TYPE_I386: + return WriteContextX86(state, register_location); + case CPU_TYPE_X86_64: + return WriteContextX86_64(state, register_location); + default: + return false; + } +} + +u_int64_t MinidumpGenerator::CurrentPCForStack( + breakpad_thread_state_data_t state) { + switch (cpu_type_) { + case CPU_TYPE_POWERPC: + return CurrentPCForStackPPC(state); + case CPU_TYPE_POWERPC64: + return CurrentPCForStackPPC64(state); + case CPU_TYPE_I386: + return CurrentPCForStackX86(state); + case CPU_TYPE_X86_64: + return CurrentPCForStackX86_64(state); + default: + assert("Unknown CPU type!"); + return 0; + } +} + +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); } u_int64_t -MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); +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); } -bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) { - TypedMDRVA<MinidumpContext> context(&writer_); - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); +u_int64_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(); - MinidumpContext *context_ptr = context.get(); + MDRawContextPPC *context_ptr = context.get(); context_ptr->context_flags = MD_CONTEXT_PPC_BASE; #define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) @@ -402,57 +470,124 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, AddGPR(29); AddGPR(30); AddGPR(31); - -#if TARGET_CPU_PPC - /* The mq register is only for PPC */ AddReg(mq); -#endif - +#undef AddReg +#undef AddGPR return true; } -#elif TARGET_CPU_X86 || TARGET_CPU_X86_64 +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); -bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_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 = REGISTER_FROM_THREADSTATE(machine_state, a) +#define AddGPR(a) context_ptr->gpr[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; +} + +bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location) { - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); + i386_thread_state_t *machine_state = + reinterpret_cast<i386_thread_state_t *>(state); -#if TARGET_CPU_X86_64 - mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp); -#else mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp); -#endif + 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 = REGISTER_FROM_THREADSTATE(machine_state, rsp); return WriteStackFromStartAddress(start_addr, stack_location); } u_int64_t -MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) { - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); +MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) { + i386_thread_state_t *machine_state = + reinterpret_cast<i386_thread_state_t *>(state); -#if TARGET_CPU_X86_64 - return REGISTER_FROM_THREADSTATE(machine_state, rip); -#else return REGISTER_FROM_THREADSTATE(machine_state, eip); -#endif } -bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, - MDLocationDescriptor *register_location) { - TypedMDRVA<MinidumpContext> context(&writer_); - breakpad_thread_state_t *machine_state = - reinterpret_cast<breakpad_thread_state_t *>(state); +u_int64_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(); - MinidumpContext *context_ptr = context.get(); + MDRawContextX86 *context_ptr = context.get(); #define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) -#if TARGET_CPU_X86 + context_ptr->context_flags = MD_CONTEXT_X86; AddReg(eax); AddReg(ebx); @@ -472,7 +607,26 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, AddReg(eflags); AddReg(eip); -#else +#undef AddReg(a) + + 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 = REGISTER_FROM_THREADSTATE(machine_state, a) + context_ptr->context_flags = MD_CONTEXT_AMD64; AddReg(rax); AddReg(rbx); @@ -495,16 +649,38 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, // 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<u_int32_t>(machine_state->__rflags); + context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags)); AddReg(cs); AddReg(fs); AddReg(gs); -#endif #undef AddReg(a) return true; } -#endif + +bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, + thread_state_t state, + mach_msg_type_number_t *count) { + thread_state_flavor_t flavor; + switch (cpu_type_) { + case CPU_TYPE_POWERPC: + flavor = PPC_THREAD_STATE; + break; + case CPU_TYPE_POWERPC64: + flavor = PPC_THREAD_STATE64; + break; + case CPU_TYPE_I386: + flavor = i386_THREAD_STATE; + break; + case CPU_TYPE_X86_64: + flavor = x86_THREAD_STATE64; + break; + default: + return false; + } + return thread_get_state(target_thread, flavor, + state, count) == KERN_SUCCESS; +} bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, MDRawThread *thread) { @@ -512,9 +688,7 @@ bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id, mach_msg_type_number_t state_count = static_cast<mach_msg_type_number_t>(sizeof(state)); - if (thread_get_state(thread_id, BREAKPAD_MACHINE_THREAD_STATE, - state, &state_count) == - KERN_SUCCESS) { + if (GetThreadState(thread_id, state, &state_count)) { if (!WriteStack(state, &thread->stack)) return false; @@ -653,21 +827,15 @@ bool MinidumpGenerator::WriteMemoryListStream( if (dynamic_images_) { // Out-of-process. - kern_return_t kr; - - void *memory = - ReadTaskMemory( - crashing_task_, - reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range), - ip_memory_d.memory.data_size, - &kr); - - if (memory == NULL) { + 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, ip_memory_d.memory.data_size); - free(memory); + ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size); } else { // In-process, just copy from local memory. ip_memory.Copy( @@ -733,23 +901,23 @@ bool MinidumpGenerator::WriteSystemInfoStream( system_info_stream->location = info.location(); // CPU Information - uint32_t cpu_type; - size_t len = sizeof(cpu_type); - sysctlbyname("hw.cputype", &cpu_type, &len, NULL, 0); uint32_t number_of_processors; - len = sizeof(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) { + switch (cpu_type_) { case CPU_TYPE_POWERPC: + case CPU_TYPE_POWERPC64: info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC; break; case CPU_TYPE_I386: case CPU_TYPE_X86_64: - // hw.cputype is currently always I386 even on an x86-64 system + 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__ - info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86; // ebx is used for PIC code, so we need // to preserve it. #define cpuid(op,eax,ebx,ecx,edx) \ @@ -763,7 +931,7 @@ bool MinidumpGenerator::WriteSystemInfoStream( "=d" (edx) \ : "0" (op)) #elif defined(__x86_64__) - info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64; + #define cpuid(op,eax,ebx,ecx,edx) \ asm ("cpuid \n\t" \ : "=a" (eax), \ @@ -837,19 +1005,12 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, if (!image) return false; - const breakpad_mach_header *header = image->GetMachHeader(); - - if (!header) - return false; - - int cpu_type = header->cputype; - memset(module, 0, sizeof(MDRawModule)); MDLocationDescriptor string_location; - const char* name = image->GetFilePath(); - if (!writer_.WriteString(name, 0, &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(); @@ -876,12 +1037,11 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, module->version_info.file_version_lo |= (modVersion & 0xff); } - if (!WriteCVRecord(module, cpu_type, name)) { + if (!WriteCVRecord(module, image->GetCPUType(), name.c_str())) { return false; } } else { - // we're getting module info in the crashed process - + // Getting module info in the crashed process const breakpad_mach_header *header; header = (breakpad_mach_header*)_dyld_get_image_header(index); if (!header) @@ -903,7 +1063,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, 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); + reinterpret_cast<const struct load_command *>(header + 1); memset(module, 0, sizeof(MDRawModule)); @@ -911,7 +1071,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index, if (cmd->cmd == LC_SEGMENT_ARCH) { const breakpad_mach_segment_command *seg = - reinterpret_cast<const breakpad_mach_segment_command *>(cmd); + reinterpret_cast<const breakpad_mach_segment_command *>(cmd); if (!strcmp(seg->segname, "__TEXT")) { MDLocationDescriptor string_location; |