mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2025-12-27 17:55:29 +01:00
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
This commit is contained in:
parent
8e28cb3898
commit
77022ac0df
12 changed files with 419 additions and 63 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
47
src/client/mac/handler/ucontext_compat.h
Normal file
47
src/client/mac/handler/ucontext_compat.h
Normal file
|
|
@ -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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue