1139776Simp/*- 216468Sdyson * Copyright (c) 1993 Jan-Simon Pendry 316468Sdyson * Copyright (c) 1993 416468Sdyson * The Regents of the University of California. All rights reserved. 516468Sdyson * 616468Sdyson * This code is derived from software contributed to Berkeley by 716468Sdyson * Jan-Simon Pendry. 816468Sdyson * 916468Sdyson * Redistribution and use in source and binary forms, with or without 1016468Sdyson * modification, are permitted provided that the following conditions 1116468Sdyson * are met: 1216468Sdyson * 1. Redistributions of source code must retain the above copyright 1316468Sdyson * notice, this list of conditions and the following disclaimer. 1416468Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1516468Sdyson * notice, this list of conditions and the following disclaimer in the 1616468Sdyson * documentation and/or other materials provided with the distribution. 1716468Sdyson * 4. Neither the name of the University nor the names of its contributors 1816468Sdyson * may be used to endorse or promote products derived from this software 1916468Sdyson * without specific prior written permission. 2016468Sdyson * 2116468Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2216468Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2316468Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2416468Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2516468Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2616468Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2716468Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2816468Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2916468Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3016468Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3116468Sdyson * SUCH DAMAGE. 3216468Sdyson * 3316468Sdyson * @(#)procfs_status.c 8.3 (Berkeley) 2/17/94 3416468Sdyson * 3550477Speter * $FreeBSD$ 3616468Sdyson */ 3716468Sdyson 38147692Speter#include "opt_compat.h" 39147692Speter 4016468Sdyson#include <sys/param.h> 4116468Sdyson#include <sys/systm.h> 4276166Smarkm#include <sys/lock.h> 43120583Srwatson#include <sys/filedesc.h> 44120583Srwatson#include <sys/malloc.h> 45168968Salc#include <sys/mount.h> 4616468Sdyson#include <sys/proc.h> 47194766Skib#include <sys/resourcevar.h> 48248084Sattilio#include <sys/rwlock.h> 49183600Skib#include <sys/sbuf.h> 50205014Snwhitehorn#ifdef COMPAT_FREEBSD32 51186562Skib#include <sys/sysent.h> 52186562Skib#endif 5387321Sdes#include <sys/uio.h> 54120583Srwatson#include <sys/vnode.h> 5576166Smarkm 5687321Sdes#include <fs/pseudofs/pseudofs.h> 5777031Sru#include <fs/procfs/procfs.h> 5816468Sdyson 5916468Sdyson#include <vm/vm.h> 60185984Skib#include <vm/vm_extern.h> 6116468Sdyson#include <vm/pmap.h> 6216468Sdyson#include <vm/vm_map.h> 6316468Sdyson#include <vm/vm_page.h> 6416468Sdyson#include <vm/vm_object.h> 6516468Sdyson 6619260Sdyson#define MEBUFFERSIZE 256 6716468Sdyson 6819260Sdyson/* 6919260Sdyson * The map entries can *almost* be read with programs like cat. However, 7019260Sdyson * large maps need special programs to read. It is not easy to implement 7119260Sdyson * a program that can sense the required size of the buffer, and then 7219260Sdyson * subsequently do a read with the appropriate size. This operation cannot 7319260Sdyson * be atomic. The best that we can do is to allow the program to do a read 7419260Sdyson * with an arbitrarily large buffer, and return as much as we can. We can 7519260Sdyson * return an error code if the buffer is too small (EFBIG), then the program 7619260Sdyson * can try a bigger buffer. 7719260Sdyson */ 7816468Sdysonint 7987321Sdesprocfs_doprocmap(PFS_FILL_ARGS) 8016468Sdyson{ 81185984Skib struct vmspace *vm; 82185984Skib vm_map_t map; 83185765Skib vm_map_entry_t entry, tmp_entry; 84168968Salc struct vnode *vp; 85120583Srwatson char *fullpath, *freepath; 86216128Strasz struct ucred *cred; 87241896Skib int error; 88185765Skib unsigned int last_timestamp; 89205014Snwhitehorn#ifdef COMPAT_FREEBSD32 90147692Speter int wrap32 = 0; 91147692Speter#endif 9216468Sdyson 93118907Srwatson PROC_LOCK(p); 94118907Srwatson error = p_candebug(td, p); 95118907Srwatson PROC_UNLOCK(p); 96118907Srwatson if (error) 97118907Srwatson return (error); 98118907Srwatson 9916468Sdyson if (uio->uio_rw != UIO_READ) 10016468Sdyson return (EOPNOTSUPP); 10116468Sdyson 102205014Snwhitehorn#ifdef COMPAT_FREEBSD32 103217896Sdchagin if (SV_CURPROC_FLAG(SV_ILP32)) { 104217896Sdchagin if (!(SV_PROC_FLAG(p, SV_ILP32))) 105147692Speter return (EOPNOTSUPP); 106147692Speter wrap32 = 1; 107147692Speter } 108147692Speter#endif 109168763Sdes 110185984Skib vm = vmspace_acquire_ref(p); 111185984Skib if (vm == NULL) 112185984Skib return (ESRCH); 113185984Skib map = &vm->vm_map; 114168968Salc vm_map_lock_read(map); 115183600Skib for (entry = map->header.next; entry != &map->header; 116183600Skib entry = entry->next) { 11716468Sdyson vm_object_t obj, tobj, lobj; 11842957Sdillon int ref_count, shadow_count, flags; 119185765Skib vm_offset_t e_start, e_end, addr; 12016468Sdyson int resident, privateresident; 12116468Sdyson char *type; 122185765Skib vm_eflags_t e_eflags; 123185765Skib vm_prot_t e_prot; 12416468Sdyson 12543748Sdillon if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 12616468Sdyson continue; 12716468Sdyson 128185765Skib e_eflags = entry->eflags; 129185765Skib e_prot = entry->protection; 130185765Skib e_start = entry->start; 131185765Skib e_end = entry->end; 132168968Salc privateresident = 0; 13316468Sdyson obj = entry->object.vm_object; 134168968Salc if (obj != NULL) { 135251423Salc VM_OBJECT_RLOCK(obj); 136168968Salc if (obj->shadow_count == 1) 137168968Salc privateresident = obj->resident_page_count; 138168968Salc } 139216128Strasz cred = (entry->cred) ? entry->cred : (obj ? obj->cred : NULL); 14016468Sdyson 14116468Sdyson resident = 0; 14216468Sdyson addr = entry->start; 14316468Sdyson while (addr < entry->end) { 144168968Salc if (pmap_extract(map->pmap, addr)) 14516468Sdyson resident++; 14616468Sdyson addr += PAGE_SIZE; 14716468Sdyson } 14816468Sdyson 149168968Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 150168968Salc if (tobj != obj) 151251423Salc VM_OBJECT_RLOCK(tobj); 152168968Salc if (lobj != obj) 153251423Salc VM_OBJECT_RUNLOCK(lobj); 15416468Sdyson lobj = tobj; 155168968Salc } 156185765Skib last_timestamp = map->timestamp; 157185765Skib vm_map_unlock_read(map); 15816468Sdyson 159120583Srwatson freepath = NULL; 160120583Srwatson fullpath = "-"; 16135497Sdyson if (lobj) { 162185765Skib switch (lobj->type) { 16387321Sdes default: 16487321Sdes case OBJT_DEFAULT: 16535497Sdyson type = "default"; 166168968Salc vp = NULL; 16735497Sdyson break; 16887321Sdes case OBJT_VNODE: 16935497Sdyson type = "vnode"; 170168968Salc vp = lobj->handle; 171168968Salc vref(vp); 17235497Sdyson break; 17387321Sdes case OBJT_SWAP: 17435497Sdyson type = "swap"; 175168968Salc vp = NULL; 17635497Sdyson break; 177195840Sjhb case OBJT_SG: 17887321Sdes case OBJT_DEVICE: 17935497Sdyson type = "device"; 180168968Salc vp = NULL; 18135497Sdyson break; 18235497Sdyson } 183168968Salc if (lobj != obj) 184251423Salc VM_OBJECT_RUNLOCK(lobj); 185123247Sdes 18635497Sdyson flags = obj->flags; 18735497Sdyson ref_count = obj->ref_count; 18835497Sdyson shadow_count = obj->shadow_count; 189251423Salc VM_OBJECT_RUNLOCK(obj); 190168968Salc if (vp != NULL) { 191184652Sjhb vn_fullpath(td, vp, &fullpath, &freepath); 192184652Sjhb vrele(vp); 193168968Salc } 19417303Sdyson } else { 19517303Sdyson type = "none"; 19635497Sdyson flags = 0; 19735497Sdyson ref_count = 0; 19835497Sdyson shadow_count = 0; 19916468Sdyson } 20016468Sdyson 20116468Sdyson /* 20216468Sdyson * format: 203194766Skib * start, end, resident, private resident, cow, access, type, 204194766Skib * charged, charged uid. 20516468Sdyson */ 206183600Skib error = sbuf_printf(sb, 207194766Skib "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s %s %d\n", 208185765Skib (u_long)e_start, (u_long)e_end, 209147692Speter resident, privateresident, 210205014Snwhitehorn#ifdef COMPAT_FREEBSD32 211147692Speter wrap32 ? NULL : obj, /* Hide 64 bit value */ 212147692Speter#else 213147692Speter obj, 214147692Speter#endif 215185765Skib (e_prot & VM_PROT_READ)?"r":"-", 216185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 217185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 21835497Sdyson ref_count, shadow_count, flags, 219185765Skib (e_eflags & MAP_ENTRY_COW)?"COW":"NCOW", 220185765Skib (e_eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC", 221194766Skib type, fullpath, 222216128Strasz cred ? "CH":"NCH", cred ? cred->cr_ruid : -1); 22316468Sdyson 224120583Srwatson if (freepath != NULL) 225120583Srwatson free(freepath, M_TEMP); 226185864Skib vm_map_lock_read(map); 227183600Skib if (error == -1) { 228183600Skib error = 0; 22919260Sdyson break; 23016468Sdyson } 231186563Skib if (last_timestamp != map->timestamp) { 232185765Skib /* 233185765Skib * Look again for the entry because the map was 234185765Skib * modified while it was unlocked. Specifically, 235185765Skib * the entry may have been clipped, merged, or deleted. 236185765Skib */ 237185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 238185765Skib entry = tmp_entry; 239185765Skib } 24016468Sdyson } 241168968Salc vm_map_unlock_read(map); 242185984Skib vmspace_free(vm); 24387321Sdes return (error); 24416468Sdyson} 245