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 {
|
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> {
|
pub fn open(inode: Arc<dyn INode>, abs_path: &str, flags: u32) -> Result<Self> {
|
||||||
let access_mode = AccessMode::from_u32(flags)?;
|
let access_mode = AccessMode::from_u32(flags)?;
|
||||||
if (access_mode.readable() && !inode.allow_read()?) {
|
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::cwd::ProcCwdSymINode;
|
||||||
use self::exe::ProcExeSymINode;
|
use self::exe::ProcExeSymINode;
|
||||||
use self::fd::LockedProcFdDirINode;
|
use self::fd::LockedProcFdDirINode;
|
||||||
|
use self::maps::ProcMapsINode;
|
||||||
use self::root::ProcRootSymINode;
|
use self::root::ProcRootSymINode;
|
||||||
use self::stat::ProcStatINode;
|
use self::stat::ProcStatINode;
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ mod comm;
|
|||||||
mod cwd;
|
mod cwd;
|
||||||
mod exe;
|
mod exe;
|
||||||
mod fd;
|
mod fd;
|
||||||
|
mod maps;
|
||||||
mod root;
|
mod root;
|
||||||
mod stat;
|
mod stat;
|
||||||
|
|
||||||
@ -60,6 +62,9 @@ impl LockedPidDirINode {
|
|||||||
// stat
|
// stat
|
||||||
let stat_inode = ProcStatINode::new(&file.process_ref);
|
let stat_inode = ProcStatINode::new(&file.process_ref);
|
||||||
file.entries.insert(String::from("stat"), stat_inode);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use super::super::elf_file::*;
|
use super::super::elf_file::*;
|
||||||
use super::ThreadRef;
|
use super::ThreadRef;
|
||||||
use crate::fs::{FileMode, INodeExt};
|
use crate::fs::{AsINodeFile, FileMode, INodeExt};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use rcore_fs::vfs::{FileType, INode, Metadata};
|
use rcore_fs::vfs::{FileType, INode, Metadata};
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
@ -13,10 +13,10 @@ use std::ffi::CString;
|
|||||||
pub fn load_exec_file_hdr_to_vec(
|
pub fn load_exec_file_hdr_to_vec(
|
||||||
file_path: &str,
|
file_path: &str,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
) -> Result<(Option<String>, Arc<dyn INode>, Vec<u8>, ElfHeader)> {
|
) -> Result<(Option<String>, FileRef, Vec<u8>, ElfHeader)> {
|
||||||
let (inode, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?;
|
let (file_ref, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?;
|
||||||
if elf_hdr.is_some() {
|
if elf_hdr.is_some() {
|
||||||
Ok((None, inode, file_buf, elf_hdr.unwrap()))
|
Ok((None, file_ref, file_buf, elf_hdr.unwrap()))
|
||||||
} else {
|
} else {
|
||||||
// loaded file is not Elf format, try script file
|
// loaded file is not Elf format, try script file
|
||||||
if !is_script_file(&file_buf) {
|
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"
|
"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)?;
|
load_file_hdr_to_vec(&interpreter_path, current_ref)?;
|
||||||
let interp_hdr = if interp_hdr.is_none() {
|
let interp_hdr = if interp_hdr.is_none() {
|
||||||
return_errno!(ENOEXEC, "scrip interpreter is not ELF format");
|
return_errno!(ENOEXEC, "scrip interpreter is not ELF format");
|
||||||
} else {
|
} else {
|
||||||
interp_hdr.unwrap()
|
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(
|
pub fn load_file_hdr_to_vec(
|
||||||
file_path: &str,
|
file_path: &str,
|
||||||
current_ref: &ThreadRef,
|
current_ref: &ThreadRef,
|
||||||
) -> Result<(Arc<dyn INode>, Vec<u8>, Option<ElfHeader>)> {
|
) -> Result<(FileRef, Vec<u8>, Option<ElfHeader>)> {
|
||||||
let inode = current_ref
|
let file_ref = current_ref
|
||||||
.fs()
|
.fs()
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.lookup_inode(file_path)
|
.open_file(file_path, 0, FileMode::S_IRUSR)?;
|
||||||
.map_err(|e| errno!(e.errno(), "cannot find the file"))?;
|
let inode = file_ref.as_inode_file()?.inode();
|
||||||
|
|
||||||
// Make sure the final file to exec is not a directory
|
// Make sure the final file to exec is not a directory
|
||||||
let metadata = inode.metadata()?;
|
let metadata = inode.metadata()?;
|
||||||
@ -105,12 +105,12 @@ pub fn load_file_hdr_to_vec(
|
|||||||
.read_elf64_lazy_as_vec()
|
.read_elf64_lazy_as_vec()
|
||||||
.map_err(|e| errno!(e.errno(), "failed to read the file"))?;
|
.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 {
|
if let Ok(elf_header) = elf_header {
|
||||||
Ok((inode, file_buf, Some(elf_header)))
|
Ok((file_ref, file_buf, Some(elf_header)))
|
||||||
} else {
|
} else {
|
||||||
// this file is not ELF format or there is something wrong when parsing
|
// this file is not ELF format or there is something wrong when parsing
|
||||||
warn!("parse elf header error = {}", elf_header.err().unwrap());
|
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>,
|
parent_process: Option<ProcessRef>,
|
||||||
) -> Result<ProcessRef> {
|
) -> Result<ProcessRef> {
|
||||||
let mut argv = argv.clone().to_vec();
|
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)?;
|
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.
|
// 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()
|
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"))?;
|
.cause_err(|e| errno!(e.errno(), "invalid executable"))?;
|
||||||
let ldso_path = exec_elf_hdr
|
let ldso_path = exec_elf_hdr
|
||||||
.elf_interpreter()
|
.elf_interpreter()
|
||||||
.ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?;
|
.ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?;
|
||||||
trace!("ldso_path = {:?}", ldso_path);
|
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)
|
load_file_hdr_to_vec(ldso_path, current_ref)
|
||||||
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
|
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
|
||||||
let ldso_elf_header = if ldso_elf_header.is_none() {
|
let ldso_elf_header = if ldso_elf_header.is_none() {
|
||||||
@ -196,7 +196,7 @@ fn new_process_common(
|
|||||||
} else {
|
} else {
|
||||||
ldso_elf_header.unwrap()
|
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"))?;
|
.cause_err(|e| errno!(e.errno(), "invalid ld.so"))?;
|
||||||
|
|
||||||
let new_process_ref = {
|
let new_process_ref = {
|
||||||
|
@ -15,7 +15,7 @@ const ELF64_HDR_SIZE: usize = 64;
|
|||||||
pub struct ElfFile<'a> {
|
pub struct ElfFile<'a> {
|
||||||
elf_buf: &'a [u8],
|
elf_buf: &'a [u8],
|
||||||
elf_inner: Elf<'a>,
|
elf_inner: Elf<'a>,
|
||||||
file_inode: &'a Arc<dyn INode>,
|
file_ref: &'a FileRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Debug for ElfFile<'a> {
|
impl<'a> Debug for ElfFile<'a> {
|
||||||
@ -30,7 +30,7 @@ impl<'a> Debug for ElfFile<'a> {
|
|||||||
|
|
||||||
impl<'a> ElfFile<'a> {
|
impl<'a> ElfFile<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
file_inode: &'a Arc<dyn INode>,
|
file_ref: &'a FileRef,
|
||||||
mut elf_buf: &'a mut [u8],
|
mut elf_buf: &'a mut [u8],
|
||||||
header: ElfHeader,
|
header: ElfHeader,
|
||||||
) -> Result<ElfFile<'a>> {
|
) -> Result<ElfFile<'a>> {
|
||||||
@ -64,7 +64,7 @@ impl<'a> ElfFile<'a> {
|
|||||||
intepreter_offset,
|
intepreter_offset,
|
||||||
intepreter_count
|
intepreter_count
|
||||||
);
|
);
|
||||||
file_inode.read_at(
|
file_ref.read_at(
|
||||||
intepreter_offset,
|
intepreter_offset,
|
||||||
&mut elf_buf[intepreter_offset..intepreter_offset + intepreter_count],
|
&mut elf_buf[intepreter_offset..intepreter_offset + intepreter_count],
|
||||||
);
|
);
|
||||||
@ -87,7 +87,7 @@ impl<'a> ElfFile<'a> {
|
|||||||
Ok(ElfFile {
|
Ok(ElfFile {
|
||||||
elf_buf,
|
elf_buf,
|
||||||
elf_inner,
|
elf_inner,
|
||||||
file_inode,
|
file_ref,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,11 +107,11 @@ impl<'a> ElfFile<'a> {
|
|||||||
self.elf_buf
|
self.elf_buf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_inode(&self) -> &Arc<dyn INode> {
|
pub fn file_ref(&self) -> &FileRef {
|
||||||
self.file_inode
|
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..
|
// TODO: Sanity check the number of program headers..
|
||||||
let mut phdr_start = 0;
|
let mut phdr_start = 0;
|
||||||
let mut phdr_end = 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;
|
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,
|
elf_hdr.e_phoff as usize,
|
||||||
&mut elf_buf[hdr_size..hdr_size + (program_hdr_table_size 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> {
|
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(
|
let vm_area = VMArea::new(
|
||||||
vm_range.clone(),
|
vm_range.clone(),
|
||||||
*options.perms(),
|
*options.perms(),
|
||||||
writeback_file,
|
options.initializer().backed_file(),
|
||||||
DUMMY_CHUNK_PROCESS_ID,
|
DUMMY_CHUNK_PROCESS_ID,
|
||||||
);
|
);
|
||||||
// Initialize the memory of the new range
|
// Initialize the memory of the new range
|
||||||
@ -178,7 +177,7 @@ impl Chunk {
|
|||||||
if internal_manager.chunk_manager().free_size() < options.size() {
|
if internal_manager.chunk_manager().free_size() < options.size() {
|
||||||
return_errno!(ENOMEM, "no enough size without trying. try other chunks");
|
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 {
|
pub fn is_single_vma(&self) -> bool {
|
||||||
@ -279,7 +278,11 @@ impl ChunkInternal {
|
|||||||
self.process_set.insert(pid);
|
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
|
&mut self.chunk_manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +75,10 @@ mod vm_util;
|
|||||||
|
|
||||||
use self::vm_layout::VMLayout;
|
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::process_vm::{MMapFlags, MRemapFlags, MSyncFlags, ProcessVM, ProcessVMBuilder};
|
||||||
pub use self::user_space_vm::USER_SPACE_VM_MANAGER;
|
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_perms::VMPerms;
|
||||||
pub use self::vm_range::VMRange;
|
pub use self::vm_range::VMRange;
|
||||||
pub use self::vm_util::{VMInitializer, VMMapOptionsBuilder};
|
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::user_space_vm::USER_SPACE_VM_MANAGER;
|
||||||
use super::vm_area::VMArea;
|
use super::vm_area::VMArea;
|
||||||
use super::vm_perms::VMPerms;
|
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::collections::HashSet;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
@ -117,7 +119,9 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> {
|
|||||||
.size(elf_layout.size())
|
.size(elf_layout.size())
|
||||||
.align(elf_layout.align())
|
.align(elf_layout.align())
|
||||||
.perms(VMPerms::ALL) // set it to read | write | exec for simplicity
|
.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()
|
.build()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
&self.handle_error_when_init(&chunks);
|
&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
|
// 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,
|
file_offset,
|
||||||
&mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size],
|
&mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size],
|
||||||
);
|
);
|
||||||
@ -318,6 +322,14 @@ impl ProcessVM {
|
|||||||
&self.mem_chunks
|
&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) {
|
pub fn add_mem_chunk(&self, chunk: ChunkRef) {
|
||||||
let mut mem_chunks = self.mem_chunks.write().unwrap();
|
let mut mem_chunks = self.mem_chunks.write().unwrap();
|
||||||
mem_chunks.insert(chunk);
|
mem_chunks.insert(chunk);
|
||||||
@ -488,28 +500,22 @@ impl ProcessVM {
|
|||||||
VMInitializer::DoNothing()
|
VMInitializer::DoNothing()
|
||||||
} else {
|
} else {
|
||||||
let file_ref = current!().file(fd)?;
|
let file_ref = current!().file(fd)?;
|
||||||
VMInitializer::LoadFromFile {
|
// Only shared, file-backed memory mappings have write-back files
|
||||||
file: file_ref,
|
let need_write_back = if flags.contains(MMapFlags::MAP_SHARED) {
|
||||||
offset: offset,
|
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()
|
let mmap_options = VMMapOptionsBuilder::default()
|
||||||
.size(size)
|
.size(size)
|
||||||
.addr(addr_option)
|
.addr(addr_option)
|
||||||
.perms(perms)
|
.perms(perms)
|
||||||
.initializer(initializer)
|
.initializer(initializer)
|
||||||
.writeback_file(writeback_file)
|
|
||||||
.build()?;
|
.build()?;
|
||||||
let mmap_addr = USER_SPACE_VM_MANAGER.mmap(&mmap_options)?;
|
let mmap_addr = USER_SPACE_VM_MANAGER.mmap(&mmap_options)?;
|
||||||
Ok(mmap_addr)
|
Ok(mmap_addr)
|
||||||
|
@ -2,6 +2,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
|
|
||||||
use super::vm_perms::VMPerms;
|
use super::vm_perms::VMPerms;
|
||||||
use super::vm_range::VMRange;
|
use super::vm_range::VMRange;
|
||||||
|
use super::vm_util::FileBacked;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use intrusive_collections::rbtree::{Link, RBTree};
|
use intrusive_collections::rbtree::{Link, RBTree};
|
||||||
@ -11,7 +12,7 @@ use intrusive_collections::{intrusive_adapter, KeyAdapter};
|
|||||||
pub struct VMArea {
|
pub struct VMArea {
|
||||||
range: VMRange,
|
range: VMRange,
|
||||||
perms: VMPerms,
|
perms: VMPerms,
|
||||||
writeback_file: Option<(FileRef, usize)>,
|
file_backed: Option<FileBacked>,
|
||||||
pid: pid_t,
|
pid: pid_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,13 +20,13 @@ impl VMArea {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
range: VMRange,
|
range: VMRange,
|
||||||
perms: VMPerms,
|
perms: VMPerms,
|
||||||
writeback_file: Option<(FileRef, usize)>,
|
file_backed: Option<FileBacked>,
|
||||||
pid: pid_t,
|
pid: pid_t,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
range,
|
range,
|
||||||
perms,
|
perms,
|
||||||
writeback_file,
|
file_backed,
|
||||||
pid,
|
pid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,20 +39,25 @@ impl VMArea {
|
|||||||
new_perms: VMPerms,
|
new_perms: VMPerms,
|
||||||
pid: pid_t,
|
pid: pid_t,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let new_writeback_file = vma.writeback_file.as_ref().map(|(file, file_offset)| {
|
let new_backed_file = vma.file_backed.as_ref().map(|file| {
|
||||||
let new_file = file.clone();
|
let mut new_file = file.clone();
|
||||||
|
let file_offset = file.offset();
|
||||||
|
|
||||||
let new_file_offset = if vma.start() < new_range.start() {
|
let new_file_offset = if vma.start() < new_range.start() {
|
||||||
let vma_offset = new_range.start() - vma.start();
|
let vma_offset = new_range.start() - vma.start();
|
||||||
*file_offset + vma_offset
|
file_offset + vma_offset
|
||||||
} else {
|
} else {
|
||||||
let vma_offset = vma.start() - new_range.start();
|
let vma_offset = vma.start() - new_range.start();
|
||||||
debug_assert!(*file_offset >= vma_offset);
|
debug_assert!(file_offset >= vma_offset);
|
||||||
*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 {
|
pub fn perms(&self) -> VMPerms {
|
||||||
@ -66,8 +72,20 @@ impl VMArea {
|
|||||||
self.pid
|
self.pid
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeback_file(&self) -> &Option<(FileRef, usize)> {
|
pub fn init_file(&self) -> Option<(&FileRef, usize)> {
|
||||||
&self.writeback_file
|
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) {
|
pub fn set_perms(&mut self, new_perms: VMPerms) {
|
||||||
@ -103,15 +121,19 @@ impl VMArea {
|
|||||||
let old_start = self.start();
|
let old_start = self.start();
|
||||||
self.range.set_start(new_start);
|
self.range.set_start(new_start);
|
||||||
|
|
||||||
// If the updates to the VMA needs to write back to a file, then the
|
if let Some(file) = self.file_backed.as_mut() {
|
||||||
// file offset must be adjusted according to the new start address.
|
if !file.need_write_back() {
|
||||||
if let Some((_, offset)) = self.writeback_file.as_mut() {
|
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 {
|
if old_start < new_start {
|
||||||
*offset += new_start - old_start;
|
file.set_offset(offset + (new_start - old_start));
|
||||||
} else {
|
} else {
|
||||||
// The caller must guarantee that the new start makes sense
|
// The caller must guarantee that the new start makes sense
|
||||||
debug_assert!(*offset >= old_start - new_start);
|
debug_assert!(offset >= old_start - new_start);
|
||||||
*offset -= old_start - new_start;
|
file.set_offset(offset - (old_start - new_start));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,22 +245,3 @@ impl VMAObj {
|
|||||||
&self.vma
|
&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
|
.free_manager
|
||||||
.find_free_range_internal(size, align, addr)?;
|
.find_free_range_internal(size, align, addr)?;
|
||||||
let new_addr = new_range.start();
|
let new_addr = new_range.start();
|
||||||
let writeback_file = options.writeback_file().clone();
|
|
||||||
let current_pid = current!().process().pid();
|
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
|
// Initialize the memory of the new range
|
||||||
let buf = unsafe { new_vma.as_slice_mut() };
|
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.
|
/// 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) {
|
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,
|
None => return,
|
||||||
Some((file_and_offset)) => file_and_offset,
|
Some((file_and_offset)) => file_and_offset,
|
||||||
};
|
};
|
||||||
@ -430,7 +434,7 @@ impl ChunkManager {
|
|||||||
if !cond_fn(file) {
|
if !cond_fn(file) {
|
||||||
return;
|
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> {
|
pub fn find_mmap_region(&self, addr: usize) -> Result<VMRange> {
|
||||||
|
@ -184,7 +184,11 @@ impl VMManager {
|
|||||||
"mmap with addr in existing default chunk: {:?}",
|
"mmap with addr in existing default chunk: {:?}",
|
||||||
chunk.range()
|
chunk.range()
|
||||||
);
|
);
|
||||||
return chunk_internal.lock().unwrap().chunk_manager().mmap(options);
|
return chunk_internal
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.chunk_manager_mut()
|
||||||
|
.mmap(options);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
match addr {
|
match addr {
|
||||||
@ -287,7 +291,7 @@ impl VMManager {
|
|||||||
ChunkType::MultiVMA(manager) => manager
|
ChunkType::MultiVMA(manager) => manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.munmap_range(munmap_range)?,
|
.munmap_range(munmap_range)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +311,7 @@ impl VMManager {
|
|||||||
return manager
|
return manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.munmap_range(munmap_range);
|
.munmap_range(munmap_range);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
@ -353,7 +357,7 @@ impl VMManager {
|
|||||||
return manager
|
return manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.mprotect(addr, size, perms);
|
.mprotect(addr, size, perms);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(_) => {
|
ChunkType::SingleVMA(_) => {
|
||||||
@ -383,7 +387,7 @@ impl VMManager {
|
|||||||
return manager
|
return manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.msync_by_range(&sync_range);
|
.msync_by_range(&sync_range);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(vma) => {
|
ChunkType::SingleVMA(vma) => {
|
||||||
@ -405,7 +409,7 @@ impl VMManager {
|
|||||||
manager
|
manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.msync_by_file(sync_file);
|
.msync_by_file(sync_file);
|
||||||
}
|
}
|
||||||
ChunkType::SingleVMA(vma) => {
|
ChunkType::SingleVMA(vma) => {
|
||||||
@ -452,7 +456,7 @@ impl VMManager {
|
|||||||
ChunkType::MultiVMA(manager) => manager
|
ChunkType::MultiVMA(manager) => manager
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.chunk_manager()
|
.chunk_manager_mut()
|
||||||
.parse_mremap_options(options),
|
.parse_mremap_options(options),
|
||||||
ChunkType::SingleVMA(vma) => {
|
ChunkType::SingleVMA(vma) => {
|
||||||
self.parse_mremap_options_for_single_vma_chunk(options, 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);
|
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 {
|
impl Default for VMPerms {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// use super::vm_area::VMArea;
|
|
||||||
// use super::free_space_manager::VMFreeSpaceManager;
|
|
||||||
use super::vm_area::*;
|
use super::vm_area::*;
|
||||||
use super::vm_perms::VMPerms;
|
use super::vm_perms::VMPerms;
|
||||||
|
use crate::fs::FileMode;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use intrusive_collections::rbtree::{Link, RBTree};
|
use intrusive_collections::rbtree::{Link, RBTree};
|
||||||
@ -18,15 +17,19 @@ pub enum VMInitializer {
|
|||||||
CopyFrom {
|
CopyFrom {
|
||||||
range: VMRange,
|
range: VMRange,
|
||||||
},
|
},
|
||||||
LoadFromFile {
|
FileBacked {
|
||||||
file: FileRef,
|
file: FileBacked,
|
||||||
offset: usize,
|
},
|
||||||
|
// 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
|
// For file-backed mremap which may move from old range to new range and read extra bytes from file
|
||||||
CopyOldAndReadNew {
|
CopyOldAndReadNew {
|
||||||
old_range: VMRange,
|
old_range: VMRange,
|
||||||
file: FileRef,
|
file: FileRef,
|
||||||
offset: usize, // read file from this offset
|
offset: usize, // read file from this offset
|
||||||
|
new_writeback_file: FileBacked,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +42,7 @@ impl Default for VMInitializer {
|
|||||||
impl VMInitializer {
|
impl VMInitializer {
|
||||||
pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> {
|
pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
VMInitializer::DoNothing() => {
|
VMInitializer::DoNothing() | VMInitializer::ElfSpecific { .. } => {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
VMInitializer::FillZeros() => {
|
VMInitializer::FillZeros() => {
|
||||||
@ -55,10 +58,11 @@ impl VMInitializer {
|
|||||||
*b = 0;
|
*b = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VMInitializer::LoadFromFile { file, offset } => {
|
VMInitializer::FileBacked { file } => {
|
||||||
// TODO: make sure that read_at does not move file cursor
|
// TODO: make sure that read_at does not move file cursor
|
||||||
let len = file
|
let len = file
|
||||||
.read_at(*offset, buf)
|
.file_ref()
|
||||||
|
.read_at(file.offset(), buf)
|
||||||
.cause_err(|_| errno!(EACCES, "failed to init memory from file"))?;
|
.cause_err(|_| errno!(EACCES, "failed to init memory from file"))?;
|
||||||
for b in &mut buf[len..] {
|
for b in &mut buf[len..] {
|
||||||
*b = 0;
|
*b = 0;
|
||||||
@ -68,6 +72,7 @@ impl VMInitializer {
|
|||||||
old_range,
|
old_range,
|
||||||
file,
|
file,
|
||||||
offset,
|
offset,
|
||||||
|
new_writeback_file,
|
||||||
} => {
|
} => {
|
||||||
// TODO: Handle old_range with non-readable subrange
|
// TODO: Handle old_range with non-readable subrange
|
||||||
let src_slice = unsafe { old_range.as_slice() };
|
let src_slice = unsafe { old_range.as_slice() };
|
||||||
@ -85,6 +90,66 @@ impl VMInitializer {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
@ -118,8 +183,6 @@ pub struct VMMapOptions {
|
|||||||
perms: VMPerms,
|
perms: VMPerms,
|
||||||
addr: VMMapAddr,
|
addr: VMMapAddr,
|
||||||
initializer: VMInitializer,
|
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
|
// VMMapOptionsBuilder is generated automatically, except the build function
|
||||||
@ -165,14 +228,12 @@ impl VMMapOptionsBuilder {
|
|||||||
Some(initializer) => initializer.clone(),
|
Some(initializer) => initializer.clone(),
|
||||||
None => VMInitializer::default(),
|
None => VMInitializer::default(),
|
||||||
};
|
};
|
||||||
let writeback_file = self.writeback_file.take().unwrap_or_default();
|
|
||||||
Ok(VMMapOptions {
|
Ok(VMMapOptions {
|
||||||
size,
|
size,
|
||||||
align,
|
align,
|
||||||
perms,
|
perms,
|
||||||
addr,
|
addr,
|
||||||
initializer,
|
initializer,
|
||||||
writeback_file,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,10 +258,6 @@ impl VMMapOptions {
|
|||||||
pub fn initializer(&self) -> &VMInitializer {
|
pub fn initializer(&self) -> &VMInitializer {
|
||||||
&self.initializer
|
&self.initializer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeback_file(&self) -> &Option<(FileRef, usize)> {
|
|
||||||
&self.writeback_file
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
@ -375,17 +432,18 @@ pub trait VMRemapParser {
|
|||||||
}
|
}
|
||||||
(MRemapFlags::None, VMRemapSizeType::Growing, Some((backed_file, offset))) => {
|
(MRemapFlags::None, VMRemapSizeType::Growing, Some((backed_file, offset))) => {
|
||||||
// Update writeback file offset
|
// Update writeback file offset
|
||||||
let new_writeback_file = Some((backed_file.clone(), offset + vma.size()));
|
let vm_initializer_for_new_range = VMInitializer::FileBacked {
|
||||||
let vm_initializer_for_new_range = VMInitializer::LoadFromFile {
|
file: FileBacked::new(
|
||||||
file: backed_file.clone(),
|
backed_file.clone(),
|
||||||
offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
|
offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
|
||||||
|
true,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
let mmap_opts = VMMapOptionsBuilder::default()
|
let mmap_opts = VMMapOptionsBuilder::default()
|
||||||
.size(new_size - old_size)
|
.size(new_size - old_size)
|
||||||
.addr(VMMapAddr::Need(old_range.end()))
|
.addr(VMMapAddr::Need(old_range.end()))
|
||||||
.perms(perms)
|
.perms(perms)
|
||||||
.initializer(vm_initializer_for_new_range)
|
.initializer(vm_initializer_for_new_range)
|
||||||
.writeback_file(new_writeback_file)
|
|
||||||
.build()?;
|
.build()?;
|
||||||
let ret_addr = Some(old_addr);
|
let ret_addr = Some(old_addr);
|
||||||
(Some(mmap_opts), ret_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)?;
|
VMRange::new_with_size(old_addr + old_size, new_size - old_size)?;
|
||||||
if self.is_free_range(&prefered_new_range) {
|
if self.is_free_range(&prefered_new_range) {
|
||||||
// Don't need to move the old range
|
// Don't need to move the old range
|
||||||
let vm_initializer_for_new_range = VMInitializer::LoadFromFile {
|
let vm_initializer_for_new_range = VMInitializer::FileBacked {
|
||||||
file: backed_file.clone(),
|
file: FileBacked::new(
|
||||||
offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
|
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()
|
let mmap_ops = VMMapOptionsBuilder::default()
|
||||||
.size(prefered_new_range.size())
|
.size(prefered_new_range.size())
|
||||||
.addr(VMMapAddr::Need(prefered_new_range.start()))
|
.addr(VMMapAddr::Need(prefered_new_range.start()))
|
||||||
.perms(perms)
|
.perms(perms)
|
||||||
.initializer(vm_initializer_for_new_range)
|
.initializer(vm_initializer_for_new_range)
|
||||||
.writeback_file(new_writeback_file)
|
|
||||||
.build()?;
|
.build()?;
|
||||||
(Some(mmap_ops), Some(old_addr))
|
(Some(mmap_ops), Some(old_addr))
|
||||||
} else {
|
} else {
|
||||||
@ -441,19 +499,19 @@ pub trait VMRemapParser {
|
|||||||
let copy_end = vma.end();
|
let copy_end = vma.end();
|
||||||
let copy_range = VMRange::new(old_range.start(), copy_end)?;
|
let copy_range = VMRange::new(old_range.start(), copy_end)?;
|
||||||
let reread_file_start_offset = copy_end - vma.start();
|
let reread_file_start_offset = copy_end - vma.start();
|
||||||
|
let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true);
|
||||||
VMInitializer::CopyOldAndReadNew {
|
VMInitializer::CopyOldAndReadNew {
|
||||||
old_range: copy_range,
|
old_range: copy_range,
|
||||||
file: backed_file.clone(),
|
file: backed_file.clone(),
|
||||||
offset: reread_file_start_offset,
|
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()
|
let mmap_ops = VMMapOptionsBuilder::default()
|
||||||
.size(new_size)
|
.size(new_size)
|
||||||
.addr(VMMapAddr::Any)
|
.addr(VMMapAddr::Any)
|
||||||
.perms(perms)
|
.perms(perms)
|
||||||
.initializer(vm_initializer_for_new_range)
|
.initializer(vm_initializer_for_new_range)
|
||||||
.writeback_file(new_writeback_file)
|
|
||||||
.build()?;
|
.build()?;
|
||||||
// Cannot determine the returned address for now, which can only be obtained after calling mmap
|
// Cannot determine the returned address for now, which can only be obtained after calling mmap
|
||||||
let ret_addr = None;
|
let ret_addr = None;
|
||||||
@ -476,19 +534,19 @@ pub trait VMRemapParser {
|
|||||||
let copy_end = vma.end();
|
let copy_end = vma.end();
|
||||||
let copy_range = VMRange::new(old_range.start(), copy_end)?;
|
let copy_range = VMRange::new(old_range.start(), copy_end)?;
|
||||||
let reread_file_start_offset = copy_end - vma.start();
|
let reread_file_start_offset = copy_end - vma.start();
|
||||||
|
let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true);
|
||||||
VMInitializer::CopyOldAndReadNew {
|
VMInitializer::CopyOldAndReadNew {
|
||||||
old_range: copy_range,
|
old_range: copy_range,
|
||||||
file: backed_file.clone(),
|
file: backed_file.clone(),
|
||||||
offset: reread_file_start_offset,
|
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()
|
let mmap_opts = VMMapOptionsBuilder::default()
|
||||||
.size(new_size)
|
.size(new_size)
|
||||||
.addr(VMMapAddr::Force(new_addr))
|
.addr(VMMapAddr::Force(new_addr))
|
||||||
.perms(perms)
|
.perms(perms)
|
||||||
.initializer(vm_initializer_for_new_range)
|
.initializer(vm_initializer_for_new_range)
|
||||||
.writeback_file(new_writeback_file)
|
|
||||||
.build()?;
|
.build()?;
|
||||||
let ret_addr = Some(new_addr);
|
let ret_addr = Some(new_addr);
|
||||||
(Some(mmap_opts), ret_addr)
|
(Some(mmap_opts), ret_addr)
|
||||||
|
@ -44,6 +44,7 @@ static int test_read_from_procfs(const char *proc_inode) {
|
|||||||
}
|
}
|
||||||
} while (len == sizeof(buf));
|
} while (len == sizeof(buf));
|
||||||
close(fd);
|
close(fd);
|
||||||
|
printf("test read from %s:\n%s\n", proc_inode, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +90,15 @@ static int test_readlink_from_proc_self_cwd() {
|
|||||||
return 0;
|
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() {
|
static int test_readlink_from_proc_self_root() {
|
||||||
char root_buf[PATH_MAX] = { 0 };
|
char root_buf[PATH_MAX] = { 0 };
|
||||||
const char *proc_root = "/proc/self/root";
|
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_root),
|
||||||
TEST_CASE(test_readdir_self),
|
TEST_CASE(test_readdir_self),
|
||||||
TEST_CASE(test_readdir_self_fd),
|
TEST_CASE(test_readdir_self_fd),
|
||||||
|
TEST_CASE(test_read_from_proc_self_maps),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char *argv[]) {
|
int main(int argc, const char *argv[]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user