//! For detailed description of the ptrace requests, consult `man ptrace`.
usecrate::errno::Errno; usecrate::sys::signal::Signal; usecrate::unistd::Pid; usecrate::Result; use cfg_if::cfg_if; use libc::{self, c_long, c_void, siginfo_t}; use std::{mem, ptr};
libc_enum! { #[repr(i32)] /// Using the ptrace options the tracer can configure the tracee to stop /// at certain events. This enum is used to define those events as defined /// in `man ptrace`. #[non_exhaustive] pubenum Event { /// Event that stops before a return from fork or clone.
PTRACE_EVENT_FORK, /// Event that stops before a return from vfork or clone.
PTRACE_EVENT_VFORK, /// Event that stops before a return from clone.
PTRACE_EVENT_CLONE, /// Event that stops before a return from execve.
PTRACE_EVENT_EXEC, /// Event for a return from vfork.
PTRACE_EVENT_VFORK_DONE, /// Event for a stop before an exit. Unlike the waitpid Exit status program. /// registers can still be examined
PTRACE_EVENT_EXIT, /// Stop triggered by a seccomp rule on a tracee.
PTRACE_EVENT_SECCOMP, /// Stop triggered by the `INTERRUPT` syscall, or a group stop, /// or when a new child is attached.
PTRACE_EVENT_STOP,
}
}
#[cfg(all(
target_os = "linux",
target_env = "gnu",
any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "aarch64",
target_arch = "riscv64",
)
))]
libc_enum! { #[repr(i32)] /// Defines a specific register set, as used in `PTRACE_GETREGSET` and `PTRACE_SETREGSET`. #[non_exhaustive] pubenum RegisterSetValue {
NT_PRSTATUS,
NT_PRFPREG,
NT_PRPSINFO,
NT_TASKSTRUCT,
NT_AUXV,
}
}
#[cfg(all(
target_os = "linux",
target_env = "gnu",
any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "aarch64",
target_arch = "riscv64",
)
))] /// Represents register set areas, such as general-purpose registers or /// floating-point registers. /// /// # Safety /// /// This trait is marked unsafe, since implementation of the trait must match /// ptrace's request `VALUE` and return data type `Regs`. pubunsafetrait RegisterSet { /// Corresponding type of registers in the kernel. const VALUE: RegisterSetValue;
/// Struct representing the register space. type Regs;
}
unsafeimpl RegisterSet for NT_PRFPREG { const VALUE: RegisterSetValue = RegisterSetValue::NT_PRFPREG; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] type Regs = libc::user_fpregs_struct; #[cfg(target_arch = "aarch64")] type Regs = libc::user_fpsimd_struct; #[cfg(target_arch = "riscv64")] type Regs = libc::__riscv_mc_d_ext_state;
}
}
libc_bitflags! { /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request. /// See `man ptrace` for more details. pubstruct Options: libc::c_int { /// When delivering system call traps set a bit to allow tracer to /// distinguish between normal stops or syscall stops. May not work on /// all systems.
PTRACE_O_TRACESYSGOOD; /// Stop tracee at next fork and start tracing the forked process.
PTRACE_O_TRACEFORK; /// Stop tracee at next vfork call and trace the vforked process.
PTRACE_O_TRACEVFORK; /// Stop tracee at next clone call and trace the cloned process.
PTRACE_O_TRACECLONE; /// Stop tracee at next execve call.
PTRACE_O_TRACEEXEC; /// Stop tracee at vfork completion.
PTRACE_O_TRACEVFORKDONE; /// Stop tracee at next exit call. Stops before exit commences allowing /// tracer to see location of exit and register states.
PTRACE_O_TRACEEXIT; /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more /// details.
PTRACE_O_TRACESECCOMP; /// Send a SIGKILL to the tracee if the tracer exits. This is useful /// for ptrace jailers to prevent tracees from escaping their control.
PTRACE_O_EXITKILL;
}
}
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` /// /// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]), /// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect /// on aarch64 and riscv64. /// /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(all(
target_os = "linux",
any(
all(
target_arch = "x86_64",
any(target_env = "gnu", target_env = "musl")
),
all(target_arch = "x86", target_env = "gnu")
)
))] pubfn getregs(pid: Pid) -> Result<user_regs_struct> {
ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
}
/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)` /// /// Note that since `PTRACE_GETREGS` are not available on all platforms (as in [ptrace(2)]), /// `ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect /// on aarch64 and riscv64. /// /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(target_arch = "aarch64", target_arch = "riscv64")
))] pubfn getregs(pid: Pid) -> Result<user_regs_struct> {
getregset::<regset::NT_PRSTATUS>(pid)
}
/// Get a particular set of user registers, as with `ptrace(PTRACE_GETREGSET, ...)` #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "aarch64",
target_arch = "riscv64",
)
))] pubfn getregset<S: RegisterSet>(pid: Pid) -> Result<S::Regs> { let request = Request::PTRACE_GETREGSET; letmut data = mem::MaybeUninit::<S::Regs>::uninit(); letmut iov = libc::iovec {
iov_base: data.as_mut_ptr().cast(),
iov_len: mem::size_of::<S::Regs>(),
}; unsafe {
ptrace_other(
request,
pid,
S::VALUE as i32 as AddressType,
(&mut iov as *mut libc::iovec).cast(),
)?;
};
Ok(unsafe { data.assume_init() })
}
/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` /// /// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]), /// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect /// on aarch64 and riscv64. /// /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(all(
target_os = "linux",
any(
all(
target_arch = "x86_64",
any(target_env = "gnu", target_env = "musl")
),
all(target_arch = "x86", target_env = "gnu")
)
))] pubfn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> { let res = unsafe {
libc::ptrace(
Request::PTRACE_SETREGS as RequestType,
libc::pid_t::from(pid),
ptr::null_mut::<c_void>(),
®s as *const user_regs_struct as *const c_void,
)
};
Errno::result(res).map(drop)
}
/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)` /// /// Note that since `PTRACE_SETREGS` are not available on all platforms (as in [ptrace(2)]), /// `ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, ...)` is used instead to achieve the same effect /// on aarch64 and riscv64. /// /// [ptrace(2)]: https://www.man7.org/linux/man-pages/man2/ptrace.2.html #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(target_arch = "aarch64", target_arch = "riscv64")
))] pubfn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
setregset::<regset::NT_PRSTATUS>(pid, regs)
}
/// Set a particular set of user registers, as with `ptrace(PTRACE_SETREGSET, ...)` #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(
target_arch = "x86_64",
target_arch = "x86",
target_arch = "aarch64",
target_arch = "riscv64",
)
))] pubfn setregset<S: RegisterSet>(pid: Pid, mut regs: S::Regs) -> Result<()> { letmut iov = libc::iovec {
iov_base: (&mut regs as *mut S::Regs).cast(),
iov_len: mem::size_of::<S::Regs>(),
}; unsafe {
ptrace_other(
Request::PTRACE_SETREGSET,
pid,
S::VALUE as i32 as AddressType,
(&mut iov as *mut libc::iovec).cast(),
)?;
}
Ok(())
}
/// Function for ptrace requests that return values from the data field. /// Some ptrace get requests populate structs or larger elements than `c_long` /// and therefore use the data field to return values. This function handles these /// requests. fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> { letmut data = mem::MaybeUninit::<T>::uninit(); let res = unsafe {
libc::ptrace(
request as RequestType,
libc::pid_t::from(pid),
ptr::null_mut::<T>(),
data.as_mut_ptr(),
)
};
Errno::result(res)?;
Ok(unsafe { data.assume_init() })
}
/// Set options, as with `ptrace(PTRACE_SETOPTIONS, ...)`. pubfn setoptions(pid: Pid, options: Options) -> Result<()> { let res = unsafe {
libc::ptrace(
Request::PTRACE_SETOPTIONS as RequestType,
libc::pid_t::from(pid),
ptr::null_mut::<c_void>(),
options.bits() as *mut c_void,
)
};
Errno::result(res).map(drop)
}
/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG, ...)` pubfn getevent(pid: Pid) -> Result<c_long> {
ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
}
/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO, ...)` pubfn getsiginfo(pid: Pid) -> Result<siginfo_t> {
ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
}
/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO, ...)` pubfn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> { let ret = unsafe {
Errno::clear();
libc::ptrace(
Request::PTRACE_SETSIGINFO as RequestType,
libc::pid_t::from(pid),
ptr::null_mut::<c_void>(),
sig as *const _ as *const c_void,
)
}; match Errno::result(ret) {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)` /// /// Indicates that this process is to be traced by its parent. /// This is the only ptrace request to be issued by the tracee. pubfn traceme() -> Result<()> { unsafe {
ptrace_other(
Request::PTRACE_TRACEME,
Pid::from_raw(0),
ptr::null_mut(),
ptr::null_mut(),
)
.map(drop) // ignore the useless return value
}
}
/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)` /// /// Arranges for the tracee to be stopped at the next entry to or exit from a system call, /// optionally delivering a signal specified by `sig`. pubfn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(Request::PTRACE_SYSCALL, pid, ptr::null_mut(), data)
.map(drop) // ignore the useless return value
}
}
/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)` /// /// In contrast to the `syscall` function, the syscall stopped at will not be executed. /// Thus the the tracee will only be stopped once per syscall, /// optionally delivering a signal specified by `sig`. #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(target_arch = "x86", target_arch = "x86_64")
))] pubfn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data)
.map(drop) // ignore the useless return value
}
}
/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)` /// /// Attaches to the process specified by `pid`, making it a tracee of the calling process. pubfn attach(pid: Pid) -> Result<()> { unsafe {
ptrace_other(
Request::PTRACE_ATTACH,
pid,
ptr::null_mut(),
ptr::null_mut(),
)
.map(drop) // ignore the useless return value
}
}
/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)` /// /// Attaches to the process specified in pid, making it a tracee of the calling process. #[cfg(target_os = "linux")] pubfn seize(pid: Pid, options: Options) -> Result<()> { unsafe {
ptrace_other(
Request::PTRACE_SEIZE,
pid,
ptr::null_mut(),
options.bits() as *mut c_void,
)
.map(drop) // ignore the useless return value
}
}
/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)` /// /// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a /// signal specified by `sig`. pubfn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(Request::PTRACE_DETACH, pid, ptr::null_mut(), data)
.map(drop)
}
}
/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)` /// /// Continues the execution of the process with PID `pid`, optionally /// delivering a signal specified by `sig`. pubfn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
}
}
/// Stop a tracee, as with `ptrace(PTRACE_INTERRUPT, ...)` /// /// This request is equivalent to `ptrace(PTRACE_INTERRUPT, ...)` #[cfg(target_os = "linux")] pubfn interrupt(pid: Pid) -> Result<()> { unsafe {
ptrace_other(
Request::PTRACE_INTERRUPT,
pid,
ptr::null_mut(),
ptr::null_mut(),
)
.map(drop)
}
}
/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)` /// /// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);` pubfn kill(pid: Pid) -> Result<()> { unsafe {
ptrace_other(
Request::PTRACE_KILL,
pid,
ptr::null_mut(),
ptr::null_mut(),
)
.map(drop)
}
}
/// Move the stopped tracee process forward by a single step as with /// `ptrace(PTRACE_SINGLESTEP, ...)` /// /// Advances the execution of the process with PID `pid` by a single step optionally delivering a /// signal specified by `sig`. /// /// # Example /// ```rust /// use nix::sys::ptrace::step; /// use nix::unistd::Pid; /// use nix::sys::signal::Signal; /// use nix::sys::wait::*; /// /// // If a process changes state to the stopped state because of a SIGUSR1 /// // signal, this will step the process forward and forward the user /// // signal to the stopped process /// match waitpid(Pid::from_raw(-1), None) { /// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => { /// let _ = step(pid, Signal::SIGUSR1); /// } /// _ => {}, /// } /// ``` pubfn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data)
.map(drop)
}
}
/// Move the stopped tracee process forward by a single step or stop at the next syscall /// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)` /// /// Advances the execution by a single step or until the next syscall. /// In case the tracee is stopped at a syscall, the syscall will not be executed. /// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation. #[cfg(all(
target_os = "linux",
target_env = "gnu",
any(target_arch = "x86", target_arch = "x86_64")
))] pubfn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> { let data = match sig.into() {
Some(s) => s as i32 as *mut c_void,
None => ptr::null_mut(),
}; unsafe {
ptrace_other(
Request::PTRACE_SYSEMU_SINGLESTEP,
pid,
ptr::null_mut(),
data,
)
.map(drop) // ignore the useless return value
}
}
/// Reads a word from a processes memory at the given address, as with /// ptrace(PTRACE_PEEKDATA, ...) pubfn read(pid: Pid, addr: AddressType) -> Result<c_long> {
ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
}
/// Writes a word into the processes memory at the given address, as with /// ptrace(PTRACE_POKEDATA, ...) #[allow(clippy::not_unsafe_ptr_arg_deref)] pubfn write(pid: Pid, addr: AddressType, data: c_long) -> Result<()> { unsafe { // Safety(not_unsafe_ptr_arg_deref): // `ptrace_other` is a common abstract // but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data as *mut c_void)
.map(drop)
}
}
/// Reads a word from a user area at `offset`, as with ptrace(PTRACE_PEEKUSER, ...). /// The user struct definition can be found in `/usr/include/sys/user.h`. pubfn read_user(pid: Pid, offset: AddressType) -> Result<c_long> {
ptrace_peek(Request::PTRACE_PEEKUSER, pid, offset, ptr::null_mut())
}
/// Writes a word to a user area at `offset`, as with ptrace(PTRACE_POKEUSER, ...). /// The user struct definition can be found in `/usr/include/sys/user.h`. #[allow(clippy::not_unsafe_ptr_arg_deref)] pubfn write_user(pid: Pid, offset: AddressType, data: c_long) -> Result<()> { unsafe { // Safety(not_unsafe_ptr_arg_deref): // `ptrace_other` is a common abstract // but in `PTRACE_POKEDATA` situation, `data` is exactly what will be wtitten
ptrace_other(Request::PTRACE_POKEUSER, pid, offset, data as *mut c_void)
.map(drop)
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-20)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.