Skip to main content

sys_rs/
hwaccess.rs

1use core::fmt;
2
3use libc::user_regs_struct;
4use nix::{sys::ptrace, unistd::Pid};
5
6use crate::diag::Result;
7
8/// Helpers for reading and writing register state of the traced process.
9///
10/// `Registers` stores a snapshot of the platform `user_regs_struct` for a
11/// given `Pid` and provides convenience accessors. Currently this module
12/// assumes `x86_64` register layout.
13pub struct Registers {
14    pid: Pid,
15    regs: user_regs_struct,
16}
17
18impl Registers {
19    /// Read the current register state for `pid`.
20    ///
21    /// # Arguments
22    ///
23    /// * `pid` - The process id of the traced process to read registers from.
24    ///
25    /// # Errors
26    ///
27    /// Returns an error if the underlying `ptrace::getregs` call fails.
28    ///
29    /// # Returns
30    ///
31    /// A `Result` containing the `Registers` snapshot on success.
32    pub fn read(pid: Pid) -> Result<Self> {
33        Ok(Self {
34            pid,
35            regs: ptrace::getregs(pid)?,
36        })
37    }
38
39    /// Write the locally-modified register state back to the tracee.
40    ///
41    /// # Errors
42    ///
43    /// Returns an error if `ptrace::setregs` fails.
44    ///
45    /// # Returns
46    ///
47    /// Returns `Ok(())` on success.
48    pub fn write(&self) -> Result<()> {
49        ptrace::setregs(self.pid, self.regs)?;
50        Ok(())
51    }
52
53    #[must_use]
54    /// Instruction pointer (RIP).
55    ///
56    /// # Returns
57    ///
58    /// The current value of the instruction pointer (RIP) for the stored
59    /// register snapshot.
60    pub fn rip(&self) -> u64 {
61        self.regs.rip
62    }
63
64    /// Set the instruction pointer.
65    ///
66    /// # Arguments
67    ///
68    /// * `value` - The new instruction pointer (RIP) value to store in the snapshot.
69    pub fn set_rip(&mut self, value: u64) {
70        self.regs.rip = value;
71    }
72
73    #[must_use]
74    /// Stack pointer (RSP).
75    ///
76    /// # Returns
77    ///
78    /// The current value of the stack pointer (RSP).
79    pub fn rsp(&self) -> u64 {
80        self.regs.rsp
81    }
82
83    #[must_use]
84    /// Return the RAX register value.
85    ///
86    /// # Returns
87    ///
88    /// The value of the `rax` register in the snapshot.
89    pub fn rax(&self) -> u64 {
90        self.regs.rax
91    }
92
93    #[must_use]
94    /// Return the original RAX value saved by the kernel (useful for syscalls).
95    ///
96    /// # Returns
97    ///
98    /// The `orig_rax` register value recorded by the kernel.
99    pub fn orig_rax(&self) -> u64 {
100        self.regs.orig_rax
101    }
102
103    #[must_use]
104    /// Return the 6 register parameters passed in registers for `x86_64`
105    /// (rdi, rsi, rdx, r10, r8, r9).
106    ///
107    /// # Returns
108    ///
109    /// An array with the six parameter registers as u64 in calling
110    /// convention order.
111    pub fn function_params(&self) -> [u64; 6] {
112        [
113            self.regs.rdi,
114            self.regs.rsi,
115            self.regs.rdx,
116            self.regs.r10,
117            self.regs.r8,
118            self.regs.r9,
119        ]
120    }
121}
122
123impl fmt::Display for Registers {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        writeln!(f, "rip: {:#x}", self.regs.rip)?;
126        writeln!(f, "rsp: {:#x}", self.regs.rsp)?;
127        writeln!(f, "rbp: {:#x}", self.regs.rbp)?;
128        writeln!(f, "eflags: {:#x}", self.regs.eflags)?;
129        writeln!(f, "orig_rax: {:#x}", self.regs.orig_rax)?;
130        writeln!(f, "rax: {:#x}", self.regs.rax)?;
131        writeln!(f, "rbx: {:#x}", self.regs.rbx)?;
132        writeln!(f, "rcx: {:#x}", self.regs.rcx)?;
133        writeln!(f, "rdx: {:#x}", self.regs.rdx)?;
134        writeln!(f, "rdi: {:#x}", self.regs.rdi)?;
135        writeln!(f, "rsi: {:#x}", self.regs.rsi)?;
136        writeln!(f, "r8: {:#x}", self.regs.r8)?;
137        writeln!(f, "r9: {:#x}", self.regs.r9)?;
138        writeln!(f, "r10: {:#x}", self.regs.r10)?;
139        writeln!(f, "r11: {:#x}", self.regs.r11)?;
140        writeln!(f, "r12: {:#x}", self.regs.r12)?;
141        writeln!(f, "r13: {:#x}", self.regs.r13)?;
142        writeln!(f, "r14: {:#x}", self.regs.r14)?;
143        writeln!(f, "r15: {:#x}", self.regs.r15)?;
144        writeln!(f, "cs: {:#x}", self.regs.cs)?;
145        writeln!(f, "ds: {:#x}", self.regs.ds)?;
146        writeln!(f, "es: {:#x}", self.regs.es)?;
147        writeln!(f, "fs: {:#x}", self.regs.fs)?;
148        writeln!(f, "gs: {:#x}", self.regs.gs)?;
149        writeln!(f, "ss: {:#x}", self.regs.ss)?;
150        writeln!(f, "fs_base: {:#x}", self.regs.fs_base)?;
151        write!(f, "gs_base: {:#x}", self.regs.gs_base)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    use libc::user_regs_struct;
160    use nix::unistd::Pid;
161
162    fn make_regs() -> user_regs_struct {
163        user_regs_struct {
164            r15: 0,
165            r14: 0,
166            r13: 0,
167            r12: 0,
168            rbp: 0x2000,
169            rbx: 0x3000,
170            r11: 0,
171            r10: 0,
172            r9: 0,
173            r8: 0,
174            rax: 1,
175            rcx: 2,
176            rdx: 3,
177            rsi: 4,
178            rdi: 5,
179            orig_rax: 0,
180            rip: 0x1000,
181            cs: 0,
182            eflags: 0,
183            rsp: 0x4000,
184            ss: 0,
185            fs_base: 0,
186            gs_base: 0,
187            ds: 0,
188            es: 0,
189            fs: 0,
190            gs: 0,
191        }
192    }
193
194    #[test]
195    fn test_registers_accessors_and_display() {
196        let regs = make_regs();
197        let r = Registers {
198            pid: Pid::from_raw(1),
199            regs,
200        };
201        assert_eq!(r.rip(), 0x1000);
202        assert_eq!(r.rsp(), 0x4000);
203        assert_eq!(r.rax(), 1);
204        assert_eq!(r.function_params()[0], 5);
205
206        let s = format!("{}", r);
207        assert!(s.contains("rip:"));
208        assert!(s.contains("rsp:"));
209    }
210}