pub struct ProcessReader { /* private fields */ }Expand description
Reads raw bytes from another Linux or Android process.
A ProcessReader is bound to a single target process ID. It can either
choose a read strategy automatically with ProcessReader::new, or be
constructed with a fixed strategy using ProcessReader::for_virtual_mem,
ProcessReader::for_file, or ProcessReader::for_ptrace.
The type does not interpret the bytes it reads. It only copies bytes from the target process into the caller’s buffer and reports how many bytes were copied.
§Process state and permissions
The operating system still enforces the usual Linux/Android access checks. Depending on the chosen strategy, the caller may need suitable ptrace-style permissions, ownership, dumpability, capabilities, or an already-stopped tracee.
ProcessReader does not suspend the target process, attach to it, detach from
it, or otherwise manage target process lifetime. It also does not provide a
consistent snapshot if the target process mutates memory while it is being
read.
Implementations§
Source§impl ProcessReader
impl ProcessReader
Sourcepub fn new(pid: pid_t) -> Self
pub fn new(pid: pid_t) -> Self
Creates a reader that automatically chooses a process-memory read strategy.
The first non-empty call to read_at tries the supported
strategies in this order:
process_vm_readv(2)/proc/<pid>/memptrace(PTRACE_PEEKDATA)
The first strategy that returns Ok(_) is cached and used for all
subsequent reads through this ProcessReader. A successful read may be
shorter than the requested buffer; a short successful read still selects
the strategy. Subsequent reads do not fall back to another strategy if the
cached strategy fails.
Empty reads succeed immediately, return Ok(0), and do not select a
strategy.
§Panics
Panics if pid < 0. Passing a negative PID is treated as a caller logic
error.
Sourcepub fn for_virtual_mem(pid: pid_t) -> Self
pub fn for_virtual_mem(pid: pid_t) -> Self
Creates a reader pinned to the process_vm_readv(2) strategy.
Reads performed through the returned reader use only process_vm_readv.
They do not fall back to /proc/<pid>/mem or ptrace.
This is generally the fastest strategy when the kernel permits it. It can
also return a short successful read if process_vm_readv transfers fewer
bytes than requested.
§Panics
Panics if pid < 0. Passing a negative PID is treated as a caller logic
error.
Sourcepub fn for_file(pid: pid_t) -> Result<Self, ReadError>
pub fn for_file(pid: pid_t) -> Result<Self, ReadError>
Creates a reader pinned to the /proc/<pid>/mem strategy.
This constructor opens /proc/<pid>/mem immediately and keeps the file
descriptor open for the lifetime of the returned reader. Reads performed
through the returned reader use only that file descriptor and do not fall
back to process_vm_readv or ptrace.
This strategy currently attempts to fill the whole requested buffer. On
success, read_at returns Ok(buf.len()). If the file
read fails or reaches EOF before the buffer is filled, read_at returns an
error, and the buffer may have been partially overwritten.
§Errors
Returns ReadError if /proc/<pid>/mem could not be opened.
§Panics
Panics if pid < 0. Passing a negative PID is treated as a caller logic
error.
Sourcepub fn for_ptrace(pid: pid_t) -> Self
pub fn for_ptrace(pid: pid_t) -> Self
Creates a reader pinned to the ptrace(PTRACE_PEEKDATA) strategy.
Reads performed through the returned reader use only
ptrace(PTRACE_PEEKDATA). They do not fall back to process_vm_readv or
/proc/<pid>/mem.
This constructor does not call PTRACE_ATTACH, PTRACE_SEIZE,
waitpid, PTRACE_CONT, or PTRACE_DETACH. The caller must arrange any
required ptrace relationship and stopped tracee state before reading.
The requested address does not need to be word-aligned; the implementation
performs aligned PTRACE_PEEKDATA reads internally and copies the requested
byte range out of those words.
This strategy currently attempts to fill the whole requested buffer. On
success, read_at returns Ok(buf.len()). If a ptrace
read fails before the buffer is filled, read_at returns an error, and the
buffer may have been partially overwritten.
§Panics
Panics if pid < 0. Passing a negative PID is treated as a caller logic
error.
Sourcepub fn read_exact_at(
&self,
address: usize,
buf: &mut [u8],
) -> Result<(), ReadExactError>
pub fn read_exact_at( &self, address: usize, buf: &mut [u8], ) -> Result<(), ReadExactError>
Reads from another process until buf is completely filled.
This is a convenience wrapper around ProcessReader::read_at. Unlike
read_at, this method does not return successful short
reads. It repeatedly calls read_at, advancing address
and the output buffer by the number of bytes read, until the entire buffer
has been filled.
If an underlying read fails before the buffer is filled, this method returns
ReadExactError::Read. If an underlying read succeeds but returns 0
bytes before the buffer is filled, this method returns
ReadExactError::UnexpectedEof.
On success, all of buf has been filled with bytes read from the target
process.
§Strategy selection
This method uses ProcessReader::read_at internally, so it follows the
same strategy-selection rules. In particular, a reader created with
ProcessReader::new caches the first strategy that succeeds for a
non-empty read, even if that read is short. Later reads performed by this
method continue using the selected strategy.
§Errors
Returns ReadExactError::Read if read_at returns an
error before the buffer is full.
Returns ReadExactError::UnexpectedEof if read_at
returns Ok(0) before the buffer is full. A zero-length successful read is
treated as an exact-read failure because this method could not make forward
progress.
If this method returns an error, buf may have been partially overwritten.
This error type does not report how many bytes were read before the failure.
§Panics
Panics if a successful partial read leaves bytes remaining in buf, but
advancing the read address by the number of bytes read would wrap past the
end of the address space.
Sourcepub fn read_at(
&self,
address: usize,
buf: &mut [u8],
) -> Result<usize, ReadError>
pub fn read_at( &self, address: usize, buf: &mut [u8], ) -> Result<usize, ReadError>
Attempts to read bytes from the target process at address.
This method copies bytes from address in the target process into buf
and returns the number of bytes copied. The returned length is in the
range 0..=buf.len() and may be smaller than buf.len(). A short
successful read is returned as Ok(n), not as an error, and callers should
only interpret buf[..n] as bytes read by this call.
If buf is empty, this method returns Ok(0) without performing a system
call and without selecting a strategy for readers created with
ProcessReader::new.
The address is a virtual address in the target process, not in the
calling process.
§Strategy behavior
For readers created with ProcessReader::new, the first Ok(_) from a
non-empty read request selects a strategy for the reader. A successful
read may be shorter than the requested buffer, and a short successful read
still selects the strategy. Future reads use that selected strategy only.
Readers created with ProcessReader::for_virtual_mem,
ProcessReader::for_file, or ProcessReader::for_ptrace always use
only the requested strategy.
The process_vm_readv(2) strategy returns the byte count reported by
process_vm_readv. The /proc/<pid>/mem and ptrace(PTRACE_PEEKDATA)
strategies currently attempt to fill the whole buffer and return
Ok(buf.len()) on success.
§Errors
Returns ReadError if the selected strategy reports an error, or if
automatic strategy selection cannot get any strategy to return success.
A failed read may have partially overwritten buf, and the error does not
report how many bytes were copied before the failure. Callers should not
rely on the contents of buf after an error.