Commit 41832aa1e6

kcbanner <kcbanner@gmail.com>
2023-06-26 06:57:28
linux: add getcontext for x86_64
1 parent 6abf1fb
Changed files (2)
lib
std
lib/std/os/linux/x86_64.zig
@@ -395,3 +395,71 @@ pub const ucontext_t = extern struct {
     sigmask: sigset_t,
     fpregs_mem: [64]usize,
 };
+
+fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
+    return @offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "gregs") + @sizeOf(usize) * reg_index;
+}
+
+pub inline fn getcontext(context: *ucontext_t) usize {
+    asm volatile (
+        \\ movq %%r8, (%[r8_offset])(%[context])
+        \\ movq %%r9, (%[r9_offset])(%[context])
+        \\ movq %%r10, (%[r10_offset])(%[context])
+        \\ movq %%r11, (%[r11_offset])(%[context])
+        \\ movq %%r12, (%[r12_offset])(%[context])
+        \\ movq %%r13, (%[r13_offset])(%[context])
+        \\ movq %%r14, (%[r14_offset])(%[context])
+        \\ movq %%r15, (%[r15_offset])(%[context])
+        \\ movq %%rdi, (%[rdi_offset])(%[context])
+        \\ movq %%rsi, (%[rsi_offset])(%[context])
+        \\ movq %%rbp, (%[rbp_offset])(%[context])
+        \\ movq %%rbx, (%[rbx_offset])(%[context])
+        \\ movq %%rdx, (%[rdx_offset])(%[context])
+        \\ movq %%rax, (%[rax_offset])(%[context])
+        \\ movq %%rcx, (%[rcx_offset])(%[context])
+        \\ movq %%rsp, (%[rsp_offset])(%[context])
+        \\ leaq (%%rip), %%rcx
+        \\ movq %%rcx, (%[rip_offset])(%[context])
+        \\ pushfq
+        \\ popq (%[efl_offset])(%[context])
+        \\ leaq (%[fpmem_offset])(%[context]), %%rcx
+        \\ movq %%rcx, (%[fpstate_offset])(%[context])
+        \\ fnstenv (%%rcx)
+        \\ stmxcsr (%[mxcsr_offset])(%[context])
+        :
+        : [context] "{rdi}" (context),
+          [r8_offset] "p" (comptime gpRegisterOffset(REG.R8)),
+          [r9_offset] "p" (comptime gpRegisterOffset(REG.R9)),
+          [r10_offset] "p" (comptime gpRegisterOffset(REG.R10)),
+          [r11_offset] "p" (comptime gpRegisterOffset(REG.R11)),
+          [r12_offset] "p" (comptime gpRegisterOffset(REG.R12)),
+          [r13_offset] "p" (comptime gpRegisterOffset(REG.R13)),
+          [r14_offset] "p" (comptime gpRegisterOffset(REG.R14)),
+          [r15_offset] "p" (comptime gpRegisterOffset(REG.R15)),
+          [rdi_offset] "p" (comptime gpRegisterOffset(REG.RDI)),
+          [rsi_offset] "p" (comptime gpRegisterOffset(REG.RSI)),
+          [rbp_offset] "p" (comptime gpRegisterOffset(REG.RBP)),
+          [rbx_offset] "p" (comptime gpRegisterOffset(REG.RBX)),
+          [rdx_offset] "p" (comptime gpRegisterOffset(REG.RDX)),
+          [rax_offset] "p" (comptime gpRegisterOffset(REG.RAX)),
+          [rcx_offset] "p" (comptime gpRegisterOffset(REG.RCX)),
+          [rsp_offset] "p" (comptime gpRegisterOffset(REG.RSP)),
+          [rip_offset] "p" (comptime gpRegisterOffset(REG.RIP)),
+          [efl_offset] "p" (comptime gpRegisterOffset(REG.EFL)),
+          [fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
+          [fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")),
+          [mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")),
+        : "memory", "rcx"
+    );
+
+    // TODO: Read GS/FS registers?
+
+    // TODO: `flags` isn't present in the getcontext man page, figure out what to write here
+    context.flags = 0;
+    context.link = null;
+
+    const altstack_result = linux.sigaltstack(null, &context.stack);
+    if (altstack_result != 0) return altstack_result;
+
+    return linux.sigprocmask(0, null, &context.sigmask);
+}
lib/std/os/linux.zig
@@ -86,6 +86,7 @@ pub const timeval = arch_bits.timeval;
 pub const timezone = arch_bits.timezone;
 pub const ucontext_t = arch_bits.ucontext_t;
 pub const user_desc = arch_bits.user_desc;
+pub const getcontext = arch_bits.getcontext;
 
 pub const tls = @import("linux/tls.zig");
 pub const pie = @import("linux/start_pie.zig");
@@ -4694,7 +4695,7 @@ else
         /// processes.
         RTPRIO,
 
-        /// Maximum CPU time in µs that a process scheduled under a real-time
+        /// Maximum CPU time in µs that a process scheduled under a real-time
         /// scheduling policy may consume without making a blocking system
         /// call before being forcibly descheduled.
         RTTIME,