use anyhow::{Context, Result};
use nix::sys::ptrace;
use nix::unistd::Pid;
pub struct PtraceRegs {
inner: libc::user_regs_struct,
}
impl PtraceRegs {
pub fn get(pid: Pid) -> Result<Self> {
let inner = ptrace::getregs(pid).context("Failed to get registers")?;
Ok(Self { inner })
}
pub fn get_nix(pid: Pid) -> std::result::Result<Self, nix::Error> {
let inner = ptrace::getregs(pid)?;
Ok(Self { inner })
}
#[cfg(target_arch = "x86_64")]
pub fn syscall_number(&self) -> i64 {
self.inner.orig_rax as i64
}
#[cfg(target_arch = "aarch64")]
pub fn syscall_number(&self) -> i64 {
self.inner.regs[8] as i64
}
#[cfg(target_arch = "x86_64")]
pub fn syscall_return(&self) -> i64 {
self.inner.rax as i64
}
#[cfg(target_arch = "aarch64")]
pub fn syscall_return(&self) -> i64 {
self.inner.regs[0] as i64
}
#[cfg(target_arch = "x86_64")]
pub fn arg1(&self) -> u64 {
self.inner.rdi
}
#[cfg(target_arch = "aarch64")]
pub fn arg1(&self) -> u64 {
self.inner.regs[0]
}
#[cfg(target_arch = "x86_64")]
pub fn arg2(&self) -> u64 {
self.inner.rsi
}
#[cfg(target_arch = "aarch64")]
pub fn arg2(&self) -> u64 {
self.inner.regs[1]
}
#[cfg(target_arch = "x86_64")]
pub fn arg3(&self) -> u64 {
self.inner.rdx
}
#[cfg(target_arch = "aarch64")]
pub fn arg3(&self) -> u64 {
self.inner.regs[2]
}
#[cfg(target_arch = "x86_64")]
pub fn instruction_pointer(&self) -> u64 {
self.inner.rip
}
#[cfg(target_arch = "aarch64")]
pub fn instruction_pointer(&self) -> u64 {
self.inner.pc
}
#[cfg(target_arch = "x86_64")]
pub fn frame_pointer(&self) -> u64 {
self.inner.rbp
}
#[cfg(target_arch = "aarch64")]
pub fn frame_pointer(&self) -> u64 {
self.inner.regs[29]
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_ptrace_regs_struct_exists() {
let _size = std::mem::size_of::<libc::user_regs_struct>();
assert!(_size > 0);
}
}