Skip to main content

starnix_registers/
x64.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{HeapRegs, RegisterStorage, RegisterStorageEnum};
6use starnix_uapi::errors::Errno;
7use starnix_uapi::{__NR_restart_syscall, error, user_regs_struct};
8
9/// The size of the syscall instruction in bytes.
10const SYSCALL_INSTRUCTION_SIZE_BYTES: u64 = 2;
11
12/// The state of the task's registers when the thread of execution entered the kernel.
13/// This is a thin wrapper around [`zx::sys::zx_restricted_state_t`].
14///
15/// Implements [`std::ops::Deref`] and [`std::ops::DerefMut`] as a way to get at the underlying
16/// [`zx::sys::zx_restricted_state_t`] that this type wraps.
17#[derive(Default, Clone, Eq, PartialEq)]
18pub struct RegisterState<T: RegisterStorage> {
19    pub real_registers: T,
20
21    /// A copy of the x64 `rax` register at the time of the `syscall` instruction. This is important
22    /// to store, as the return value of a syscall overwrites `rax`, making it impossible to recover
23    /// the original syscall number in the case of syscall restart and strace output.
24    pub orig_rax: u64,
25}
26
27impl<T: RegisterStorage> RegisterState<T> {
28    pub fn to_user_regs_struct(&self) -> user_regs_struct {
29        user_regs_struct {
30            r15: self.r15,
31            r14: self.r14,
32            r13: self.r13,
33            r12: self.r12,
34            rbp: self.rbp,
35            rbx: self.rbx,
36            r11: self.r11,
37            r10: self.r10,
38            r9: self.r9,
39            r8: self.r8,
40            rax: self.rax,
41            rcx: self.rcx,
42            rdx: self.rdx,
43            rsi: self.rsi,
44            rdi: self.rdi,
45            orig_rax: self.orig_rax,
46            rip: self.ip,
47            cs: 0,
48            eflags: self.flags,
49            rsp: self.rsp,
50            ss: 0,
51            fs_base: self.fs_base,
52            gs_base: self.gs_base,
53            ds: 0,
54            es: 0,
55            fs: 0,
56            gs: 0,
57        }
58    }
59
60    pub fn to_user_regs_struct_arch32(&self) -> starnix_uapi::arch32::user_regs_struct {
61        unreachable!("arch32 not supported on x64")
62    }
63
64    pub fn from_user_regs_struct(&mut self, regs: &user_regs_struct) {
65        self.r15 = regs.r15;
66        self.r14 = regs.r14;
67        self.r13 = regs.r13;
68        self.r12 = regs.r12;
69        self.rbp = regs.rbp;
70        self.rbx = regs.rbx;
71        self.r11 = regs.r11;
72        self.r10 = regs.r10;
73        self.r9 = regs.r9;
74        self.r8 = regs.r8;
75        self.rax = regs.rax;
76        self.rcx = regs.rcx;
77        self.rdx = regs.rdx;
78        self.rsi = regs.rsi;
79        self.rdi = regs.rdi;
80        self.orig_rax = regs.orig_rax;
81        self.ip = regs.rip;
82        self.flags = regs.eflags;
83        self.rsp = regs.rsp;
84        self.fs_base = regs.fs_base;
85        self.gs_base = regs.gs_base;
86    }
87
88    pub fn from_user_regs_struct_arch32(&mut self, _regs: &starnix_uapi::arch32::user_regs_struct) {
89        unreachable!("arch32 not supported on x64")
90    }
91
92    /// Saves any register state required to restart `syscall_number`.
93    pub fn save_registers_for_restart(&mut self, syscall_number: u64) {
94        // The `rax` register read from the thread's state is clobbered by
95        // zircon with ZX_ERR_BAD_SYSCALL.  Similarly, Linux sets it to ENOSYS
96        // until it has determined the correct return value for the syscall; we
97        // emulate this behavior because ptrace callers expect it.
98        self.rax = -(starnix_uapi::ENOSYS as i64) as u64;
99
100        // `orig_rax` should hold the original value loaded into `rax` by the userspace process.
101        self.orig_rax = syscall_number;
102    }
103
104    /// Custom restart, invoke restart_syscall instead of the original syscall.
105    pub fn prepare_for_custom_restart(&mut self) {
106        self.rax = __NR_restart_syscall as u64;
107    }
108
109    /// Restores `rax` to match its value before restarting.
110    pub fn restore_original_return_register(&mut self) {
111        self.rax = self.orig_rax;
112    }
113
114    /// Returns the register that indicates the single-machine-word return value from a
115    /// function call.
116    pub fn instruction_pointer_register(&self) -> u64 {
117        self.ip
118    }
119
120    /// Sets the register that indicates the single-machine-word return value from a
121    /// function call.
122    pub fn set_instruction_pointer_register(&mut self, new_ip: u64) {
123        self.ip = new_ip;
124    }
125
126    /// Rewind the the register that indicates the instruction pointer by one syscall instruction.
127    pub fn rewind_syscall_instruction(&mut self) {
128        self.ip -= SYSCALL_INSTRUCTION_SIZE_BYTES;
129    }
130
131    /// Returns the register that indicates the single-machine-word return value from a
132    /// function call.
133    pub fn return_register(&self) -> u64 {
134        self.rax
135    }
136
137    /// Sets the register that indicates the single-machine-word return value from a
138    /// function call.
139    pub fn set_return_register(&mut self, return_value: u64) {
140        self.rax = return_value;
141    }
142
143    /// Gets the register that indicates the current stack pointer.
144    pub fn stack_pointer_register(&self) -> u64 {
145        self.rsp
146    }
147
148    /// Sets the register that indicates the current stack pointer.
149    pub fn set_stack_pointer_register(&mut self, sp: u64) {
150        self.rsp = sp;
151    }
152
153    /// Sets the register that indicates the TLS.
154    pub fn set_thread_pointer_register(&mut self, tp: u64) {
155        self.fs_base = tp;
156    }
157
158    /// Sets the register that indicates the first argument to a function.
159    pub fn set_arg0_register(&mut self, rdi: u64) {
160        self.rdi = rdi;
161    }
162
163    /// Sets the register that indicates the second argument to a function.
164    pub fn set_arg1_register(&mut self, rsi: u64) {
165        self.rsi = rsi;
166    }
167
168    /// Sets the register that indicates the third argument to a function.
169    pub fn set_arg2_register(&mut self, rdx: u64) {
170        self.rdx = rdx;
171    }
172
173    /// Returns the register that contains the syscall number.
174    pub fn syscall_register(&self) -> u64 {
175        self.orig_rax
176    }
177
178    /// Resets the register that contains the application status flags.
179    pub fn reset_flags(&mut self) {
180        self.flags = 0;
181    }
182
183    /// Executes the given predicate on the register.
184    pub fn apply_user_register(
185        &mut self,
186        offset: usize,
187        f: &mut dyn FnMut(&mut u64),
188    ) -> Result<(), Errno> {
189        if offset == memoffset::offset_of!(user_regs_struct, r15) {
190            f(&mut self.r15);
191        } else if offset == memoffset::offset_of!(user_regs_struct, r14) {
192            f(&mut self.r14);
193        } else if offset == memoffset::offset_of!(user_regs_struct, r13) {
194            f(&mut self.r13);
195        } else if offset == memoffset::offset_of!(user_regs_struct, r12) {
196            f(&mut self.r12);
197        } else if offset == memoffset::offset_of!(user_regs_struct, rbp) {
198            f(&mut self.rbp);
199        } else if offset == memoffset::offset_of!(user_regs_struct, rbx) {
200            f(&mut self.rbx);
201        } else if offset == memoffset::offset_of!(user_regs_struct, r11) {
202            f(&mut self.r11);
203        } else if offset == memoffset::offset_of!(user_regs_struct, r10) {
204            f(&mut self.r10);
205        } else if offset == memoffset::offset_of!(user_regs_struct, r9) {
206            f(&mut self.r9);
207        } else if offset == memoffset::offset_of!(user_regs_struct, r8) {
208            f(&mut self.r8);
209        } else if offset == memoffset::offset_of!(user_regs_struct, rax) {
210            f(&mut self.rax);
211        } else if offset == memoffset::offset_of!(user_regs_struct, rcx) {
212            f(&mut self.rcx);
213        } else if offset == memoffset::offset_of!(user_regs_struct, rdx) {
214            f(&mut self.rdx);
215        } else if offset == memoffset::offset_of!(user_regs_struct, rsi) {
216            f(&mut self.rsi);
217        } else if offset == memoffset::offset_of!(user_regs_struct, rdi) {
218            f(&mut self.rdi);
219        } else if offset == memoffset::offset_of!(user_regs_struct, orig_rax) {
220            f(&mut self.orig_rax);
221        } else if offset == memoffset::offset_of!(user_regs_struct, rip) {
222            f(&mut self.ip);
223        } else if offset == memoffset::offset_of!(user_regs_struct, cs) {
224            let mut val = 0;
225            f(&mut val);
226        } else if offset == memoffset::offset_of!(user_regs_struct, eflags) {
227            f(&mut self.flags);
228        } else if offset == memoffset::offset_of!(user_regs_struct, rsp) {
229            f(&mut self.rsp);
230        } else if offset == memoffset::offset_of!(user_regs_struct, ss) {
231            let mut val = 0;
232            f(&mut val);
233        } else if offset == memoffset::offset_of!(user_regs_struct, fs_base) {
234            f(&mut self.fs_base);
235        } else if offset == memoffset::offset_of!(user_regs_struct, gs_base) {
236            f(&mut self.gs_base);
237        } else if offset == memoffset::offset_of!(user_regs_struct, ds) {
238            let mut val = 0;
239            f(&mut val);
240        } else if offset == memoffset::offset_of!(user_regs_struct, es) {
241            let mut val = 0;
242            f(&mut val);
243        } else if offset == memoffset::offset_of!(user_regs_struct, fs) {
244            let mut val = 0;
245            f(&mut val);
246        } else if offset == memoffset::offset_of!(user_regs_struct, gs) {
247            let mut val = 0;
248            f(&mut val);
249        } else {
250            return error!(EINVAL);
251        };
252        Ok(())
253    }
254
255    pub fn load(&mut self, regs: zx::sys::zx_restricted_state_t) {
256        *self.real_registers = regs;
257        self.sync_stack_ptr();
258    }
259
260    pub fn sync_stack_ptr(&mut self) {
261        self.orig_rax = self.rax;
262    }
263}
264
265impl<T: RegisterStorage> std::fmt::Debug for RegisterState<T> {
266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267        f.debug_struct("RegisterState")
268            .field("real_registers", &self.real_registers)
269            .field("orig_rax", &format_args!("{:#x}", &self.orig_rax))
270            .finish()
271    }
272}
273
274impl<T: RegisterStorage> std::ops::Deref for RegisterState<T> {
275    type Target = zx::sys::zx_restricted_state_t;
276
277    fn deref(&self) -> &Self::Target {
278        &*self.real_registers
279    }
280}
281
282impl<T: RegisterStorage> std::ops::DerefMut for RegisterState<T> {
283    fn deref_mut(&mut self) -> &mut Self::Target {
284        &mut *self.real_registers
285    }
286}
287
288impl From<RegisterState<HeapRegs>> for RegisterState<RegisterStorageEnum> {
289    fn from(regs: RegisterState<HeapRegs>) -> Self {
290        Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
291    }
292}
293
294impl From<RegisterState<RegisterStorageEnum>> for RegisterState<HeapRegs> {
295    fn from(regs: RegisterState<RegisterStorageEnum>) -> Self {
296        Self { real_registers: regs.real_registers.into(), orig_rax: regs.orig_rax }
297    }
298}