procfs_map.c revision 186562
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: head/sys/fs/procfs/procfs_map.c 186562 2008-12-29 12:41:32Z kib $ 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> 4676827Salfred#include <sys/mutex.h> 4716468Sdyson#include <sys/proc.h> 48183600Skib#include <sys/sbuf.h> 49186562Skib#ifdef COMPAT_IA32 50186562Skib#include <sys/sysent.h> 51186562Skib#endif 5287321Sdes#include <sys/uio.h> 53120583Srwatson#include <sys/vnode.h> 5476166Smarkm 5587321Sdes#include <fs/pseudofs/pseudofs.h> 5677031Sru#include <fs/procfs/procfs.h> 5716468Sdyson 5816468Sdyson#include <vm/vm.h> 59185984Skib#include <vm/vm_extern.h> 6016468Sdyson#include <vm/pmap.h> 6116468Sdyson#include <vm/vm_map.h> 6216468Sdyson#include <vm/vm_page.h> 6316468Sdyson#include <vm/vm_object.h> 6416468Sdyson 6519260Sdyson#define MEBUFFERSIZE 256 6616468Sdyson 6719260Sdyson/* 6819260Sdyson * The map entries can *almost* be read with programs like cat. However, 6919260Sdyson * large maps need special programs to read. It is not easy to implement 7019260Sdyson * a program that can sense the required size of the buffer, and then 7119260Sdyson * subsequently do a read with the appropriate size. This operation cannot 7219260Sdyson * be atomic. The best that we can do is to allow the program to do a read 7319260Sdyson * with an arbitrarily large buffer, and return as much as we can. We can 7419260Sdyson * return an error code if the buffer is too small (EFBIG), then the program 7519260Sdyson * can try a bigger buffer. 7619260Sdyson */ 7716468Sdysonint 7887321Sdesprocfs_doprocmap(PFS_FILL_ARGS) 7916468Sdyson{ 80185984Skib struct vmspace *vm; 81185984Skib vm_map_t map; 82185765Skib vm_map_entry_t entry, tmp_entry; 83168968Salc struct vnode *vp; 84120583Srwatson char *fullpath, *freepath; 85185766Skib int error, vfslocked; 86185765Skib unsigned int last_timestamp; 87147692Speter#ifdef COMPAT_IA32 88147692Speter int wrap32 = 0; 89147692Speter#endif 9016468Sdyson 91118907Srwatson PROC_LOCK(p); 92118907Srwatson error = p_candebug(td, p); 93118907Srwatson PROC_UNLOCK(p); 94118907Srwatson if (error) 95118907Srwatson return (error); 96118907Srwatson 9716468Sdyson if (uio->uio_rw != UIO_READ) 9816468Sdyson return (EOPNOTSUPP); 9916468Sdyson 100147692Speter#ifdef COMPAT_IA32 101186562Skib if (curproc->p_sysent->sv_flags & SV_ILP32) { 102186562Skib if (!(p->p_sysent->sv_flags & SV_ILP32)) 103147692Speter return (EOPNOTSUPP); 104147692Speter wrap32 = 1; 105147692Speter } 106147692Speter#endif 107168763Sdes 108185984Skib vm = vmspace_acquire_ref(p); 109185984Skib if (vm == NULL) 110185984Skib return (ESRCH); 111185984Skib map = &vm->vm_map; 112168968Salc vm_map_lock_read(map); 113183600Skib for (entry = map->header.next; entry != &map->header; 114183600Skib entry = entry->next) { 11516468Sdyson vm_object_t obj, tobj, lobj; 11642957Sdillon int ref_count, shadow_count, flags; 117185765Skib vm_offset_t e_start, e_end, addr; 11816468Sdyson int resident, privateresident; 11916468Sdyson char *type; 120185765Skib vm_eflags_t e_eflags; 121185765Skib vm_prot_t e_prot; 12216468Sdyson 12343748Sdillon if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 12416468Sdyson continue; 12516468Sdyson 126185765Skib e_eflags = entry->eflags; 127185765Skib e_prot = entry->protection; 128185765Skib e_start = entry->start; 129185765Skib e_end = entry->end; 130168968Salc privateresident = 0; 13116468Sdyson obj = entry->object.vm_object; 132168968Salc if (obj != NULL) { 133168968Salc VM_OBJECT_LOCK(obj); 134168968Salc if (obj->shadow_count == 1) 135168968Salc privateresident = obj->resident_page_count; 136168968Salc } 13716468Sdyson 13816468Sdyson resident = 0; 13916468Sdyson addr = entry->start; 14016468Sdyson while (addr < entry->end) { 141168968Salc if (pmap_extract(map->pmap, addr)) 14216468Sdyson resident++; 14316468Sdyson addr += PAGE_SIZE; 14416468Sdyson } 14516468Sdyson 146168968Salc for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 147168968Salc if (tobj != obj) 148168968Salc VM_OBJECT_LOCK(tobj); 149168968Salc if (lobj != obj) 150168968Salc VM_OBJECT_UNLOCK(lobj); 15116468Sdyson lobj = tobj; 152168968Salc } 153185765Skib last_timestamp = map->timestamp; 154185765Skib vm_map_unlock_read(map); 15516468Sdyson 156120583Srwatson freepath = NULL; 157120583Srwatson fullpath = "-"; 15835497Sdyson if (lobj) { 159185765Skib switch (lobj->type) { 16087321Sdes default: 16187321Sdes case OBJT_DEFAULT: 16235497Sdyson type = "default"; 163168968Salc vp = NULL; 16435497Sdyson break; 16587321Sdes case OBJT_VNODE: 16635497Sdyson type = "vnode"; 167168968Salc vp = lobj->handle; 168168968Salc vref(vp); 16935497Sdyson break; 17087321Sdes case OBJT_SWAP: 17135497Sdyson type = "swap"; 172168968Salc vp = NULL; 17335497Sdyson break; 17487321Sdes case OBJT_DEVICE: 17535497Sdyson type = "device"; 176168968Salc vp = NULL; 17735497Sdyson break; 17835497Sdyson } 179168968Salc if (lobj != obj) 180168968Salc VM_OBJECT_UNLOCK(lobj); 181123247Sdes 18235497Sdyson flags = obj->flags; 18335497Sdyson ref_count = obj->ref_count; 18435497Sdyson shadow_count = obj->shadow_count; 185168968Salc VM_OBJECT_UNLOCK(obj); 186168968Salc if (vp != NULL) { 187184652Sjhb vn_fullpath(td, vp, &fullpath, &freepath); 188168968Salc vfslocked = VFS_LOCK_GIANT(vp->v_mount); 189184652Sjhb vrele(vp); 190168968Salc VFS_UNLOCK_GIANT(vfslocked); 191168968Salc } 19217303Sdyson } else { 19317303Sdyson type = "none"; 19435497Sdyson flags = 0; 19535497Sdyson ref_count = 0; 19635497Sdyson shadow_count = 0; 19716468Sdyson } 19816468Sdyson 19916468Sdyson /* 20016468Sdyson * format: 20116468Sdyson * start, end, resident, private resident, cow, access, type. 20216468Sdyson */ 203183600Skib error = sbuf_printf(sb, 204120583Srwatson "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s\n", 205185765Skib (u_long)e_start, (u_long)e_end, 206147692Speter resident, privateresident, 207147692Speter#ifdef COMPAT_IA32 208147692Speter wrap32 ? NULL : obj, /* Hide 64 bit value */ 209147692Speter#else 210147692Speter obj, 211147692Speter#endif 212185765Skib (e_prot & VM_PROT_READ)?"r":"-", 213185765Skib (e_prot & VM_PROT_WRITE)?"w":"-", 214185765Skib (e_prot & VM_PROT_EXECUTE)?"x":"-", 21535497Sdyson ref_count, shadow_count, flags, 216185765Skib (e_eflags & MAP_ENTRY_COW)?"COW":"NCOW", 217185765Skib (e_eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC", 218120583Srwatson type, fullpath); 21916468Sdyson 220120583Srwatson if (freepath != NULL) 221120583Srwatson free(freepath, M_TEMP); 222185864Skib vm_map_lock_read(map); 223183600Skib if (error == -1) { 224183600Skib error = 0; 22519260Sdyson break; 22616468Sdyson } 227185765Skib if (last_timestamp + 1 != map->timestamp) { 228185765Skib /* 229185765Skib * Look again for the entry because the map was 230185765Skib * modified while it was unlocked. Specifically, 231185765Skib * the entry may have been clipped, merged, or deleted. 232185765Skib */ 233185765Skib vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 234185765Skib entry = tmp_entry; 235185765Skib } 23616468Sdyson } 237168968Salc vm_map_unlock_read(map); 238185984Skib vmspace_free(vm); 23987321Sdes return (error); 24016468Sdyson} 241