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},
|
utils::{Inode, mkmod},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::Process,
|
process::{Process, posix_thread::AsPosixThread},
|
||||||
vm::vmar::{VMAR_CAP_ADDR, VMAR_LOWEST_ADDR},
|
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");
|
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);
|
let guard = vmar.query(VMAR_LOWEST_ADDR..VMAR_CAP_ADDR);
|
||||||
for vm_mapping in guard.iter() {
|
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, vmar, &path_resolver)?;
|
||||||
vm_mapping.print_to_maps(&mut printer, "[stack]")?;
|
|
||||||
} else {
|
|
||||||
// TODO: Print the status of mappings other than the stack.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(printer.bytes_written())
|
Ok(printer.bytes_written())
|
||||||
|
|
|
||||||
|
|
@ -75,11 +75,11 @@ impl Heap {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the current heap end.
|
/// Returns the current heap range.
|
||||||
pub fn heap_end(&self) -> Vaddr {
|
pub fn heap_range(&self) -> Range<Vaddr> {
|
||||||
let inner = self.inner.lock();
|
let inner = self.inner.lock();
|
||||||
let inner = inner.as_ref().expect("Heap is not initialized");
|
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.
|
/// Modifies the end address of the heap.
|
||||||
|
|
|
||||||
|
|
@ -385,6 +385,7 @@ fn map_segment_vmo(
|
||||||
let mut vm_map_options = vmar
|
let mut vm_map_options = vmar
|
||||||
.new_map(segment_size, perms)?
|
.new_map(segment_size, perms)?
|
||||||
.vmo(elf_vmo.clone())
|
.vmo(elf_vmo.clone())
|
||||||
|
.path(elf_file.clone())
|
||||||
.vmo_offset(segment_offset)
|
.vmo_offset(segment_offset)
|
||||||
.can_overwrite(true);
|
.can_overwrite(true);
|
||||||
vm_map_options = vm_map_options.offset(offset).handle_page_faults_around();
|
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
|
Some(addr) => user_heap
|
||||||
.modify_heap_end(addr, ctx)
|
.modify_heap_end(addr, ctx)
|
||||||
.unwrap_or_else(|cur_heap_end| cur_heap_end),
|
.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 _))
|
Ok(SyscallReturn::Return(current_heap_end as _))
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ fn do_sys_mmap(
|
||||||
|
|
||||||
options = options
|
options = options
|
||||||
.may_perms(vm_may_perms)
|
.may_perms(vm_may_perms)
|
||||||
.mappable(file.mappable()?)
|
.mappable(file.as_ref().as_ref())?
|
||||||
.vmo_offset(offset)
|
.vmo_offset(offset)
|
||||||
.handle_page_faults_around();
|
.handle_page_faults_around();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use alloc::{borrow::Cow, format};
|
||||||
use core::{
|
use core::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
|
|
@ -17,9 +18,12 @@ use ostd::{
|
||||||
task::disable_preempt,
|
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::{
|
use crate::{
|
||||||
fs::utils::Inode,
|
fs::{
|
||||||
|
path::{Path, PathResolver},
|
||||||
|
utils::Inode,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
thread::exception::PageFaultInfo,
|
thread::exception::PageFaultInfo,
|
||||||
vm::{
|
vm::{
|
||||||
|
|
@ -69,6 +73,8 @@ pub struct VmMapping {
|
||||||
/// And the `mapped_mem` field must be the page cache of the inode, i.e.
|
/// And the `mapped_mem` field must be the page cache of the inode, i.e.
|
||||||
/// [`MappedMemory::Vmo`].
|
/// [`MappedMemory::Vmo`].
|
||||||
inode: Option<Arc<dyn Inode>>,
|
inode: Option<Arc<dyn Inode>>,
|
||||||
|
/// The path of the file that backs the mapping.
|
||||||
|
path: Option<Path>,
|
||||||
/// Whether the mapping is shared.
|
/// Whether the mapping is shared.
|
||||||
///
|
///
|
||||||
/// The updates to a shared mapping are visible among processes, or carried
|
/// The updates to a shared mapping are visible among processes, or carried
|
||||||
|
|
@ -92,11 +98,13 @@ impl Interval<Vaddr> for VmMapping {
|
||||||
/***************************** Basic methods *********************************/
|
/***************************** Basic methods *********************************/
|
||||||
|
|
||||||
impl VmMapping {
|
impl VmMapping {
|
||||||
|
#[expect(clippy::too_many_arguments)]
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
map_size: NonZeroUsize,
|
map_size: NonZeroUsize,
|
||||||
map_to_addr: Vaddr,
|
map_to_addr: Vaddr,
|
||||||
mapped_mem: MappedMemory,
|
mapped_mem: MappedMemory,
|
||||||
inode: Option<Arc<dyn Inode>>,
|
inode: Option<Arc<dyn Inode>>,
|
||||||
|
path: Option<Path>,
|
||||||
is_shared: bool,
|
is_shared: bool,
|
||||||
handle_page_faults_around: bool,
|
handle_page_faults_around: bool,
|
||||||
perms: VmPerms,
|
perms: VmPerms,
|
||||||
|
|
@ -106,6 +114,7 @@ impl VmMapping {
|
||||||
map_to_addr,
|
map_to_addr,
|
||||||
mapped_mem,
|
mapped_mem,
|
||||||
inode,
|
inode,
|
||||||
|
path,
|
||||||
is_shared,
|
is_shared,
|
||||||
handle_page_faults_around,
|
handle_page_faults_around,
|
||||||
perms,
|
perms,
|
||||||
|
|
@ -116,6 +125,7 @@ impl VmMapping {
|
||||||
VmMapping {
|
VmMapping {
|
||||||
mapped_mem: self.mapped_mem.dup(),
|
mapped_mem: self.mapped_mem.dup(),
|
||||||
inode: self.inode.clone(),
|
inode: self.inode.clone(),
|
||||||
|
path: self.path.clone(),
|
||||||
..*self
|
..*self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,7 +215,12 @@ impl VmMapping {
|
||||||
/// Prints the mapping information in the format of `/proc/[pid]/maps`.
|
/// 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>
|
/// 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 start = self.map_to_addr;
|
||||||
let end = self.map_end();
|
let end = self.map_end();
|
||||||
let read_char = if self.perms.contains(VmPerms::READ) {
|
let read_char = if self.perms.contains(VmPerms::READ) {
|
||||||
|
|
@ -231,9 +246,8 @@ impl VmMapping {
|
||||||
.unwrap_or((0, 0));
|
.unwrap_or((0, 0));
|
||||||
let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0);
|
let ino = self.inode().map(|inode| inode.ino()).unwrap_or(0);
|
||||||
|
|
||||||
writeln!(
|
let line = format!(
|
||||||
printer,
|
"{:x}-{:x} {}{}{}{} {:08x} {:02x}:{:02x} {} ",
|
||||||
"{:x}-{:x} {}{}{}{} {:08x} {:02x}:{:02x} {:<26} {}",
|
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
read_char,
|
read_char,
|
||||||
|
|
@ -244,8 +258,57 @@ impl VmMapping {
|
||||||
dev_major,
|
dev_major,
|
||||||
dev_minor,
|
dev_minor,
|
||||||
ino,
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -578,6 +641,7 @@ impl VmMapping {
|
||||||
map_size: NonZeroUsize::new(left_size).unwrap(),
|
map_size: NonZeroUsize::new(left_size).unwrap(),
|
||||||
mapped_mem: l_mapped_mem,
|
mapped_mem: l_mapped_mem,
|
||||||
inode: self.inode.clone(),
|
inode: self.inode.clone(),
|
||||||
|
path: self.path.clone(),
|
||||||
..self
|
..self
|
||||||
};
|
};
|
||||||
let right = Self {
|
let right = Self {
|
||||||
|
|
@ -900,6 +964,7 @@ fn try_merge(left: &VmMapping, right: &VmMapping) -> Option<VmMapping> {
|
||||||
map_size,
|
map_size,
|
||||||
mapped_mem,
|
mapped_mem,
|
||||||
inode: left.inode.clone(),
|
inode: left.inode.clone(),
|
||||||
|
path: left.path.clone(),
|
||||||
..*left
|
..*left
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ use core::num::NonZeroUsize;
|
||||||
|
|
||||||
use super::{MappedMemory, MappedVmo, RssDelta, VmMapping, Vmar};
|
use super::{MappedMemory, MappedVmo, RssDelta, VmMapping, Vmar};
|
||||||
use crate::{
|
use crate::{
|
||||||
fs::{file_handle::Mappable, ramfs::memfd::MemfdInode},
|
fs::{
|
||||||
|
file_handle::{FileLike, Mappable},
|
||||||
|
path::Path,
|
||||||
|
ramfs::memfd::MemfdInode,
|
||||||
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
vm::{perms::VmPerms, vmo::Vmo},
|
vm::{perms::VmPerms, vmo::Vmo},
|
||||||
};
|
};
|
||||||
|
|
@ -50,6 +54,7 @@ pub struct VmarMapOptions<'a> {
|
||||||
parent: &'a Vmar,
|
parent: &'a Vmar,
|
||||||
vmo: Option<Arc<Vmo>>,
|
vmo: Option<Arc<Vmo>>,
|
||||||
mappable: Option<Mappable>,
|
mappable: Option<Mappable>,
|
||||||
|
path: Option<Path>,
|
||||||
perms: VmPerms,
|
perms: VmPerms,
|
||||||
may_perms: VmPerms,
|
may_perms: VmPerms,
|
||||||
vmo_offset: usize,
|
vmo_offset: usize,
|
||||||
|
|
@ -71,6 +76,7 @@ impl<'a> VmarMapOptions<'a> {
|
||||||
parent,
|
parent,
|
||||||
vmo: None,
|
vmo: None,
|
||||||
mappable: None,
|
mappable: None,
|
||||||
|
path: None,
|
||||||
perms,
|
perms,
|
||||||
may_perms: VmPerms::ALL_MAY_PERMS,
|
may_perms: VmPerms::ALL_MAY_PERMS,
|
||||||
vmo_offset: 0,
|
vmo_offset: 0,
|
||||||
|
|
@ -124,6 +130,19 @@ impl<'a> VmarMapOptions<'a> {
|
||||||
self
|
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
|
/// Sets the offset of the first memory page in the VMO that is to be
|
||||||
/// mapped into the VMAR.
|
/// mapped into the VMAR.
|
||||||
///
|
///
|
||||||
|
|
@ -194,23 +213,34 @@ impl<'a> VmarMapOptions<'a> {
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This function panics if a [`Vmo`] or [`Mappable`] is already provided.
|
/// This function panics if a [`Vmo`], [`Path`] or [`Mappable`] is already provided.
|
||||||
pub fn mappable(mut self, mappable: Mappable) -> Self {
|
///
|
||||||
|
/// # 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() {
|
if self.vmo.is_some() {
|
||||||
panic!("Cannot set `mappable` when `vmo` is already set");
|
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() {
|
if self.mappable.is_some() {
|
||||||
panic!("Cannot set `mappable` when `mappable` is already set");
|
panic!("Cannot set `mappable` when `mappable` is already set");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mappable = file.mappable()?;
|
||||||
|
|
||||||
// Verify whether the page cache inode is valid.
|
// Verify whether the page cache inode is valid.
|
||||||
if let Mappable::Inode(ref inode) = mappable {
|
if let Mappable::Inode(ref inode) = mappable {
|
||||||
self.vmo = Some(inode.page_cache().expect("Map an inode without page cache"));
|
self.vmo = Some(inode.page_cache().expect("Map an inode without page cache"));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mappable = Some(mappable);
|
self.mappable = Some(mappable);
|
||||||
|
self.path = Some(file.path().clone());
|
||||||
|
|
||||||
self
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the mapping and adds it to the parent VMAR.
|
/// Creates the mapping and adds it to the parent VMAR.
|
||||||
|
|
@ -224,6 +254,7 @@ impl<'a> VmarMapOptions<'a> {
|
||||||
parent,
|
parent,
|
||||||
vmo,
|
vmo,
|
||||||
mappable,
|
mappable,
|
||||||
|
path,
|
||||||
perms,
|
perms,
|
||||||
mut may_perms,
|
mut may_perms,
|
||||||
vmo_offset,
|
vmo_offset,
|
||||||
|
|
@ -321,6 +352,7 @@ impl<'a> VmarMapOptions<'a> {
|
||||||
map_to_addr,
|
map_to_addr,
|
||||||
mapped_mem,
|
mapped_mem,
|
||||||
inode,
|
inode,
|
||||||
|
path,
|
||||||
is_shared,
|
is_shared,
|
||||||
handle_page_faults_around,
|
handle_page_faults_around,
|
||||||
perms | may_perms,
|
perms | may_perms,
|
||||||
|
|
|
||||||
|
|
@ -28,11 +28,9 @@ ProcSelfCwd.Absolute
|
||||||
ProcSelfFd.OpenFd
|
ProcSelfFd.OpenFd
|
||||||
# TODO: Support `O_LARGEFILE` flag.
|
# TODO: Support `O_LARGEFILE` flag.
|
||||||
ProcSelfFdInfo.Flags
|
ProcSelfFdInfo.Flags
|
||||||
ProcSelfMaps.Basic
|
# TODO: Mappings created with only `PROT_WRITE` should be shown as `-w-`.
|
||||||
ProcSelfMaps.Map1
|
|
||||||
ProcSelfMaps.Map2
|
ProcSelfMaps.Map2
|
||||||
ProcSelfMaps.MapUnmap
|
ProcSelfMaps.MapUnmap
|
||||||
ProcSelfMaps.SharedAnon
|
|
||||||
ProcSelfMounts.ContainsProcfsEntry
|
ProcSelfMounts.ContainsProcfsEntry
|
||||||
ProcSelfMounts.RequiredFieldsArePresent
|
ProcSelfMounts.RequiredFieldsArePresent
|
||||||
ProcSelfRoot.IsRoot
|
ProcSelfRoot.IsRoot
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue