procfs_map.c revision 272461
1/*-
2 * Copyright (c) 1993 Jan-Simon Pendry
3 * Copyright (c) 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *	@(#)procfs_status.c	8.3 (Berkeley) 2/17/94
34 *
35 * $FreeBSD: releng/10.1/sys/fs/procfs/procfs_map.c 251423 2013-06-05 17:00:10Z alc $
36 */
37
38#include "opt_compat.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/lock.h>
43#include <sys/filedesc.h>
44#include <sys/malloc.h>
45#include <sys/mount.h>
46#include <sys/proc.h>
47#include <sys/resourcevar.h>
48#include <sys/rwlock.h>
49#include <sys/sbuf.h>
50#ifdef COMPAT_FREEBSD32
51#include <sys/sysent.h>
52#endif
53#include <sys/uio.h>
54#include <sys/vnode.h>
55
56#include <fs/pseudofs/pseudofs.h>
57#include <fs/procfs/procfs.h>
58
59#include <vm/vm.h>
60#include <vm/vm_extern.h>
61#include <vm/pmap.h>
62#include <vm/vm_map.h>
63#include <vm/vm_page.h>
64#include <vm/vm_object.h>
65
66#define MEBUFFERSIZE 256
67
68/*
69 * The map entries can *almost* be read with programs like cat.  However,
70 * large maps need special programs to read.  It is not easy to implement
71 * a program that can sense the required size of the buffer, and then
72 * subsequently do a read with the appropriate size.  This operation cannot
73 * be atomic.  The best that we can do is to allow the program to do a read
74 * with an arbitrarily large buffer, and return as much as we can.  We can
75 * return an error code if the buffer is too small (EFBIG), then the program
76 * can try a bigger buffer.
77 */
78int
79procfs_doprocmap(PFS_FILL_ARGS)
80{
81	struct vmspace *vm;
82	vm_map_t map;
83	vm_map_entry_t entry, tmp_entry;
84	struct vnode *vp;
85	char *fullpath, *freepath;
86	struct ucred *cred;
87	int error;
88	unsigned int last_timestamp;
89#ifdef COMPAT_FREEBSD32
90	int wrap32 = 0;
91#endif
92
93	PROC_LOCK(p);
94	error = p_candebug(td, p);
95	PROC_UNLOCK(p);
96	if (error)
97		return (error);
98
99	if (uio->uio_rw != UIO_READ)
100		return (EOPNOTSUPP);
101
102#ifdef COMPAT_FREEBSD32
103        if (SV_CURPROC_FLAG(SV_ILP32)) {
104                if (!(SV_PROC_FLAG(p, SV_ILP32)))
105                        return (EOPNOTSUPP);
106                wrap32 = 1;
107        }
108#endif
109
110	vm = vmspace_acquire_ref(p);
111	if (vm == NULL)
112		return (ESRCH);
113	map = &vm->vm_map;
114	vm_map_lock_read(map);
115	for (entry = map->header.next; entry != &map->header;
116	     entry = entry->next) {
117		vm_object_t obj, tobj, lobj;
118		int ref_count, shadow_count, flags;
119		vm_offset_t e_start, e_end, addr;
120		int resident, privateresident;
121		char *type;
122		vm_eflags_t e_eflags;
123		vm_prot_t e_prot;
124
125		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
126			continue;
127
128		e_eflags = entry->eflags;
129		e_prot = entry->protection;
130		e_start = entry->start;
131		e_end = entry->end;
132		privateresident = 0;
133		obj = entry->object.vm_object;
134		if (obj != NULL) {
135			VM_OBJECT_RLOCK(obj);
136			if (obj->shadow_count == 1)
137				privateresident = obj->resident_page_count;
138		}
139		cred = (entry->cred) ? entry->cred : (obj ? obj->cred : NULL);
140
141		resident = 0;
142		addr = entry->start;
143		while (addr < entry->end) {
144			if (pmap_extract(map->pmap, addr))
145				resident++;
146			addr += PAGE_SIZE;
147		}
148
149		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
150			if (tobj != obj)
151				VM_OBJECT_RLOCK(tobj);
152			if (lobj != obj)
153				VM_OBJECT_RUNLOCK(lobj);
154			lobj = tobj;
155		}
156		last_timestamp = map->timestamp;
157		vm_map_unlock_read(map);
158
159		freepath = NULL;
160		fullpath = "-";
161		if (lobj) {
162			switch (lobj->type) {
163			default:
164			case OBJT_DEFAULT:
165				type = "default";
166				vp = NULL;
167				break;
168			case OBJT_VNODE:
169				type = "vnode";
170				vp = lobj->handle;
171				vref(vp);
172				break;
173			case OBJT_SWAP:
174				type = "swap";
175				vp = NULL;
176				break;
177			case OBJT_SG:
178			case OBJT_DEVICE:
179				type = "device";
180				vp = NULL;
181				break;
182			}
183			if (lobj != obj)
184				VM_OBJECT_RUNLOCK(lobj);
185
186			flags = obj->flags;
187			ref_count = obj->ref_count;
188			shadow_count = obj->shadow_count;
189			VM_OBJECT_RUNLOCK(obj);
190			if (vp != NULL) {
191				vn_fullpath(td, vp, &fullpath, &freepath);
192				vrele(vp);
193			}
194		} else {
195			type = "none";
196			flags = 0;
197			ref_count = 0;
198			shadow_count = 0;
199		}
200
201		/*
202		 * format:
203		 *  start, end, resident, private resident, cow, access, type,
204		 *         charged, charged uid.
205		 */
206		error = sbuf_printf(sb,
207		    "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s %s %d\n",
208			(u_long)e_start, (u_long)e_end,
209			resident, privateresident,
210#ifdef COMPAT_FREEBSD32
211			wrap32 ? NULL : obj,	/* Hide 64 bit value */
212#else
213			obj,
214#endif
215			(e_prot & VM_PROT_READ)?"r":"-",
216			(e_prot & VM_PROT_WRITE)?"w":"-",
217			(e_prot & VM_PROT_EXECUTE)?"x":"-",
218			ref_count, shadow_count, flags,
219			(e_eflags & MAP_ENTRY_COW)?"COW":"NCOW",
220			(e_eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC",
221			type, fullpath,
222			cred ? "CH":"NCH", cred ? cred->cr_ruid : -1);
223
224		if (freepath != NULL)
225			free(freepath, M_TEMP);
226		vm_map_lock_read(map);
227		if (error == -1) {
228			error = 0;
229			break;
230		}
231		if (last_timestamp != map->timestamp) {
232			/*
233			 * Look again for the entry because the map was
234			 * modified while it was unlocked.  Specifically,
235			 * the entry may have been clipped, merged, or deleted.
236			 */
237			vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
238			entry = tmp_entry;
239		}
240	}
241	vm_map_unlock_read(map);
242	vmspace_free(vm);
243	return (error);
244}
245