Skip to content

Commit f4980ba

Browse files
committed
feat: Use type parameters to allow {get,set}regset to use different register set structs
1 parent 1c2cad8 commit f4980ba

File tree

2 files changed

+100
-38
lines changed

2 files changed

+100
-38
lines changed

src/sys/ptrace/linux.rs

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -172,21 +172,21 @@ libc_enum! {
172172
}
173173
}
174174

175+
#[cfg(all(
176+
target_os = "linux",
177+
target_env = "gnu",
178+
any(
179+
target_arch = "x86_64",
180+
target_arch = "x86",
181+
target_arch = "aarch64",
182+
target_arch = "riscv64",
183+
)
184+
))]
175185
libc_enum! {
176-
#[cfg(all(
177-
target_os = "linux",
178-
target_env = "gnu",
179-
any(
180-
target_arch = "x86_64",
181-
target_arch = "x86",
182-
target_arch = "aarch64",
183-
target_arch = "riscv64",
184-
)
185-
))]
186186
#[repr(i32)]
187-
/// Defining a specific register set, as used in [`getregset`] and [`setregset`].
187+
/// Defines a specific register set, as used in `PTRACE_GETREGSET` and `PTRACE_SETREGSET`.
188188
#[non_exhaustive]
189-
pub enum RegisterSet {
189+
pub enum RegisterSetValue {
190190
NT_PRSTATUS,
191191
NT_PRFPREG,
192192
NT_PRPSINFO,
@@ -195,6 +195,63 @@ libc_enum! {
195195
}
196196
}
197197

198+
#[cfg(all(
199+
target_os = "linux",
200+
target_env = "gnu",
201+
any(
202+
target_arch = "x86_64",
203+
target_arch = "x86",
204+
target_arch = "aarch64",
205+
target_arch = "riscv64",
206+
)
207+
))]
208+
/// Represents register set areas, such as general-purpose registers or floating-point registers.
209+
pub trait RegisterSet {
210+
/// Corresponding type of registers in the kernel.
211+
const VALUE: RegisterSetValue;
212+
213+
/// Struct representing the register space.
214+
type Regs;
215+
}
216+
217+
#[cfg(all(
218+
target_os = "linux",
219+
target_env = "gnu",
220+
any(
221+
target_arch = "x86_64",
222+
target_arch = "x86",
223+
target_arch = "aarch64",
224+
target_arch = "riscv64",
225+
)
226+
))]
227+
/// Register sets used in [`getregset`] and [`setregset`]
228+
pub mod regset {
229+
use super::*;
230+
231+
#[derive(Debug, Clone, Copy)]
232+
/// General-purpose registers.
233+
pub enum NT_PRSTATUS {}
234+
235+
impl RegisterSet for NT_PRSTATUS {
236+
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRSTATUS;
237+
type Regs = user_regs_struct;
238+
}
239+
240+
#[derive(Debug, Clone, Copy)]
241+
/// Floating-point registers.
242+
pub enum NT_PRFPREG {}
243+
244+
impl RegisterSet for NT_PRFPREG {
245+
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRFPREG;
246+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
247+
type Regs = libc::user_fpregs_struct;
248+
#[cfg(target_arch = "aarch64")]
249+
type Regs = libc::user_fpsimd_struct;
250+
#[cfg(target_arch = "riscv64")]
251+
type Regs = libc::__riscv_mc_d_ext_state;
252+
}
253+
}
254+
198255
libc_bitflags! {
199256
/// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
200257
/// See `man ptrace` for more details.
@@ -275,7 +332,7 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
275332
any(target_arch = "aarch64", target_arch = "riscv64")
276333
))]
277334
pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
278-
getregset(pid, RegisterSet::NT_PRSTATUS)
335+
getregset::<regset::NT_PRSTATUS>(pid)
279336
}
280337

281338
/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
@@ -289,18 +346,18 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
289346
target_arch = "riscv64",
290347
)
291348
))]
292-
pub fn getregset(pid: Pid, set: RegisterSet) -> Result<user_regs_struct> {
349+
pub fn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> {
293350
let request = Request::PTRACE_GETREGSET;
294-
let mut data = mem::MaybeUninit::<user_regs_struct>::uninit();
351+
let mut data = mem::MaybeUninit::<S::Regs>::uninit();
295352
let mut iov = libc::iovec {
296353
iov_base: data.as_mut_ptr().cast(),
297-
iov_len: mem::size_of::<user_regs_struct>(),
354+
iov_len: mem::size_of::<S::Regs>(),
298355
};
299356
unsafe {
300357
ptrace_other(
301358
request,
302359
pid,
303-
set as i32 as AddressType,
360+
S::VALUE as i32 as AddressType,
304361
(&mut iov as *mut libc::iovec).cast(),
305362
)?;
306363
};
@@ -349,7 +406,7 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
349406
any(target_arch = "aarch64", target_arch = "riscv64")
350407
))]
351408
pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
352-
setregset(pid, RegisterSet::NT_PRSTATUS, regs)
409+
setregset::<regset::NT_PRSTATUS>(pid, regs)
353410
}
354411

355412
/// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)`
@@ -363,20 +420,16 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
363420
target_arch = "riscv64",
364421
)
365422
))]
366-
pub fn setregset(
367-
pid: Pid,
368-
set: RegisterSet,
369-
mut regs: user_regs_struct,
370-
) -> Result<()> {
423+
pub fn setregset<S: RegisterSet>(pid: Pid, mut regs: S::Regs) -> Result<()> {
371424
let mut iov = libc::iovec {
372-
iov_base: (&mut regs as *mut user_regs_struct).cast(),
373-
iov_len: mem::size_of::<user_regs_struct>(),
425+
iov_base: (&mut regs as *mut S::Regs).cast(),
426+
iov_len: mem::size_of::<S::Regs>(),
374427
};
375428
unsafe {
376429
ptrace_other(
377430
Request::PTRACE_SETREGSET,
378431
pid,
379-
set as i32 as AddressType,
432+
S::VALUE as i32 as AddressType,
380433
(&mut iov as *mut libc::iovec).cast(),
381434
)?;
382435
}

test/sys/test_ptrace.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ fn test_ptrace_syscall() {
302302
))]
303303
#[test]
304304
fn test_ptrace_regsets() {
305-
use nix::sys::ptrace::{self, getregset, setregset, RegisterSet};
305+
use nix::sys::ptrace::{self, getregset, regset, setregset};
306306
use nix::sys::signal::*;
307307
use nix::sys::wait::{waitpid, WaitStatus};
308308
use nix::unistd::fork;
@@ -328,30 +328,39 @@ fn test_ptrace_regsets() {
328328
Ok(WaitStatus::Stopped(child, Signal::SIGTRAP))
329329
);
330330
let mut regstruct =
331-
getregset(child, RegisterSet::NT_PRSTATUS).unwrap();
331+
getregset::<regset::NT_PRSTATUS>(child).unwrap();
332+
let mut fpregstruct =
333+
getregset::<regset::NT_PRFPREG>(child).unwrap();
332334

333335
#[cfg(target_arch = "x86_64")]
334-
let reg = &mut regstruct.r15;
336+
let (reg, fpreg) =
337+
(&mut regstruct.r15, &mut fpregstruct.st_space[5]);
335338
#[cfg(target_arch = "x86")]
336-
let reg = &mut regstruct.edx;
339+
let (reg, fpreg) =
340+
(&mut regstruct.edx, &mut fpregstruct.st_space[5]);
337341
#[cfg(target_arch = "aarch64")]
338-
let reg = &mut regstruct.regs[16];
342+
let (reg, fpreg) =
343+
(&mut regstruct.regs[16], &mut fpregstruct.vregs[5]);
339344
#[cfg(target_arch = "riscv64")]
340-
let reg = &mut regstruct.regs[16];
345+
let (reg, fpreg) = (&mut regstruct.t1, &mut fpregstruct.__f[5]);
341346

342347
*reg = 0xdeadbeefu32 as _;
343-
let _ = setregset(child, RegisterSet::NT_PRSTATUS, regstruct);
344-
regstruct = getregset(child, RegisterSet::NT_PRSTATUS).unwrap();
348+
*fpreg = 0xfeedfaceu32 as _;
349+
let _ = setregset::<regset::NT_PRSTATUS>(child, regstruct);
350+
regstruct = getregset::<regset::NT_PRSTATUS>(child).unwrap();
351+
let _ = setregset::<regset::NT_PRFPREG>(child, fpregstruct);
352+
fpregstruct = getregset::<regset::NT_PRFPREG>(child).unwrap();
345353

346354
#[cfg(target_arch = "x86_64")]
347-
let reg = regstruct.r15;
355+
let (reg, fpreg) = (regstruct.r15, fpregstruct.st_space[5]);
348356
#[cfg(target_arch = "x86")]
349-
let reg = regstruct.edx;
357+
let (reg, fpreg) = (regstruct.edx, fpregstruct.st_space[5]);
350358
#[cfg(target_arch = "aarch64")]
351-
let reg = regstruct.regs[16];
359+
let (reg, fpreg) = (regstruct.regs[16], fpregstruct.vregs[5]);
352360
#[cfg(target_arch = "riscv64")]
353-
let reg = regstruct.regs[16];
361+
let (reg, fpreg) = (regstruct.t1, fpregstruct.__f[5]);
354362
assert_eq!(reg, 0xdeadbeefu32 as _);
363+
assert_eq!(fpreg, 0xfeedfaceu32 as _);
355364

356365
ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
357366
match waitpid(child, None) {

0 commit comments

Comments
 (0)