Add entries other than `[stack]` in `/proc/[pid]/maps`
This commit is contained in:
parent
fb8c9e0c27
commit
08d54ec6ad
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
utils::{Inode, mkmod},
|
||||
},
|
||||
prelude::*,
|
||||
process::Process,
|
||||
process::{Process, posix_thread::AsPosixThread},
|
||||
vm::vmar::{VMAR_CAP_ADDR, VMAR_LOWEST_ADDR},
|
||||
};
|
||||
|
||||
|
|
@ -36,16 +36,13 @@ impl FileOps for MapsFileOps {
|
|||
return_errno_with_message!(Errno::ESRCH, "the process has exited");
|
||||
};
|
||||
|
||||
let user_stack_top = vmar.process_vm().init_stack().user_stack_top();
|
||||
let current = current_thread!();
|
||||
let fs_ref = current.as_posix_thread().unwrap().read_fs();
|
||||
let path_resolver = fs_ref.resolver().read();
|
||||
|
||||
let guard = vmar.query(VMAR_LOWEST_ADDR..VMAR_CAP_ADDR);
|
||||
for vm_mapping in guard.iter() {
|
||||
if vm_mapping.map_to_addr() <= user_stack_top && vm_mapping.map_end() > user_stack_top {
|
||||
vm_mapping.print_to_maps(&mut printer, "[stack]")?;
|
||||
} else {
|
||||
// TODO: Print the status of mappings other than the stack.
|
||||
continue;
|
||||
}
|
||||
vm_mapping.print_to_maps(&mut printer, vmar, &path_resolver)?;
|
||||
}
|
||||
|
||||
Ok(printer.bytes_written())
|
||||
|
|
|
|||
|
|
@ -75,11 +75,11 @@ impl Heap {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the current heap end.
|
||||
pub fn heap_end(&self) -> Vaddr {
|
||||
/// Returns the current heap range.
|
||||
pub fn heap_range(&self) -> Range<Vaddr> {
|
||||
let inner = self.inner.lock();
|
||||
let inner = inner.as_ref().expect("Heap is not initialized");
|
||||
inner.heap_range.end
|
||||
inner.heap_range.clone()
|
||||
}
|
||||
|
||||
/// Modifies the end address of the heap.
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@ fn map_segment_vmo(
|
|||
let mut vm_map_options = vmar
|
||||
.new_map(segment_size, perms)?
|
||||
.vmo(elf_vmo.clone())
|
||||
.path(elf_file.clone())
|
||||
.vmo_offset(segment_offset)
|
||||
.can_overwrite(true);
|
||||
vm_map_options = vm_map_options.offset(offset).handle_page_faults_around();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub fn sys_brk(heap_end: u64, ctx: &Context) -> Result<SyscallReturn> {
|
|||
Some(addr) => user_heap
|
||||
.modify_heap_end(addr, ctx)
|
||||
.unwrap_or_else(|cur_heap_end| cur_heap_end),
|
||||
None => user_heap.heap_end(),
|
||||
None => user_heap.heap_range().end,
|
||||
};
|
||||
|
||||
Ok(SyscallReturn::Return(current_heap_end as _))
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ fn do_sys_mmap(
|
|||
|
||||
options = options
|
||||
.may_perms(vm_may_perms)
|
||||
.mappable(file.mappable()?)
|
||||
.mappable(file.as_ref().as_ref())?
|
||||
.vmo_offset(offset)
|
||||
.handle_page_faults_around();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use alloc::{borrow::Cow, format};
|
||||
use core::{
|
||||
cmp::{max, min},
|
||||
num::NonZeroUsize,
|
||||
|
|
@ -17,9 +18,12 @@ use ostd::{
|
|||
task::disable_preempt,
|
||||
};
|
||||
|
||||
use super::{RssType, interval_set::Interval, util::is_intersected, vmar_impls::RssDelta};
|
||||
use super::{RssType, Vmar, interval_set::Interval, util::is_intersected, vmar_impls::RssDelta};
|
||||
use crate::{
|
||||
fs::utils::Inode,
|
||||
fs::{
|
||||
path::{Path, PathResolver},
|
||||
utils::Inode,
|
||||
},
|
||||
prelude::*,
|
||||
thread::exception::PageFaultInfo,
|
||||
vm::{
|
||||
|
|
@ -69,6 +73,8 @@ pub struct VmMapping {
|
|||
/// And the `mapped_mem` field must be the page cache of the inode, i.e.
|
||||
/// [`MappedMemory::Vmo`].
|
||||
inode: Option<Arc<dyn Inode>>,
|
||||
/// The path of the file that backs the mapping.
|
||||
path: Option<Path>,
|
||||
/// Whether the mapping is shared.
|
||||
///
|
||||
/// The updates to a shared mapping are visible among processes, or carried
|
||||
|
|
@ -92,11 +98,13 @@ impl Interval<Vaddr> for VmMapping {
|
|||
/***************************** Basic methods *********************************/
|
||||
|
||||
impl VmMapping {
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub(super) fn new(
|
||||
map_size: NonZeroUsize,
|
||||
map_to_addr: Vaddr,
|
||||
mapped_mem: MappedMemory,
|
||||
inode: Option<Arc<dyn Inode>>,
|
||||
path: Option<Path>,
|
||||
is_shared: bool,
|
||||
handle_page_faults_around: bool,
|
||||
perms: VmPerms,
|
||||
|
|
@ -106,6 +114,7 @@ impl VmMapping {
|
|||
map_to_addr,
|
||||
mapped_mem,
|
||||
inode,
|
||||
path,
|
||||
is_shared,
|
||||
handle_page_faults_around,
|
||||
perms,
|
||||
|
|
@ -116,6 +125,7 @@ impl VmMapping {
|
|||
VmMapping {
|
||||
mapped_mem: self.mapped_mem.dup(),
|
||||
inode: self.inode.clone(),
|
||||
path: self.path.clone(),
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
|
@ -205,7 +215,12 @@ impl VmMapping {
|
|||
/// Prints the mapping information in the format of `/proc/[pid]/maps`.
|
||||
///
|
||||
/// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/fs/proc/task_mmu.c#L304-L359>
|
||||
pub fn print_to_maps(&self, printer: &mut VmPrinter, name: &str) -> Result<()> {
|
||||
pub fn print_to_maps(
|
||||
&self,
|
||||
printer: &mut VmPrinter,
|
||||
parent_vmar: &Vmar,
|
||||
path_resolver: &PathResolver,
|
||||
) -> Result<()> {
|
||||
let start = self.map_to_addr;
|
||||
let end = self.map_end();
|
||||
let read_char = if self.perms.contains(VmPerms::READ) {
|
||||
|
|
@ -231,9 +246,8 @@ impl VmMapping {
|
|||
.unwrap_or((0, 0));
|
||||
let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0);
|
||||
|
||||
writeln!(
|
||||
printer,
|
||||
"{:x}-{:x} {}{}{}{} {:08x} {:02x}:{:02x} {:<26} {}",
|
||||
let line = format!(
|
||||
"{:x}-{:x} {}{}{}{} {:08x} {:02x}:{:02x} {} ",
|
||||
start,
|
||||
end,
|
||||
read_char,
|
||||
|
|
@ -244,8 +258,57 @@ impl VmMapping {
|
|||
dev_major,
|
||||
dev_minor,
|
||||
ino,
|
||||
name
|
||||
)?;
|
||||
);
|
||||
|
||||
let name = || {
|
||||
let process_vm = parent_vmar.process_vm();
|
||||
let user_stack_top = process_vm.init_stack().user_stack_top();
|
||||
|
||||
if self.map_to_addr <= user_stack_top && self.map_end() > user_stack_top {
|
||||
return Some(Cow::Borrowed("[stack]"));
|
||||
}
|
||||
|
||||
let heap_range = process_vm.heap().heap_range();
|
||||
if self.map_to_addr >= heap_range.start && self.map_end() <= heap_range.end {
|
||||
return Some(Cow::Borrowed("[heap]"));
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
|
||||
if let Some(vmo) = self.vmo() {
|
||||
use crate::vdso::{VDSO_VMO_LAYOUT, vdso_vmo};
|
||||
|
||||
if let Some(vdso_vmo) = vdso_vmo()
|
||||
&& Arc::ptr_eq(vmo.vmo(), &vdso_vmo)
|
||||
{
|
||||
let offset = vmo.offset();
|
||||
if offset == VDSO_VMO_LAYOUT.data_segment_offset {
|
||||
return Some(Cow::Borrowed("[vvar]"));
|
||||
} else if offset == VDSO_VMO_LAYOUT.text_segment_offset {
|
||||
return Some(Cow::Borrowed("[vdso]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(path) = &self.path {
|
||||
return Some(Cow::Owned(path_resolver.make_abs_path(path).into_string()));
|
||||
}
|
||||
|
||||
// Reference: <https://github.com/google/gvisor/blob/38123b53da96ff6983fcc103dfe2a9cc4e0d80c8/test/syscalls/linux/proc.cc#L1158-L1172>
|
||||
if matches!(&self.mapped_mem, MappedMemory::Vmo(_)) && self.is_shared {
|
||||
return Some(Cow::Borrowed("/dev/zero (deleted)"));
|
||||
}
|
||||
|
||||
// Common anonymous mappings do not have names.
|
||||
None
|
||||
};
|
||||
|
||||
let name = name();
|
||||
|
||||
if let Some(name) = name {
|
||||
writeln!(printer, "{:<72} {}", line, name)?;
|
||||
} else {
|
||||
writeln!(printer, "{}", line)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -578,6 +641,7 @@ impl VmMapping {
|
|||
map_size: NonZeroUsize::new(left_size).unwrap(),
|
||||
mapped_mem: l_mapped_mem,
|
||||
inode: self.inode.clone(),
|
||||
path: self.path.clone(),
|
||||
..self
|
||||
};
|
||||
let right = Self {
|
||||
|
|
@ -900,6 +964,7 @@ fn try_merge(left: &VmMapping, right: &VmMapping) -> Option<VmMapping> {
|
|||
map_size,
|
||||
mapped_mem,
|
||||
inode: left.inode.clone(),
|
||||
path: left.path.clone(),
|
||||
..*left
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,11 @@ use core::num::NonZeroUsize;
|
|||
|
||||
use super::{MappedMemory, MappedVmo, RssDelta, VmMapping, Vmar};
|
||||
use crate::{
|
||||
fs::{file_handle::Mappable, ramfs::memfd::MemfdInode},
|
||||
fs::{
|
||||
file_handle::{FileLike, Mappable},
|
||||
path::Path,
|
||||
ramfs::memfd::MemfdInode,
|
||||
},
|
||||
prelude::*,
|
||||
vm::{perms::VmPerms, vmo::Vmo},
|
||||
};
|
||||
|
|
@ -50,6 +54,7 @@ pub struct VmarMapOptions<'a> {
|
|||
parent: &'a Vmar,
|
||||
vmo: Option<Arc<Vmo>>,
|
||||
mappable: Option<Mappable>,
|
||||
path: Option<Path>,
|
||||
perms: VmPerms,
|
||||
may_perms: VmPerms,
|
||||
vmo_offset: usize,
|
||||
|
|
@ -71,6 +76,7 @@ impl<'a> VmarMapOptions<'a> {
|
|||
parent,
|
||||
vmo: None,
|
||||
mappable: None,
|
||||
path: None,
|
||||
perms,
|
||||
may_perms: VmPerms::ALL_MAY_PERMS,
|
||||
vmo_offset: 0,
|
||||
|
|
@ -124,6 +130,19 @@ impl<'a> VmarMapOptions<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the [`Path`] of the mapping.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if a [`Mappable`] is already provided.
|
||||
pub fn path(mut self, path: Path) -> Self {
|
||||
if self.mappable.is_some() {
|
||||
panic!("Cannot set `path` when `mappable` is already set");
|
||||
}
|
||||
self.path = Some(path);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the offset of the first memory page in the VMO that is to be
|
||||
/// mapped into the VMAR.
|
||||
///
|
||||
|
|
@ -194,23 +213,34 @@ impl<'a> VmarMapOptions<'a> {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function panics if a [`Vmo`] or [`Mappable`] is already provided.
|
||||
pub fn mappable(mut self, mappable: Mappable) -> Self {
|
||||
/// This function panics if a [`Vmo`], [`Path`] or [`Mappable`] is already provided.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function returns an error if the file does not have a corresponding
|
||||
/// mappable object of [`crate::fs::file_handle::Mappable`].
|
||||
pub fn mappable(mut self, file: &dyn FileLike) -> Result<Self> {
|
||||
if self.vmo.is_some() {
|
||||
panic!("Cannot set `mappable` when `vmo` is already set");
|
||||
}
|
||||
if self.path.is_some() {
|
||||
panic!("Cannot set `mappable` when `path` is already set");
|
||||
}
|
||||
if self.mappable.is_some() {
|
||||
panic!("Cannot set `mappable` when `mappable` is already set");
|
||||
}
|
||||
|
||||
let mappable = file.mappable()?;
|
||||
|
||||
// Verify whether the page cache inode is valid.
|
||||
if let Mappable::Inode(ref inode) = mappable {
|
||||
self.vmo = Some(inode.page_cache().expect("Map an inode without page cache"));
|
||||
}
|
||||
|
||||
self.mappable = Some(mappable);
|
||||
self.path = Some(file.path().clone());
|
||||
|
||||
self
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Creates the mapping and adds it to the parent VMAR.
|
||||
|
|
@ -224,6 +254,7 @@ impl<'a> VmarMapOptions<'a> {
|
|||
parent,
|
||||
vmo,
|
||||
mappable,
|
||||
path,
|
||||
perms,
|
||||
mut may_perms,
|
||||
vmo_offset,
|
||||
|
|
@ -321,6 +352,7 @@ impl<'a> VmarMapOptions<'a> {
|
|||
map_to_addr,
|
||||
mapped_mem,
|
||||
inode,
|
||||
path,
|
||||
is_shared,
|
||||
handle_page_faults_around,
|
||||
perms | may_perms,
|
||||
|
|
|
|||
|
|
@ -28,11 +28,9 @@ ProcSelfCwd.Absolute
|
|||
ProcSelfFd.OpenFd
|
||||
# TODO: Support `O_LARGEFILE` flag.
|
||||
ProcSelfFdInfo.Flags
|
||||
ProcSelfMaps.Basic
|
||||
ProcSelfMaps.Map1
|
||||
# TODO: Mappings created with only `PROT_WRITE` should be shown as `-w-`.
|
||||
ProcSelfMaps.Map2
|
||||
ProcSelfMaps.MapUnmap
|
||||
ProcSelfMaps.SharedAnon
|
||||
ProcSelfMounts.ContainsProcfsEntry
|
||||
ProcSelfMounts.RequiredFieldsArePresent
|
||||
ProcSelfRoot.IsRoot
|
||||
|
|
|
|||
Loading…
Reference in New Issue