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