aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-11-21 17:44:57 +0000
committermark@chromium.org <mark@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-11-21 17:44:57 +0000
commit77022ac0df3e079fb0abea05033b0239d12a4e72 (patch)
tree6f7207ff153e8306c441fa0cdb18b728ef971fe5
parentProvide BreakpadGetCrashReportCount() and -[BreakpadController (diff)
downloadbreakpad-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
-rw-r--r--src/client/ios/Breakpad.xcodeproj/project.pbxproj16
-rw-r--r--src/client/ios/handler/ios_exception_minidump_generator.h11
-rw-r--r--src/client/ios/handler/ios_exception_minidump_generator.mm94
-rw-r--r--src/client/mac/handler/dynamic_images.h2
-rw-r--r--src/client/mac/handler/exception_handler.cc24
-rw-r--r--src/client/mac/handler/exception_handler.h3
-rw-r--r--src/client/mac/handler/mach_vm_compat.h8
-rw-r--r--src/client/mac/handler/minidump_generator.cc117
-rw-r--r--src/client/mac/handler/minidump_generator.h16
-rw-r--r--src/client/mac/handler/ucontext_compat.h47
-rw-r--r--src/google_breakpad/common/minidump_cpu_arm64.h140
-rw-r--r--src/google_breakpad/common/minidump_format.h2
12 files changed, 418 insertions, 62 deletions
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 = "<group>"; };
+ 14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; };
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; };
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_exception_minidump_generator.mm; sourceTree = "<group>"; };
16C7C968147D4A4200776EAD /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadDefines.h; sourceTree = "<group>"; };
@@ -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 = "<group>";
@@ -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 <pthread.h>
+#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<MDRawContextARM> 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<MDRawContextARM64> 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<MDRawExceptionStream> 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<uint8_t> stack_memory(new uint8_t[size]);
- uint32_t sp = size - 4;
- uint32_t fp = 0;
- uint32_t lr = 0;
+ scoped_array<uint8_t> 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<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_
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;