summaryrefslogtreecommitdiffstats
path: root/third_party/rust/crash-context/src/linux/getcontext
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/crash-context/src/linux/getcontext')
-rw-r--r--third_party/rust/crash-context/src/linux/getcontext/aarch64.rs86
-rw-r--r--third_party/rust/crash-context/src/linux/getcontext/arm.rs53
-rw-r--r--third_party/rust/crash-context/src/linux/getcontext/x86.rs68
-rw-r--r--third_party/rust/crash-context/src/linux/getcontext/x86_64.rs105
4 files changed, 312 insertions, 0 deletions
diff --git a/third_party/rust/crash-context/src/linux/getcontext/aarch64.rs b/third_party/rust/crash-context/src/linux/getcontext/aarch64.rs
new file mode 100644
index 0000000000..3cc7e66c97
--- /dev/null
+++ b/third_party/rust/crash-context/src/linux/getcontext/aarch64.rs
@@ -0,0 +1,86 @@
+// GREGS_OFFSET = 184
+// REGISTER_SIZE = 8
+// SIMD_REGISTER_SIZE = 16
+
+std::arch::global_asm! {
+ ".text",
+ ".global crash_context_getcontext",
+ ".hidden crash_context_getcontext",
+ ".type crash_context_getcontext, #function",
+ ".align 4",
+ ".cfi_startproc",
+"crash_context_getcontext:",
+
+ // The saved context will return to the getcontext() call point
+ // with a return value of 0
+ "str xzr, [x0, 184]", // GREGS_OFFSET
+
+ "stp x18, x19, [x0, 328]", // GREGS_OFFSET + 18 * REGISTER_SIZE
+ "stp x20, x21, [x0, 344]", // GREGS_OFFSET + 20 * REGISTER_SIZE
+ "stp x22, x23, [x0, 360]", // GREGS_OFFSET + 22 * REGISTER_SIZE
+ "stp x24, x25, [x0, 376]", // GREGS_OFFSET + 24 * REGISTER_SIZE
+ "stp x26, x27, [x0, 392]", // GREGS_OFFSET + 26 * REGISTER_SIZE
+ "stp x28, x29, [x0, 408]", // GREGS_OFFSET + 28 * REGISTER_SIZE
+ "str x30, [x0, 424]", // GREGS_OFFSET + 30 * REGISTER_SIZE
+
+ // Place LR into the saved PC, this will ensure that when switching to this
+ // saved context with setcontext() control will pass back to the caller of
+ // getcontext(), we have already arranged to return the appropriate return
+ // value in x0 above.
+ "str x30, [x0, 440]",
+
+ // Save the current SP
+ "mov x2, sp",
+ "str x2, [x0, 432]",
+
+ // Initialize the pstate.
+ "str xzr, [x0, 448]",
+
+ // Figure out where to place the first context extension block.
+ "add x2, x0, #464",
+
+ // Write the context extension fpsimd header.
+ // FPSIMD_MAGIC = 0x46508001
+ "mov w3, #(0x46508001 & 0xffff)",
+ "movk w3, #(0x46508001 >> 16), lsl #16",
+ "str w3, [x2, #0]", // FPSIMD_CONTEXT_MAGIC_OFFSET
+ "mov w3, #528", // FPSIMD_CONTEXT_SIZE
+ "str w3, [x2, #4]", // FPSIMD_CONTEXT_SIZE_OFFSET
+
+ // Fill in the FP SIMD context.
+ "add x3, x2, #144", // VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE
+ "stp d8, d9, [x3], #32",
+ "stp d10, d11, [x3], #32",
+ "stp d12, d13, [x3], #32",
+ "stp d14, d15, [x3], #32",
+
+ "add x3, x2, 8", // FPSR_OFFSET
+
+ "mrs x4, fpsr",
+ "str w4, [x3]",
+
+ "mrs x4, fpcr",
+ "str w4, [x3, 4]", // FPCR_OFFSET - FPSR_OFFSET
+
+ // Write the termination context extension header.
+ "add x2, x2, #528", // FPSIMD_CONTEXT_SIZE
+
+ "str xzr, [x2, #0]", // FPSIMD_CONTEXT_MAGIC_OFFSET
+ "str xzr, [x2, #4]", // FPSIMD_CONTEXT_SIZE_OFFSET
+
+ // Grab the signal mask
+ // rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8)
+ "add x2, x0, #40", // UCONTEXT_SIGMASK_OFFSET
+ "mov x0, #0", // SIG_BLOCK
+ "mov x1, #0", // NULL
+ "mov x3, #(64 / 8)", // _NSIG / 8
+ "mov x8, #135", // __NR_rt_sigprocmask
+ "svc 0",
+
+ // Return x0 for success
+ "mov x0, 0",
+ "ret",
+
+ ".cfi_endproc",
+ ".size crash_context_getcontext, . - crash_context_getcontext",
+}
diff --git a/third_party/rust/crash-context/src/linux/getcontext/arm.rs b/third_party/rust/crash-context/src/linux/getcontext/arm.rs
new file mode 100644
index 0000000000..0734634a3e
--- /dev/null
+++ b/third_party/rust/crash-context/src/linux/getcontext/arm.rs
@@ -0,0 +1,53 @@
+std::arch::global_asm! {
+ ".text",
+ ".global crash_context_getcontext",
+ ".hidden crash_context_getcontext",
+ ".type crash_context_getcontext, #function",
+ ".align 0",
+ ".fnstart",
+"crash_context_getcontext:",
+
+ // First, save r4-r11
+ "add r1, r0, #(32 + 4 * 4)",
+ "stm r1, {{r4-r11}}",
+
+ // r12 is a scratch register, don't save it
+
+ // Save sp and lr explicitly.
+ // - sp can't be stored with stmia in Thumb-2
+ // - STM instructions that store sp and pc are deprecated in ARM
+ "str sp, [r0, #(32 + 13 * 4)]",
+ "str lr, [r0, #(32 + 14 * 4)]",
+
+ // Save the caller's address in 'pc'
+ "str lr, [r0, #(32 + 15 * 4)]",
+
+ // Save ucontext_t* pointer across next call
+ "mov r4, r0",
+
+ // Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask))
+ "mov r0, #0", // SIG_BLOCK
+ "mov r1, #0", // NULL
+ "add r2, r4, #104", // UCONTEXT_SIGMASK_OFFSET
+ "bl sigprocmask(PLT)",
+
+ /* Intentionally do not save the FPU state here. This is because on
+ * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or
+ * ptrace(PTRACE_GETVFPREGS) to get it.
+ *
+ * Note that a real implementation of getcontext() would need to save
+ * this here to allow setcontext()/swapcontext() to work correctly.
+ */
+
+ // Restore the values of r4 and lr
+ "mov r0, r4",
+ "ldr lr, [r0, #(32 + 14 * 4)]",
+ "ldr r4, [r0, #(32 + 4 * 4)]",
+
+ // Return 0
+ "mov r0, #0",
+ "bx lr",
+
+ ".fnend",
+ ".size crash_context_getcontext, . - crash_context_getcontext",
+}
diff --git a/third_party/rust/crash-context/src/linux/getcontext/x86.rs b/third_party/rust/crash-context/src/linux/getcontext/x86.rs
new file mode 100644
index 0000000000..cb823e1182
--- /dev/null
+++ b/third_party/rust/crash-context/src/linux/getcontext/x86.rs
@@ -0,0 +1,68 @@
+// Unfortunately, the asm! macro has a few really annoying limitations at the
+// moment
+//
+// 1. const operands are unstable
+// 2. cfg attributes can't be used inside the asm macro at all
+//
+// and the worst part is we need it for literally only 1 thing, using a different
+// offset to the fpstate in ucontext depending on whether we are targeting android
+// or not :(
+macro_rules! asm_func {
+ ($offset:expr) => {
+ std::arch::global_asm! {
+ ".text",
+ ".global crash_context_getcontext",
+ ".hidden crash_context_getcontext",
+ ".align 4",
+ ".type crash_context_getcontext, @function",
+ "crash_context_getcontext:",
+ "movl 4(%esp), %eax", // eax = uc
+
+ // Save register values
+ "movl %ecx, 0x3c(%eax)",
+ "movl %edx, 0x38(%eax)",
+ "movl %ebx, 0x34(%eax)",
+ "movl %edi, 0x24(%eax)",
+ "movl %esi, 0x28(%eax)",
+ "movl %ebp, 0x2c(%eax)",
+
+ "movl (%esp), %edx", /* return address */
+ "lea 4(%esp), %ecx", /* exclude return address from stack */
+ "mov %edx, 0x4c(%eax)",
+ "mov %ecx, 0x30(%eax)",
+
+ "xorl %ecx, %ecx",
+ "movw %fs, %cx",
+ "mov %ecx, 0x18(%eax)",
+
+ "movl $0, 0x40(%eax)",
+
+ // Save floating point state to fpregstate, then update
+ // the fpregs pointer to point to it
+ stringify!(leal $offset(%eax),%ecx),
+ "fnstenv (%ecx)",
+ "fldenv (%ecx)",
+ "mov %ecx, 0x60(%eax)",
+
+ // Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask)
+ "leal 0x6c(%eax), %edx",
+ "xorl %ecx, %ecx",
+ "push %edx", /* &uc->uc_sigmask */
+ "push %ecx", /* NULL */
+ "push %ecx", /* SIGBLOCK == 0 on i386 */
+ "call sigprocmask@PLT",
+ "addl $12, %esp",
+
+ "movl $0, %eax",
+ "ret",
+
+ ".size crash_context_getcontext, . - crash_context_getcontext",
+ options(att_syntax)
+ }
+ };
+}
+
+#[cfg(target_os = "linux")]
+asm_func!(0xec);
+#[cfg(target_os = "android")]
+asm_func!(0x74);
diff --git a/third_party/rust/crash-context/src/linux/getcontext/x86_64.rs b/third_party/rust/crash-context/src/linux/getcontext/x86_64.rs
new file mode 100644
index 0000000000..2ecbf2c24c
--- /dev/null
+++ b/third_party/rust/crash-context/src/linux/getcontext/x86_64.rs
@@ -0,0 +1,105 @@
+/* The x64 implementation of breakpad_getcontext was derived in part
+from the implementation of libunwind which requires the following
+notice. */
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2008 Google, Inc
+ Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
+ Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+// Oof, unfortunately android libc and normal linux libc don't have the same
+// fpregs offset in ucontext_t, but asm! in Rust is...not convenient for only
+// adding certain lines/blocks of asm based using cfg https://github.com/rust-lang/rust/issues/15701
+// and they're not really inputs, just literals, so...yah
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+
+// Unfortunately, the asm! macro has a few really annoying limitations at the
+// moment
+//
+// 1. const operands are unstable
+// 2. cfg attributes can't be used inside the asm macro at all
+//
+// and the worst part is we need it for literally only 1 thing, using a different
+// offset to the fpstate in ucontext depending on whether we are targeting android
+// or not :(
+macro_rules! asm_func {
+ ($offset:expr) => {
+ std::arch::global_asm! {
+ ".text",
+ ".global crash_context_getcontext",
+ ".hidden crash_context_getcontext",
+ ".align 4",
+ ".type crash_context_getcontext, @function",
+ "crash_context_getcontext:",
+ ".cfi_startproc",
+ // Callee saved: RBX, RBP, R12-R15
+ "movq %r12, 0x48(%rdi)",
+ "movq %r13, 0x50(%rdi)",
+ "movq %r14, 0x58(%rdi)",
+ "movq %r15, 0x60(%rdi)",
+ "movq %rbp, 0x78(%rdi)",
+ "movq %rbx, 0x80(%rdi)",
+
+ // Save argument registers
+ "movq %r8, 0x28(%rdi)",
+ "movq %r9, 0x30(%rdi)",
+ "movq %rdi, 0x68(%rdi)",
+ "movq %rsi, 0x70(%rdi)",
+ "movq %rdx, 0x88(%rdi)",
+ "movq %rax, 0x90(%rdi)",
+ "movq %rcx, 0x98(%rdi)",
+
+ // Save fp state
+ stringify!(leaq $offset(%rdi),%r8),
+ "movq %r8, 0xe0(%rdi)",
+ "fnstenv (%r8)",
+ "stmxcsr 0x18(%r8)",
+
+ // Exclude this call
+ "leaq 8(%rsp), %rax",
+ "movq %rax, 0xa0(%rdi)",
+
+ "movq 0(%rsp), %rax",
+ "movq %rax, 0xa8(%rdi)",
+
+ // Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask)
+ "leaq 0x128(%rdi), %rdx", // arg3
+ "xorq %rsi, %rsi", // arg2 NULL
+ "xorq %rdi, %rdi", // arg1 SIGBLOCK == 0
+ "call sigprocmask@PLT",
+
+ // Always return 0 for success, even if sigprocmask failed.
+ "xorl %eax, %eax",
+ "ret",
+ ".cfi_endproc",
+ ".size crash_context_getcontext, . - crash_context_getcontext",
+ options(att_syntax)
+ }
+ };
+}
+
+#[cfg(target_os = "linux")]
+asm_func!(0x1a8);
+#[cfg(target_os = "android")]
+asm_func!(0x130);