mac: Crashpad for macOS on arm64, phase 1: build it

This gets all production code for Chrome building, excluding tests.
There aren’t any guarantees that anything works yet.

This is mostly a lot of CPU context shuffling.

In contrast to macOS on x86, there’s no need to support 32-bit arm on
macOS, because this new platform is 64-bit-only from its inception.

Bug: crashpad:345
Change-Id: I187239b6a969005a3458af7fe30c44147a57f95f
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2285961
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Mark Mentovai 2020-07-07 23:43:11 -04:00 committed by Commit Bot
parent b9c828ea83
commit 809939c9d1
13 changed files with 144 additions and 28 deletions

View File

@ -95,6 +95,15 @@ bool DeliverException(thread_t thread,
state_count = cpu_context.tsh.count;
break;
#endif
#elif defined(ARCH_CPU_ARM64)
case ARM_UNIFIED_THREAD_STATE:
state = reinterpret_cast<ConstThreadState>(&cpu_context);
state_count = ARM_UNIFIED_THREAD_STATE_COUNT;
break;
case ARM_THREAD_STATE64:
state = reinterpret_cast<ConstThreadState>(&cpu_context.ts_64);
state_count = cpu_context.ash.count;
break;
#else
#error Port to your CPU architecture
#endif
@ -187,6 +196,13 @@ void SimulateCrash(const NativeCPUContext& cpu_context) {
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.tsh.count),
x86_THREAD_STATE64_COUNT);
#elif defined(ARCH_CPU_ARM64)
DCHECK_EQ(implicit_cast<thread_state_flavor_t>(cpu_context.ash.flavor),
implicit_cast<thread_state_flavor_t>(ARM_THREAD_STATE64));
DCHECK_EQ(implicit_cast<mach_msg_type_number_t>(cpu_context.ash.count),
ARM_THREAD_STATE64_COUNT);
#else
#error Port to your CPU architecture
#endif
base::mac::ScopedMachSendRight thread(mach_thread_self());

View File

@ -56,12 +56,16 @@ void ExceptionSnapshotIOS::InitializeFromSignal(const siginfo_t* siginfo,
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_arm64_;
arm_debug_state64_t empty_debug_state = {};
InitializeCPUContextARM64(&context_arm64_,
THREAD_STATE_NONE,
nullptr,
0,
&mcontext->__ss,
&mcontext->__ns);
&mcontext->__ns,
&empty_debug_state);
#else
#error Port to your CPU architecture
#endif
// Thread ID.
@ -127,10 +131,13 @@ void ExceptionSnapshotIOS::InitializeFromMachException(
#elif defined(ARCH_CPU_ARM64)
arm_thread_state64_t thread_state;
arm_neon_state64_t float_state;
arm_debug_state64_t debug_state;
mach_msg_type_number_t float_state_count = ARM_NEON_STATE64_COUNT;
mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT;
mach_msg_type_number_t debug_state_count = ARM_DEBUG_STATE64_COUNT;
const thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64;
const thread_state_flavor_t kFloatStateFlavor = ARM_NEON_STATE64;
const thread_state_flavor_t kDebugStateFlavor = ARM_DEBUG_STATE64;
#endif
kern_return_t kr =
@ -150,7 +157,6 @@ void ExceptionSnapshotIOS::InitializeFromMachException(
MACH_LOG(ERROR, kr) << "thread_get_state(" << kFloatStateFlavor << ")";
}
#if defined(ARCH_CPU_X86_64)
kr = thread_get_state(exception_thread,
kDebugStateFlavor,
reinterpret_cast<thread_state_t>(&debug_state),
@ -158,7 +164,6 @@ void ExceptionSnapshotIOS::InitializeFromMachException(
if (kr != KERN_SUCCESS) {
MACH_LOG(ERROR, kr) << "thread_get_state(" << kDebugStateFlavor << ")";
}
#endif
#if defined(ARCH_CPU_X86_64)
context_.architecture = kCPUArchitectureX86_64;
@ -173,8 +178,15 @@ void ExceptionSnapshotIOS::InitializeFromMachException(
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_arm64_;
InitializeCPUContextARM64(
&context_arm64_, flavor, state, state_count, &thread_state, &float_state);
InitializeCPUContextARM64(&context_arm64_,
flavor,
state,
state_count,
&thread_state,
&float_state,
&debug_state);
#else
#error Port to your CPU architecture
#endif
// Thread ID.

View File

@ -26,6 +26,7 @@ const thread_state_flavor_t kDebugStateFlavor = x86_DEBUG_STATE64;
#elif defined(ARCH_CPU_ARM64)
const thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64;
const thread_state_flavor_t kFloatStateFlavor = ARM_NEON_STATE64;
const thread_state_flavor_t kDebugStateFlavor = ARM_DEBUG_STATE64;
#endif
kern_return_t MachVMRegionRecurseDeepest(task_t task,
@ -324,8 +325,10 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) {
#elif defined(ARCH_CPU_ARM64)
arm_thread_state64_t thread_state;
arm_neon_state64_t float_state;
arm_debug_state64_t debug_state;
mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT;
mach_msg_type_number_t float_state_count = ARM_NEON_STATE64_COUNT;
mach_msg_type_number_t debug_state_count = ARM_DEBUG_STATE64_COUNT;
#endif
kern_return_t kr =
@ -345,7 +348,6 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) {
MACH_LOG(ERROR, kr) << "thread_get_state(" << kFloatStateFlavor << ")";
}
#if defined(ARCH_CPU_X86_64)
kr = thread_get_state(thread,
kDebugStateFlavor,
reinterpret_cast<thread_state_t>(&debug_state),
@ -353,7 +355,6 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) {
if (kr != KERN_SUCCESS) {
MACH_LOG(ERROR, kr) << "thread_get_state(" << kDebugStateFlavor << ")";
}
#endif
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
kr = thread_info(thread,
@ -388,7 +389,7 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) {
#if defined(ARCH_CPU_X86_64)
vm_address_t stack_pointer = thread_state.__rsp;
#elif defined(ARCH_CPU_ARM64)
vm_address_t stack_pointer = thread_state.__sp;
vm_address_t stack_pointer = arm_thread_state64_get_sp(thread_state);
#endif
stack_region_address =
CalculateStackRegion(stack_pointer, &stack_region_size);
@ -432,7 +433,10 @@ bool ThreadSnapshotIOS::Initialize(thread_t thread) {
nullptr,
0,
&thread_state,
&float_state);
&float_state,
&debug_state);
#else
#error Port to your CPU architecture
#endif
INITIALIZATION_STATE_SET_VALID(initialized_);

View File

@ -437,20 +437,22 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context,
} // namespace internal
#elif defined(ARCH_CPU_ARM_FAMILY)
#elif defined(ARCH_CPU_ARM64)
namespace {
void InitializeCPUContextARM64Thread(
CPUContextARM64* context,
const arm_thread_state64_t* arm_thread_state64) {
// The structures of context->regs and arm_thread_state64->__x are laid out
// identically for this copy, even though the members are organized
// differently. Because of this difference, there can't be a static assert
// similar to the one below for fpsimd.
memcpy(context->regs, arm_thread_state64->__x, sizeof(context->regs));
context->sp = arm_thread_state64->__sp;
context->pc = arm_thread_state64->__pc;
// The first 29 fields of context->regs is laid out identically to
// arm_thread_state64->__x.
memcpy(
context->regs, arm_thread_state64->__x, sizeof(arm_thread_state64->__x));
context->regs[29] = arm_thread_state64_get_fp(*arm_thread_state64);
context->regs[30] = arm_thread_state64_get_lr(*arm_thread_state64);
context->sp = arm_thread_state64_get_sp(*arm_thread_state64);
context->pc = arm_thread_state64_get_pc(*arm_thread_state64);
context->spsr =
static_cast<decltype(context->spsr)>(arm_thread_state64->__cpsr);
}
@ -464,6 +466,12 @@ void InitializeCPUContextARM64Neon(CPUContextARM64* context,
context->fpcr = arm_neon_state64->__fpcr;
}
void InitializeCPUContextARM64Debug(
CPUContextARM64* context,
const arm_debug_state64_t* arm_debug_state64) {
// TODO(macos_arm64): Create a spot in CPUContextARM64 to keep this.
}
thread_state_flavor_t InitializeCPUContextARM64Flavor(
CPUContextARM64* context,
thread_state_flavor_t flavor,
@ -471,8 +479,8 @@ thread_state_flavor_t InitializeCPUContextARM64Flavor(
mach_msg_type_number_t state_count) {
mach_msg_type_number_t expected_state_count;
switch (flavor) {
case ARM_THREAD_STATE:
expected_state_count = ARM_THREAD_STATE_COUNT;
case ARM_UNIFIED_THREAD_STATE:
expected_state_count = ARM_UNIFIED_THREAD_STATE_COUNT;
break;
case ARM_THREAD_STATE64:
expected_state_count = ARM_THREAD_STATE64_COUNT;
@ -480,6 +488,9 @@ thread_state_flavor_t InitializeCPUContextARM64Flavor(
case ARM_NEON_STATE64:
expected_state_count = ARM_NEON_STATE64_COUNT;
break;
case ARM_DEBUG_STATE64:
expected_state_count = ARM_DEBUG_STATE64_COUNT;
break;
case THREAD_STATE_NONE: {
// This may happen without error when called without exception-style
// flavor data, or even from an exception handler when the exception
@ -498,7 +509,7 @@ thread_state_flavor_t InitializeCPUContextARM64Flavor(
}
switch (flavor) {
case ARM_THREAD_STATE: {
case ARM_UNIFIED_THREAD_STATE: {
const arm_unified_thread_state_t* arm_thread_state =
reinterpret_cast<const arm_unified_thread_state_t*>(state);
if (arm_thread_state->ash.flavor != ARM_THREAD_STATE64) {
@ -527,6 +538,13 @@ thread_state_flavor_t InitializeCPUContextARM64Flavor(
return ARM_NEON_STATE64;
}
case ARM_DEBUG_STATE64: {
const arm_debug_state64_t* arm_debug_state =
reinterpret_cast<const arm_debug_state64_t*>(state);
InitializeCPUContextARM64Debug(context, arm_debug_state);
return ARM_DEBUG_STATE64;
}
case THREAD_STATE_NONE: {
// This may happen without error when called without exception-style
// flavor data, or even from an exception handler when the exception
@ -550,7 +568,8 @@ void InitializeCPUContextARM64(CPUContextARM64* context,
ConstThreadState state,
mach_msg_type_number_t state_count,
const arm_thread_state64_t* arm_thread_state64,
const arm_neon_state64_t* arm_neon_state64) {
const arm_neon_state64_t* arm_neon_state64,
const arm_debug_state64_t* arm_debug_state64) {
thread_state_flavor_t set_flavor = THREAD_STATE_NONE;
if (flavor != THREAD_STATE_NONE) {
set_flavor =
@ -563,6 +582,9 @@ void InitializeCPUContextARM64(CPUContextARM64* context,
if (set_flavor != ARM_NEON_STATE64) {
InitializeCPUContextARM64Neon(context, arm_neon_state64);
}
if (set_flavor != ARM_DEBUG_STATE64) {
InitializeCPUContextARM64Debug(context, arm_debug_state64);
}
}
} // namespace internal

View File

@ -108,9 +108,9 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context,
const x86_float_state64_t* x86_float_state64,
const x86_debug_state64_t* x86_debug_state64);
#elif defined(ARCH_CPU_ARM_FAMILY) || DOXYGEN
#elif defined(ARCH_CPU_ARM64) || DOXYGEN
//! \brief Initializes a CPUContextARM64 structure from native context
//! structures on iOS.
//! structures on macOS or iOS.
//!
//! \a flavor, \a state, and \a state_count may be supplied by exception
//! handlers in order for the \a context parameter to be initialized by the
@ -140,12 +140,14 @@ void InitializeCPUContextX86_64(CPUContextX86_64* context,
//! \param[in] arm_thread_state64 The state of the threads integer registers.
//! \param[in] arm_neon_state64 The state of the threads floating-point
//! registers.
//! \param[in] arm_debug_state64 The state of the threads debug registers.
void InitializeCPUContextARM64(CPUContextARM64* context,
thread_state_flavor_t flavor,
ConstThreadState state,
mach_msg_type_number_t state_count,
const arm_thread_state64_t* arm_thread_state64,
const arm_neon_state64_t* arm_neon_state64);
const arm_neon_state64_t* arm_neon_state64,
const arm_debug_state64_t* arm_debug_state64);
#endif
} // namespace internal

View File

@ -187,6 +187,18 @@ bool ExceptionSnapshotMac::Initialize(ProcessReaderMac* process_reader,
exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) {
code_1_is_exception_address = false;
}
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_union_.arm64;
InitializeCPUContextARM64(context_.arm64,
flavor,
state,
state_count,
&thread->thread_context,
&thread->float_context,
&thread->debug_context);
#else
#error Port to your architecture
#endif
if (code_1_is_exception_address) {

View File

@ -79,12 +79,16 @@ class ExceptionSnapshotMac final : public ExceptionSnapshot {
virtual std::vector<const MemorySnapshot*> ExtraMemory() const override;
private:
#if defined(ARCH_CPU_X86_FAMILY)
union {
#if defined(ARCH_CPU_X86_FAMILY)
CPUContextX86 x86;
CPUContextX86_64 x86_64;
} context_union_;
#elif defined(ARCH_CPU_ARM64)
CPUContextARM64 arm64;
#else
#error Port to your CPU architecture
#endif
} context_union_;
CPUContext context_;
std::vector<uint64_t> codes_;
uint64_t thread_id_;

View File

@ -280,6 +280,15 @@ void ProcessReaderMac::InitializeThreads() {
Is64Bit() ? x86_DEBUG_STATE64 : x86_DEBUG_STATE32;
mach_msg_type_number_t debug_state_count =
Is64Bit() ? x86_DEBUG_STATE64_COUNT : x86_DEBUG_STATE32_COUNT;
#elif defined(ARCH_CPU_ARM64)
const thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64;
mach_msg_type_number_t thread_state_count = ARM_THREAD_STATE64_COUNT;
const thread_state_flavor_t kFloatStateFlavor = ARM_NEON_STATE64;
mach_msg_type_number_t float_state_count = ARM_NEON_STATE64_COUNT;
const thread_state_flavor_t kDebugStateFlavor = ARM_DEBUG_STATE64;
mach_msg_type_number_t debug_state_count = ARM_DEBUG_STATE64_COUNT;
#endif
kr = thread_get_state(
@ -366,6 +375,9 @@ void ProcessReaderMac::InitializeThreads() {
mach_vm_address_t stack_pointer = Is64Bit()
? thread.thread_context.t64.__rsp
: thread.thread_context.t32.__esp;
#elif defined(ARCH_CPU_ARM64)
mach_vm_address_t stack_pointer =
arm_thread_state64_get_sp(thread.thread_context);
#endif
thread.stack_region_address =

View File

@ -55,6 +55,10 @@ class ProcessReaderMac {
x86_debug_state64_t d64;
x86_debug_state32_t d32;
};
#elif defined(ARCH_CPU_ARM64)
using ThreadContext = arm_thread_state64_t;
using FloatContext = arm_neon_state64_t;
using DebugContext = arm_debug_state64_t;
#endif
Thread();

View File

@ -23,6 +23,7 @@
#include <algorithm>
#include "base/logging.h"
#include "base/notreached.h"
#include "base/scoped_clear_last_error.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
@ -157,6 +158,8 @@ CPUArchitecture SystemSnapshotMac::GetCPUArchitecture() const {
#if defined(ARCH_CPU_X86_FAMILY)
return process_reader_->Is64Bit() ? kCPUArchitectureX86_64
: kCPUArchitectureX86;
#elif defined(ARCH_CPU_ARM64)
return kCPUArchitectureARM64;
#else
#error port to your architecture
#endif
@ -174,6 +177,11 @@ uint32_t SystemSnapshotMac::CPURevision() const {
uint8_t stepping = CastIntSysctlByName<uint8_t>("machdep.cpu.stepping", 0);
return (family << 16) | (model << 8) | stepping;
#elif defined(ARCH_CPU_ARM64)
// TODO(macos_arm64): Verify that this is correct, and pack more information
// if feasible. The Apple A12Z returns hw.cputype = 0x100000c and
// hw.cpusubtype = 2.
return CastIntSysctlByName<uint32_t>("hw.cputype", 0);
#else
#error port to your architecture
#endif
@ -189,6 +197,8 @@ std::string SystemSnapshotMac::CPUVendor() const {
#if defined(ARCH_CPU_X86_FAMILY)
return ReadStringSysctlByName("machdep.cpu.vendor");
#elif defined(ARCH_CPU_ARM64)
return ReadStringSysctlByName("machdep.cpu.brand_string");
#else
#error port to your architecture
#endif

View File

@ -75,6 +75,18 @@ bool ThreadSnapshotMac::Initialize(
&process_reader_thread.float_context.f32,
&process_reader_thread.debug_context.d32);
}
#elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_union_.arm64;
InitializeCPUContextARM64(context_.arm64,
THREAD_STATE_NONE,
nullptr,
0,
&process_reader_thread.thread_context,
&process_reader_thread.float_context,
&process_reader_thread.debug_context);
#else
#error Port to your CPU architecture
#endif
INITIALIZATION_STATE_SET_VALID(initialized_);

View File

@ -63,12 +63,16 @@ class ThreadSnapshotMac final : public ThreadSnapshot {
std::vector<const MemorySnapshot*> ExtraMemory() const override;
private:
#if defined(ARCH_CPU_X86_FAMILY)
union {
#if defined(ARCH_CPU_X86_FAMILY)
CPUContextX86 x86;
CPUContextX86_64 x86_64;
} context_union_;
#elif defined(ARCH_CPU_ARM64)
CPUContextARM64 arm64;
#else
#error Port to your CPU architecture
#endif
} context_union_;
CPUContext context_;
MemorySnapshotGeneric stack_;
uint64_t thread_id_;

View File

@ -91,6 +91,8 @@ NSString* UserAgentString() {
NSString* arch = @"i386";
#elif defined(ARCH_CPU_X86_64)
NSString* arch = @"x86_64";
#elif defined(ARCH_CPU_ARM64)
NSString* arch = @"arm64";
#else
#error Port
#endif