@@ -40,14 +40,56 @@ libc_bitflags!(
40
40
target_os = "android" ) ) ]
41
41
const WSTOPPED : WaitPidFlag = WUNTRACED ;
42
42
43
+ /// Possible return values from `wait()` or `waitpid()`.
44
+ ///
45
+ /// Each status (other than `StillAlive`) describes a state transition
46
+ /// in a child process `Pid`, such as the process exiting or stopping,
47
+ /// plus additional data about the transition if any.
48
+ ///
49
+ /// Note that there are two Linux-specific enum variants, `PtraceEvent`
50
+ /// and `PtraceSyscall`. Portable code should avoid exhaustively
51
+ /// matching on `WaitStatus`.
43
52
#[ derive( Eq , PartialEq , Clone , Copy , Debug ) ]
44
53
pub enum WaitStatus {
54
+ /// The process exited normally (as with `exit()` or returning from
55
+ /// `main`) with the given exit code. This case matches the C macro
56
+ /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`.
45
57
Exited ( Pid , i8 ) ,
58
+ /// The process was killed by the given signal. The third field
59
+ /// indicates whether the signal generated a core dump. This case
60
+ /// matches the C macro `WIFSIGNALED(status)`; the last two fields
61
+ /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`.
46
62
Signaled ( Pid , Signal , bool ) ,
63
+ /// The process is alive, but was stopped by the given signal. This
64
+ /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This
65
+ /// case matches the C macro `WIFSTOPPED(status)`; the second field
66
+ /// is `WSTOPSIG(status)`.
47
67
Stopped ( Pid , Signal ) ,
68
+ /// The traced process was stopped by a `PTRACE_EVENT_*` event. See
69
+ /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All
70
+ /// currently-defined events use `SIGTRAP` as the signal; the third
71
+ /// field is the `PTRACE_EVENT_*` value of the event.
72
+ ///
73
+ /// [`nix::sys::ptrace`]: ../ptrace/index.html
74
+ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
48
75
#[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
49
76
PtraceEvent ( Pid , Signal , c_int ) ,
77
+ /// The traced process was stopped by execution of a system call,
78
+ /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
79
+ /// more information.
80
+ ///
81
+ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
82
+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
83
+ PtraceSyscall ( Pid ) ,
84
+ /// The process was previously stopped but has resumed execution
85
+ /// after receiving a `SIGCONT` signal. This is only reported if
86
+ /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C
87
+ /// macro `WIFCONTINUED(status)`.
50
88
Continued ( Pid ) ,
89
+ /// There are currently no state changes to report in any awaited
90
+ /// child process. This is only returned if `WaitPidFlag::WNOHANG`
91
+ /// was used (otherwise `wait()` or `waitpid()` would block until
92
+ /// there was something to report).
51
93
StillAlive
52
94
}
53
95
@@ -56,6 +98,7 @@ pub enum WaitStatus {
56
98
mod status {
57
99
use sys:: signal:: Signal ;
58
100
use libc:: c_int;
101
+ use libc:: SIGTRAP ;
59
102
60
103
pub fn exited ( status : i32 ) -> bool {
61
104
( status & 0x7F ) == 0
@@ -82,7 +125,17 @@ mod status {
82
125
}
83
126
84
127
pub fn stop_signal ( status : i32 ) -> Signal {
85
- Signal :: from_c_int ( ( status & 0xFF00 ) >> 8 ) . unwrap ( )
128
+ // Keep only 7 bits of the signal: the high bit
129
+ // is used to indicate syscall stops, below.
130
+ Signal :: from_c_int ( ( status & 0x7F00 ) >> 8 ) . unwrap ( )
131
+ }
132
+
133
+ pub fn syscall_stop ( status : i32 ) -> bool {
134
+ // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
135
+ // of delivering SIGTRAP | 0x80 as the signal number for syscall
136
+ // stops. This allows easily distinguishing syscall stops from
137
+ // genuine SIGTRAP signals.
138
+ ( ( status & 0xFF00 ) >> 8 ) == SIGTRAP | 0x80
86
139
}
87
140
88
141
pub fn stop_additional ( status : i32 ) -> c_int {
@@ -196,7 +249,9 @@ fn decode(pid : Pid, status: i32) -> WaitStatus {
196
249
if #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ] {
197
250
fn decode_stopped( pid: Pid , status: i32 ) -> WaitStatus {
198
251
let status_additional = status:: stop_additional( status) ;
199
- if status_additional == 0 {
252
+ if status:: syscall_stop( status) {
253
+ WaitStatus :: PtraceSyscall ( pid)
254
+ } else if status_additional == 0 {
200
255
WaitStatus :: Stopped ( pid, status:: stop_signal( status) )
201
256
} else {
202
257
WaitStatus :: PtraceEvent ( pid, status:: stop_signal( status) , status:: stop_additional( status) )
0 commit comments