diff options
author | mark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2013-11-21 17:44:57 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e> | 2013-11-21 17:44:57 +0000 |
commit | 77022ac0df3e079fb0abea05033b0239d12a4e72 (patch) | |
tree | 6f7207ff153e8306c441fa0cdb18b728ef971fe5 /src/client/mac | |
parent | Provide BreakpadGetCrashReportCount() and -[BreakpadController (diff) | |
download | breakpad-77022ac0df3e079fb0abea05033b0239d12a4e72.tar.xz |
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 <blundell@chromium.org>
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
Diffstat (limited to 'src/client/mac')
-rw-r--r-- | src/client/mac/handler/dynamic_images.h | 2 | ||||
-rw-r--r-- | src/client/mac/handler/exception_handler.cc | 24 | ||||
-rw-r--r-- | src/client/mac/handler/exception_handler.h | 3 | ||||
-rw-r--r-- | src/client/mac/handler/mach_vm_compat.h | 8 | ||||
-rw-r--r-- | src/client/mac/handler/minidump_generator.cc | 117 | ||||
-rw-r--r-- | src/client/mac/handler/minidump_generator.h | 16 | ||||
-rw-r--r-- | src/client/mac/handler/ucontext_compat.h | 47 |
7 files changed, 194 insertions, 23 deletions
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<ucontext_t*>(uc), + static_cast<breakpad_ucontext_t*>(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 <string> +#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 <TargetConditionals.h> -// 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 <mach/vm_map.h> #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 <mach/mach_vm.h> 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 <mach/arm/thread_status.h> #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<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; @@ -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<size_t>(*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<size_t>(*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<size_t>(*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 <string> +#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 <sys/ucontext.h> + +// 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__) +// <sys/ucontext.h> doesn't include the below file. +#include <sys/_types/_ucontext64.h> +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_ |