From 77022ac0df3e079fb0abea05033b0239d12a4e72 Mon Sep 17 00:00:00 2001 From: "mark@chromium.org" Date: Thu, 21 Nov 2013 17:44:57 +0000 Subject: Generate minidumps for 64-bit ARM apps on iOS. Adds an ARM64-specific definition of MDRawContext and support for writing out a minidump when running on ARM64. Additionally, extends the iOS minidump generator for NSExceptions to work on ARM64 as well as ARM. Patch by Colin Blundell BUG=542 Review URL: https://breakpad.appspot.com/664002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1235 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/ios/Breakpad.xcodeproj/project.pbxproj | 16 +++- .../ios/handler/ios_exception_minidump_generator.h | 11 ++- .../handler/ios_exception_minidump_generator.mm | 94 ++++++++++++++-------- 3 files changed, 82 insertions(+), 39 deletions(-) (limited to 'src/client/ios') 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 + +#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 -uint32_t IosExceptionMinidumpGenerator::GetPCFromException() { +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 -- cgit v1.2.1