diff --git a/kernel/src/fs/procfs/pid/task/maps.rs b/kernel/src/fs/procfs/pid/task/maps.rs index e2a69c597..3f17a82f7 100644 --- a/kernel/src/fs/procfs/pid/task/maps.rs +++ b/kernel/src/fs/procfs/pid/task/maps.rs @@ -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()) diff --git a/kernel/src/process/process_vm/heap.rs b/kernel/src/process/process_vm/heap.rs index 0c2046207..8656af2c8 100644 --- a/kernel/src/process/process_vm/heap.rs +++ b/kernel/src/process/process_vm/heap.rs @@ -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 { 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. diff --git a/kernel/src/process/program_loader/elf/load_elf.rs b/kernel/src/process/program_loader/elf/load_elf.rs index 475b7a3eb..30a8bd2bb 100644 --- a/kernel/src/process/program_loader/elf/load_elf.rs +++ b/kernel/src/process/program_loader/elf/load_elf.rs @@ -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(); diff --git a/kernel/src/syscall/brk.rs b/kernel/src/syscall/brk.rs index 758cba229..632cb1781 100644 --- a/kernel/src/syscall/brk.rs +++ b/kernel/src/syscall/brk.rs @@ -18,7 +18,7 @@ pub fn sys_brk(heap_end: u64, ctx: &Context) -> Result { 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 _)) diff --git a/kernel/src/syscall/mmap.rs b/kernel/src/syscall/mmap.rs index e963c1be3..bbee017e5 100644 --- a/kernel/src/syscall/mmap.rs +++ b/kernel/src/syscall/mmap.rs @@ -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(); } diff --git a/kernel/src/vm/vmar/vm_mapping.rs b/kernel/src/vm/vmar/vm_mapping.rs index 59d4f7676..e78e24183 100644 --- a/kernel/src/vm/vmar/vm_mapping.rs +++ b/kernel/src/vm/vmar/vm_mapping.rs @@ -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>, + /// The path of the file that backs the mapping. + path: Option, /// Whether the mapping is shared. /// /// The updates to a shared mapping are visible among processes, or carried @@ -92,11 +98,13 @@ impl Interval 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>, + path: Option, 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: - 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: + 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 { map_size, mapped_mem, inode: left.inode.clone(), + path: left.path.clone(), ..*left }) } diff --git a/kernel/src/vm/vmar/vmar_impls/map.rs b/kernel/src/vm/vmar/vmar_impls/map.rs index 982aac930..8f9dd1beb 100644 --- a/kernel/src/vm/vmar/vmar_impls/map.rs +++ b/kernel/src/vm/vmar/vmar_impls/map.rs @@ -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>, mappable: Option, + path: Option, 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 { 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, diff --git a/test/initramfs/src/syscall/gvisor/blocklists/proc_test b/test/initramfs/src/syscall/gvisor/blocklists/proc_test index 457b08dee..0e072e159 100644 --- a/test/initramfs/src/syscall/gvisor/blocklists/proc_test +++ b/test/initramfs/src/syscall/gvisor/blocklists/proc_test @@ -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