procfs_map.c revision 168968
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: head/sys/fs/procfs/procfs_map.c 168968 2007-04-23 06:12:24Z 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/mutex.h>
47#include <sys/proc.h>
48#include <sys/uio.h>
49#include <sys/vnode.h>
50
51#include <fs/pseudofs/pseudofs.h>
52#include <fs/procfs/procfs.h>
53
54#include <vm/vm.h>
55#include <vm/pmap.h>
56#include <vm/vm_map.h>
57#include <vm/vm_page.h>
58#include <vm/vm_object.h>
59
60#ifdef COMPAT_IA32
61#include <sys/procfs.h>
62#include <machine/fpu.h>
63#include <compat/ia32/ia32_reg.h>
64
65extern struct sysentvec ia32_freebsd_sysvec;
66#endif
67
68
69#define MEBUFFERSIZE 256
70
71/*
72 * The map entries can *almost* be read with programs like cat.  However,
73 * large maps need special programs to read.  It is not easy to implement
74 * a program that can sense the required size of the buffer, and then
75 * subsequently do a read with the appropriate size.  This operation cannot
76 * be atomic.  The best that we can do is to allow the program to do a read
77 * with an arbitrarily large buffer, and return as much as we can.  We can
78 * return an error code if the buffer is too small (EFBIG), then the program
79 * can try a bigger buffer.
80 */
81int
82procfs_doprocmap(PFS_FILL_ARGS)
83{
84	int len;
85	int error, vfslocked;
86	vm_map_t map = &p->p_vmspace->vm_map;
87	vm_map_entry_t entry, tmp_entry;
88	struct vnode *vp;
89	char mebuffer[MEBUFFERSIZE];
90	char *fullpath, *freepath;
91	unsigned int last_timestamp;
92#ifdef COMPAT_IA32
93	int wrap32 = 0;
94#endif
95
96	PROC_LOCK(p);
97	error = p_candebug(td, p);
98	PROC_UNLOCK(p);
99	if (error)
100		return (error);
101
102	if (uio->uio_rw != UIO_READ)
103		return (EOPNOTSUPP);
104
105	if (uio->uio_offset != 0)
106		return (0);
107
108#ifdef COMPAT_IA32
109        if (curthread->td_proc->p_sysent == &ia32_freebsd_sysvec) {
110                if (p->p_sysent != &ia32_freebsd_sysvec)
111                        return (EOPNOTSUPP);
112                wrap32 = 1;
113        }
114#endif
115
116	vm_map_lock_read(map);
117	for (entry = map->header.next;
118		((uio->uio_resid > 0) && (entry != &map->header));
119		entry = entry->next) {
120		vm_object_t obj, tobj, lobj;
121		int ref_count, shadow_count, flags;
122		vm_offset_t addr;
123		int resident, privateresident;
124		char *type;
125
126		if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
127			continue;
128
129		privateresident = 0;
130		obj = entry->object.vm_object;
131		if (obj != NULL) {
132			VM_OBJECT_LOCK(obj);
133			if (obj->shadow_count == 1)
134				privateresident = obj->resident_page_count;
135		}
136
137		resident = 0;
138		addr = entry->start;
139		while (addr < entry->end) {
140			if (pmap_extract(map->pmap, addr))
141				resident++;
142			addr += PAGE_SIZE;
143		}
144
145		for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
146			if (tobj != obj)
147				VM_OBJECT_LOCK(tobj);
148			if (lobj != obj)
149				VM_OBJECT_UNLOCK(lobj);
150			lobj = tobj;
151		}
152
153		freepath = NULL;
154		fullpath = "-";
155		if (lobj) {
156			switch(lobj->type) {
157			default:
158			case OBJT_DEFAULT:
159				type = "default";
160				vp = NULL;
161				break;
162			case OBJT_VNODE:
163				type = "vnode";
164				vp = lobj->handle;
165				vref(vp);
166				break;
167			case OBJT_SWAP:
168				type = "swap";
169				vp = NULL;
170				break;
171			case OBJT_DEVICE:
172				type = "device";
173				vp = NULL;
174				break;
175			}
176			if (lobj != obj)
177				VM_OBJECT_UNLOCK(lobj);
178
179			flags = obj->flags;
180			ref_count = obj->ref_count;
181			shadow_count = obj->shadow_count;
182			VM_OBJECT_UNLOCK(obj);
183			if (vp != NULL) {
184				vfslocked = VFS_LOCK_GIANT(vp->v_mount);
185				vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
186				vn_fullpath(td, vp, &fullpath, &freepath);
187				vput(vp);
188				VFS_UNLOCK_GIANT(vfslocked);
189			}
190		} else {
191			type = "none";
192			flags = 0;
193			ref_count = 0;
194			shadow_count = 0;
195		}
196
197		/*
198		 * format:
199		 *  start, end, resident, private resident, cow, access, type.
200		 */
201		snprintf(mebuffer, sizeof mebuffer,
202		    "0x%lx 0x%lx %d %d %p %s%s%s %d %d 0x%x %s %s %s %s\n",
203			(u_long)entry->start, (u_long)entry->end,
204			resident, privateresident,
205#ifdef COMPAT_IA32
206			wrap32 ? NULL : obj,	/* Hide 64 bit value */
207#else
208			obj,
209#endif
210			(entry->protection & VM_PROT_READ)?"r":"-",
211			(entry->protection & VM_PROT_WRITE)?"w":"-",
212			(entry->protection & VM_PROT_EXECUTE)?"x":"-",
213			ref_count, shadow_count, flags,
214			(entry->eflags & MAP_ENTRY_COW)?"COW":"NCOW",
215			(entry->eflags & MAP_ENTRY_NEEDS_COPY)?"NC":"NNC",
216			type, fullpath);
217
218		if (freepath != NULL)
219			free(freepath, M_TEMP);
220
221		len = strlen(mebuffer);
222		if (len > uio->uio_resid) {
223			error = EFBIG;
224			break;
225		}
226		last_timestamp = map->timestamp;
227		vm_map_unlock_read(map);
228		error = uiomove(mebuffer, len, uio);
229		vm_map_lock_read(map);
230		if (error)
231			break;
232		if (last_timestamp + 1 != map->timestamp) {
233			/*
234			 * Look again for the entry because the map was
235			 * modified while it was unlocked.  Specifically,
236			 * the entry may have been clipped, merged, or deleted.
237			 */
238			vm_map_lookup_entry(map, addr - 1, &tmp_entry);
239			entry = tmp_entry;
240		}
241	}
242	vm_map_unlock_read(map);
243	return (error);
244}
245