5252mod errors;
5353#[ cfg( test) ]
5454mod tests;
55+ mod utils;
5556
5657extern crate alloc;
5758
5859use errors:: Result ;
5960pub use errors:: { Error , ErrorKind } ;
6061
62+ use core:: cmp;
6163use core:: ffi:: c_void;
62- use core:: num:: NonZero ;
63- use core:: { cmp, slice} ;
6464use std:: io:: { IoSlice , IoSliceMut , Read , Seek , SeekFrom , Write } ;
6565use std:: os:: raw:: c_ulong;
6666use std:: { io, panic} ;
6767
68- use lazy_static:: lazy_static;
6968use smallvec:: SmallVec ;
7069
71- lazy_static ! {
72- /// Size in bytes of the smallest possible virtual memory page.
73- ///
74- /// Failure to fetch the information will result in a size
75- /// of `u64::max_value()`.
76- static ref MIN_SYSTEM_PAGE_SIZE : NonZero <u64 > =
77- match unsafe { libc:: sysconf( libc:: _SC_PAGE_SIZE) } {
78- -1 => NonZero :: <u64 >:: MAX ,
79- 0 => unsafe { NonZero :: <u64 >:: new_unchecked( 4096 ) } ,
80- result => unsafe { NonZero :: <u64 >:: new_unchecked( result as u64 ) } ,
81- } ;
82-
83- /// Maximum number of the `iovec` structures that can be provided to
84- /// one system call.
85- ///
86- /// Failure to fetch the information will result in a count of `1`.
87- static ref SYSTEM_IOV_MAX : usize =
88- match unsafe { libc:: sysconf( libc:: _SC_IOV_MAX) } {
89- -1 => 1 ,
90- result => result as usize ,
91- } ;
92- }
93-
94- /// Align a given number down to a specified alignment boundary.
95- const fn align_down ( n : u64 , alignment : NonZero < u64 > ) -> u64 {
96- // Notice that the calculation below never causes an overflow.
97- n & !alignment. get ( ) . saturating_sub ( 1 )
98- }
70+ use crate :: utils:: {
71+ align_down, ensure_process_exists, io_vectors_from_io_slices, io_vectors_from_io_slices_mut,
72+ min_system_page_size, system_iov_max,
73+ } ;
9974
10075/// Prototype of the APIs `process_vm_readv()` and `process_vm_writev()`.
10176type ProcessVMReadVProc = unsafe extern "C" fn (
@@ -124,17 +99,17 @@ struct PageAwareAddressRange {
12499impl PageAwareAddressRange {
125100 /// Convert a plain address range into an address range which is split,
126101 /// at page boundaries, over multiple sections.
127- fn new ( start_address : u64 , mut size : u64 ) -> Self {
102+ fn new ( start_address : u64 , mut size : u64 ) -> Result < Self > {
128103 if size == 0 {
129- return Self {
104+ return Ok ( Self {
130105 start_address,
131106 size_in_first_page : 0 ,
132107 size_of_inner_pages : 0 ,
133108 size_in_last_page : 0 ,
134- } ;
109+ } ) ;
135110 }
136111
137- let min_page_size = * MIN_SYSTEM_PAGE_SIZE ;
112+ let min_page_size = min_system_page_size ( ) ? ;
138113 let distance_to_preceeding_page_boundary =
139114 start_address - align_down ( start_address, min_page_size) ;
140115
@@ -145,19 +120,19 @@ impl PageAwareAddressRange {
145120 // | -- distance_to_preceeding_page_boundary -- v ---- size ---- v |
146121 // preceeding_page_boundary --> start_address --> end_address --> next_page_boundary
147122 return if distance_to_preceeding_page_boundary == 0 && size == min_page_size. get ( ) {
148- Self {
123+ Ok ( Self {
149124 start_address,
150125 size_in_first_page : 0 ,
151126 size_of_inner_pages : size,
152127 size_in_last_page : 0 ,
153- }
128+ } )
154129 } else {
155- Self {
130+ Ok ( Self {
156131 start_address,
157132 size_in_first_page : size,
158133 size_of_inner_pages : 0 ,
159134 size_in_last_page : 0 ,
160- }
135+ } )
161136 } ;
162137 }
163138
@@ -180,12 +155,12 @@ impl PageAwareAddressRange {
180155 let size_of_inner_pages = align_down ( size, min_page_size) ;
181156 let size_in_last_page = size - size_of_inner_pages;
182157
183- Self {
158+ Ok ( Self {
184159 start_address,
185160 size_in_first_page,
186161 size_of_inner_pages,
187162 size_in_last_page,
188- }
163+ } )
189164 }
190165
191166 /// Transform this address range into a vector of `iovec`s.
@@ -196,8 +171,8 @@ impl PageAwareAddressRange {
196171 /// (if any) is also returned. Returning a vector of `iovec`s that covers
197172 /// only a prefix of this address range is not considered a failure.
198173 fn into_iov_buffers ( mut self ) -> Result < ( SmallVec < [ libc:: iovec ; 3 ] > , u64 ) > {
199- let min_page_size = MIN_SYSTEM_PAGE_SIZE . get ( ) ;
200- let max_iov_count = * SYSTEM_IOV_MAX ;
174+ let min_page_size = min_system_page_size ( ) ? . get ( ) ;
175+ let max_iov_count = system_iov_max ( ) . get ( ) ;
201176 let mut size_of_not_covered_suffix = 0 ;
202177
203178 let mut inner_pages_count = usize:: try_from ( self . size_of_inner_pages / min_page_size) ?;
@@ -342,7 +317,7 @@ impl ProcessVirtualMemoryIO {
342317 ) ) ;
343318 }
344319
345- Self :: ensure_process_exists ( process_id) ?;
320+ ensure_process_exists ( process_id) ?;
346321
347322 Ok ( Self {
348323 process_id,
@@ -356,28 +331,12 @@ impl ProcessVirtualMemoryIO {
356331 self . process_id as u32
357332 }
358333
359- /// Ensure that the process, identified by the given process identifier,
360- /// currently exists in the system.
361- fn ensure_process_exists ( process_id : libc:: pid_t ) -> Result < ( ) > {
362- if unsafe { libc:: kill ( process_id, 0 ) } != -1 {
363- return Ok ( ( ) ) ;
364- }
365-
366- let mut err = io:: Error :: last_os_error ( ) ;
367- err = match err. raw_os_error ( ) {
368- Some ( libc:: ESRCH ) => io:: Error :: from ( io:: ErrorKind :: NotFound ) ,
369- Some ( libc:: EINVAL ) => io:: Error :: from ( io:: ErrorKind :: InvalidInput ) ,
370- Some ( libc:: EPERM ) => io:: Error :: from ( io:: ErrorKind :: PermissionDenied ) ,
371- _ => err,
372- } ;
373- Err ( Error :: from_io3 ( err, "kill" , process_id) )
374- }
375-
376334 /// Perform vectored (i.e., scatter/gather) I/O on the virtual memory of the
377335 /// target process.
378336 fn io_vectored (
379337 & mut self ,
380338 process_vm_io_v : ProcessVMReadVProc ,
339+ process_vm_io_v_name : & ' static str ,
381340 local_io_vectors : & [ libc:: iovec ] ,
382341 mut byte_count : u64 ,
383342 ) -> Result < usize > {
@@ -392,7 +351,7 @@ impl ProcessVirtualMemoryIO {
392351 byte_count = cmp:: min ( byte_count, max_remaining_bytes) ;
393352
394353 let ( remote_io_vectors, _size_of_not_covered_suffix) =
395- PageAwareAddressRange :: new ( address, byte_count) . into_iov_buffers ( ) ?;
354+ PageAwareAddressRange :: new ( address, byte_count) ? . into_iov_buffers ( ) ?;
396355
397356 let transferred_bytes_count = unsafe {
398357 process_vm_io_v (
@@ -408,7 +367,7 @@ impl ProcessVirtualMemoryIO {
408367 if transferred_bytes_count == -1 {
409368 return Err ( Error :: from_io3 (
410369 io:: Error :: last_os_error ( ) ,
411- "process_vm_readv/process_vm_writev" ,
370+ process_vm_io_v_name ,
412371 self . process_id ,
413372 ) ) ;
414373 }
@@ -470,16 +429,25 @@ impl Read for ProcessVirtualMemoryIO {
470429 iov_len : buf. len ( ) ,
471430 } ;
472431
473- self . io_vectored ( libc:: process_vm_readv, & [ local_io_vector] , buf. len ( ) as u64 )
474- . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
432+ self . io_vectored (
433+ libc:: process_vm_readv,
434+ "process_vm_readv" ,
435+ & [ local_io_vector] ,
436+ buf. len ( ) as u64 ,
437+ )
438+ . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
475439 }
476440
477441 fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut ] ) -> io:: Result < usize > {
478- let bytes_to_read = bufs. iter ( ) . map ( |buf| buf. len ( ) as u64 ) . sum ( ) ;
479- let local_io_vectors = unsafe { slice:: from_raw_parts ( bufs. as_ptr ( ) . cast ( ) , bufs. len ( ) ) } ;
442+ let ( byte_count, local_io_vectors) = io_vectors_from_io_slices_mut ( bufs) ;
480443
481- self . io_vectored ( libc:: process_vm_readv, local_io_vectors, bytes_to_read)
482- . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
444+ self . io_vectored (
445+ libc:: process_vm_readv,
446+ "process_vm_readv" ,
447+ local_io_vectors,
448+ byte_count,
449+ )
450+ . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
483451 }
484452}
485453
@@ -492,18 +460,23 @@ impl Write for ProcessVirtualMemoryIO {
492460
493461 self . io_vectored (
494462 libc:: process_vm_writev,
463+ "process_vm_writev" ,
495464 & [ local_io_vector] ,
496465 buf. len ( ) as u64 ,
497466 )
498467 . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
499468 }
500469
501470 fn write_vectored ( & mut self , bufs : & [ IoSlice ] ) -> io:: Result < usize > {
502- let bytes_to_write = bufs. iter ( ) . map ( |buf| buf. len ( ) as u64 ) . sum ( ) ;
503- let local_io_vectors = unsafe { slice:: from_raw_parts ( bufs. as_ptr ( ) . cast ( ) , bufs. len ( ) ) } ;
471+ let ( byte_count, local_io_vectors) = io_vectors_from_io_slices ( bufs) ;
504472
505- self . io_vectored ( libc:: process_vm_writev, local_io_vectors, bytes_to_write)
506- . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
473+ self . io_vectored (
474+ libc:: process_vm_writev,
475+ "process_vm_writev" ,
476+ local_io_vectors,
477+ byte_count,
478+ )
479+ . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) )
507480 }
508481
509482 fn flush ( & mut self ) -> io:: Result < ( ) > {
0 commit comments