Add support for /proc/self(pid)/maps
This commit is contained in:
		
							parent
							
								
									dd295c1391
								
							
						
					
					
						commit
						d1acb84362
					
				| @ -266,6 +266,10 @@ impl File for INodeFile { | ||||
| } | ||||
| 
 | ||||
| impl INodeFile { | ||||
|     pub fn inode(&self) -> &Arc<dyn INode> { | ||||
|         &self.inode | ||||
|     } | ||||
| 
 | ||||
|     pub fn open(inode: Arc<dyn INode>, abs_path: &str, flags: u32) -> Result<Self> { | ||||
|         let access_mode = AccessMode::from_u32(flags)?; | ||||
|         if (access_mode.readable() && !inode.allow_read()?) { | ||||
|  | ||||
							
								
								
									
										134
									
								
								src/libos/src/fs/procfs/pid/maps.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										134
									
								
								src/libos/src/fs/procfs/pid/maps.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| use crate::vm::{ChunkType, VMArea, VMPerms, VMRange}; | ||||
| 
 | ||||
| // This file is to implement /proc/self(pid)/maps file system.
 | ||||
| //
 | ||||
| // Print format:
 | ||||
| // vmrange_start-vmrange_end, permission, shared/private, offset, device ID, inode, pathname
 | ||||
| //
 | ||||
| // Example:
 | ||||
| // - cat /proc/self/maps
 | ||||
| // 555555554000-555555556000 r--p 00000000 08:12 39321752                   /usr/bin/cat
 | ||||
| // 555555556000-55555555b000 r-xp 00002000 08:12 39321752                   /usr/bin/cat
 | ||||
| // 55555555b000-55555555e000 r--p 00007000 08:12 39321752                   /usr/bin/cat
 | ||||
| // 55555555e000-55555555f000 r--p 00009000 08:12 39321752                   /usr/bin/cat
 | ||||
| // 55555555f000-555555560000 rw-p 0000a000 08:12 39321752                   /usr/bin/cat
 | ||||
| // 555555560000-555555581000 rw-p 00000000 00:00 0                          [heap]
 | ||||
| // 7ffff7536000-7ffff7558000 rw-p 00000000 00:00 0
 | ||||
| // 7ffff7558000-7ffff7dc8000 r--p 00000000 08:12 39322175                   /usr/lib/locale/locale-archive
 | ||||
| // 7ffff7dc8000-7ffff7dea000 r--p 00000000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||
| // 7ffff7dea000-7ffff7f62000 r-xp 00022000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||
| // 7ffff7f62000-7ffff7fb0000 r--p 0019a000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||
| // 7ffff7fb0000-7ffff7fb4000 r--p 001e7000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||
| // 7ffff7fb4000-7ffff7fb6000 rw-p 001eb000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||
| // 7ffff7fb6000-7ffff7fbc000 rw-p 00000000 00:00 0
 | ||||
| // 7ffff7fcf000-7ffff7fd0000 r--p 00000000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||
| // 7ffff7fd0000-7ffff7ff3000 r-xp 00001000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||
| // 7ffff7ff3000-7ffff7ffb000 r--p 00024000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||
| // 7ffff7ffc000-7ffff7ffd000 r--p 0002c000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||
| // 7ffff7ffd000-7ffff7ffe000 rw-p 0002d000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||
| // 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
 | ||||
| // 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
 | ||||
| // 80000006b000-80000006f000 r--p 00000000 00:00 0                          [vvar]
 | ||||
| // 80000006f000-800000071000 r-xp 00000000 00:00 0                          [vdso]
 | ||||
| // ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
 | ||||
| //
 | ||||
| // Known limitation:
 | ||||
| // - Device ID is not provided by FS
 | ||||
| // - Not shown in address order
 | ||||
| 
 | ||||
| pub struct ProcMapsINode(ProcessRef); | ||||
| 
 | ||||
| impl ProcMapsINode { | ||||
|     pub fn new(process_ref: &ProcessRef) -> Arc<dyn INode> { | ||||
|         Arc::new(File::new(Self(Arc::clone(process_ref)))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ProcINode for ProcMapsINode { | ||||
|     fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> { | ||||
|         let result_string = { | ||||
|             let main_thread = self.0.main_thread().unwrap(); | ||||
|             let process_vm = main_thread.vm(); | ||||
|             let heap_range = process_vm.heap_range(); | ||||
|             let stack_range = process_vm.stack_range(); | ||||
| 
 | ||||
|             let process_vm_chunks = process_vm.mem_chunks().read().unwrap(); | ||||
|             process_vm_chunks | ||||
|                 .iter() | ||||
|                 .map(|chunk| match chunk.internal() { | ||||
|                     ChunkType::SingleVMA(vma) => { | ||||
|                         let range = chunk.range(); | ||||
|                         let heap_or_stack = if range == heap_range { | ||||
|                             Some(" [heap]") | ||||
|                         } else if range == stack_range { | ||||
|                             Some(" [stack]") | ||||
|                         } else { | ||||
|                             None | ||||
|                         }; | ||||
|                         let vma = vma.lock().unwrap(); | ||||
|                         get_output_for_vma(&vma, heap_or_stack) | ||||
|                     } | ||||
|                     ChunkType::MultiVMA(internal_manager) => { | ||||
|                         let internal = internal_manager.lock().unwrap(); | ||||
|                         let vmas_list = internal.chunk_manager().vmas(); | ||||
|                         vmas_list | ||||
|                             .iter() | ||||
|                             .map(|obj| get_output_for_vma(obj.vma(), None)) | ||||
|                             .fold(String::new(), |acc, vma_info| acc + &vma_info) | ||||
|                     } | ||||
|                 }) | ||||
|                 .fold(String::new(), |acc, vma_info| acc + &vma_info) | ||||
|         }; | ||||
| 
 | ||||
|         Ok(result_string.into_bytes()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn get_output_for_vma(vma: &VMArea, heap_or_stack: Option<&str>) -> String { | ||||
|     let range = vma.range(); | ||||
|     let perms = vma.perms(); | ||||
| 
 | ||||
|     let (file_path, offset, device_id, inode_num) = { | ||||
|         if let Some((file, offset)) = vma.init_file() { | ||||
|             let inode_file = file.as_inode_file().unwrap(); | ||||
|             let file_path = inode_file.abs_path(); | ||||
|             let inode_num = inode_file.inode().metadata().unwrap().inode; | ||||
|             let device_id = inode_file.inode().metadata().unwrap().dev; | ||||
|             (file_path, offset, device_id, inode_num) | ||||
|         } else if heap_or_stack.is_some() { | ||||
|             (heap_or_stack.unwrap(), 0, 0, 0) | ||||
|         } else { | ||||
|             ("", 0, 0, 0) | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     let shared = vma.writeback_file().is_some(); | ||||
|     print_each_map( | ||||
|         range, perms, shared, offset, device_id, inode_num, file_path, | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| fn print_each_map( | ||||
|     range: &VMRange, | ||||
|     perms: VMPerms, | ||||
|     shared: bool, | ||||
|     offset: usize, | ||||
|     device_id: usize, | ||||
|     inode_num: usize, | ||||
|     file_path: &str, | ||||
| ) -> String { | ||||
|     let result_str = format!( | ||||
|         "{:x}-{:x} {}{} {:08x} {} {}      {}\n", | ||||
|         range.start(), | ||||
|         range.end(), | ||||
|         perms.display(), | ||||
|         if shared { "s" } else { "p" }, | ||||
|         offset, | ||||
|         device_id, | ||||
|         inode_num, | ||||
|         file_path | ||||
|     ); | ||||
|     result_str | ||||
| } | ||||
| @ -7,6 +7,7 @@ use self::comm::ProcCommINode; | ||||
| use self::cwd::ProcCwdSymINode; | ||||
| use self::exe::ProcExeSymINode; | ||||
| use self::fd::LockedProcFdDirINode; | ||||
| use self::maps::ProcMapsINode; | ||||
| use self::root::ProcRootSymINode; | ||||
| use self::stat::ProcStatINode; | ||||
| 
 | ||||
| @ -15,6 +16,7 @@ mod comm; | ||||
| mod cwd; | ||||
| mod exe; | ||||
| mod fd; | ||||
| mod maps; | ||||
| mod root; | ||||
| mod stat; | ||||
| 
 | ||||
| @ -60,6 +62,9 @@ impl LockedPidDirINode { | ||||
|         // stat
 | ||||
|         let stat_inode = ProcStatINode::new(&file.process_ref); | ||||
|         file.entries.insert(String::from("stat"), stat_inode); | ||||
|         // maps
 | ||||
|         let maps_inode = ProcMapsINode::new(&file.process_ref); | ||||
|         file.entries.insert(String::from("maps"), maps_inode); | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| use super::super::elf_file::*; | ||||
| use super::ThreadRef; | ||||
| use crate::fs::{FileMode, INodeExt}; | ||||
| use crate::fs::{AsINodeFile, FileMode, INodeExt}; | ||||
| use crate::prelude::*; | ||||
| use rcore_fs::vfs::{FileType, INode, Metadata}; | ||||
| use std::ffi::CString; | ||||
| @ -13,10 +13,10 @@ use std::ffi::CString; | ||||
| pub fn load_exec_file_hdr_to_vec( | ||||
|     file_path: &str, | ||||
|     current_ref: &ThreadRef, | ||||
| ) -> Result<(Option<String>, Arc<dyn INode>, Vec<u8>, ElfHeader)> { | ||||
|     let (inode, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?; | ||||
| ) -> Result<(Option<String>, FileRef, Vec<u8>, ElfHeader)> { | ||||
|     let (file_ref, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?; | ||||
|     if elf_hdr.is_some() { | ||||
|         Ok((None, inode, file_buf, elf_hdr.unwrap())) | ||||
|         Ok((None, file_ref, file_buf, elf_hdr.unwrap())) | ||||
|     } else { | ||||
|         // loaded file is not Elf format, try script file
 | ||||
|         if !is_script_file(&file_buf) { | ||||
| @ -30,14 +30,14 @@ pub fn load_exec_file_hdr_to_vec( | ||||
|                 "libos doesn't support executing binaries from \"/host\" directory" | ||||
|             ); | ||||
|         } | ||||
|         let (interp_inode, interp_buf, interp_hdr) = | ||||
|         let (interp_file, interp_buf, interp_hdr) = | ||||
|             load_file_hdr_to_vec(&interpreter_path, current_ref)?; | ||||
|         let interp_hdr = if interp_hdr.is_none() { | ||||
|             return_errno!(ENOEXEC, "scrip interpreter is not ELF format"); | ||||
|         } else { | ||||
|             interp_hdr.unwrap() | ||||
|         }; | ||||
|         Ok((Some(interpreter_path), interp_inode, interp_buf, interp_hdr)) | ||||
|         Ok((Some(interpreter_path), interp_file, interp_buf, interp_hdr)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -72,13 +72,13 @@ fn parse_script_interpreter(file_buf: &Vec<u8>) -> Result<String> { | ||||
| pub fn load_file_hdr_to_vec( | ||||
|     file_path: &str, | ||||
|     current_ref: &ThreadRef, | ||||
| ) -> Result<(Arc<dyn INode>, Vec<u8>, Option<ElfHeader>)> { | ||||
|     let inode = current_ref | ||||
| ) -> Result<(FileRef, Vec<u8>, Option<ElfHeader>)> { | ||||
|     let file_ref = current_ref | ||||
|         .fs() | ||||
|         .read() | ||||
|         .unwrap() | ||||
|         .lookup_inode(file_path) | ||||
|         .map_err(|e| errno!(e.errno(), "cannot find the file"))?; | ||||
|         .open_file(file_path, 0, FileMode::S_IRUSR)?; | ||||
|     let inode = file_ref.as_inode_file()?.inode(); | ||||
| 
 | ||||
|     // Make sure the final file to exec is not a directory
 | ||||
|     let metadata = inode.metadata()?; | ||||
| @ -105,12 +105,12 @@ pub fn load_file_hdr_to_vec( | ||||
|         .read_elf64_lazy_as_vec() | ||||
|         .map_err(|e| errno!(e.errno(), "failed to read the file"))?; | ||||
| 
 | ||||
|     let elf_header = ElfFile::parse_elf_hdr(&inode, &mut file_buf); | ||||
|     let elf_header = ElfFile::parse_elf_hdr(&file_ref, &mut file_buf); | ||||
|     if let Ok(elf_header) = elf_header { | ||||
|         Ok((inode, file_buf, Some(elf_header))) | ||||
|         Ok((file_ref, file_buf, Some(elf_header))) | ||||
|     } else { | ||||
|         // this file is not ELF format or there is something wrong when parsing
 | ||||
|         warn!("parse elf header error = {}", elf_header.err().unwrap()); | ||||
|         Ok((inode, file_buf, None)) | ||||
|         Ok((file_ref, file_buf, None)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -166,7 +166,7 @@ fn new_process_common( | ||||
|     parent_process: Option<ProcessRef>, | ||||
| ) -> Result<ProcessRef> { | ||||
|     let mut argv = argv.clone().to_vec(); | ||||
|     let (is_script, elf_inode, mut elf_buf, elf_header) = | ||||
|     let (is_script, elf_file, mut elf_buf, elf_header) = | ||||
|         load_exec_file_hdr_to_vec(file_path, current_ref)?; | ||||
| 
 | ||||
|     // elf_path might be different from file_path because file_path could lead to a script text file.
 | ||||
| @ -182,13 +182,13 @@ fn new_process_common( | ||||
|         file_path.to_string() | ||||
|     }; | ||||
| 
 | ||||
|     let exec_elf_hdr = ElfFile::new(&elf_inode, &mut elf_buf, elf_header) | ||||
|     let exec_elf_hdr = ElfFile::new(&elf_file, &mut elf_buf, elf_header) | ||||
|         .cause_err(|e| errno!(e.errno(), "invalid executable"))?; | ||||
|     let ldso_path = exec_elf_hdr | ||||
|         .elf_interpreter() | ||||
|         .ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?; | ||||
|     trace!("ldso_path = {:?}", ldso_path); | ||||
|     let (ldso_inode, mut ldso_elf_hdr_buf, ldso_elf_header) = | ||||
|     let (ldso_file, mut ldso_elf_hdr_buf, ldso_elf_header) = | ||||
|         load_file_hdr_to_vec(ldso_path, current_ref) | ||||
|             .cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?; | ||||
|     let ldso_elf_header = if ldso_elf_header.is_none() { | ||||
| @ -196,7 +196,7 @@ fn new_process_common( | ||||
|     } else { | ||||
|         ldso_elf_header.unwrap() | ||||
|     }; | ||||
|     let ldso_elf_hdr = ElfFile::new(&ldso_inode, &mut ldso_elf_hdr_buf, ldso_elf_header) | ||||
|     let ldso_elf_hdr = ElfFile::new(&ldso_file, &mut ldso_elf_hdr_buf, ldso_elf_header) | ||||
|         .cause_err(|e| errno!(e.errno(), "invalid ld.so"))?; | ||||
| 
 | ||||
|     let new_process_ref = { | ||||
|  | ||||
| @ -15,7 +15,7 @@ const ELF64_HDR_SIZE: usize = 64; | ||||
| pub struct ElfFile<'a> { | ||||
|     elf_buf: &'a [u8], | ||||
|     elf_inner: Elf<'a>, | ||||
|     file_inode: &'a Arc<dyn INode>, | ||||
|     file_ref: &'a FileRef, | ||||
| } | ||||
| 
 | ||||
| impl<'a> Debug for ElfFile<'a> { | ||||
| @ -30,7 +30,7 @@ impl<'a> Debug for ElfFile<'a> { | ||||
| 
 | ||||
| impl<'a> ElfFile<'a> { | ||||
|     pub fn new( | ||||
|         file_inode: &'a Arc<dyn INode>, | ||||
|         file_ref: &'a FileRef, | ||||
|         mut elf_buf: &'a mut [u8], | ||||
|         header: ElfHeader, | ||||
|     ) -> Result<ElfFile<'a>> { | ||||
| @ -64,7 +64,7 @@ impl<'a> ElfFile<'a> { | ||||
|                     intepreter_offset, | ||||
|                     intepreter_count | ||||
|                 ); | ||||
|                 file_inode.read_at( | ||||
|                 file_ref.read_at( | ||||
|                     intepreter_offset, | ||||
|                     &mut elf_buf[intepreter_offset..intepreter_offset + intepreter_count], | ||||
|                 ); | ||||
| @ -87,7 +87,7 @@ impl<'a> ElfFile<'a> { | ||||
|         Ok(ElfFile { | ||||
|             elf_buf, | ||||
|             elf_inner, | ||||
|             file_inode, | ||||
|             file_ref, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
| @ -107,11 +107,11 @@ impl<'a> ElfFile<'a> { | ||||
|         self.elf_buf | ||||
|     } | ||||
| 
 | ||||
|     pub fn file_inode(&self) -> &Arc<dyn INode> { | ||||
|         self.file_inode | ||||
|     pub fn file_ref(&self) -> &FileRef { | ||||
|         self.file_ref | ||||
|     } | ||||
| 
 | ||||
|     pub fn parse_elf_hdr(inode: &Arc<dyn INode>, elf_buf: &mut Vec<u8>) -> Result<ElfHeader> { | ||||
|     pub fn parse_elf_hdr(elf_file: &FileRef, elf_buf: &mut Vec<u8>) -> Result<ElfHeader> { | ||||
|         // TODO: Sanity check the number of program headers..
 | ||||
|         let mut phdr_start = 0; | ||||
|         let mut phdr_end = 0; | ||||
| @ -130,7 +130,7 @@ impl<'a> ElfFile<'a> { | ||||
|         } | ||||
| 
 | ||||
|         let program_hdr_table_size = elf_hdr.e_phnum * elf_hdr.e_phentsize; | ||||
|         inode.read_at( | ||||
|         elf_file.read_at( | ||||
|             elf_hdr.e_phoff as usize, | ||||
|             &mut elf_buf[hdr_size..hdr_size + (program_hdr_table_size as usize)], | ||||
|         )?; | ||||
|  | ||||
| @ -93,11 +93,10 @@ impl Chunk { | ||||
|     } | ||||
| 
 | ||||
|     pub fn new_single_vma_chunk(vm_range: &VMRange, options: &VMMapOptions) -> Result<Self> { | ||||
|         let writeback_file = options.writeback_file().clone(); | ||||
|         let vm_area = VMArea::new( | ||||
|             vm_range.clone(), | ||||
|             *options.perms(), | ||||
|             writeback_file, | ||||
|             options.initializer().backed_file(), | ||||
|             DUMMY_CHUNK_PROCESS_ID, | ||||
|         ); | ||||
|         // Initialize the memory of the new range
 | ||||
| @ -178,7 +177,7 @@ impl Chunk { | ||||
|         if internal_manager.chunk_manager().free_size() < options.size() { | ||||
|             return_errno!(ENOMEM, "no enough size without trying. try other chunks"); | ||||
|         } | ||||
|         internal_manager.chunk_manager().mmap(options) | ||||
|         internal_manager.chunk_manager_mut().mmap(options) | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_single_vma(&self) -> bool { | ||||
| @ -279,7 +278,11 @@ impl ChunkInternal { | ||||
|         self.process_set.insert(pid); | ||||
|     } | ||||
| 
 | ||||
|     pub fn chunk_manager(&mut self) -> &mut ChunkManager { | ||||
|     pub fn chunk_manager(&self) -> &ChunkManager { | ||||
|         &self.chunk_manager | ||||
|     } | ||||
| 
 | ||||
|     pub fn chunk_manager_mut(&mut self) -> &mut ChunkManager { | ||||
|         &mut self.chunk_manager | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -75,9 +75,10 @@ mod vm_util; | ||||
| 
 | ||||
| use self::vm_layout::VMLayout; | ||||
| 
 | ||||
| pub use self::chunk::ChunkRef; | ||||
| pub use self::chunk::{ChunkRef, ChunkType}; | ||||
| pub use self::process_vm::{MMapFlags, MRemapFlags, MSyncFlags, ProcessVM, ProcessVMBuilder}; | ||||
| pub use self::user_space_vm::USER_SPACE_VM_MANAGER; | ||||
| pub use self::vm_area::VMArea; | ||||
| pub use self::vm_perms::VMPerms; | ||||
| pub use self::vm_range::VMRange; | ||||
| pub use self::vm_util::{VMInitializer, VMMapOptionsBuilder}; | ||||
|  | ||||
| @ -7,7 +7,9 @@ use super::process::elf_file::{ElfFile, ProgramHeaderExt}; | ||||
| use super::user_space_vm::USER_SPACE_VM_MANAGER; | ||||
| use super::vm_area::VMArea; | ||||
| use super::vm_perms::VMPerms; | ||||
| use super::vm_util::{VMInitializer, VMMapAddr, VMMapOptions, VMMapOptionsBuilder, VMRemapOptions}; | ||||
| use super::vm_util::{ | ||||
|     FileBacked, VMInitializer, VMMapAddr, VMMapOptions, VMMapOptionsBuilder, VMRemapOptions, | ||||
| }; | ||||
| use std::collections::HashSet; | ||||
| use std::sync::atomic::{AtomicUsize, Ordering}; | ||||
| 
 | ||||
| @ -117,7 +119,9 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> { | ||||
|                     .size(elf_layout.size()) | ||||
|                     .align(elf_layout.align()) | ||||
|                     .perms(VMPerms::ALL) // set it to read | write | exec for simplicity
 | ||||
|                     .initializer(VMInitializer::DoNothing()) | ||||
|                     .initializer(VMInitializer::ElfSpecific { | ||||
|                         elf_file: elf_file.file_ref().clone(), | ||||
|                     }) | ||||
|                     .build() | ||||
|                     .map_err(|e| { | ||||
|                         &self.handle_error_when_init(&chunks); | ||||
| @ -244,7 +248,7 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> { | ||||
|                 } | ||||
| 
 | ||||
|                 // Bytes of file_size length are loaded from the ELF file
 | ||||
|                 elf_file.file_inode().read_at( | ||||
|                 elf_file.file_ref().read_at( | ||||
|                     file_offset, | ||||
|                     &mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size], | ||||
|                 ); | ||||
| @ -318,6 +322,14 @@ impl ProcessVM { | ||||
|         &self.mem_chunks | ||||
|     } | ||||
| 
 | ||||
|     pub fn stack_range(&self) -> &VMRange { | ||||
|         &self.stack_range | ||||
|     } | ||||
| 
 | ||||
|     pub fn heap_range(&self) -> &VMRange { | ||||
|         &self.heap_range | ||||
|     } | ||||
| 
 | ||||
|     pub fn add_mem_chunk(&self, chunk: ChunkRef) { | ||||
|         let mut mem_chunks = self.mem_chunks.write().unwrap(); | ||||
|         mem_chunks.insert(chunk); | ||||
| @ -488,28 +500,22 @@ impl ProcessVM { | ||||
|                 VMInitializer::DoNothing() | ||||
|             } else { | ||||
|                 let file_ref = current!().file(fd)?; | ||||
|                 VMInitializer::LoadFromFile { | ||||
|                     file: file_ref, | ||||
|                     offset: offset, | ||||
|                 // Only shared, file-backed memory mappings have write-back files
 | ||||
|                 let need_write_back = if flags.contains(MMapFlags::MAP_SHARED) { | ||||
|                     true | ||||
|                 } else { | ||||
|                     false | ||||
|                 }; | ||||
|                 VMInitializer::FileBacked { | ||||
|                     file: FileBacked::new(file_ref, offset, need_write_back), | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|         // Only shared, file-backed memory mappings have write-back files
 | ||||
|         let writeback_file = if flags.contains(MMapFlags::MAP_SHARED) { | ||||
|             if let VMInitializer::LoadFromFile { file, offset } = &initializer { | ||||
|                 Some((file.clone(), *offset)) | ||||
|             } else { | ||||
|                 None | ||||
|             } | ||||
|         } else { | ||||
|             None | ||||
|         }; | ||||
|         let mmap_options = VMMapOptionsBuilder::default() | ||||
|             .size(size) | ||||
|             .addr(addr_option) | ||||
|             .perms(perms) | ||||
|             .initializer(initializer) | ||||
|             .writeback_file(writeback_file) | ||||
|             .build()?; | ||||
|         let mmap_addr = USER_SPACE_VM_MANAGER.mmap(&mmap_options)?; | ||||
|         Ok(mmap_addr) | ||||
|  | ||||
| @ -2,6 +2,7 @@ use std::ops::{Deref, DerefMut}; | ||||
| 
 | ||||
| use super::vm_perms::VMPerms; | ||||
| use super::vm_range::VMRange; | ||||
| use super::vm_util::FileBacked; | ||||
| use super::*; | ||||
| 
 | ||||
| use intrusive_collections::rbtree::{Link, RBTree}; | ||||
| @ -11,7 +12,7 @@ use intrusive_collections::{intrusive_adapter, KeyAdapter}; | ||||
| pub struct VMArea { | ||||
|     range: VMRange, | ||||
|     perms: VMPerms, | ||||
|     writeback_file: Option<(FileRef, usize)>, | ||||
|     file_backed: Option<FileBacked>, | ||||
|     pid: pid_t, | ||||
| } | ||||
| 
 | ||||
| @ -19,13 +20,13 @@ impl VMArea { | ||||
|     pub fn new( | ||||
|         range: VMRange, | ||||
|         perms: VMPerms, | ||||
|         writeback_file: Option<(FileRef, usize)>, | ||||
|         file_backed: Option<FileBacked>, | ||||
|         pid: pid_t, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             range, | ||||
|             perms, | ||||
|             writeback_file, | ||||
|             file_backed, | ||||
|             pid, | ||||
|         } | ||||
|     } | ||||
| @ -38,20 +39,25 @@ impl VMArea { | ||||
|         new_perms: VMPerms, | ||||
|         pid: pid_t, | ||||
|     ) -> Self { | ||||
|         let new_writeback_file = vma.writeback_file.as_ref().map(|(file, file_offset)| { | ||||
|             let new_file = file.clone(); | ||||
|         let new_backed_file = vma.file_backed.as_ref().map(|file| { | ||||
|             let mut new_file = file.clone(); | ||||
|             let file_offset = file.offset(); | ||||
| 
 | ||||
|             let new_file_offset = if vma.start() < new_range.start() { | ||||
|                 let vma_offset = new_range.start() - vma.start(); | ||||
|                 *file_offset + vma_offset | ||||
|                 file_offset + vma_offset | ||||
|             } else { | ||||
|                 let vma_offset = vma.start() - new_range.start(); | ||||
|                 debug_assert!(*file_offset >= vma_offset); | ||||
|                 *file_offset - vma_offset | ||||
|                 debug_assert!(file_offset >= vma_offset); | ||||
|                 file_offset - vma_offset | ||||
|             }; | ||||
|             (new_file, new_file_offset) | ||||
| 
 | ||||
|             new_file.set_offset(new_file_offset); | ||||
| 
 | ||||
|             new_file | ||||
|         }); | ||||
|         Self::new(new_range, new_perms, new_writeback_file, pid) | ||||
| 
 | ||||
|         Self::new(new_range, new_perms, new_backed_file, pid) | ||||
|     } | ||||
| 
 | ||||
|     pub fn perms(&self) -> VMPerms { | ||||
| @ -66,8 +72,20 @@ impl VMArea { | ||||
|         self.pid | ||||
|     } | ||||
| 
 | ||||
|     pub fn writeback_file(&self) -> &Option<(FileRef, usize)> { | ||||
|         &self.writeback_file | ||||
|     pub fn init_file(&self) -> Option<(&FileRef, usize)> { | ||||
|         if let Some(file) = &self.file_backed { | ||||
|             Some(file.init_file()) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn writeback_file(&self) -> Option<(&FileRef, usize)> { | ||||
|         if let Some(file) = &self.file_backed { | ||||
|             file.writeback_file() | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_perms(&mut self, new_perms: VMPerms) { | ||||
| @ -103,15 +121,19 @@ impl VMArea { | ||||
|         let old_start = self.start(); | ||||
|         self.range.set_start(new_start); | ||||
| 
 | ||||
|         // If the updates to the VMA needs to write back to a file, then the
 | ||||
|         // file offset must be adjusted according to the new start address.
 | ||||
|         if let Some((_, offset)) = self.writeback_file.as_mut() { | ||||
|         if let Some(file) = self.file_backed.as_mut() { | ||||
|             if !file.need_write_back() { | ||||
|                 return; | ||||
|             } | ||||
|             // If the updates to the VMA needs to write back to a file, then the
 | ||||
|             // file offset must be adjusted according to the new start address.
 | ||||
|             let offset = file.offset(); | ||||
|             if old_start < new_start { | ||||
|                 *offset += new_start - old_start; | ||||
|                 file.set_offset(offset + (new_start - old_start)); | ||||
|             } else { | ||||
|                 // The caller must guarantee that the new start makes sense
 | ||||
|                 debug_assert!(*offset >= old_start - new_start); | ||||
|                 *offset -= old_start - new_start; | ||||
|                 debug_assert!(offset >= old_start - new_start); | ||||
|                 file.set_offset(offset - (old_start - new_start)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -223,22 +245,3 @@ impl VMAObj { | ||||
|         &self.vma | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VMArea { | ||||
|     pub fn new_obj( | ||||
|         range: VMRange, | ||||
|         perms: VMPerms, | ||||
|         writeback_file: Option<(FileRef, usize)>, | ||||
|         pid: pid_t, | ||||
|     ) -> Box<VMAObj> { | ||||
|         Box::new(VMAObj { | ||||
|             link: Link::new(), | ||||
|             vma: VMArea { | ||||
|                 range, | ||||
|                 perms, | ||||
|                 writeback_file, | ||||
|                 pid, | ||||
|             }, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -116,9 +116,13 @@ impl ChunkManager { | ||||
|             .free_manager | ||||
|             .find_free_range_internal(size, align, addr)?; | ||||
|         let new_addr = new_range.start(); | ||||
|         let writeback_file = options.writeback_file().clone(); | ||||
|         let current_pid = current!().process().pid(); | ||||
|         let new_vma = VMArea::new(new_range, *options.perms(), writeback_file, current_pid); | ||||
|         let new_vma = VMArea::new( | ||||
|             new_range, | ||||
|             *options.perms(), | ||||
|             options.initializer().backed_file(), | ||||
|             current_pid, | ||||
|         ); | ||||
| 
 | ||||
|         // Initialize the memory of the new range
 | ||||
|         let buf = unsafe { new_vma.as_slice_mut() }; | ||||
| @ -416,7 +420,7 @@ impl ChunkManager { | ||||
| 
 | ||||
|     /// Same as flush_vma, except that an extra condition on the file needs to satisfy.
 | ||||
|     pub fn flush_file_vma_with_cond<F: Fn(&FileRef) -> bool>(vma: &VMArea, cond_fn: F) { | ||||
|         let (file, file_offset) = match vma.writeback_file().as_ref() { | ||||
|         let (file, file_offset) = match vma.writeback_file() { | ||||
|             None => return, | ||||
|             Some((file_and_offset)) => file_and_offset, | ||||
|         }; | ||||
| @ -430,7 +434,7 @@ impl ChunkManager { | ||||
|         if !cond_fn(file) { | ||||
|             return; | ||||
|         } | ||||
|         file.write_at(*file_offset, unsafe { vma.as_slice() }); | ||||
|         file.write_at(file_offset, unsafe { vma.as_slice() }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn find_mmap_region(&self, addr: usize) -> Result<VMRange> { | ||||
|  | ||||
| @ -184,7 +184,11 @@ impl VMManager { | ||||
|                         "mmap with addr in existing default chunk: {:?}", | ||||
|                         chunk.range() | ||||
|                     ); | ||||
|                     return chunk_internal.lock().unwrap().chunk_manager().mmap(options); | ||||
|                     return chunk_internal | ||||
|                         .lock() | ||||
|                         .unwrap() | ||||
|                         .chunk_manager_mut() | ||||
|                         .mmap(options); | ||||
|                 } | ||||
|                 ChunkType::SingleVMA(_) => { | ||||
|                     match addr { | ||||
| @ -287,7 +291,7 @@ impl VMManager { | ||||
|                         ChunkType::MultiVMA(manager) => manager | ||||
|                             .lock() | ||||
|                             .unwrap() | ||||
|                             .chunk_manager() | ||||
|                             .chunk_manager_mut() | ||||
|                             .munmap_range(munmap_range)?, | ||||
|                     } | ||||
|                 } | ||||
| @ -307,7 +311,7 @@ impl VMManager { | ||||
|                 return manager | ||||
|                     .lock() | ||||
|                     .unwrap() | ||||
|                     .chunk_manager() | ||||
|                     .chunk_manager_mut() | ||||
|                     .munmap_range(munmap_range); | ||||
|             } | ||||
|             ChunkType::SingleVMA(_) => { | ||||
| @ -353,7 +357,7 @@ impl VMManager { | ||||
|                 return manager | ||||
|                     .lock() | ||||
|                     .unwrap() | ||||
|                     .chunk_manager() | ||||
|                     .chunk_manager_mut() | ||||
|                     .mprotect(addr, size, perms); | ||||
|             } | ||||
|             ChunkType::SingleVMA(_) => { | ||||
| @ -383,7 +387,7 @@ impl VMManager { | ||||
|                 return manager | ||||
|                     .lock() | ||||
|                     .unwrap() | ||||
|                     .chunk_manager() | ||||
|                     .chunk_manager_mut() | ||||
|                     .msync_by_range(&sync_range); | ||||
|             } | ||||
|             ChunkType::SingleVMA(vma) => { | ||||
| @ -405,7 +409,7 @@ impl VMManager { | ||||
|                     manager | ||||
|                         .lock() | ||||
|                         .unwrap() | ||||
|                         .chunk_manager() | ||||
|                         .chunk_manager_mut() | ||||
|                         .msync_by_file(sync_file); | ||||
|                 } | ||||
|                 ChunkType::SingleVMA(vma) => { | ||||
| @ -452,7 +456,7 @@ impl VMManager { | ||||
|             ChunkType::MultiVMA(manager) => manager | ||||
|                 .lock() | ||||
|                 .unwrap() | ||||
|                 .chunk_manager() | ||||
|                 .chunk_manager_mut() | ||||
|                 .parse_mremap_options(options), | ||||
|             ChunkType::SingleVMA(vma) => { | ||||
|                 self.parse_mremap_options_for_single_vma_chunk(options, vma) | ||||
|  | ||||
| @ -55,6 +55,26 @@ impl VMPerms { | ||||
|             assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn display(&self) -> String { | ||||
|         let mut str = String::new(); | ||||
|         if self.can_read() { | ||||
|             str += "r"; | ||||
|         } else { | ||||
|             str += "-"; | ||||
|         } | ||||
|         if self.can_write() { | ||||
|             str += "w"; | ||||
|         } else { | ||||
|             str += "-"; | ||||
|         } | ||||
|         if self.can_execute() { | ||||
|             str += "x"; | ||||
|         } else { | ||||
|             str += "-"; | ||||
|         } | ||||
|         str | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Default for VMPerms { | ||||
|  | ||||
| @ -1,9 +1,8 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| // use super::vm_area::VMArea;
 | ||||
| // use super::free_space_manager::VMFreeSpaceManager;
 | ||||
| use super::vm_area::*; | ||||
| use super::vm_perms::VMPerms; | ||||
| use crate::fs::FileMode; | ||||
| use std::collections::BTreeSet; | ||||
| 
 | ||||
| use intrusive_collections::rbtree::{Link, RBTree}; | ||||
| @ -18,15 +17,19 @@ pub enum VMInitializer { | ||||
|     CopyFrom { | ||||
|         range: VMRange, | ||||
|     }, | ||||
|     LoadFromFile { | ||||
|         file: FileRef, | ||||
|         offset: usize, | ||||
|     FileBacked { | ||||
|         file: FileBacked, | ||||
|     }, | ||||
|     // For ELF files, there is specical handling to not copy all the contents of the file. This is only used for tracking.
 | ||||
|     ElfSpecific { | ||||
|         elf_file: FileRef, | ||||
|     }, | ||||
|     // For file-backed mremap which may move from old range to new range and read extra bytes from file
 | ||||
|     CopyOldAndReadNew { | ||||
|         old_range: VMRange, | ||||
|         file: FileRef, | ||||
|         offset: usize, // read file from this offset
 | ||||
|         new_writeback_file: FileBacked, | ||||
|     }, | ||||
| } | ||||
| 
 | ||||
| @ -39,7 +42,7 @@ impl Default for VMInitializer { | ||||
| impl VMInitializer { | ||||
|     pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> { | ||||
|         match self { | ||||
|             VMInitializer::DoNothing() => { | ||||
|             VMInitializer::DoNothing() | VMInitializer::ElfSpecific { .. } => { | ||||
|                 // Do nothing
 | ||||
|             } | ||||
|             VMInitializer::FillZeros() => { | ||||
| @ -55,10 +58,11 @@ impl VMInitializer { | ||||
|                     *b = 0; | ||||
|                 } | ||||
|             } | ||||
|             VMInitializer::LoadFromFile { file, offset } => { | ||||
|             VMInitializer::FileBacked { file } => { | ||||
|                 // TODO: make sure that read_at does not move file cursor
 | ||||
|                 let len = file | ||||
|                     .read_at(*offset, buf) | ||||
|                     .file_ref() | ||||
|                     .read_at(file.offset(), buf) | ||||
|                     .cause_err(|_| errno!(EACCES, "failed to init memory from file"))?; | ||||
|                 for b in &mut buf[len..] { | ||||
|                     *b = 0; | ||||
| @ -68,6 +72,7 @@ impl VMInitializer { | ||||
|                 old_range, | ||||
|                 file, | ||||
|                 offset, | ||||
|                 new_writeback_file, | ||||
|             } => { | ||||
|                 // TODO: Handle old_range with non-readable subrange
 | ||||
|                 let src_slice = unsafe { old_range.as_slice() }; | ||||
| @ -85,6 +90,66 @@ impl VMInitializer { | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn backed_file(&self) -> Option<FileBacked> { | ||||
|         match self { | ||||
|             VMInitializer::ElfSpecific { elf_file } => { | ||||
|                 let file_ref = elf_file.clone(); | ||||
|                 Some(FileBacked::new(file_ref, 0, false)) | ||||
|             } | ||||
|             VMInitializer::FileBacked { file } => Some(file.clone()), | ||||
|             VMInitializer::CopyOldAndReadNew { | ||||
|                 new_writeback_file, .. | ||||
|             } => Some(new_writeback_file.clone()), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // This struct is used to record file-backed memory type.
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FileBacked { | ||||
|     file: FileRef, | ||||
|     offset: usize, | ||||
|     write_back: bool, | ||||
| } | ||||
| 
 | ||||
| impl FileBacked { | ||||
|     pub fn new(file: FileRef, offset: usize, write_back: bool) -> Self { | ||||
|         Self { | ||||
|             file, | ||||
|             offset, | ||||
|             write_back, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn file_ref(&self) -> &FileRef { | ||||
|         &self.file | ||||
|     } | ||||
| 
 | ||||
|     pub fn offset(&self) -> usize { | ||||
|         self.offset | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_offset(&mut self, offset: usize) { | ||||
|         self.offset = offset; | ||||
|     } | ||||
| 
 | ||||
|     pub fn need_write_back(&self) -> bool { | ||||
|         self.write_back | ||||
|     } | ||||
| 
 | ||||
|     pub fn init_file(&self) -> (&FileRef, usize) { | ||||
|         (&self.file, self.offset) | ||||
|     } | ||||
| 
 | ||||
|     pub fn writeback_file(&self) -> Option<(&FileRef, usize)> { | ||||
|         if self.write_back { | ||||
|             Some((&self.file, self.offset)) | ||||
|         } else { | ||||
|             None | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq)] | ||||
| @ -118,8 +183,6 @@ pub struct VMMapOptions { | ||||
|     perms: VMPerms, | ||||
|     addr: VMMapAddr, | ||||
|     initializer: VMInitializer, | ||||
|     // The content of the VMA can be written back to a given file at a given offset
 | ||||
|     writeback_file: Option<(FileRef, usize)>, | ||||
| } | ||||
| 
 | ||||
| // VMMapOptionsBuilder is generated automatically, except the build function
 | ||||
| @ -165,14 +228,12 @@ impl VMMapOptionsBuilder { | ||||
|             Some(initializer) => initializer.clone(), | ||||
|             None => VMInitializer::default(), | ||||
|         }; | ||||
|         let writeback_file = self.writeback_file.take().unwrap_or_default(); | ||||
|         Ok(VMMapOptions { | ||||
|             size, | ||||
|             align, | ||||
|             perms, | ||||
|             addr, | ||||
|             initializer, | ||||
|             writeback_file, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| @ -197,10 +258,6 @@ impl VMMapOptions { | ||||
|     pub fn initializer(&self) -> &VMInitializer { | ||||
|         &self.initializer | ||||
|     } | ||||
| 
 | ||||
|     pub fn writeback_file(&self) -> &Option<(FileRef, usize)> { | ||||
|         &self.writeback_file | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, PartialEq)] | ||||
| @ -375,17 +432,18 @@ pub trait VMRemapParser { | ||||
|             } | ||||
|             (MRemapFlags::None, VMRemapSizeType::Growing, Some((backed_file, offset))) => { | ||||
|                 // Update writeback file offset
 | ||||
|                 let new_writeback_file = Some((backed_file.clone(), offset + vma.size())); | ||||
|                 let vm_initializer_for_new_range = VMInitializer::LoadFromFile { | ||||
|                     file: backed_file.clone(), | ||||
|                     offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||
|                 let vm_initializer_for_new_range = VMInitializer::FileBacked { | ||||
|                     file: FileBacked::new( | ||||
|                         backed_file.clone(), | ||||
|                         offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||
|                         true, | ||||
|                     ), | ||||
|                 }; | ||||
|                 let mmap_opts = VMMapOptionsBuilder::default() | ||||
|                     .size(new_size - old_size) | ||||
|                     .addr(VMMapAddr::Need(old_range.end())) | ||||
|                     .perms(perms) | ||||
|                     .initializer(vm_initializer_for_new_range) | ||||
|                     .writeback_file(new_writeback_file) | ||||
|                     .build()?; | ||||
|                 let ret_addr = Some(old_addr); | ||||
|                 (Some(mmap_opts), ret_addr) | ||||
| @ -421,18 +479,18 @@ pub trait VMRemapParser { | ||||
|                     VMRange::new_with_size(old_addr + old_size, new_size - old_size)?; | ||||
|                 if self.is_free_range(&prefered_new_range) { | ||||
|                     // Don't need to move the old range
 | ||||
|                     let vm_initializer_for_new_range = VMInitializer::LoadFromFile { | ||||
|                         file: backed_file.clone(), | ||||
|                         offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||
|                     let vm_initializer_for_new_range = VMInitializer::FileBacked { | ||||
|                         file: FileBacked::new( | ||||
|                             backed_file.clone(), | ||||
|                             offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||
|                             true, | ||||
|                         ), | ||||
|                     }; | ||||
|                     // Write back file should start from new offset
 | ||||
|                     let new_writeback_file = Some((backed_file.clone(), offset + vma.size())); | ||||
|                     let mmap_ops = VMMapOptionsBuilder::default() | ||||
|                         .size(prefered_new_range.size()) | ||||
|                         .addr(VMMapAddr::Need(prefered_new_range.start())) | ||||
|                         .perms(perms) | ||||
|                         .initializer(vm_initializer_for_new_range) | ||||
|                         .writeback_file(new_writeback_file) | ||||
|                         .build()?; | ||||
|                     (Some(mmap_ops), Some(old_addr)) | ||||
|                 } else { | ||||
| @ -441,19 +499,19 @@ pub trait VMRemapParser { | ||||
|                         let copy_end = vma.end(); | ||||
|                         let copy_range = VMRange::new(old_range.start(), copy_end)?; | ||||
|                         let reread_file_start_offset = copy_end - vma.start(); | ||||
|                         let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true); | ||||
|                         VMInitializer::CopyOldAndReadNew { | ||||
|                             old_range: copy_range, | ||||
|                             file: backed_file.clone(), | ||||
|                             offset: reread_file_start_offset, | ||||
|                             new_writeback_file: new_writeback_file, | ||||
|                         } | ||||
|                     }; | ||||
|                     let new_writeback_file = Some((backed_file.clone(), *offset)); | ||||
|                     let mmap_ops = VMMapOptionsBuilder::default() | ||||
|                         .size(new_size) | ||||
|                         .addr(VMMapAddr::Any) | ||||
|                         .perms(perms) | ||||
|                         .initializer(vm_initializer_for_new_range) | ||||
|                         .writeback_file(new_writeback_file) | ||||
|                         .build()?; | ||||
|                     // Cannot determine the returned address for now, which can only be obtained after calling mmap
 | ||||
|                     let ret_addr = None; | ||||
| @ -476,19 +534,19 @@ pub trait VMRemapParser { | ||||
|                     let copy_end = vma.end(); | ||||
|                     let copy_range = VMRange::new(old_range.start(), copy_end)?; | ||||
|                     let reread_file_start_offset = copy_end - vma.start(); | ||||
|                     let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true); | ||||
|                     VMInitializer::CopyOldAndReadNew { | ||||
|                         old_range: copy_range, | ||||
|                         file: backed_file.clone(), | ||||
|                         offset: reread_file_start_offset, | ||||
|                         new_writeback_file: new_writeback_file, | ||||
|                     } | ||||
|                 }; | ||||
|                 let new_writeback_file = Some((backed_file.clone(), *offset)); | ||||
|                 let mmap_opts = VMMapOptionsBuilder::default() | ||||
|                     .size(new_size) | ||||
|                     .addr(VMMapAddr::Force(new_addr)) | ||||
|                     .perms(perms) | ||||
|                     .initializer(vm_initializer_for_new_range) | ||||
|                     .writeback_file(new_writeback_file) | ||||
|                     .build()?; | ||||
|                 let ret_addr = Some(new_addr); | ||||
|                 (Some(mmap_opts), ret_addr) | ||||
|  | ||||
| @ -44,6 +44,7 @@ static int test_read_from_procfs(const char *proc_inode) { | ||||
|         } | ||||
|     } while (len == sizeof(buf)); | ||||
|     close(fd); | ||||
|     printf("test read from %s:\n%s\n", proc_inode, buf); | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| @ -89,6 +90,15 @@ static int test_readlink_from_proc_self_cwd() { | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int test_read_from_proc_self_maps() { | ||||
|     const char *proc_maps = "/proc/self/maps"; | ||||
| 
 | ||||
|     if (test_read_from_procfs(proc_maps) < 0) { | ||||
|         THROW_ERROR("failed to read the cpuinfo"); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int test_readlink_from_proc_self_root() { | ||||
|     char root_buf[PATH_MAX] = { 0 }; | ||||
|     const char *proc_root = "/proc/self/root"; | ||||
| @ -282,6 +292,7 @@ static test_case_t test_cases[] = { | ||||
|     TEST_CASE(test_readdir_root), | ||||
|     TEST_CASE(test_readdir_self), | ||||
|     TEST_CASE(test_readdir_self_fd), | ||||
|     TEST_CASE(test_read_from_proc_self_maps), | ||||
| }; | ||||
| 
 | ||||
| int main(int argc, const char *argv[]) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user