Skip to content

Commit 6aa2b9b

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

File tree

2 files changed

+101
-38
lines changed

2 files changed

+101
-38
lines changed

src/sys/ptrace/linux.rs

Lines changed: 80 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,64 @@ 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
209+
/// floating-point registers.
210+
pub unsafe trait RegisterSet {
211+
/// Corresponding type of registers in the kernel.
212+
const VALUE: RegisterSetValue;
213+
214+
/// Struct representing the register space.
215+
type Regs;
216+
}
217+
218+
#[cfg(all(
219+
target_os = "linux",
220+
target_env = "gnu",
221+
any(
222+
target_arch = "x86_64",
223+
target_arch = "x86",
224+
target_arch = "aarch64",
225+
target_arch = "riscv64",
226+
)
227+
))]
228+
/// Register sets used in [`getregset`] and [`setregset`]
229+
pub mod regset {
230+
use super::*;
231+
232+
#[derive(Debug, Clone, Copy)]
233+
/// General-purpose registers.
234+
pub struct NT_PRSTATUS;
235+
236+
unsafe impl RegisterSet for NT_PRSTATUS {
237+
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRSTATUS;
238+
type Regs = user_regs_struct;
239+
}
240+
241+
#[derive(Debug, Clone, Copy)]
242+
/// Floating-point registers.
243+
pub struct NT_PRFPREG;
244+
245+
unsafe impl RegisterSet for NT_PRFPREG {
246+
const VALUE: RegisterSetValue = RegisterSetValue::NT_PRFPREG;
247+
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
248+
type Regs = libc::user_fpregs_struct;
249+
#[cfg(target_arch = "aarch64")]
250+
type Regs = libc::user_fpsimd_struct;
251+
#[cfg(target_arch = "riscv64")]
252+
type Regs = libc::__riscv_mc_d_ext_state;
253+
}
254+
}
255+
198256
libc_bitflags! {
199257
/// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
200258
/// See `man ptrace` for more details.
@@ -275,7 +333,7 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
275333
any(target_arch = "aarch64", target_arch = "riscv64")
276334
))]
277335
pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
278-
getregset(pid, RegisterSet::NT_PRSTATUS)
336+
getregset::<regset::NT_PRSTATUS>(pid)
279337
}
280338

281339
/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)`
@@ -289,18 +347,18 @@ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
289347
target_arch = "riscv64",
290348
)
291349
))]
292-
pub fn getregset(pid: Pid, set: RegisterSet) -> Result<user_regs_struct> {
350+
pub fn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> {
293351
let request = Request::PTRACE_GETREGSET;
294-
let mut data = mem::MaybeUninit::<user_regs_struct>::uninit();
352+
let mut data = mem::MaybeUninit::<S::Regs>::uninit();
295353
let mut iov = libc::iovec {
296354
iov_base: data.as_mut_ptr().cast(),
297-
iov_len: mem::size_of::<user_regs_struct>(),
355+
iov_len: mem::size_of::<S::Regs>(),
298356
};
299357
unsafe {
300358
ptrace_other(
301359
request,
302360
pid,
303-
set as i32 as AddressType,
361+
S::VALUE as i32 as AddressType,
304362
(&mut iov as *mut libc::iovec).cast(),
305363
)?;
306364
};
@@ -349,7 +407,7 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
349407
any(target_arch = "aarch64", target_arch = "riscv64")
350408
))]
351409
pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
352-
setregset(pid, RegisterSet::NT_PRSTATUS, regs)
410+
setregset::<regset::NT_PRSTATUS>(pid, regs)
353411
}
354412

355413
/// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)`
@@ -363,20 +421,16 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
363421
target_arch = "riscv64",
364422
)
365423
))]
366-
pub fn setregset(
367-
pid: Pid,
368-
set: RegisterSet,
369-
mut regs: user_regs_struct,
370-
) -> Result<()> {
424+
pub fn setregset<S: RegisterSet>(pid: Pid, mut regs: S::Regs) -> Result<()> {
371425
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>(),
426+
iov_base: (&mut regs as *mut S::Regs).cast(),
427+
iov_len: mem::size_of::<S::Regs>(),
374428
};
375429
unsafe {
376430
ptrace_other(
377431
Request::PTRACE_SETREGSET,
378432
pid,
379-
set as i32 as AddressType,
433+
S::VALUE as i32 as AddressType,
380434
(&mut iov as *mut libc::iovec).cast(),
381435
)?;
382436
}

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)