diff --git a/kernel/src/fs/procfs/pid/task/maps.rs b/kernel/src/fs/procfs/pid/task/maps.rs new file mode 100644 index 000000000..77090ed7c --- /dev/null +++ b/kernel/src/fs/procfs/pid/task/maps.rs @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MPL-2.0 + +use aster_util::printer::VmPrinter; + +use super::TidDirOps; +use crate::{ + fs::{ + procfs::template::{FileOps, ProcFileBuilder}, + utils::{Inode, mkmod}, + }, + prelude::*, + process::Process, + vm::vmar::userspace_range, +}; + +/// Represents the inode at `/proc/[pid]/task/[tid]/maps` (and also `/proc/[pid]/maps`). +pub struct MapsFileOps(Arc); + +impl MapsFileOps { + pub fn new_inode(dir: &TidDirOps, parent: Weak) -> Arc { + let process_ref = dir.process_ref.clone(); + // Reference: + ProcFileBuilder::new(Self(process_ref), mkmod!(a+r)) + .parent(parent) + .build() + .unwrap() + } +} + +impl FileOps for MapsFileOps { + fn read_at(&self, offset: usize, writer: &mut VmWriter) -> Result { + let mut printer = VmPrinter::new_skip(writer, offset); + + let vmar_guard = self.0.lock_vmar(); + let Some(vmar) = vmar_guard.as_ref() else { + return_errno_with_message!(Errno::ESRCH, "the process has exited"); + }; + + let user_stack_top = vmar.process_vm().init_stack().user_stack_top(); + + let guard = vmar.query(userspace_range()); + 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; + } + } + + Ok(printer.bytes_written()) + } +} diff --git a/kernel/src/fs/procfs/pid/task/mod.rs b/kernel/src/fs/procfs/pid/task/mod.rs index 6a72b3ef3..4750341fa 100644 --- a/kernel/src/fs/procfs/pid/task/mod.rs +++ b/kernel/src/fs/procfs/pid/task/mod.rs @@ -11,8 +11,9 @@ use crate::{ pid::task::{ cgroup::CgroupFileOps, cmdline::CmdlineFileOps, comm::CommFileOps, environ::EnvironFileOps, exe::ExeSymOps, fd::FdDirOps, gid_map::GidMapFileOps, - mem::MemFileOps, mountinfo::MountInfoFileOps, oom_score_adj::OomScoreAdjFileOps, - stat::StatFileOps, status::StatusFileOps, uid_map::UidMapFileOps, + maps::MapsFileOps, mem::MemFileOps, mountinfo::MountInfoFileOps, + oom_score_adj::OomScoreAdjFileOps, stat::StatFileOps, status::StatusFileOps, + uid_map::UidMapFileOps, }, template::{ DirOps, ProcDir, ProcDirBuilder, lookup_child_from_table, @@ -33,6 +34,7 @@ mod environ; mod exe; mod fd; mod gid_map; +mod maps; mod mem; mod mountinfo; mod oom_score_adj; @@ -112,6 +114,7 @@ impl TidDirOps { ("stat", StatFileOps::new_inode), ("status", StatusFileOps::new_inode), ("uid_map", UidMapFileOps::new_inode), + ("maps", MapsFileOps::new_inode), ]; } diff --git a/kernel/src/process/process_vm/mod.rs b/kernel/src/process/process_vm/mod.rs index 8730b6ab0..f044b7745 100644 --- a/kernel/src/process/process_vm/mod.rs +++ b/kernel/src/process/process_vm/mod.rs @@ -99,7 +99,7 @@ impl ProcessVm { } /// Returns the initial portion of the main stack of a process. - pub(super) fn init_stack(&self) -> &InitStack { + pub fn init_stack(&self) -> &InitStack { &self.init_stack } diff --git a/kernel/src/vm/vmar/mod.rs b/kernel/src/vm/vmar/mod.rs index 0dede3e72..8ee42805c 100644 --- a/kernel/src/vm/vmar/mod.rs +++ b/kernel/src/vm/vmar/mod.rs @@ -932,6 +932,11 @@ pub fn is_userspace_vaddr(vaddr: Vaddr) -> bool { (VMAR_LOWEST_ADDR..VMAR_CAP_ADDR).contains(&vaddr) } +/// Returns the full user space virtual address range. +pub fn userspace_range() -> Range { + VMAR_LOWEST_ADDR..VMAR_CAP_ADDR +} + fn check_userspace_page_range(vaddr: Vaddr, len: usize) -> Result> { let Some(end) = vaddr.checked_add(len) else { return_errno_with_message!(Errno::EINVAL, "address overflow"); diff --git a/kernel/src/vm/vmar/vm_mapping.rs b/kernel/src/vm/vmar/vm_mapping.rs index 56f2f6224..9ea7f3b34 100644 --- a/kernel/src/vm/vmar/vm_mapping.rs +++ b/kernel/src/vm/vmar/vm_mapping.rs @@ -7,6 +7,7 @@ use core::{ }; use align_ext::AlignExt; +use aster_util::printer::VmPrinter; use ostd::{ io::IoMem, mm::{ @@ -200,6 +201,54 @@ impl VmMapping { Ok(()) } + /// Prints the mapping information in the format of `/proc/[pid]/maps`. + /// + /// Reference: + pub fn print_to_maps(&self, printer: &mut VmPrinter, name: &str) -> Result<()> { + let start = self.map_to_addr; + let end = self.map_end(); + let read_char = if self.perms.contains(VmPerms::READ) { + 'r' + } else { + '-' + }; + let write_char = if self.perms.contains(VmPerms::WRITE) { + 'w' + } else { + '-' + }; + let exec_char = if self.perms.contains(VmPerms::EXEC) { + 'x' + } else { + '-' + }; + let shared_char = if self.is_shared { 's' } else { 'p' }; + let offset = self.vmo().map(|vmo| vmo.offset).unwrap_or(0); + let (dev_major, dev_minor) = self + .inode() + .map(|inode| device_id::decode_device_numbers(inode.metadata().dev)) + .unwrap_or((0, 0)); + let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0); + + writeln!( + printer, + "{:x}-{:x} {}{}{}{} {:08x} {:02x}:{:02x} {:<26} {}", + start, + end, + read_char, + write_char, + exec_char, + shared_char, + offset, + dev_major, + dev_minor, + ino, + name + )?; + + Ok(()) + } + /// Returns whether this mapping is a COW mapping. /// /// Reference: