Implemented stepi but does not work when program exits
This commit is contained in:
parent
1dac90f0d2
commit
3e4520e055
|
|
@ -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 {
|
||||||
|
|
|
||||||
46
src/main.rs
46
src/main.rs
|
|
@ -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);
|
|
||||||
match wait_status {
|
|
||||||
Ok(WaitStatus::Stopped(_, _)) => {
|
|
||||||
instruction_number += 1;
|
instruction_number += 1;
|
||||||
let regs = getregs(child_pid).unwrap();
|
let regs = target.get_registers()?;
|
||||||
println!("🔎 [==> {}] rip= 0x{:016X}, rax = 0x{rax:X} ({rax})", instruction_number, regs.rip, rax = regs.rax);
|
println!("🔎 [==> {}] rip= {:#016x}, rax = 0x{rax:x} ({rax})", instruction_number, regs.rip, rax = regs.rax);
|
||||||
step(child_pid, None)?;
|
target = target.stepi()?;
|
||||||
}
|
|
||||||
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) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue