shadow_rs/host/memory_manager/
memory_copier.rs1use std::fmt::Debug;
2
3use linux_api::errno::Errno;
4use linux_api::posix_types::Pid;
5use log::*;
6use shadow_pod::Pod;
7
8use crate::core::worker::Worker;
9use crate::host::memory_manager::page_size;
10use crate::host::syscall::types::ForeignArrayPtr;
11
12#[derive(Debug, Clone)]
14pub struct MemoryCopier {
15 pid: Pid,
16}
17
18impl MemoryCopier {
19 pub fn new(pid: Pid) -> Self {
20 Self { pid }
21 }
22
23 #[allow(clippy::uninit_vec)]
26 pub unsafe fn clone_mem<T: Pod>(&self, ptr: ForeignArrayPtr<T>) -> Result<Vec<T>, Errno> {
27 let mut v = Vec::with_capacity(ptr.len());
28 unsafe { v.set_len(v.capacity()) };
29 unsafe { self.copy_from_ptr(&mut v, ptr)? };
30 Ok(v)
31 }
32
33 #[allow(clippy::uninit_vec)]
36 pub unsafe fn clone_mem_prefix<T: Pod>(
37 &self,
38 ptr: ForeignArrayPtr<T>,
39 ) -> Result<Vec<T>, Errno> {
40 let mut v = Vec::with_capacity(ptr.len());
41 unsafe { v.set_len(v.capacity()) };
42 let copied = unsafe { self.copy_prefix_from_ptr(&mut v, ptr)? };
43 v.truncate(copied);
44 Ok(v)
45 }
46
47 pub unsafe fn copy_prefix_from_ptr<T>(
50 &self,
51 dst: &mut [T],
52 src: ForeignArrayPtr<T>,
53 ) -> Result<usize, Errno>
54 where
55 T: Pod,
56 {
57 let buf: &mut [std::mem::MaybeUninit<u8>] = unsafe { shadow_pod::to_u8_slice_mut(dst) };
60 let mut buf: &mut [u8] =
65 unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) };
66
67 let ptr = src.cast_u8();
68
69 let mut slices = Vec::with_capacity(buf.len().div_ceil(page_size()) + 1);
71 let mut total_bytes_toread = std::cmp::min(buf.len(), ptr.len());
72
73 let prev_page_boundary = usize::from(ptr.ptr()) / page_size() * page_size();
75 let next_page_boundary = prev_page_boundary + page_size();
76 let mut next_bytes_toread = std::cmp::min(
77 next_page_boundary - usize::from(ptr.ptr()),
78 total_bytes_toread,
79 );
80
81 while next_bytes_toread > 0 {
82 let (prefix, suffix) = buf.split_at_mut(next_bytes_toread);
84 buf = suffix;
85 slices.push(prefix);
86 total_bytes_toread -= next_bytes_toread;
87
88 next_bytes_toread = std::cmp::min(total_bytes_toread, page_size());
91 }
92 let bytes_read = unsafe { self.readv_ptrs(&mut slices, &[ptr])? };
93 Ok(bytes_read / std::mem::size_of::<T>())
94 }
95
96 pub unsafe fn copy_from_ptr<T: Pod>(
99 &self,
100 dst: &mut [T],
101 src: ForeignArrayPtr<T>,
102 ) -> Result<(), Errno> {
103 assert_eq!(dst.len(), src.len());
104 let buf = unsafe { shadow_pod::to_u8_slice_mut(dst) };
106 let buf: &mut [u8] =
111 unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) };
112 let ptr = src.cast_u8();
113 let bytes_read = unsafe { self.readv_ptrs(&mut [buf], &[ptr])? };
114 if bytes_read != buf.len() {
115 warn!(
116 "Tried to read {} bytes but only got {}",
117 buf.len(),
118 bytes_read
119 );
120 return Err(Errno::EFAULT);
121 }
122 Ok(())
123 }
124
125 unsafe fn readv_ptrs(
130 &self,
131 dsts: &mut [&mut [u8]],
132 srcs: &[ForeignArrayPtr<u8>],
133 ) -> Result<usize, Errno> {
134 let srcs: Vec<_> = srcs
135 .iter()
136 .map(|src| nix::sys::uio::RemoteIoVec {
137 base: usize::from(src.ptr()),
138 len: src.len(),
139 })
140 .collect();
141 let mut dsts: Vec<_> = dsts
142 .iter_mut()
143 .map(|dst: &mut &mut [u8]| -> std::io::IoSliceMut { std::io::IoSliceMut::new(dst) })
144 .collect();
145
146 unsafe { self.readv_iovecs(&mut dsts, &srcs) }
147 }
148
149 unsafe fn readv_iovecs(
154 &self,
155 dsts: &mut [std::io::IoSliceMut],
156 srcs: &[nix::sys::uio::RemoteIoVec],
157 ) -> Result<usize, Errno> {
158 trace!(
159 "Reading from srcs of len {}",
160 srcs.iter().map(|s| s.len).sum::<usize>()
161 );
162 trace!(
163 "Reading to dsts of len {}",
164 dsts.iter().map(|d| d.len()).sum::<usize>()
165 );
166
167 let tid = Worker::with_active_host(|host| {
171 Worker::with_active_process(|process| {
172 assert_eq!(process.native_pid(), self.pid);
174 let thread = process.first_live_thread_borrow(host.root()).unwrap();
175 let thread = thread.borrow(host.root());
176 thread.native_tid()
177 })
178 .unwrap()
179 })
180 .unwrap();
181
182 let nread = nix::sys::uio::process_vm_readv(
183 nix::unistd::Pid::from_raw(tid.as_raw_nonzero().get()),
184 dsts,
185 srcs,
186 )
187 .map_err(|e| Errno::try_from(e as i32).unwrap())?;
188
189 Ok(nread)
190 }
191
192 pub unsafe fn copy_to_ptr<T: Pod>(
196 &self,
197 dst: ForeignArrayPtr<T>,
198 src: &[T],
199 ) -> Result<(), Errno> {
200 let dst = dst.cast_u8();
201 let src: &[std::mem::MaybeUninit<u8>] = shadow_pod::to_u8_slice(src);
202 let src: &[u8] =
209 unsafe { std::slice::from_raw_parts(src.as_ptr() as *const u8, src.len()) };
210 assert_eq!(src.len(), dst.len());
211
212 let towrite = src.len();
213 trace!("write_ptr writing {towrite} bytes");
214 let local = [std::io::IoSlice::new(src)];
215 let remote = [nix::sys::uio::RemoteIoVec {
216 base: usize::from(dst.ptr()),
217 len: towrite,
218 }];
219
220 let tid = Worker::with_active_host(|host| {
227 Worker::with_active_process(|process| {
228 if process.native_pid() != self.pid {
229 self.pid
237 } else {
238 let thread = process.first_live_thread_borrow(host.root()).unwrap();
239 let thread = thread.borrow(host.root());
240 thread.native_tid()
241 }
242 })
243 .unwrap()
244 })
245 .unwrap();
246
247 let nwritten = nix::sys::uio::process_vm_writev(
248 nix::unistd::Pid::from_raw(tid.as_raw_nonzero().get()),
249 &local,
250 &remote,
251 )
252 .map_err(|e| Errno::try_from(e as i32).unwrap())?;
253 assert_eq!(nwritten, towrite);
255 Ok(())
256 }
257}