ios: CaptureContext arm64.
Change-Id: I2db8ead3103391af4d198f213524ea34ffef022b
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2167211
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/client/crashpad_client_ios_test.mm b/client/crashpad_client_ios_test.mm
index 002fddb..292b27f 100644
--- a/client/crashpad_client_ios_test.mm
+++ b/client/crashpad_client_ios_test.mm
@@ -32,18 +32,7 @@
client.StartCrashpadInProcessHandler();
NativeCPUContext context;
-#if defined(ARCH_CPU_X86_64)
CaptureContext(&context);
-#elif defined(ARCH_CPU_ARM64)
- // TODO(justincohen): Implement CaptureContext for ARM64.
- mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
- kern_return_t kr =
- thread_get_state(mach_thread_self(),
- MACHINE_THREAD_STATE,
- reinterpret_cast<thread_state_t>(&context),
- &thread_state_count);
- ASSERT_EQ(kr, KERN_SUCCESS);
-#endif
client.DumpWithoutCrash(&context);
}
diff --git a/util/BUILD.gn b/util/BUILD.gn
index 9dc80ac..f3ffedd 100644
--- a/util/BUILD.gn
+++ b/util/BUILD.gn
@@ -723,6 +723,7 @@
"mach/mach_extensions_test.cc",
"mach/mach_message_test.cc",
"mach/symbolic_constants_mach_test.cc",
+ "misc/capture_context_test_util_mac.cc",
]
}
@@ -740,7 +741,6 @@
"mach/mach_message_server_test.cc",
"mach/notify_server_test.cc",
"mach/scoped_task_suspend_test.cc",
- "misc/capture_context_test_util_mac.cc",
"process/process_memory_mac_test.cc",
]
}
@@ -749,7 +749,6 @@
sources += [ "ios/exception_processor_test.mm" ]
sources -= [
- "misc/capture_context_test.cc",
"process/process_memory_range_test.cc",
"process/process_memory_test.cc",
]
diff --git a/util/misc/capture_context_mac.S b/util/misc/capture_context_mac.S
index 39c6ca6..f6acafb 100644
--- a/util/misc/capture_context_mac.S
+++ b/util/misc/capture_context_mac.S
@@ -12,17 +12,29 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
+#if defined(__i386__) || defined(__x86_64__)
// namespace crashpad {
// void CaptureContext(x86_thread_state_t* x86_thread_state);
// } // namespace crashpad
#define CAPTURECONTEXT_SYMBOL __ZN8crashpad14CaptureContextEP16x86_thread_state
+#elif defined(__aarch64__)
+// namespace crashpad {
+// void CaptureContext(arm_unified_thread_state_t* arm_unified_thread_state);
+// } // namespace crashpad
+#define CAPTURECONTEXT_SYMBOL \
+ __ZN8crashpad14CaptureContextEP24arm_unified_thread_state
+#endif
.section __TEXT,__text,regular,pure_instructions
.private_extern CAPTURECONTEXT_SYMBOL
.globl CAPTURECONTEXT_SYMBOL
- .balign 16, 0x90
+#if defined(__i386__) || defined(__x86_64__)
+ .p2align 4, 0x90
+#elif defined(__aarch64__)
+ .p2align 2
+#endif
CAPTURECONTEXT_SYMBOL:
#if defined(__i386__)
@@ -211,6 +223,64 @@
.cfi_endproc
+#elif defined(__aarch64__)
+
+ .cfi_startproc
+
+ // Save general-purpose registers in arm_unified_thread_state->ts_64.__x[0].
+ // The original x0 can't be recovered.
+ stp x0, x1, [x0, #0x8]
+ stp x2, x3, [x0, #0x18]
+ stp x4, x5, [x0, #0x28]
+ stp x6, x7, [x0, #0x38]
+ stp x8, x9, [x0, #0x48]
+ stp x10, x11, [x0, #0x58]
+ stp x12, x13, [x0, #0x68]
+ stp x14, x15, [x0, #0x78]
+ stp x16, x17, [x0, #0x88]
+ stp x18, x19, [x0, #0x98]
+ stp x20, x21, [x0, #0xa8]
+ stp x22, x23, [x0, #0xb8]
+ stp x24, x25, [x0, #0xc8]
+ stp x26, x27, [x0, #0xd8]
+
+ // Save the last general-purpose register (x28) and the frame pointer (x29).
+ stp x28, x29, [x0, #0xe8] // __x[28] and __fp
+
+ // Save the link register (x30) and the stack pointer (using x1 as a scratch
+ // register)
+ mov x1, sp
+ stp x30, x1, [x0, #0xf8] // __lr and __sp
+
+ // The link register (x30) holds the return address for this function.
+ // __cpsr should hold current program status register, but nzcv are the only
+ // bits we know about (saved using x1 as a scratch register). The 64-bit x1
+ // covers both the 32-bit __cpsr (which receives the nzcv bits) and __pad
+ // (which will be zeroed).
+ mrs x1, nzcv
+ stp x30, x1, [x0, #0x108] // __pc and __cpsr and __pad
+
+ // Initialize the header identifying the arm_unified_thread_state structure as
+ // carrying an arm_thread_state64_t (flavor ARM_THREAD_STATE64) of size
+ // ARM_THREAD_STATE64_COUNT 32-bit values.
+ mov x1, #6
+ movk x1, #68, lsl #32
+ str x1, [x0, #0x0] // arm_thread_state->ash.flavor and count
+
+ // Restore x1 from the saved context.
+ ldr x1, [x0, #0x10]
+
+ // TODO(justincohen): Consider saving floating-point registers into
+ // arm_neon_state64_t as second parameter, or as a a second function call
+ // after all of the general-purpose state is captured, or as a new struct that
+ // has both arm_unified_state_t and arm_neon_state64_t members. That may be
+ // better than a second parameter (which occupies another register) and better
+ // than a second function call.
+
+ ret
+
+ .cfi_endproc
+
#endif
.subsections_via_symbols
diff --git a/util/misc/capture_context_test_util_mac.cc b/util/misc/capture_context_test_util_mac.cc
index afe0916..6d4143f 100644
--- a/util/misc/capture_context_test_util_mac.cc
+++ b/util/misc/capture_context_test_util_mac.cc
@@ -31,6 +31,11 @@
implicit_cast<thread_state_flavor_t>(x86_THREAD_STATE64));
ASSERT_EQ(implicit_cast<uint32_t>(context.tsh.count),
implicit_cast<uint32_t>(x86_THREAD_STATE64_COUNT));
+#elif defined(ARCH_CPU_ARM64)
+ ASSERT_EQ(implicit_cast<thread_state_flavor_t>(context.ash.flavor),
+ implicit_cast<thread_state_flavor_t>(ARM_THREAD_STATE64));
+ ASSERT_EQ(implicit_cast<uint32_t>(context.ash.count),
+ implicit_cast<uint32_t>(ARM_THREAD_STATE64_COUNT));
#endif
#if defined(ARCH_CPU_X86_FAMILY)
@@ -61,6 +66,18 @@
EXPECT_EQ(context.uts.ts64.__gs & ~UINT64_C(0xffff), 0u);
EXPECT_EQ(context.uts.ts64.__rflags & UINT64_C(0xffffffffffc0802a), 2u);
#endif
+
+#elif defined(ARCH_CPU_ARM64)
+ // Check that the bits other than nzcv in __cpsr read 0.
+ EXPECT_EQ(context.ts_64.__cpsr & 0x0fffffff, 0u);
+
+ // Check that __pad is entirely zeroed out.
+ EXPECT_EQ(context.ts_64.__pad, 0u);
+
+ // Because ARM ret doesn’t change %lr, and because CaptureContext captures the
+ // the state at CaptureContext’s return to its caller, check for equivalence
+ // of __lr and __pc.
+ EXPECT_EQ(context.ts_64.__lr, context.ts_64.__pc);
#endif
}
@@ -69,6 +86,8 @@
return context.uts.ts32.__eip;
#elif defined(ARCH_CPU_X86_64)
return context.uts.ts64.__rip;
+#elif defined(ARCH_CPU_ARM64)
+ return context.ts_64.__pc;
#endif
}
@@ -77,6 +96,8 @@
return context.uts.ts32.__esp;
#elif defined(ARCH_CPU_X86_64)
return context.uts.ts64.__rsp;
+#elif defined(ARCH_CPU_ARM64)
+ return context.ts_64.__sp;
#endif
}