Add `/proc/[pid]/maps`
This commit is contained in:
parent
b1b909dd0f
commit
4e0ae560bf
|
|
@ -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<Process>);
|
||||
|
||||
impl MapsFileOps {
|
||||
pub fn new_inode(dir: &TidDirOps, parent: Weak<dyn Inode>) -> Arc<dyn Inode> {
|
||||
let process_ref = dir.process_ref.clone();
|
||||
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/fs/proc/base.c#L3343>
|
||||
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<usize> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Vaddr> {
|
||||
VMAR_LOWEST_ADDR..VMAR_CAP_ADDR
|
||||
}
|
||||
|
||||
fn check_userspace_page_range(vaddr: Vaddr, len: usize) -> Result<Range<Vaddr>> {
|
||||
let Some(end) = vaddr.checked_add(len) else {
|
||||
return_errno_with_message!(Errno::EINVAL, "address overflow");
|
||||
|
|
|
|||
|
|
@ -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: <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<()> {
|
||||
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: <https://elixir.bootlin.com/linux/v6.16.5/source/include/linux/mm.h#L1470-L1473>
|
||||
|
|
|
|||
Loading…
Reference in New Issue