| 
 | 1 | +//! Traces a child process using `ptrace`.  | 
 | 2 | +//!  | 
 | 3 | +//! The child issues a single `write` syscall, which is printed upon entry and exit.  | 
 | 4 | +
  | 
 | 5 | +#[cfg(target_os = "linux")]  | 
 | 6 | +fn main() {  | 
 | 7 | +    let pid = unsafe { nix::unistd::fork().unwrap() };  | 
 | 8 | + | 
 | 9 | +    match pid {  | 
 | 10 | +        nix::unistd::ForkResult::Child => {  | 
 | 11 | +            nix::sys::ptrace::traceme().unwrap();  | 
 | 12 | +            nix::sys::signal::raise(nix::sys::signal::Signal::SIGCONT).unwrap();  | 
 | 13 | +            println!("I'm issuing a syscall!");  | 
 | 14 | +        }  | 
 | 15 | +        nix::unistd::ForkResult::Parent { child } => {  | 
 | 16 | +            nix::sys::wait::waitpid(Some(child), None).unwrap();  | 
 | 17 | +            nix::sys::ptrace::setoptions(  | 
 | 18 | +                child,  | 
 | 19 | +                nix::sys::ptrace::Options::PTRACE_O_TRACESYSGOOD,  | 
 | 20 | +            )  | 
 | 21 | +            .unwrap();  | 
 | 22 | + | 
 | 23 | +            nix::sys::ptrace::syscall(child, None).unwrap();  | 
 | 24 | +            nix::sys::wait::waitpid(Some(child), None).unwrap();  | 
 | 25 | +            let syscall_info = nix::sys::ptrace::syscall_info(child).unwrap();  | 
 | 26 | +            println!("{syscall_info:?}");  | 
 | 27 | +            assert!(syscall_info.op == libc::PTRACE_SYSCALL_INFO_ENTRY);  | 
 | 28 | + | 
 | 29 | +            nix::sys::ptrace::syscall(child, None).unwrap();  | 
 | 30 | +            nix::sys::wait::waitpid(Some(child), None).unwrap();  | 
 | 31 | +            let syscall_info = nix::sys::ptrace::syscall_info(child).unwrap();  | 
 | 32 | +            println!("{syscall_info:?}");  | 
 | 33 | +            assert!(syscall_info.op == libc::PTRACE_SYSCALL_INFO_EXIT);  | 
 | 34 | +        }  | 
 | 35 | +    }  | 
 | 36 | +}  | 
 | 37 | + | 
 | 38 | +#[cfg(not(target_os = "linux"))]  | 
 | 39 | +fn main() {}  | 
0 commit comments