Implemented stepi but does not work when program exits

This commit is contained in:
Elnath 2025-05-17 16:47:12 +02:00
parent 1dac90f0d2
commit 3e4520e055
2 changed files with 41 additions and 27 deletions

View File

@ -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::sys::wait::{waitid, Id, WaitPidFlag, WaitStatus};
use nix::unistd::Pid; 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)] #[derive(thiserror::Error, Debug)]
pub enum DebugError { pub enum DebugError {
#[error("Error when calling ptrace: {0}")] #[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")] #[error("Child stopped with status {0:?}, but was not expecting to catch this one")]
UnexpectedWaitStatus(nix::sys::wait::WaitStatus), UnexpectedWaitStatus(nix::sys::wait::WaitStatus),
@ -37,6 +43,18 @@ impl DebugTarget<Stopped> {
nix::sys::ptrace::cont(self.state.pid, None)?; nix::sys::ptrace::cont(self.state.pid, None)?;
Ok(DebugTarget { state: Running { pid: self.state.pid } }) Ok(DebugTarget { state: Running { pid: self.state.pid } })
} }
pub fn stepi(self) -> Result<Self, DebugError> {
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<user_regs_struct, PTraceError> {
Ok(nix::sys::ptrace::getregs(self.state.pid)?)
}
} }
pub struct Running { pub struct Running {

View File

@ -1,7 +1,7 @@
mod child; mod child;
mod debug_target; mod debug_target;
use crate::debug_target::DebugTarget; use crate::debug_target::{DebugTarget, Stopped};
use color_eyre::eyre::eyre; use color_eyre::eyre::eyre;
use nix::libc::user_regs_struct; use nix::libc::user_regs_struct;
use nix::sys::ptrace::*; use nix::sys::ptrace::*;
@ -11,25 +11,13 @@ use nix::unistd::{fork, ForkResult, Pid};
use std::ffi::{c_long, c_void, CString}; use std::ffi::{c_long, c_void, CString};
#[allow(dead_code)] #[allow(dead_code)]
fn single_step_all(child_pid: Pid) -> color_eyre::Result<()> { fn single_step_all(mut target: DebugTarget<Stopped>) -> color_eyre::Result<()> {
let mut instruction_number = 0; let mut instruction_number = 0;
loop { loop {
let wait_status = waitpid(child_pid, None); instruction_number += 1;
match wait_status { let regs = target.get_registers()?;
Ok(WaitStatus::Stopped(_, _)) => { println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax);
instruction_number += 1; target = target.stepi()?;
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:?}"))
}
}
} }
} }
@ -97,16 +85,24 @@ fn main() -> color_eyre::Result<()> {
let target = DebugTarget::new(child_pid)?; let target = DebugTarget::new(child_pid)?;
println!("✔️ Child ready!"); println!("✔️ Child ready!");
println!("⚙️ Continuing execution"); // println!("🔎 rip: {:#x}", target.get_registers()?.rip);
let target = target.cont()?; // println!("➡️➡️➡️ Stepping three times");
let exit_code = target.wait_for_exit()?; // let mut target = target;
// for _i in 0..3 {
println!("👋 Child exited with code {exit_code}"); // target = target.stepi()?;
// }
Ok(()) // 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) // breakpoint_fun(child_pid)
} }
Err(e) => { Err(e) => {