summaryrefslogtreecommitdiff
path: root/test/sys/test_ptrace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'test/sys/test_ptrace.rs')
-rw-r--r--test/sys/test_ptrace.rs60
1 files changed, 60 insertions, 0 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)));
+ },
+ }
+}