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