11use libc:: { self , pid_t, c_int} ;
22use { Errno , Result } ;
33
4+ #[ cfg( any( target_os = "linux" ,
5+ target_os = "android" ) ) ]
6+ use sys:: ptrace:: ptrace:: { PTRACE_EVENT_FORK , PTRACE_EVENT_VFORK , PTRACE_EVENT_CLONE , PTRACE_EVENT_EXEC , PTRACE_EVENT_VFORK_DONE , PTRACE_EVENT_EXIT , PTRACE_EVENT_SECCOMP , PTRACE_EVENT_STOP } ;
47use sys:: signal:: Signal ;
58
69mod ffi {
@@ -39,19 +42,54 @@ bitflags!(
3942 target_os = "android" ) ) ]
4043const WSTOPPED : WaitPidFlag = WUNTRACED ;
4144
45+ #[ cfg( any( target_os = "linux" ,
46+ target_os = "android" ) ) ]
47+ #[ derive( Eq , PartialEq , Clone , Copy , Debug ) ]
48+ #[ repr( i32 ) ]
49+ pub enum PtraceEvent {
50+ Fork = PTRACE_EVENT_FORK ,
51+ Vfork = PTRACE_EVENT_VFORK ,
52+ Clone = PTRACE_EVENT_CLONE ,
53+ Exec = PTRACE_EVENT_EXEC ,
54+ VforkDone = PTRACE_EVENT_VFORK_DONE ,
55+ Exit = PTRACE_EVENT_EXIT ,
56+ Seccomp = PTRACE_EVENT_SECCOMP ,
57+ Stop = PTRACE_EVENT_STOP ,
58+ }
59+
60+ #[ cfg( any( target_os = "linux" ,
61+ target_os = "android" ) ) ]
62+ impl PtraceEvent {
63+ #[ inline]
64+ pub fn from_c_int ( event : libc:: c_int ) -> Option < PtraceEvent > {
65+ use std:: mem;
66+
67+ if ( event >= PTRACE_EVENT_FORK && event <= PTRACE_EVENT_SECCOMP ) || event == PTRACE_EVENT_STOP {
68+ Some ( unsafe { mem:: transmute ( event) } )
69+ } else {
70+ None
71+ }
72+ }
73+ }
74+
4275#[ derive( Eq , PartialEq , Clone , Copy , Debug ) ]
4376pub enum WaitStatus {
4477 Exited ( pid_t , i8 ) ,
4578 Signaled ( pid_t , Signal , bool ) ,
4679 Stopped ( pid_t , Signal ) ,
80+ #[ cfg( any( target_os = "linux" ,
81+ target_os = "android" ) ) ]
82+ StoppedPtraceEvent ( pid_t , PtraceEvent ) ,
4783 Continued ( pid_t ) ,
4884 StillAlive
4985}
5086
5187#[ cfg( any( target_os = "linux" ,
5288 target_os = "android" ) ) ]
5389mod status {
90+ use libc:: pid_t;
5491 use sys:: signal:: Signal ;
92+ use super :: { PtraceEvent , WaitStatus } ;
5593
5694 pub fn exited ( status : i32 ) -> bool {
5795 ( status & 0x7F ) == 0
@@ -76,11 +114,19 @@ mod status {
76114 pub fn stopped ( status : i32 ) -> bool {
77115 ( status & 0xff ) == 0x7f
78116 }
79-
80117 pub fn stop_signal ( status : i32 ) -> Signal {
81118 Signal :: from_c_int ( ( status & 0xFF00 ) >> 8 ) . unwrap ( )
82119 }
83120
121+ pub fn decode_ptrace_event ( pid : pid_t , status : i32 ) -> Option < WaitStatus > {
122+ if stop_signal ( status) == Signal :: SIGTRAP {
123+ PtraceEvent :: from_c_int ( ( status & 0xFF0000 ) >> 16 )
124+ . map ( |event| WaitStatus :: StoppedPtraceEvent ( pid, event) )
125+ } else {
126+ None
127+ }
128+ }
129+
84130 pub fn continued ( status : i32 ) -> bool {
85131 status == 0xFFFF
86132 }
@@ -89,6 +135,7 @@ mod status {
89135#[ cfg( any( target_os = "macos" ,
90136 target_os = "ios" ) ) ]
91137mod status {
138+ use libc:: pid_t;
92139 use sys:: signal:: { Signal , SIGCONT } ;
93140
94141 const WCOREFLAG : i32 = 0x80 ;
@@ -114,6 +161,10 @@ mod status {
114161 wstatus ( status) == WSTOPPED && stop_signal ( status) != SIGCONT
115162 }
116163
164+ pub fn decode_ptrace_event ( pid : pid_t , status : i32 ) -> Option < WaitStatus > {
165+ None
166+ }
167+
117168 pub fn exited ( status : i32 ) -> bool {
118169 wstatus ( status) == 0
119170 }
@@ -136,6 +187,7 @@ mod status {
136187 target_os = "dragonfly" ,
137188 target_os = "netbsd" ) ) ]
138189mod status {
190+ use libc:: pid_t;
139191 use sys:: signal:: Signal ;
140192
141193 const WCOREFLAG : i32 = 0x80 ;
@@ -153,6 +205,10 @@ mod status {
153205 Signal :: from_c_int ( status >> 8 ) . unwrap ( )
154206 }
155207
208+ pub fn decode_ptrace_event ( pid : pid_t , status : i32 ) -> Option < WaitStatus > {
209+ None
210+ }
211+
156212 pub fn signaled ( status : i32 ) -> bool {
157213 wstatus ( status) != WSTOPPED && wstatus ( status) != 0 && status != 0x13
158214 }
@@ -184,7 +240,8 @@ fn decode(pid : pid_t, status: i32) -> WaitStatus {
184240 } else if status:: signaled ( status) {
185241 WaitStatus :: Signaled ( pid, status:: term_signal ( status) , status:: dumped_core ( status) )
186242 } else if status:: stopped ( status) {
187- WaitStatus :: Stopped ( pid, status:: stop_signal ( status) )
243+ status:: decode_ptrace_event ( pid, status)
244+ . unwrap_or_else ( || WaitStatus :: Stopped ( pid, status:: stop_signal ( status) ) )
188245 } else {
189246 assert ! ( status:: continued( status) ) ;
190247 WaitStatus :: Continued ( pid)
0 commit comments