Skip to content

Commit bc1cc08

Browse files
committed
Merge #749
749: Moved ptrace constants into enum types plus minor additions r=Susurrus a=xd009642 Reopening of #734 hence the branch name, changelog will be updated once the pr number of this new pull request is known.
2 parents 202f30e + 1784519 commit bc1cc08

File tree

5 files changed

+177
-86
lines changed

5 files changed

+177
-86
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
2222
([#739](https://github.com/nix-rust/nix/pull/739))
2323
- Expose `signalfd` module on Android as well.
2424
([#739](https://github.com/nix-rust/nix/pull/739))
25+
- Added nix::sys::ptrace::detach.
26+
([#749](https://github.com/nix-rust/nix/pull/749))
2527

2628
### Changed
2729
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
@@ -47,6 +49,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4749
([#731](https://github.com/nix-rust/nix/pull/731))
4850
- Marked `pty::ptsname` function as `unsafe`
4951
([#744](https://github.com/nix-rust/nix/pull/744))
52+
- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly.
53+
([#749](https://github.com/nix-rust/nix/pull/749))
5054

5155
# Fixed
5256
- Fix compilation and tests for OpenBSD targets

src/macros.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,23 @@ macro_rules! libc_enum {
379379
}
380380
};
381381

382+
// Munch an ident and cast it to the given type; covers terminating comma.
383+
(@accumulate_entries
384+
$prefix:tt,
385+
[$($entries:tt)*];
386+
$entry:ident as $ty:ty, $($tail:tt)*
387+
) => {
388+
libc_enum! {
389+
@accumulate_entries
390+
$prefix,
391+
[
392+
$($entries)*
393+
$entry = libc::$entry as $ty,
394+
];
395+
$($tail)*
396+
}
397+
};
398+
382399
// (non-pub) Entry rule.
383400
(
384401
$(#[$attr:meta])*

src/sys/ptrace.rs

Lines changed: 153 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -6,68 +6,117 @@ use libc::{self, c_void, c_long, siginfo_t};
66
use ::unistd::Pid;
77
use sys::signal::Signal;
88

9-
pub mod ptrace {
10-
use libc::c_int;
11-
12-
cfg_if! {
13-
if #[cfg(any(all(target_os = "linux", arch = "s390x"),
14-
all(target_os = "linux", target_env = "gnu")))] {
15-
pub type PtraceRequest = ::libc::c_uint;
16-
} else {
17-
pub type PtraceRequest = c_int;
18-
}
9+
10+
cfg_if! {
11+
if #[cfg(any(all(target_os = "linux", arch = "s390x"),
12+
all(target_os = "linux", target_env = "gnu")))] {
13+
#[doc(hidden)]
14+
pub type RequestType = ::libc::c_uint;
15+
} else {
16+
#[doc(hidden)]
17+
pub type RequestType = ::libc::c_int;
18+
}
19+
}
20+
21+
libc_enum!{
22+
#[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
23+
#[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
24+
/// Ptrace Request enum defining the action to be taken.
25+
pub enum Request {
26+
PTRACE_TRACEME,
27+
PTRACE_PEEKTEXT,
28+
PTRACE_PEEKDATA,
29+
PTRACE_PEEKUSER,
30+
PTRACE_POKETEXT,
31+
PTRACE_POKEDATA,
32+
PTRACE_POKEUSER,
33+
PTRACE_CONT,
34+
PTRACE_KILL,
35+
PTRACE_SINGLESTEP,
36+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
37+
PTRACE_GETREGS,
38+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
39+
PTRACE_SETREGS,
40+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
41+
PTRACE_GETFPREGS,
42+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
43+
PTRACE_SETFPREGS,
44+
PTRACE_ATTACH,
45+
PTRACE_DETACH,
46+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64"), not(target_os = "android")))]
47+
PTRACE_GETFPXREGS,
48+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64"), not(target_os = "android")))]
49+
PTRACE_SETFPXREGS,
50+
PTRACE_SYSCALL,
51+
PTRACE_SETOPTIONS,
52+
PTRACE_GETEVENTMSG,
53+
PTRACE_GETSIGINFO,
54+
PTRACE_SETSIGINFO,
55+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
56+
PTRACE_GETREGSET,
57+
#[cfg(all(any(target_env = "musl", target_arch ="x86_64", target_arch = "s390x"), not(target_os = "android")))]
58+
PTRACE_SETREGSET,
59+
#[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))]
60+
PTRACE_SEIZE,
61+
#[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))]
62+
PTRACE_INTERRUPT,
63+
#[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))]
64+
PTRACE_LISTEN,
65+
#[cfg(not(any(target_os = "android", target_arch = "mips", target_arch = "mips64")))]
66+
PTRACE_PEEKSIGINFO,
67+
}
68+
}
69+
70+
libc_enum!{
71+
#[repr(i32)]
72+
/// Using the ptrace options the tracer can configure the tracee to stop
73+
/// at certain events. This enum is used to define those events as defined
74+
/// in `man ptrace`.
75+
pub enum Event {
76+
/// Event that stops before a return from fork or clone.
77+
PTRACE_EVENT_FORK,
78+
/// Event that stops before a return from vfork or clone.
79+
PTRACE_EVENT_VFORK,
80+
/// Event that stops before a return from clone.
81+
PTRACE_EVENT_CLONE,
82+
/// Event that stops before a return from execve.
83+
PTRACE_EVENT_EXEC,
84+
/// Event for a return from vfork.
85+
PTRACE_EVENT_VFORK_DONE,
86+
/// Event for a stop before an exit. Unlike the waitpid Exit status program.
87+
/// registers can still be examined
88+
PTRACE_EVENT_EXIT,
89+
/// STop triggered by a seccomp rule on a tracee.
90+
PTRACE_EVENT_SECCOMP,
91+
// PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
1992
}
93+
}
2094

21-
pub const PTRACE_TRACEME: PtraceRequest = 0;
22-
pub const PTRACE_PEEKTEXT: PtraceRequest = 1;
23-
pub const PTRACE_PEEKDATA: PtraceRequest = 2;
24-
pub const PTRACE_PEEKUSER: PtraceRequest = 3;
25-
pub const PTRACE_POKETEXT: PtraceRequest = 4;
26-
pub const PTRACE_POKEDATA: PtraceRequest = 5;
27-
pub const PTRACE_POKEUSER: PtraceRequest = 6;
28-
pub const PTRACE_CONT: PtraceRequest = 7;
29-
pub const PTRACE_KILL: PtraceRequest = 8;
30-
pub const PTRACE_SINGLESTEP: PtraceRequest = 9;
31-
pub const PTRACE_GETREGS: PtraceRequest = 12;
32-
pub const PTRACE_SETREGS: PtraceRequest = 13;
33-
pub const PTRACE_GETFPREGS: PtraceRequest = 14;
34-
pub const PTRACE_SETFPREGS: PtraceRequest = 15;
35-
pub const PTRACE_ATTACH: PtraceRequest = 16;
36-
pub const PTRACE_DETACH: PtraceRequest = 17;
37-
pub const PTRACE_GETFPXREGS: PtraceRequest = 18;
38-
pub const PTRACE_SETFPXREGS: PtraceRequest = 19;
39-
pub const PTRACE_SYSCALL: PtraceRequest = 24;
40-
pub const PTRACE_SETOPTIONS: PtraceRequest = 0x4200;
41-
pub const PTRACE_GETEVENTMSG: PtraceRequest = 0x4201;
42-
pub const PTRACE_GETSIGINFO: PtraceRequest = 0x4202;
43-
pub const PTRACE_SETSIGINFO: PtraceRequest = 0x4203;
44-
pub const PTRACE_GETREGSET: PtraceRequest = 0x4204;
45-
pub const PTRACE_SETREGSET: PtraceRequest = 0x4205;
46-
pub const PTRACE_SEIZE: PtraceRequest = 0x4206;
47-
pub const PTRACE_INTERRUPT: PtraceRequest = 0x4207;
48-
pub const PTRACE_LISTEN: PtraceRequest = 0x4208;
49-
pub const PTRACE_PEEKSIGINFO: PtraceRequest = 0x4209;
50-
51-
pub type PtraceEvent = c_int;
52-
53-
pub const PTRACE_EVENT_FORK: PtraceEvent = 1;
54-
pub const PTRACE_EVENT_VFORK: PtraceEvent = 2;
55-
pub const PTRACE_EVENT_CLONE: PtraceEvent = 3;
56-
pub const PTRACE_EVENT_EXEC: PtraceEvent = 4;
57-
pub const PTRACE_EVENT_VFORK_DONE: PtraceEvent = 5;
58-
pub const PTRACE_EVENT_EXIT: PtraceEvent = 6;
59-
pub const PTRACE_EVENT_SECCOMP: PtraceEvent = 6;
60-
pub const PTRACE_EVENT_STOP: PtraceEvent = 128;
61-
62-
pub type PtraceOptions = c_int;
63-
pub const PTRACE_O_TRACESYSGOOD: PtraceOptions = 1;
64-
pub const PTRACE_O_TRACEFORK: PtraceOptions = (1 << PTRACE_EVENT_FORK);
65-
pub const PTRACE_O_TRACEVFORK: PtraceOptions = (1 << PTRACE_EVENT_VFORK);
66-
pub const PTRACE_O_TRACECLONE: PtraceOptions = (1 << PTRACE_EVENT_CLONE);
67-
pub const PTRACE_O_TRACEEXEC: PtraceOptions = (1 << PTRACE_EVENT_EXEC);
68-
pub const PTRACE_O_TRACEVFORKDONE: PtraceOptions = (1 << PTRACE_EVENT_VFORK_DONE);
69-
pub const PTRACE_O_TRACEEXIT: PtraceOptions = (1 << PTRACE_EVENT_EXIT);
70-
pub const PTRACE_O_TRACESECCOMP: PtraceOptions = (1 << PTRACE_EVENT_SECCOMP);
95+
libc_bitflags! {
96+
/// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
97+
/// See `man ptrace` for more details.
98+
pub struct Options: libc::c_int {
99+
/// When delivering system call traps set a bit to allow tracer to
100+
/// distinguish between normal stops or syscall stops. May not work on
101+
/// all systems.
102+
PTRACE_O_TRACESYSGOOD;
103+
/// Stop tracee at next fork and start tracing the forked process.
104+
PTRACE_O_TRACEFORK;
105+
/// Stop tracee at next vfork call and trace the vforked process.
106+
PTRACE_O_TRACEVFORK;
107+
/// Stop tracee at next clone call and trace the cloned process.
108+
PTRACE_O_TRACECLONE;
109+
/// Stop tracee at next execve call.
110+
PTRACE_O_TRACEEXEC;
111+
/// Stop tracee at vfork completion.
112+
PTRACE_O_TRACEVFORKDONE;
113+
/// Stop tracee at next exit call. Stops before exit commences allowing
114+
/// tracer to see location of exit and register states.
115+
PTRACE_O_TRACEEXIT;
116+
/// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
117+
/// details.
118+
PTRACE_O_TRACESECCOMP;
119+
}
71120
}
72121

73122
/// Performs a ptrace request. If the request in question is provided by a specialised function
@@ -76,20 +125,19 @@ pub mod ptrace {
76125
since="0.10.0",
77126
note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
78127
)]
79-
pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
80-
use self::ptrace::*;
81-
128+
pub unsafe fn ptrace(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
129+
use self::Request::*;
82130
match request {
83131
PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_PEEKUSER => ptrace_peek(request, pid, addr, data),
84132
PTRACE_GETSIGINFO | PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS => Err(Error::UnsupportedOperation),
85133
_ => ptrace_other(request, pid, addr, data)
86134
}
87135
}
88136

89-
fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
137+
fn ptrace_peek(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
90138
let ret = unsafe {
91139
Errno::clear();
92-
libc::ptrace(request, libc::pid_t::from(pid), addr, data)
140+
libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
93141
};
94142
match Errno::result(ret) {
95143
Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
@@ -101,45 +149,54 @@ fn ptrace_peek(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data
101149
/// Some ptrace get requests populate structs or larger elements than c_long
102150
/// and therefore use the data field to return values. This function handles these
103151
/// requests.
104-
fn ptrace_get_data<T>(request: ptrace::PtraceRequest, pid: Pid) -> Result<T> {
152+
fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
105153
// Creates an uninitialized pointer to store result in
106154
let data: T = unsafe { mem::uninitialized() };
107-
let res = unsafe { libc::ptrace(request, libc::pid_t::from(pid), ptr::null_mut::<T>(), &data as *const _ as *const c_void) };
155+
let res = unsafe {
156+
libc::ptrace(request as RequestType,
157+
libc::pid_t::from(pid),
158+
ptr::null_mut::<T>(),
159+
&data as *const _ as *const c_void)
160+
};
108161
Errno::result(res)?;
109162
Ok(data)
110163
}
111164

112-
unsafe fn ptrace_other(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
113-
Errno::result(libc::ptrace(request, libc::pid_t::from(pid), addr, data)).map(|_| 0)
165+
unsafe fn ptrace_other(request: Request, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
166+
Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
114167
}
115168

116169
/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
117-
pub fn setoptions(pid: Pid, options: ptrace::PtraceOptions) -> Result<()> {
118-
use self::ptrace::*;
170+
pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
119171
use std::ptr;
120172

121-
let res = unsafe { libc::ptrace(PTRACE_SETOPTIONS, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), options as *mut c_void) };
173+
let res = unsafe {
174+
libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
175+
libc::pid_t::from(pid),
176+
ptr::null_mut::<libc::c_void>(),
177+
options.bits() as *mut c_void)
178+
};
122179
Errno::result(res).map(|_| ())
123180
}
124181

125182
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
126183
pub fn getevent(pid: Pid) -> Result<c_long> {
127-
use self::ptrace::*;
128-
ptrace_get_data::<c_long>(PTRACE_GETEVENTMSG, pid)
184+
ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
129185
}
130186

131187
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
132188
pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
133-
use self::ptrace::*;
134-
ptrace_get_data::<siginfo_t>(PTRACE_GETSIGINFO, pid)
189+
ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
135190
}
136191

137192
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
138193
pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
139-
use self::ptrace::*;
140194
let ret = unsafe{
141195
Errno::clear();
142-
libc::ptrace(PTRACE_SETSIGINFO, libc::pid_t::from(pid), ptr::null_mut::<libc::c_void>(), sig as *const _ as *const c_void)
196+
libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
197+
libc::pid_t::from(pid),
198+
ptr::null_mut::<libc::c_void>(),
199+
sig as *const _ as *const c_void)
143200
};
144201
match Errno::result(ret) {
145202
Ok(_) => Ok(()),
@@ -154,7 +211,7 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
154211
pub fn traceme() -> Result<()> {
155212
unsafe {
156213
ptrace_other(
157-
ptrace::PTRACE_TRACEME,
214+
Request::PTRACE_TRACEME,
158215
Pid::from_raw(0),
159216
ptr::null_mut(),
160217
ptr::null_mut(),
@@ -168,7 +225,7 @@ pub fn traceme() -> Result<()> {
168225
pub fn syscall(pid: Pid) -> Result<()> {
169226
unsafe {
170227
ptrace_other(
171-
ptrace::PTRACE_SYSCALL,
228+
Request::PTRACE_SYSCALL,
172229
pid,
173230
ptr::null_mut(),
174231
ptr::null_mut(),
@@ -182,14 +239,28 @@ pub fn syscall(pid: Pid) -> Result<()> {
182239
pub fn attach(pid: Pid) -> Result<()> {
183240
unsafe {
184241
ptrace_other(
185-
ptrace::PTRACE_ATTACH,
242+
Request::PTRACE_ATTACH,
186243
pid,
187244
ptr::null_mut(),
188245
ptr::null_mut(),
189246
).map(|_| ()) // ignore the useless return value
190247
}
191248
}
192249

250+
/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
251+
///
252+
/// Detaches from the process specified in pid allowing it to run freely
253+
pub fn detach(pid: Pid) -> Result<()> {
254+
unsafe {
255+
ptrace_other(
256+
Request::PTRACE_DETACH,
257+
pid,
258+
ptr::null_mut(),
259+
ptr::null_mut()
260+
).map(|_| ())
261+
}
262+
}
263+
193264
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
194265
///
195266
/// Continues the execution of the process with PID `pid`, optionally
@@ -200,7 +271,7 @@ pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
200271
None => ptr::null_mut(),
201272
};
202273
unsafe {
203-
ptrace_other(ptrace::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value
274+
ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(|_| ()) // ignore the useless return value
204275
}
205276
}
206277

test/sys/test_ptrace.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ fn test_ptrace() {
1616
// Just make sure ptrace_setoptions can be called at all, for now.
1717
#[test]
1818
fn test_ptrace_setoptions() {
19-
use nix::sys::ptrace::ptrace::PTRACE_O_TRACESYSGOOD;
20-
let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err();
19+
let err = ptrace::setoptions(getpid(), ptrace::PTRACE_O_TRACESYSGOOD).unwrap_err();
2120
assert!(err != Error::UnsupportedOperation);
2221
}
2322

test/sys/test_wait.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn test_waitstatus_pid() {
5555
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
5656
mod ptrace {
5757
use nix::sys::ptrace;
58-
use nix::sys::ptrace::ptrace::*;
58+
use nix::sys::ptrace::*;
5959
use nix::sys::signal::*;
6060
use nix::sys::wait::*;
6161
use nix::unistd::*;
@@ -81,7 +81,7 @@ mod ptrace {
8181
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
8282
// Then get the ptrace event for the process exiting
8383
assert!(ptrace::cont(child, None).is_ok());
84-
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, PTRACE_EVENT_EXIT)));
84+
assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)));
8585
// Finally get the normal wait() result, now that the process has exited
8686
assert!(ptrace::cont(child, None).is_ok());
8787
assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));

0 commit comments

Comments
 (0)