in reverie-ptrace/src/trace/memory.rs [124:159]
fn read<'a, A>(&self, addr: A, buf: &mut [u8]) -> Result<usize, Errno>
where
A: Into<Addr<'a, u8>>,
{
let addr = addr.into();
let size = buf.len();
if size == 0 {
return Ok(0);
} else if size <= mem::size_of::<u64>() {
// This needs to be benchmarked, but according to @wangbj
// PTRACE_PEEKDATA is faster than `process_vm_readv` for small
// reads.
let value = self.read_u64(addr.cast::<u64>())?;
let bytes = value.to_ne_bytes();
buf.copy_from_slice(&bytes[0..size]);
return Ok(size);
}
let addr_slice = unsafe { AddrSlice::from_raw_parts(addr, buf.len()) };
// Since process_vm_readv partial transfers apply at the granularity of
// the iovec elements, we need to know if the address range spans a page
// boundary and split the remote read if it does. This helps ensure that
// we get a read length >0 while there is still more data to read.
if let Some((first, second)) = addr_slice.split_at_page_boundary() {
let remote = unsafe { [first.as_ioslice(), second.as_ioslice()] };
// The two remote reads are merged into a single local buffer.
let mut local = [io::IoSliceMut::new(buf)];
self.read_vectored(&remote, &mut local)
} else {
// The address range fits into one page. Nothing special to do.
self.read_aligned(addr, buf)
}
}