diff --git a/src/clibwrap/ptrace.rs b/src/clibwrap/ptrace.rs index 511caf4..53501df 100644 --- a/src/clibwrap/ptrace.rs +++ b/src/clibwrap/ptrace.rs @@ -1,16 +1,18 @@ use crate::clibwrap::{ErrnoError, Pid}; use bitflags::bitflags; -use std::ffi::{c_long, c_void}; +use std::ffi::{c_long, c_ulonglong, c_void}; +use std::mem::MaybeUninit; #[allow(non_camel_case_types)] #[repr(u32)] enum PTraceRequest { PTRACE_CONT = 7, PTRACE_SINGLESTEP = 9, + PTRACE_GETREGS = 12, + PTRACE_SETREGS = 13, PTRACE_SYSCALL = 24, PTRACE_SETOPTIONS = 0x4200, } - unsafe extern "C" { fn ptrace(request: PTraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> c_long; } @@ -58,3 +60,83 @@ pub fn set_options(pid: Pid, options: PTraceOptions) -> Result<(), ErrnoError> { unsafe { Err(ErrnoError::from_current_errno()) } } } + +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(derive_more::Debug)] +pub struct registers { + #[debug("{r15:#x} ({r15})")] + pub r15: c_ulonglong, + #[debug("{r14:#x} ({r14})")] + pub r14: c_ulonglong, + #[debug("{r13:#x} ({r13})")] + pub r13: c_ulonglong, + #[debug("{r12:#x} ({r12})")] + pub r12: c_ulonglong, + #[debug("{rbp:#x} ({rbp})")] + pub rbp: c_ulonglong, + #[debug("{rbx:#x} ({rbx})")] + pub rbx: c_ulonglong, + #[debug("{r11:#x} ({r11})")] + pub r11: c_ulonglong, + #[debug("{r10:#x} ({r10})")] + pub r10: c_ulonglong, + #[debug("{r9:#x} ({r9})")] + pub r9: c_ulonglong, + #[debug("{r8:#x} ({r8})")] + pub r8: c_ulonglong, + #[debug("{rax:#x} ({rax})")] + pub rax: c_ulonglong, + #[debug("{rcx:#x} ({rcx})")] + pub rcx: c_ulonglong, + #[debug("{rdx:#x} ({rdx})")] + pub rdx: c_ulonglong, + #[debug("{rsi:#x} ({rsi})")] + pub rsi: c_ulonglong, + #[debug("{rdi:#x} ({rdi})")] + pub rdi: c_ulonglong, + #[debug(skip)] + pub orig_rax: c_ulonglong, + #[debug("{rip:#x} ({rip})")] + pub rip: c_ulonglong, + #[debug(skip)] + pub cs: c_ulonglong, + #[debug("{eflags:#x} ({eflags:#b})")] + pub eflags: c_ulonglong, + #[debug("{rsp:#x} ({rsp})")] + pub rsp: c_ulonglong, + #[debug(skip)] + pub ss: c_ulonglong, + #[debug(skip)] + pub fs_base: c_ulonglong, + #[debug(skip)] + pub gs_base: c_ulonglong, + #[debug(skip)] + pub ds: c_ulonglong, + #[debug(skip)] + pub es: c_ulonglong, + #[debug(skip)] + pub fs: c_ulonglong, + #[debug(skip)] + pub gs: c_ulonglong, +} + +pub fn get_regs(pid: Pid) -> Result { + let mut registers = MaybeUninit::::uninit(); + let return_code = unsafe { ptrace(PTraceRequest::PTRACE_GETREGS, pid, 0 as _, registers.as_mut_ptr() as _) }; + if return_code == 0 { + unsafe { Ok(registers.assume_init()) } + } else { + unsafe { Err(ErrnoError::from_current_errno()) } + } +} + +pub fn set_regs(pid: Pid, registers: registers) -> Result<(), ErrnoError> { + let register_address: *const registers = ®isters; + let return_code = unsafe { ptrace(PTraceRequest::PTRACE_SETREGS, pid, 0 as _, register_address as _) }; + if return_code == 0 { + Ok(()) + } else { + unsafe { Err(ErrnoError::from_current_errno()) } + } +} diff --git a/src/debug_target/stopped_target.rs b/src/debug_target/stopped_target.rs index b8050dc..d9022b4 100644 --- a/src/debug_target/stopped_target.rs +++ b/src/debug_target/stopped_target.rs @@ -1,7 +1,7 @@ use crate::clibwrap; use crate::debug_target::{CustomPTraceError, DebugError, PTraceError, RunningTarget, WaitError}; use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError}; -use libc::{c_long, user_regs_struct}; +use libc::c_long; use nix::sys::wait::{waitid, Id, WaitPidFlag}; use nix::unistd::Pid; use std::collections::HashMap; @@ -26,7 +26,7 @@ impl StoppedTarget { Ok(Self { pid, breakpoints: HashMap::new() }) } - pub fn on_breakpoint(&self) -> Result { + pub fn on_breakpoint(&self) -> Result { let rip = self.get_registers()?.rip; Ok(self.breakpoints.contains_key(&(rip - 1))) } @@ -35,7 +35,7 @@ impl StoppedTarget { let mut registers = self.get_registers()?; self.remove_breakpoint(registers.rip - 1)?; registers.rip -= 1; - nix::sys::ptrace::setregs(self.pid, registers).map_err(PTraceError)?; + clibwrap::ptrace::set_regs(self.pid.as_raw(), registers).map_err(CustomPTraceError)?; Ok(()) } @@ -63,8 +63,8 @@ impl StoppedTarget { Ok(self.to_running()) } - pub fn get_registers(&self) -> Result { - Ok(nix::sys::ptrace::getregs(self.pid)?) + pub fn get_registers(&self) -> Result { + clibwrap::ptrace::get_regs(self.pid.as_raw()).map_err(CustomPTraceError) } pub fn get_syscall_info(&self) -> Result { diff --git a/src/main.rs b/src/main.rs index 595fcf4..32ad2e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ fn single_step_all(mut target: StoppedTarget) -> color_eyre::Result<()> { loop { instruction_number += 1; let regs = target.get_registers()?; - println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax); + println!("🔎 [==> {instruction_number} {regs:?}"); match target.stepi()?.wait_for_something()? { Either::Left(t) => target = t, Either::Right(ExitedTarget { exit_code, was_pid: _was_pid }) => { @@ -68,8 +68,8 @@ fn main() -> color_eyre::Result<()> { println!("🚧 We are on a breakpoint!") } println!("🔎 rip: {:#x}", t.get_registers()?.rip); - // single_step_all(t)?; - strace(t)?; + single_step_all(t)?; + // strace(t)?; } Either::Right(ExitedTarget { exit_code, .. }) => { println!("👋 Child exited with code {exit_code}");