Skip to main content

ProcessReader

Struct ProcessReader 

Source
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

Source

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:

  1. process_vm_readv(2)
  2. /proc/<pid>/mem
  3. ptrace(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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl Debug for ProcessReader

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.