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: I0604fe481159d12b3c07ecad051922a427b49849
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>
GitOrigin-RevId: 809939c9d110e47749e9e83fe5681e2b7c4b7889
diff --git a/client/simulate_crash_mac.cc b/client/simulate_crash_mac.cc
index 8d6e8bd..ae00816 100644
--- a/client/simulate_crash_mac.cc
+++ b/client/simulate_crash_mac.cc
@@ -95,6 +95,15 @@
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 @@
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());
diff --git a/snapshot/ios/exception_snapshot_ios.cc b/snapshot/ios/exception_snapshot_ios.cc
index db9e489..5d6adc8 100644
--- a/snapshot/ios/exception_snapshot_ios.cc
+++ b/snapshot/ios/exception_snapshot_ios.cc
@@ -56,12 +56,16 @@
#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 @@
#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 @@
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 @@
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 @@
#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.
diff --git a/snapshot/ios/thread_snapshot_ios.cc b/snapshot/ios/thread_snapshot_ios.cc
index a52be51..ffd5a45 100644
--- a/snapshot/ios/thread_snapshot_ios.cc
+++ b/snapshot/ios/thread_snapshot_ios.cc
@@ -26,6 +26,7 @@
#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 @@
#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 @@
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 @@
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 @@
#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 @@
nullptr,
0,
&thread_state,
- &float_state);
+ &float_state,
+ &debug_state);
+#else
+#error Port to your CPU architecture
#endif
INITIALIZATION_STATE_SET_VALID(initialized_);
diff --git a/snapshot/mac/cpu_context_mac.cc b/snapshot/mac/cpu_context_mac.cc
index 6e2950a..0a30fde 100644
--- a/snapshot/mac/cpu_context_mac.cc
+++ b/snapshot/mac/cpu_context_mac.cc
@@ -437,20 +437,22 @@
} // 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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
if (set_flavor != ARM_NEON_STATE64) {
InitializeCPUContextARM64Neon(context, arm_neon_state64);
}
+ if (set_flavor != ARM_DEBUG_STATE64) {
+ InitializeCPUContextARM64Debug(context, arm_debug_state64);
+ }
}
} // namespace internal
diff --git a/snapshot/mac/cpu_context_mac.h b/snapshot/mac/cpu_context_mac.h
index 05c035a..154dccd 100644
--- a/snapshot/mac/cpu_context_mac.h
+++ b/snapshot/mac/cpu_context_mac.h
@@ -108,9 +108,9 @@
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 @@
//! \param[in] arm_thread_state64 The state of the thread’s integer registers.
//! \param[in] arm_neon_state64 The state of the thread’s floating-point
//! registers.
+//! \param[in] arm_debug_state64 The state of the thread’s 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
diff --git a/snapshot/mac/exception_snapshot_mac.cc b/snapshot/mac/exception_snapshot_mac.cc
index 8eefac9..39d8fb2 100644
--- a/snapshot/mac/exception_snapshot_mac.cc
+++ b/snapshot/mac/exception_snapshot_mac.cc
@@ -187,6 +187,18 @@
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) {
diff --git a/snapshot/mac/exception_snapshot_mac.h b/snapshot/mac/exception_snapshot_mac.h
index 52ef519..7c0b87c 100644
--- a/snapshot/mac/exception_snapshot_mac.h
+++ b/snapshot/mac/exception_snapshot_mac.h
@@ -79,12 +79,16 @@
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_;
diff --git a/snapshot/mac/process_reader_mac.cc b/snapshot/mac/process_reader_mac.cc
index 61dc3a1..ca2c1f7 100644
--- a/snapshot/mac/process_reader_mac.cc
+++ b/snapshot/mac/process_reader_mac.cc
@@ -280,6 +280,15 @@
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 @@
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 =
diff --git a/snapshot/mac/process_reader_mac.h b/snapshot/mac/process_reader_mac.h
index 9feb8b0..ac57a06 100644
--- a/snapshot/mac/process_reader_mac.h
+++ b/snapshot/mac/process_reader_mac.h
@@ -55,6 +55,10 @@
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();
diff --git a/snapshot/mac/system_snapshot_mac.cc b/snapshot/mac/system_snapshot_mac.cc
index 5410be0..2d6620d 100644
--- a/snapshot/mac/system_snapshot_mac.cc
+++ b/snapshot/mac/system_snapshot_mac.cc
@@ -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 @@
#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 @@
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 @@
#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
diff --git a/snapshot/mac/thread_snapshot_mac.cc b/snapshot/mac/thread_snapshot_mac.cc
index ddb4def..d261f19 100644
--- a/snapshot/mac/thread_snapshot_mac.cc
+++ b/snapshot/mac/thread_snapshot_mac.cc
@@ -75,6 +75,18 @@
&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_);
diff --git a/snapshot/mac/thread_snapshot_mac.h b/snapshot/mac/thread_snapshot_mac.h
index 946b008..06331fa 100644
--- a/snapshot/mac/thread_snapshot_mac.h
+++ b/snapshot/mac/thread_snapshot_mac.h
@@ -63,12 +63,16 @@
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_;
diff --git a/util/net/http_transport_mac.mm b/util/net/http_transport_mac.mm
index a433bb3..8faa1b8 100644
--- a/util/net/http_transport_mac.mm
+++ b/util/net/http_transport_mac.mm
@@ -91,6 +91,8 @@
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