diff --git a/src/clibwrap/mod.rs b/src/clibwrap/mod.rs index d8516f5..bd5aa5f 100644 --- a/src/clibwrap/mod.rs +++ b/src/clibwrap/mod.rs @@ -13,6 +13,10 @@ unsafe fn errno() -> c_int { unsafe { *__errno_location() } } +unsafe fn set_errno(errno: c_int) { + unsafe { *__errno_location() = errno; } +} + #[derive(Debug, thiserror::Error)] #[error("{}", self.error_message())] pub struct ErrnoError { diff --git a/src/clibwrap/ptrace.rs b/src/clibwrap/ptrace.rs index 53501df..466f0af 100644 --- a/src/clibwrap/ptrace.rs +++ b/src/clibwrap/ptrace.rs @@ -1,4 +1,4 @@ -use crate::clibwrap::{ErrnoError, Pid}; +use crate::clibwrap::{errno, set_errno, ErrnoError, Pid}; use bitflags::bitflags; use std::ffi::{c_long, c_ulonglong, c_void}; use std::mem::MaybeUninit; @@ -6,6 +6,8 @@ use std::mem::MaybeUninit; #[allow(non_camel_case_types)] #[repr(u32)] enum PTraceRequest { + PTRACE_PEEKDATA = 2, + PTRACE_POKEDATA = 5, PTRACE_CONT = 7, PTRACE_SINGLESTEP = 9, PTRACE_GETREGS = 12, @@ -140,3 +142,25 @@ pub fn set_regs(pid: Pid, registers: registers) -> Result<(), ErrnoError> { unsafe { Err(ErrnoError::from_current_errno()) } } } + +pub fn peek_data(pid: Pid, address: u64) -> Result { + unsafe { + set_errno(0); + let data = ptrace(PTraceRequest::PTRACE_PEEKDATA, pid, address as _, 0 as _); + let errno = errno(); + if errno != 0 { + Err(ErrnoError::from_current_errno()) + } else { + Ok(data) + } + } +} + +pub fn poke_data(pid: Pid, address: u64, data: c_long) -> Result<(), ErrnoError> { + let return_code = unsafe { ptrace(PTraceRequest::PTRACE_POKEDATA, pid, address as _, data 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 d9022b4..24e658c 100644 --- a/src/debug_target/stopped_target.rs +++ b/src/debug_target/stopped_target.rs @@ -1,11 +1,10 @@ use crate::clibwrap; -use crate::debug_target::{CustomPTraceError, DebugError, PTraceError, RunningTarget, WaitError}; +use crate::debug_target::{CustomPTraceError, DebugError, RunningTarget, WaitError}; use crate::syscall_info::{syscall_info, SyscallInfo, SyscallInfoError}; use libc::c_long; use nix::sys::wait::{waitid, Id, WaitPidFlag}; use nix::unistd::Pid; use std::collections::HashMap; -use std::ffi::c_void; pub struct StoppedTarget { pub pid: Pid, @@ -76,10 +75,10 @@ impl StoppedTarget { if self.breakpoints.contains_key(&address) { return Err(DebugError::DuplicateBreakpoint { address }); } - let orig_bytes = nix::sys::ptrace::read(self.pid, address as *mut c_void).map_err(PTraceError)?; + let orig_bytes = clibwrap::ptrace::peek_data(self.pid.as_raw(), address).map_err(CustomPTraceError)?; let target_byte: u8 = (orig_bytes & 0xFF as c_long) as u8; let new_content = (orig_bytes & (!0xff as c_long)) | (0xCC as c_long); - nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?; + clibwrap::ptrace::poke_data(self.pid.as_raw(), address, new_content).map_err(CustomPTraceError)?; self.breakpoints.insert(address, target_byte); Ok(()) @@ -90,9 +89,9 @@ impl StoppedTarget { match self.breakpoints.remove(&address) { None => Err(DebugError::NonExistingBreakpoint { address }), Some(original_byte) => { - let content = nix::sys::ptrace::read(self.pid, address as *mut c_void).map_err(PTraceError)?; + let content = clibwrap::ptrace::peek_data(self.pid.as_raw(), address).map_err(CustomPTraceError)?; let new_content = (content & (!0xff as c_long)) | (original_byte as c_long); - nix::sys::ptrace::write(self.pid, address as *mut c_void, new_content).map_err(PTraceError)?; + clibwrap::ptrace::poke_data(self.pid.as_raw(), address, new_content).map_err(CustomPTraceError)?; Ok(()) } }