ptrace used to single-step child program
This commit is contained in:
parent
0528a6af22
commit
775d909585
|
|
@ -0,0 +1,15 @@
|
||||||
|
use nix::libc;
|
||||||
|
use nix::sys::ptrace::traceme;
|
||||||
|
use nix::unistd::execv;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
pub fn starti(child_exec_path: CString) -> ! {
|
||||||
|
// ⚠️ There is a limited amount of things that can be done here, see fork's safety
|
||||||
|
match traceme() {
|
||||||
|
Ok(_) => {
|
||||||
|
execv(&child_exec_path, &[&child_exec_path]).unwrap();
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
Err(errno) => unsafe { libc::exit(errno as i32) },
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/main.rs
49
src/main.rs
|
|
@ -1,33 +1,48 @@
|
||||||
use nix::unistd::{execv, fork, ForkResult};
|
mod child;
|
||||||
|
|
||||||
|
use nix::sys::ptrace::*;
|
||||||
|
use nix::sys::wait::waitpid;
|
||||||
|
use nix::unistd::{ForkResult, fork};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
use nix::sys::wait::{waitid, WaitPidFlag, WaitStatus};
|
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
let child_exec_path = CString::new(env!("TEST_PROG_PATH")).unwrap();
|
let child_exec_path = CString::new(env!("TEST_PROG_PATH")).unwrap();
|
||||||
|
|
||||||
match unsafe { fork() } {
|
match unsafe { fork() } {
|
||||||
Ok(ForkResult::Child) => {
|
Ok(ForkResult::Child) => child::starti(child_exec_path),
|
||||||
// ⚠️ There is a limited amount of things that can be done here, see fork's safety
|
|
||||||
execv(&child_exec_path, &[&child_exec_path]).unwrap();
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
Ok(ForkResult::Parent { child: child_pid }) => {
|
Ok(ForkResult::Parent { child: child_pid }) => {
|
||||||
println!("✔️ Started child {child_pid}");
|
println!("✔️ Started child {child_pid}");
|
||||||
println!("⏳️ Waiting for child to exit...");
|
println!("⚙️ Waiting for child signals...");
|
||||||
use nix::sys::wait::Id::Pid;
|
|
||||||
match waitid(Pid(child_pid), WaitPidFlag::WEXITED) {
|
loop {
|
||||||
|
use nix::sys::signal::Signal::*;
|
||||||
|
use nix::sys::wait::WaitStatus::*;
|
||||||
|
match waitpid(child_pid, None) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("❌ Wait failed: {e}");
|
println!("❌ Wait failed: {e}");
|
||||||
ExitCode::FAILURE
|
return ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
Ok(WaitStatus::Exited(_pid, exit_code)) => {
|
Ok(status) => match status {
|
||||||
println!("👋 child exited with code {exit_code}");
|
Exited(_pid, exit_code) => {
|
||||||
ExitCode::SUCCESS
|
println!("👋 Child exited with code {exit_code}");
|
||||||
|
return ExitCode::SUCCESS;
|
||||||
}
|
}
|
||||||
Ok(status) => {
|
Signaled(_, signal, _) => match signal {
|
||||||
println!("⚠️ Unexpected status from wait! {status:#?}");
|
SIGKILL => {
|
||||||
ExitCode::FAILURE
|
println!("💀 Child killed by SIGKILL");
|
||||||
|
return ExitCode::SUCCESS;
|
||||||
|
}
|
||||||
|
s => println!("💡 Child received signal {s:?}"),
|
||||||
|
},
|
||||||
|
Stopped(_pid, _signal) => {
|
||||||
|
println!("⚙️ Single-stepping child");
|
||||||
|
step(child_pid, None).unwrap()
|
||||||
|
}
|
||||||
|
status => {
|
||||||
|
println!("⚠️ Other (unexpected) wait status: {status:?}");
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue