diff options
Diffstat (limited to 'test/sys')
-rw-r--r-- | test/sys/test_ptrace.rs | 60 | ||||
-rw-r--r-- | test/sys/test_wait.rs | 2 |
2 files changed, 61 insertions, 1 deletions
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs index b875e323..cb2f04e9 100644 --- a/test/sys/test_ptrace.rs +++ b/test/sys/test_ptrace.rs @@ -112,3 +112,63 @@ fn test_ptrace_cont() { }, } } + +// ptrace::{setoptions, getregs} are only available in these platforms +#[cfg(all(target_os = "linux", + any(target_arch = "x86_64", + target_arch = "x86"), + target_env = "gnu"))] +#[test] +fn test_ptrace_syscall() { + use nix::sys::signal::kill; + use nix::sys::ptrace; + use nix::sys::signal::Signal; + use nix::sys::wait::{waitpid, WaitStatus}; + use nix::unistd::fork; + use nix::unistd::getpid; + use nix::unistd::ForkResult::*; + + let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test"); + + match fork().expect("Error: Fork Failed") { + Child => { + ptrace::traceme().unwrap(); + // first sigstop until parent is ready to continue + let pid = getpid(); + kill(pid, Signal::SIGSTOP).unwrap(); + kill(pid, Signal::SIGTERM).unwrap(); + unsafe { ::libc::_exit(0); } + }, + + Parent { child } => { + assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP))); + + // set this option to recognize syscall-stops + ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap(); + + #[cfg(target_pointer_width = "64")] + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64; + + #[cfg(target_pointer_width = "32")] + let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32; + + // kill entry + ptrace::syscall(child, None).unwrap(); + assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + assert_eq!(get_syscall_id(), ::libc::SYS_kill); + + // kill exit + ptrace::syscall(child, None).unwrap(); + assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); + assert_eq!(get_syscall_id(), ::libc::SYS_kill); + + // receive signal + ptrace::syscall(child, None).unwrap(); + assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM))); + + // inject signal + ptrace::syscall(child, Signal::SIGTERM).unwrap(); + assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false))); + }, + } +} diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs index d61c2a1c..1a189a33 100644 --- a/test/sys/test_wait.rs +++ b/test/sys/test_wait.rs @@ -82,7 +82,7 @@ mod ptrace { assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok()); // First, stop on the next system call, which will be exit() - assert!(ptrace::syscall(child).is_ok()); + assert!(ptrace::syscall(child, None).is_ok()); assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child))); // Then get the ptrace event for the process exiting assert!(ptrace::cont(child, None).is_ok()); |