diff --git a/src/debug_target.rs b/src/debug_target.rs index e0347a3..2ec1ce9 100644 --- a/src/debug_target.rs +++ b/src/debug_target.rs @@ -1,10 +1,16 @@ +use nix::libc::user_regs_struct; +use nix::sys::signal::Signal; use nix::sys::wait::{waitid, Id, WaitPidFlag, WaitStatus}; use nix::unistd::Pid; +#[derive(thiserror::Error, Debug)] +#[error("Error when calling ptrace: {0}")] +pub struct PTraceError(#[from] nix::errno::Errno); + #[derive(thiserror::Error, Debug)] pub enum DebugError { #[error("Error when calling ptrace: {0}")] - PTraceError(#[from] nix::errno::Errno), + PTraceError(#[from] nix::errno::Errno), // TODO: do not repeat above implem #[error("Child stopped with status {0:?}, but was not expecting to catch this one")] UnexpectedWaitStatus(nix::sys::wait::WaitStatus), @@ -37,6 +43,18 @@ impl DebugTarget { nix::sys::ptrace::cont(self.state.pid, None)?; Ok(DebugTarget { state: Running { pid: self.state.pid } }) } + + pub fn stepi(self) -> Result { + nix::sys::ptrace::step(self.state.pid, None)?; + match waitid(Id::Pid(self.state.pid), WaitPidFlag::WSTOPPED | WaitPidFlag::WEXITED)? { + WaitStatus::PtraceEvent(_pid, Signal::SIGTRAP, _c_event) => Ok(self), + status => Err(DebugError::UnexpectedWaitStatus(status)), + } + } + + pub fn get_registers(&self) -> Result { + Ok(nix::sys::ptrace::getregs(self.state.pid)?) + } } pub struct Running { diff --git a/src/main.rs b/src/main.rs index f258813..9fec6ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ mod child; mod debug_target; -use crate::debug_target::DebugTarget; +use crate::debug_target::{DebugTarget, Stopped}; use color_eyre::eyre::eyre; use nix::libc::user_regs_struct; use nix::sys::ptrace::*; @@ -11,25 +11,13 @@ use nix::unistd::{fork, ForkResult, Pid}; use std::ffi::{c_long, c_void, CString}; #[allow(dead_code)] -fn single_step_all(child_pid: Pid) -> color_eyre::Result<()> { +fn single_step_all(mut target: DebugTarget) -> color_eyre::Result<()> { let mut instruction_number = 0; loop { - let wait_status = waitpid(child_pid, None); - match wait_status { - Ok(WaitStatus::Stopped(_, _)) => { - instruction_number += 1; - let regs = getregs(child_pid).unwrap(); - println!("🔎 [==> {}] rip= 0x{:016X}, rax = 0x{rax:X} ({rax})", instruction_number, regs.rip, rax = regs.rax); - step(child_pid, None)?; - } - Ok(WaitStatus::Exited(_, exit_code)) => { - println!("👋 Child exited with code {exit_code}"); - return Ok(()); - } - other => { - return Err(eyre!("⚠️ Other (unexpected) wait status: {other:?}")) - } - } + instruction_number += 1; + let regs = target.get_registers()?; + println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax); + target = target.stepi()?; } } @@ -97,16 +85,24 @@ fn main() -> color_eyre::Result<()> { let target = DebugTarget::new(child_pid)?; println!("✔️ Child ready!"); - println!("⚙️ Continuing execution"); - let target = target.cont()?; - let exit_code = target.wait_for_exit()?; - - println!("👋 Child exited with code {exit_code}"); - - Ok(()) + // println!("🔎 rip: {:#x}", target.get_registers()?.rip); + // println!("➡️➡️➡️ Stepping three times"); + // let mut target = target; + // for _i in 0..3 { + // target = target.stepi()?; + // } + // println!("🔎 rip: {:#x}", target.get_registers()?.rip); + // + // println!("⚙️ Continuing execution"); + // let target = target.cont()?; + // let exit_code = target.wait_for_exit()?; + // + // println!("👋 Child exited with code {exit_code}"); + // + // Ok(()) - // single_step_all(child_pid) + single_step_all(target) // breakpoint_fun(child_pid) } Err(e) => {