@@ -112,3 +112,63 @@ fn test_ptrace_cont() {
112112 } ,
113113 }
114114}
115+
116+ // ptrace::{setoptions, getregs} are only available in these platforms
117+ #[ cfg( all( target_os = "linux" ,
118+ any( target_arch = "x86_64" ,
119+ target_arch = "x86" ) ,
120+ target_env = "gnu" ) ) ]
121+ #[ test]
122+ fn test_ptrace_syscall ( ) {
123+ use nix:: sys:: signal:: kill;
124+ use nix:: sys:: ptrace;
125+ use nix:: sys:: signal:: Signal ;
126+ use nix:: sys:: wait:: { waitpid, WaitStatus } ;
127+ use nix:: unistd:: fork;
128+ use nix:: unistd:: getpid;
129+ use nix:: unistd:: ForkResult :: * ;
130+
131+ let _m = :: FORK_MTX . lock ( ) . expect ( "Mutex got poisoned by another test" ) ;
132+
133+ match fork ( ) . expect ( "Error: Fork Failed" ) {
134+ Child => {
135+ ptrace:: traceme ( ) . unwrap ( ) ;
136+ // first sigstop until parent is ready to continue
137+ let pid = getpid ( ) ;
138+ kill ( pid, Signal :: SIGSTOP ) . unwrap ( ) ;
139+ kill ( pid, Signal :: SIGTERM ) . unwrap ( ) ;
140+ unsafe { :: libc:: _exit ( 0 ) ; }
141+ } ,
142+
143+ Parent { child } => {
144+ assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: Stopped ( child, Signal :: SIGSTOP ) ) ) ;
145+
146+ // set this option to recognize syscall-stops
147+ ptrace:: setoptions ( child, ptrace:: Options :: PTRACE_O_TRACESYSGOOD ) . unwrap ( ) ;
148+
149+ #[ cfg( target_pointer_width = "64" ) ]
150+ let get_syscall_id = || ptrace:: getregs ( child) . unwrap ( ) . orig_rax as i64 ;
151+
152+ #[ cfg( target_pointer_width = "32" ) ]
153+ let get_syscall_id = || ptrace:: getregs ( child) . unwrap ( ) . orig_eax as i32 ;
154+
155+ // kill entry
156+ ptrace:: syscall ( child, None ) . unwrap ( ) ;
157+ assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: PtraceSyscall ( child) ) ) ;
158+ assert_eq ! ( get_syscall_id( ) , :: libc:: SYS_kill ) ;
159+
160+ // kill exit
161+ ptrace:: syscall ( child, None ) . unwrap ( ) ;
162+ assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: PtraceSyscall ( child) ) ) ;
163+ assert_eq ! ( get_syscall_id( ) , :: libc:: SYS_kill ) ;
164+
165+ // receive signal
166+ ptrace:: syscall ( child, None ) . unwrap ( ) ;
167+ assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: Stopped ( child, Signal :: SIGTERM ) ) ) ;
168+
169+ // inject signal
170+ ptrace:: syscall ( child, Signal :: SIGTERM ) . unwrap ( ) ;
171+ assert_eq ! ( waitpid( child, None ) , Ok ( WaitStatus :: Signaled ( child, Signal :: SIGTERM , false ) ) ) ;
172+ } ,
173+ }
174+ }
0 commit comments