Stepi now returning running state for handling program exit
This commit is contained in:
parent
b20fa4672d
commit
99999346ed
|
|
@ -37,6 +37,7 @@ name = "bdb"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"color-eyre",
|
"color-eyre",
|
||||||
|
"either",
|
||||||
"nix",
|
"nix",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
@ -95,6 +96,12 @@ dependencies = [
|
||||||
"tracing-error",
|
"tracing-error",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eyre"
|
name = "eyre"
|
||||||
version = "0.6.12"
|
version = "0.6.12"
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ publish = false
|
||||||
nix = { version = "0.29.0", features = ["process", "ptrace"] }
|
nix = { version = "0.29.0", features = ["process", "ptrace"] }
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
|
either = "1.15.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
color-eyre = "0.6.3"
|
color-eyre = "0.6.3"
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
|
use either::{Either, Left, Right};
|
||||||
use nix::libc::user_regs_struct;
|
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;
|
||||||
|
|
||||||
|
|
@ -40,6 +40,7 @@ impl DebugState for Stopped {
|
||||||
fn pid(&self) -> Pid { self.pid }
|
fn pid(&self) -> Pid { self.pid }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl DebugTarget<Stopped> {
|
impl DebugTarget<Stopped> {
|
||||||
pub fn new(pid: Pid) -> Result<Self, WaitError> {
|
pub fn new(pid: Pid) -> Result<Self, WaitError> {
|
||||||
waitid(Id::Pid(pid), WaitPidFlag::WSTOPPED).map_err(WaitError)?;
|
waitid(Id::Pid(pid), WaitPidFlag::WSTOPPED).map_err(WaitError)?;
|
||||||
|
|
@ -51,12 +52,9 @@ impl DebugTarget<Stopped> {
|
||||||
Ok(DebugTarget { state: Running { pid: self.state.pid } })
|
Ok(DebugTarget { state: Running { pid: self.state.pid } })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stepi(self) -> Result<Self, DebugError> {
|
pub fn stepi(self) -> Result<DebugTarget<Running>, PTraceError> {
|
||||||
nix::sys::ptrace::step(self.state.pid, None).map_err(PTraceError)?;
|
nix::sys::ptrace::step(self.state.pid, None).map_err(PTraceError)?;
|
||||||
match waitid(Id::Pid(self.state.pid), WaitPidFlag::WSTOPPED).map_err(WaitError)? {
|
Ok(DebugTarget { state: Running { pid: self.state.pid } })
|
||||||
WaitStatus::PtraceEvent(_pid, Signal::SIGTRAP, _c_event) => Ok(self),
|
|
||||||
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
pub fn get_registers(&self) -> Result<user_regs_struct, PTraceError> {
|
||||||
|
|
@ -72,8 +70,16 @@ impl DebugState for Running {
|
||||||
fn pid(&self) -> Pid { self.pid }
|
fn pid(&self) -> Pid { self.pid }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl DebugTarget<Running> {
|
impl DebugTarget<Running> {
|
||||||
|
pub fn wait_for_something(self) -> Result<Either<DebugTarget<Stopped>, i32>, DebugError> {
|
||||||
|
match waitid(Id::Pid(self.state.pid), WaitPidFlag::WSTOPPED | WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||||
|
WaitStatus::Exited(_pid, exit_code) => Ok(Right(exit_code)),
|
||||||
|
WaitStatus::PtraceEvent(_pid, _signal, _c_event) => Ok(Left(DebugTarget { state: Stopped { pid: self.state.pid } })),
|
||||||
|
status => Err(DebugError::UnexpectedWaitStatus(status)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn wait_for_exit(self) -> Result<i32, DebugError> {
|
pub fn wait_for_exit(self) -> Result<i32, DebugError> {
|
||||||
match waitid(Id::Pid(self.state.pid), WaitPidFlag::WEXITED).map_err(WaitError)? {
|
match waitid(Id::Pid(self.state.pid), WaitPidFlag::WEXITED).map_err(WaitError)? {
|
||||||
WaitStatus::Exited(_pid, exit_code) => Ok(exit_code),
|
WaitStatus::Exited(_pid, exit_code) => Ok(exit_code),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ mod debug_target;
|
||||||
|
|
||||||
use crate::debug_target::{DebugTarget, Stopped};
|
use crate::debug_target::{DebugTarget, Stopped};
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
|
use either::Either;
|
||||||
use nix::libc::user_regs_struct;
|
use nix::libc::user_regs_struct;
|
||||||
use nix::sys::ptrace::*;
|
use nix::sys::ptrace::*;
|
||||||
use nix::sys::signal::Signal::*;
|
use nix::sys::signal::Signal::*;
|
||||||
|
|
@ -17,7 +18,13 @@ fn single_step_all(mut target: DebugTarget<Stopped>) -> color_eyre::Result<()> {
|
||||||
instruction_number += 1;
|
instruction_number += 1;
|
||||||
let regs = target.get_registers()?;
|
let regs = target.get_registers()?;
|
||||||
println!("🔎 [==> {}] rip= {:#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);
|
||||||
target = target.stepi()?;
|
match target.stepi()?.wait_for_something()? {
|
||||||
|
Either::Left(t) => target = t,
|
||||||
|
Either::Right(exit_code) => {
|
||||||
|
println!("👋 Child exited with code {exit_code}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue