diff --git a/src/client/ios/Breakpad.xcodeproj/project.pbxproj b/src/client/ios/Breakpad.xcodeproj/project.pbxproj index 8ac22381..10888c8f 100644 --- a/src/client/ios/Breakpad.xcodeproj/project.pbxproj +++ b/src/client/ios/Breakpad.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; }; + 14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; }; 16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; }; 16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */; }; 16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C968147D4A4200776EAD /* BreakpadDefines.h */; }; @@ -58,6 +60,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = ""; }; + 14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = ""; }; 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = ""; }; 16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_exception_minidump_generator.mm; sourceTree = ""; }; 16C7C968147D4A4200776EAD /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadDefines.h; sourceTree = ""; }; @@ -238,10 +242,12 @@ 16C7CBB0147D4A4300776EAD /* dynamic_images.h */, 16C7CBB1147D4A4300776EAD /* exception_handler.cc */, 16C7CBB2147D4A4300776EAD /* exception_handler.h */, + 14569322182CE2C10029C465 /* mach_vm_compat.h */, 16C7CBB4147D4A4300776EAD /* minidump_generator.cc */, 16C7CBB5147D4A4300776EAD /* minidump_generator.h */, 16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */, 16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */, + 14569320182CE29F0029C465 /* ucontext_compat.h */, ); path = handler; sourceTree = ""; @@ -312,6 +318,7 @@ 16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */, 16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */, 16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */, + 14569321182CE29F0029C465 /* ucontext_compat.h in Headers */, 16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */, 16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */, 16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */, @@ -333,6 +340,7 @@ 16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */, 16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */, 1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */, + 14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -431,7 +439,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; COPY_PHASE_STRIP = NO; DSTROOT = /tmp/Breakpad.dst; FRAMEWORK_SEARCH_PATHS = ( @@ -463,7 +471,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; DSTROOT = /tmp/Breakpad.dst; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -491,7 +499,7 @@ 1DEB922308733DC00010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; @@ -517,7 +525,7 @@ 1DEB922408733DC00010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/src/client/ios/handler/ios_exception_minidump_generator.h b/src/client/ios/handler/ios_exception_minidump_generator.h index fd2f0149..21133e63 100644 --- a/src/client/ios/handler/ios_exception_minidump_generator.h +++ b/src/client/ios/handler/ios_exception_minidump_generator.h @@ -51,13 +51,20 @@ class IosExceptionMinidumpGenerator : public MinidumpGenerator { private: // Get the crashing program counter from the exception. - uint32_t GetPCFromException(); + uintptr_t GetPCFromException(); // Get the crashing link register from the exception. - uint32_t GetLRFromException(); + uintptr_t GetLRFromException(); // Write a virtual thread context for the crashing site. bool WriteCrashingContext(MDLocationDescriptor *register_location); + // Per-CPU implementations of the above method. +#ifdef HAS_ARM_SUPPORT + bool WriteCrashingContextARM(MDLocationDescriptor *register_location); +#endif +#ifdef HAS_ARM64_SUPPORT + bool WriteCrashingContextARM64(MDLocationDescriptor *register_location); +#endif NSArray *return_addresses_; }; diff --git a/src/client/ios/handler/ios_exception_minidump_generator.mm b/src/client/ios/handler/ios_exception_minidump_generator.mm index 50bc3093..491c4916 100644 --- a/src/client/ios/handler/ios_exception_minidump_generator.mm +++ b/src/client/ios/handler/ios_exception_minidump_generator.mm @@ -31,25 +31,32 @@ #include +#include "google_breakpad/common/minidump_cpu_arm.h" +#include "google_breakpad/common/minidump_cpu_arm64.h" #include "google_breakpad/common/minidump_exception_mac.h" #include "client/minidump_file_writer-inl.h" #include "common/scoped_ptr.h" +#if !defined(HAS_ARM_SUPPORT) && !defined(HAS_ARM64_SUPPORT) +#error "This file should only be compiled for ARM processors" +#endif + +#if defined(HAS_ARM_SUPPORT) && defined(HAS_ARM64_SUPPORT) +#error "This file should be compiled for only one architecture at a time" +#endif + namespace { -const uint32_t kExpectedFinalFp = 4; -const uint32_t kExpectedFinalSp = 0; +const uintptr_t kExpectedFinalFp = sizeof(uintptr_t); +const uintptr_t kExpectedFinalSp = 0; const int kExceptionType = EXC_SOFTWARE; const int kExceptionCode = MD_EXCEPTION_CODE_MAC_NS_EXCEPTION; -#ifdef HAS_ARM_SUPPORT -// Append the given 4 bytes value to the sp position of the stack represented +// Append the given value to the sp position of the stack represented // by memory. -void AppendToMemory(uint8_t *memory, uint32_t sp, uint32_t data) { - assert(sizeof(data) == 4); +void AppendToMemory(uint8_t *memory, uintptr_t sp, uintptr_t data) { memcpy(memory + sp, &data, sizeof(data)); } -#endif } // namespace @@ -72,6 +79,18 @@ IosExceptionMinidumpGenerator::~IosExceptionMinidumpGenerator() { bool IosExceptionMinidumpGenerator::WriteCrashingContext( MDLocationDescriptor *register_location) { #ifdef HAS_ARM_SUPPORT + return WriteCrashingContextARM(register_location); +#elif defined(HAS_ARM64_SUPPORT) + return WriteCrashingContextARM64(register_location); +#else +#error "This file should only be compiled on ARM processors" + return false; +#endif +} + +#ifdef HAS_ARM_SUPPORT +bool IosExceptionMinidumpGenerator::WriteCrashingContextARM( + MDLocationDescriptor *register_location) { TypedMDRVA context(&writer_); if (!context.Allocate()) return false; @@ -79,28 +98,42 @@ bool IosExceptionMinidumpGenerator::WriteCrashingContext( MDRawContextARM *context_ptr = context.get(); memset(context_ptr, 0, sizeof(MDRawContextARM)); context_ptr->context_flags = MD_CONTEXT_ARM_FULL; - context_ptr->iregs[7] = kExpectedFinalFp; // FP - context_ptr->iregs[13] = kExpectedFinalSp; // SP - context_ptr->iregs[14] = GetLRFromException(); // LR - context_ptr->iregs[15] = GetPCFromException(); // PC + context_ptr->iregs[MD_CONTEXT_ARM_REG_IOS_FP] = kExpectedFinalFp; // FP + context_ptr->iregs[MD_CONTEXT_ARM_REG_SP] = kExpectedFinalSp; // SP + context_ptr->iregs[MD_CONTEXT_ARM_REG_LR] = GetLRFromException(); // LR + context_ptr->iregs[MD_CONTEXT_ARM_REG_PC] = GetPCFromException(); // PC return true; -#else - assert(false); - return false; -#endif } +#endif -uint32_t IosExceptionMinidumpGenerator::GetPCFromException() { +#ifdef HAS_ARM64_SUPPORT +bool IosExceptionMinidumpGenerator::WriteCrashingContextARM64( + MDLocationDescriptor *register_location) { + TypedMDRVA context(&writer_); + if (!context.Allocate()) + return false; + *register_location = context.location(); + MDRawContextARM64 *context_ptr = context.get(); + memset(context_ptr, 0, sizeof(*context_ptr)); + context_ptr->context_flags = MD_CONTEXT_ARM64_FULL; + context_ptr->iregs[MD_CONTEXT_ARM64_REG_FP] = kExpectedFinalFp; // FP + context_ptr->iregs[MD_CONTEXT_ARM64_REG_SP] = kExpectedFinalSp; // SP + context_ptr->iregs[MD_CONTEXT_ARM64_REG_LR] = GetLRFromException(); // LR + context_ptr->iregs[MD_CONTEXT_ARM64_REG_PC] = GetPCFromException(); // PC + return true; +} +#endif + +uintptr_t IosExceptionMinidumpGenerator::GetPCFromException() { return [[return_addresses_ objectAtIndex:0] unsignedIntegerValue]; } -uint32_t IosExceptionMinidumpGenerator::GetLRFromException() { +uintptr_t IosExceptionMinidumpGenerator::GetLRFromException() { return [[return_addresses_ objectAtIndex:1] unsignedIntegerValue]; } bool IosExceptionMinidumpGenerator::WriteExceptionStream( MDRawDirectory *exception_stream) { -#ifdef HAS_ARM_SUPPORT TypedMDRVA exception(&writer_); if (!exception.Allocate()) @@ -121,37 +154,35 @@ bool IosExceptionMinidumpGenerator::WriteExceptionStream( exception_ptr->exception_record.exception_address = GetPCFromException(); return true; -#else - return MinidumpGenerator::WriteExceptionStream(exception_stream); -#endif } bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id, MDRawThread *thread) { -#ifdef HAS_ARM_SUPPORT if (pthread_mach_thread_np(pthread_self()) != thread_id) return MinidumpGenerator::WriteThreadStream(thread_id, thread); size_t frame_count = [return_addresses_ count]; UntypedMDRVA memory(&writer_); - size_t size = 8 * (frame_count - 1) + 4; - if (!memory.Allocate(size)) + size_t pointer_size = sizeof(uintptr_t); + size_t frame_record_size = 2 * pointer_size; + size_t stack_size = frame_record_size * (frame_count - 1) + pointer_size; + if (!memory.Allocate(stack_size)) return false; - scoped_array stack_memory(new uint8_t[size]); - uint32_t sp = size - 4; - uint32_t fp = 0; - uint32_t lr = 0; + scoped_array stack_memory(new uint8_t[stack_size]); + uintptr_t sp = stack_size - pointer_size; + uintptr_t fp = 0; + uintptr_t lr = 0; for (int current_frame = frame_count - 1; current_frame > 0; --current_frame) { AppendToMemory(stack_memory.get(), sp, lr); - sp -= 4; + sp -= pointer_size; AppendToMemory(stack_memory.get(), sp, fp); fp = sp; - sp -= 4; + sp -= pointer_size; lr = [[return_addresses_ objectAtIndex:current_frame] unsignedIntegerValue]; } - if (!memory.Copy(stack_memory.get(), size)) + if (!memory.Copy(stack_memory.get(), stack_size)) return false; assert(sp == kExpectedFinalSp); assert(fp == kExpectedFinalFp); @@ -165,9 +196,6 @@ bool IosExceptionMinidumpGenerator::WriteThreadStream(mach_port_t thread_id, thread->thread_id = thread_id; return true; -#else - return MinidumpGenerator::WriteThreadStream(thread_id, thread); -#endif } } // namespace google_breakpad diff --git a/src/client/mac/handler/dynamic_images.h b/src/client/mac/handler/dynamic_images.h index d039eda0..6f4c3377 100644 --- a/src/client/mac/handler/dynamic_images.h +++ b/src/client/mac/handler/dynamic_images.h @@ -285,6 +285,8 @@ class DynamicImages { return CPU_TYPE_POWERPC64; #elif defined(__arm__) return CPU_TYPE_ARM; +#elif defined(__arm64__) + return CPU_TYPE_ARM64; #else #error "GetNativeCPUType not implemented for this architecture" #endif diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc index e2ae4e31..58ecc415 100644 --- a/src/client/mac/handler/exception_handler.cc +++ b/src/client/mac/handler/exception_handler.cc @@ -326,7 +326,7 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, EXC_I386_BPT, #elif defined(__ppc__) || defined(__ppc64__) EXC_PPC_BREAKPOINT, -#elif defined(__arm__) +#elif defined(__arm__) || defined(__arm64__) EXC_ARM_BREAKPOINT, #else #error architecture not supported @@ -342,13 +342,14 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, return result; } -bool ExceptionHandler::WriteMinidumpWithException(int exception_type, - int exception_code, - int exception_subcode, - ucontext_t* task_context, - mach_port_t thread_name, - bool exit_after_write, - bool report_current_thread) { +bool ExceptionHandler::WriteMinidumpWithException( + int exception_type, + int exception_code, + int exception_subcode, + breakpad_ucontext_t* task_context, + mach_port_t thread_name, + bool exit_after_write, + bool report_current_thread) { bool result = false; if (directCallback_) { @@ -453,12 +454,13 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread, exception_behavior_t target_behavior = current.behaviors[found]; kern_return_t result; + // TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES + // set. https://code.google.com/p/google-breakpad/issues/detail?id=551 switch (target_behavior) { case EXCEPTION_DEFAULT: result = exception_raise(target_port, failed_thread, task, exception, code, code_count); break; - default: fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior); result = KERN_FAILURE; @@ -520,7 +522,7 @@ void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { exception_code = EXC_I386_BPT; #elif defined(__ppc__) || defined(__ppc64__) exception_code = EXC_PPC_BREAKPOINT; -#elif defined(__arm__) +#elif defined(__arm__) || defined(__arm64__) exception_code = EXC_ARM_BREAKPOINT; #else #error architecture not supported @@ -611,7 +613,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { EXC_SOFTWARE, MD_EXCEPTION_CODE_MAC_ABORT, 0, - static_cast(uc), + static_cast(uc), mach_thread_self(), true, true); diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h index b5e8bbaa..f1d9ae92 100644 --- a/src/client/mac/handler/exception_handler.h +++ b/src/client/mac/handler/exception_handler.h @@ -41,6 +41,7 @@ #include +#include "client/mac/handler/ucontext_compat.h" #include "common/scoped_ptr.h" #if !TARGET_OS_IPHONE @@ -188,7 +189,7 @@ class ExceptionHandler { bool WriteMinidumpWithException(int exception_type, int exception_code, int exception_subcode, - ucontext_t *task_context, + breakpad_ucontext_t *task_context, mach_port_t thread_name, bool exit_after_write, bool report_current_thread); diff --git a/src/client/mac/handler/mach_vm_compat.h b/src/client/mac/handler/mach_vm_compat.h index 5af2f204..cb5cf2bd 100644 --- a/src/client/mac/handler/mach_vm_compat.h +++ b/src/client/mac/handler/mach_vm_compat.h @@ -32,14 +32,18 @@ #include -// On iOS 5, mach/mach_vm.h is not supported anymore. As the architecture is 32 -// bits, we can use the simple vm_ functions instead of the mach_vm_ ones. +// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding +// vm_map functions instead. #if TARGET_OS_IPHONE #include #define mach_vm_address_t vm_address_t #define mach_vm_deallocate vm_deallocate #define mach_vm_read vm_read +#if defined(__LP64__) +#define mach_vm_region_recurse vm_region_recurse_64 +#else #define mach_vm_region_recurse vm_region_recurse +#endif #define mach_vm_size_t vm_size_t #else #include diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc index 809e684f..a85c6704 100644 --- a/src/client/mac/handler/minidump_generator.cc +++ b/src/client/mac/handler/minidump_generator.cc @@ -42,7 +42,7 @@ #include "client/mac/handler/minidump_generator.h" -#ifdef HAS_ARM_SUPPORT +#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT) #include #endif #ifdef HAS_PPC_SUPPORT @@ -171,7 +171,7 @@ void MinidumpGenerator::GatherSystemInformation() { os_build_number_ = IntegerValueAtIndex(product_str, 2); } -void MinidumpGenerator::SetTaskContext(ucontext_t *task_context) { +void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { task_context_ = task_context; } @@ -369,6 +369,10 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state, 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); @@ -393,6 +397,10 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state, 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); @@ -417,6 +425,10 @@ uint64_t MinidumpGenerator::CurrentPCForStack( 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); @@ -486,7 +498,82 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state, AddGPR(10); AddGPR(11); AddGPR(12); -#undef AddReg +#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(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(state); + + return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool +MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location) +{ + TypedMDRVA context(&writer_); + arm_thread_state64_t *machine_state = + reinterpret_cast(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; @@ -780,10 +867,18 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, if (task_context_ && target_thread == mach_thread_self()) { switch (cpu_type_) { #ifdef HAS_ARM_SUPPORT - case CPU_TYPE_ARM: { + case CPU_TYPE_ARM: size_t final_size = std::min(static_cast(*count), sizeof(arm_thread_state_t)); - memcpy(state, &task_context_->uc_mcontext->__ss, final_size); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); + *count = final_size; + return true; +#endif +#ifdef HAS_ARM64_SUPPORT + case CPU_TYPE_ARM64: { + size_t final_size = + std::min(static_cast(*count), sizeof(arm_thread_state64_t)); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); *count = final_size; return true; } @@ -795,7 +890,7 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); size_t final_size = std::min(static_cast(*count), state_size); - memcpy(state, &task_context_->uc_mcontext->__ss, final_size); + memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); *count = final_size; return true; } @@ -810,6 +905,11 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread, 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; @@ -1060,6 +1160,11 @@ bool MinidumpGenerator::WriteSystemInfoStream( 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: diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h index c79873fa..3f7f8de0 100644 --- a/src/client/mac/handler/minidump_generator.h +++ b/src/client/mac/handler/minidump_generator.h @@ -37,6 +37,7 @@ #include +#include "client/mac/handler/ucontext_compat.h" #include "client/minidump_file_writer.h" #include "common/memory.h" #include "common/mac/macho_utilities.h" @@ -49,7 +50,9 @@ #define HAS_PPC_SUPPORT #endif #if defined(__arm__) - #define HAS_ARM_SUPPORT +#define HAS_ARM_SUPPORT +#elif defined(__arm64__) +#define HAS_ARM64_SUPPORT #elif defined(__i386__) || defined(__x86_64__) #define HAS_X86_SUPPORT #endif @@ -105,7 +108,7 @@ class MinidumpGenerator { // Specify the task context. If |task_context| is not NULL, it will be used // to retrieve the context of the current thread, instead of using // |thread_get_state|. - void SetTaskContext(ucontext_t *task_context); + void SetTaskContext(breakpad_ucontext_t *task_context); // Gather system information. This should be call at least once before using // the MinidumpGenerator class. @@ -153,6 +156,13 @@ class MinidumpGenerator { MDLocationDescriptor *register_location); uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state); #endif +#ifdef HAS_ARM64_SUPPORT + bool WriteStackARM64(breakpad_thread_state_data_t state, + MDMemoryDescriptor *stack_location); + bool WriteContextARM64(breakpad_thread_state_data_t state, + MDLocationDescriptor *register_location); + uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state); +#endif #ifdef HAS_PPC_SUPPORT bool WriteStackPPC(breakpad_thread_state_data_t state, MDMemoryDescriptor *stack_location); @@ -205,7 +215,7 @@ class MinidumpGenerator { static int os_build_number_; // Context of the task to dump. - ucontext_t *task_context_; + breakpad_ucontext_t *task_context_; // Information about dynamically loaded code DynamicImages *dynamic_images_; diff --git a/src/client/mac/handler/ucontext_compat.h b/src/client/mac/handler/ucontext_compat.h new file mode 100644 index 00000000..093f9a24 --- /dev/null +++ b/src/client/mac/handler/ucontext_compat.h @@ -0,0 +1,47 @@ +// Copyright 2013 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. + +#ifndef CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ +#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ + +#include + +// The purpose of this file is to work around the fact that ucontext_t's +// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64. +#if defined(__arm64__) +// doesn't include the below file. +#include +typedef ucontext64_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext64 +#else +typedef ucontext_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext +#endif // defined(__arm64__) + +#endif // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ diff --git a/src/google_breakpad/common/minidump_cpu_arm64.h b/src/google_breakpad/common/minidump_cpu_arm64.h new file mode 100644 index 00000000..5ace0d9d --- /dev/null +++ b/src/google_breakpad/common/minidump_cpu_arm64.h @@ -0,0 +1,140 @@ +/* Copyright 2013 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ARM. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Colin Blundell + */ + +/* + * ARM64 support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ + +#define MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT 32 + +typedef struct { + uint32_t fpsr; /* FPU status register */ + uint32_t fpcr; /* FPU control register */ + + /* 32 128-bit floating point registers, d0 .. d31. */ + uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT]; +} MDFloatingSaveAreaARM64; + +#define MD_CONTEXT_ARM64_GPR_COUNT 33 + +/* Use the same 32-bit alignment when accessing this structure from 64-bit code + * as is used natively in 32-bit code. */ +#pragma pack(push, 4) + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint64_t context_flags; + + /* 33 64-bit integer registers, x0 .. x31 + the PC + * Note the following fixed uses: + * x29 is the frame pointer + * x30 is the link register + * x31 is the stack pointer + * The PC is effectively x32. + */ + uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM64 float_save; + +} MDRawContextARM64; + +#pragma pack(pop) + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARM64RegisterNumbers { + MD_CONTEXT_ARM64_REG_FP = 29, + MD_CONTEXT_ARM64_REG_LR = 30, + MD_CONTEXT_ARM64_REG_SP = 31, + MD_CONTEXT_ARM64_REG_PC = 32 +}; + +/* For (MDRawContextARM64).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_ARM64 is Breakpad-defined. + * This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM64 0x80000000 +#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002) +#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004) + +#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) + +#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ */ diff --git a/src/google_breakpad/common/minidump_format.h b/src/google_breakpad/common/minidump_format.h index 6b425ea8..b7ad7bda 100644 --- a/src/google_breakpad/common/minidump_format.h +++ b/src/google_breakpad/common/minidump_format.h @@ -114,6 +114,7 @@ typedef struct { #include "minidump_cpu_amd64.h" #include "minidump_cpu_arm.h" +#include "minidump_cpu_arm64.h" #include "minidump_cpu_mips.h" #include "minidump_cpu_ppc.h" #include "minidump_cpu_ppc64.h" @@ -636,6 +637,7 @@ typedef enum { /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ + MD_CPU_ARCHITECTURE_ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */ MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ } MDCPUArchitecture;