1 |
|
|
/* $OpenBSD: procmap.c,v 1.63 2016/09/16 04:45:35 dlg Exp $ */ |
2 |
|
|
/* $NetBSD: pmap.c,v 1.1 2002/09/01 20:32:44 atatat Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 2002 The NetBSD Foundation, Inc. |
6 |
|
|
* All rights reserved. |
7 |
|
|
* |
8 |
|
|
* This code is derived from software contributed to The NetBSD Foundation |
9 |
|
|
* by Andrew Brown. |
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 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 |
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 |
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 |
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 |
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 |
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 |
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 |
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 |
|
|
* POSSIBILITY OF SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#define _KERNEL |
34 |
|
|
#include <sys/tree.h> |
35 |
|
|
#undef _KERNEL |
36 |
|
|
|
37 |
|
|
#include <sys/param.h> /* MAXCOMLEN */ |
38 |
|
|
#include <sys/types.h> |
39 |
|
|
#include <sys/time.h> |
40 |
|
|
#include <sys/exec.h> |
41 |
|
|
#include <sys/proc.h> |
42 |
|
|
#include <sys/vnode.h> |
43 |
|
|
#include <sys/mount.h> |
44 |
|
|
#include <sys/uio.h> |
45 |
|
|
#include <sys/namei.h> |
46 |
|
|
#include <sys/sysctl.h> |
47 |
|
|
|
48 |
|
|
/* XXX until uvm gets cleaned up */ |
49 |
|
|
typedef int boolean_t; |
50 |
|
|
|
51 |
|
|
#include <uvm/uvm.h> |
52 |
|
|
#include <uvm/uvm_device.h> |
53 |
|
|
#include <uvm/uvm_amap.h> |
54 |
|
|
#include <uvm/uvm_vnode.h> |
55 |
|
|
|
56 |
|
|
#include <ufs/ufs/quota.h> |
57 |
|
|
#include <ufs/ufs/inode.h> |
58 |
|
|
#undef doff_t |
59 |
|
|
#undef IN_ACCESS |
60 |
|
|
#undef i_size |
61 |
|
|
#undef i_devvp |
62 |
|
|
#include <isofs/cd9660/iso.h> |
63 |
|
|
#include <isofs/cd9660/cd9660_node.h> |
64 |
|
|
|
65 |
|
|
#include <kvm.h> |
66 |
|
|
#include <fcntl.h> |
67 |
|
|
#include <errno.h> |
68 |
|
|
#include <err.h> |
69 |
|
|
#include <stdlib.h> |
70 |
|
|
#include <stddef.h> |
71 |
|
|
#include <unistd.h> |
72 |
|
|
#include <stdio.h> |
73 |
|
|
#include <limits.h> |
74 |
|
|
#include <string.h> |
75 |
|
|
|
76 |
|
|
/* |
77 |
|
|
* stolen (and munged) from #include <uvm/uvm_object.h> |
78 |
|
|
*/ |
79 |
|
|
#define UVM_OBJ_IS_VNODE(uobj) ((uobj)->pgops == uvm_vnodeops) |
80 |
|
|
#define UVM_OBJ_IS_AOBJ(uobj) ((uobj)->pgops == aobj_pager) |
81 |
|
|
#define UVM_OBJ_IS_DEVICE(uobj) ((uobj)->pgops == uvm_deviceops) |
82 |
|
|
|
83 |
|
|
#define PRINT_VMSPACE 0x00000001 |
84 |
|
|
#define PRINT_VM_MAP 0x00000002 |
85 |
|
|
#define PRINT_VM_MAP_HEADER 0x00000004 |
86 |
|
|
#define PRINT_VM_MAP_ENTRY 0x00000008 |
87 |
|
|
#define DUMP_NAMEI_CACHE 0x00000010 |
88 |
|
|
|
89 |
|
|
struct cache_entry { |
90 |
|
|
LIST_ENTRY(cache_entry) ce_next; |
91 |
|
|
struct vnode *ce_vp, *ce_pvp; |
92 |
|
|
u_long ce_cid, ce_pcid; |
93 |
|
|
unsigned int ce_nlen; |
94 |
|
|
char ce_name[256]; |
95 |
|
|
}; |
96 |
|
|
|
97 |
|
|
LIST_HEAD(cache_head, cache_entry) lcache; |
98 |
|
|
TAILQ_HEAD(namecache_head, namecache) nclruhead; |
99 |
|
|
int namecache_loaded; |
100 |
|
|
void *uvm_vnodeops, *uvm_deviceops, *aobj_pager; |
101 |
|
|
u_long kernel_map_addr, nclruhead_addr; |
102 |
|
|
int debug, verbose; |
103 |
|
|
int print_all, print_map, print_maps, print_solaris, print_ddb, print_amap; |
104 |
|
|
int rwx = PROT_READ | PROT_WRITE | PROT_EXEC; |
105 |
|
|
rlim_t maxssiz; |
106 |
|
|
|
107 |
|
|
struct sum { |
108 |
|
|
unsigned long s_am_nslots; |
109 |
|
|
unsigned long s_am_nusedslots; |
110 |
|
|
}; |
111 |
|
|
|
112 |
|
|
struct kbit { |
113 |
|
|
/* |
114 |
|
|
* size of data chunk |
115 |
|
|
*/ |
116 |
|
|
size_t k_size; |
117 |
|
|
|
118 |
|
|
/* |
119 |
|
|
* something for printf() and something for kvm_read() |
120 |
|
|
*/ |
121 |
|
|
union { |
122 |
|
|
void *k_addr_p; |
123 |
|
|
u_long k_addr_ul; |
124 |
|
|
} k_addr; |
125 |
|
|
|
126 |
|
|
/* |
127 |
|
|
* where we actually put the "stuff" |
128 |
|
|
*/ |
129 |
|
|
union { |
130 |
|
|
char data[1]; |
131 |
|
|
struct vmspace vmspace; |
132 |
|
|
struct vm_map vm_map; |
133 |
|
|
struct vm_map_entry vm_map_entry; |
134 |
|
|
struct uvm_vnode uvm_vnode; |
135 |
|
|
struct vnode vnode; |
136 |
|
|
struct uvm_object uvm_object; |
137 |
|
|
struct mount mount; |
138 |
|
|
struct inode inode; |
139 |
|
|
struct iso_node iso_node; |
140 |
|
|
struct uvm_device uvm_device; |
141 |
|
|
struct vm_amap vm_amap; |
142 |
|
|
} k_data; |
143 |
|
|
}; |
144 |
|
|
|
145 |
|
|
/* the size of the object in the kernel */ |
146 |
|
|
#define S(x) ((x)->k_size) |
147 |
|
|
/* the address of the object in kernel, two forms */ |
148 |
|
|
#define A(x) ((x)->k_addr.k_addr_ul) |
149 |
|
|
#define P(x) ((x)->k_addr.k_addr_p) |
150 |
|
|
/* the data from the kernel */ |
151 |
|
|
#define D(x,d) (&((x)->k_data.d)) |
152 |
|
|
|
153 |
|
|
/* suck the data from the kernel */ |
154 |
|
|
#define _KDEREF(kd, addr, dst, sz) do { \ |
155 |
|
|
ssize_t len; \ |
156 |
|
|
len = kvm_read((kd), (addr), (dst), (sz)); \ |
157 |
|
|
if (len != (sz)) \ |
158 |
|
|
errx(1, "%s == %ld vs. %lu @ %lx", \ |
159 |
|
|
kvm_geterr(kd), (long)len, (unsigned long)(sz), (addr)); \ |
160 |
|
|
} while (0/*CONSTCOND*/) |
161 |
|
|
|
162 |
|
|
/* suck the data using the structure */ |
163 |
|
|
#define KDEREF(kd, item) _KDEREF((kd), A(item), D(item, data), S(item)) |
164 |
|
|
|
165 |
|
|
struct nlist nl[] = { |
166 |
|
|
{ "_maxsmap" }, |
167 |
|
|
#define NL_MAXSSIZ 0 |
168 |
|
|
{ "_uvm_vnodeops" }, |
169 |
|
|
#define NL_UVM_VNODEOPS 1 |
170 |
|
|
{ "_uvm_deviceops" }, |
171 |
|
|
#define NL_UVM_DEVICEOPS 2 |
172 |
|
|
{ "_aobj_pager" }, |
173 |
|
|
#define NL_AOBJ_PAGER 3 |
174 |
|
|
{ "_kernel_map" }, |
175 |
|
|
#define NL_KERNEL_MAP 4 |
176 |
|
|
{ "_nclruhead" }, |
177 |
|
|
#define NL_NCLRUHEAD 5 |
178 |
|
|
{ NULL } |
179 |
|
|
}; |
180 |
|
|
|
181 |
|
|
void load_symbols(kvm_t *); |
182 |
|
|
void process_map(kvm_t *, pid_t, struct kinfo_proc *, struct sum *); |
183 |
|
|
struct vm_map_entry *load_vm_map_entries(kvm_t *, struct vm_map_entry *, |
184 |
|
|
struct vm_map_entry *); |
185 |
|
|
void unload_vm_map_entries(struct vm_map_entry *); |
186 |
|
|
size_t dump_vm_map_entry(kvm_t *, struct kbit *, struct vm_map_entry *, |
187 |
|
|
struct sum *); |
188 |
|
|
char *findname(kvm_t *, struct kbit *, struct vm_map_entry *, struct kbit *, |
189 |
|
|
struct kbit *, struct kbit *); |
190 |
|
|
int search_cache(kvm_t *, struct kbit *, char **, char *, size_t); |
191 |
|
|
void load_name_cache(kvm_t *); |
192 |
|
|
void cache_enter(struct namecache *); |
193 |
|
|
static void __dead usage(void); |
194 |
|
|
static pid_t strtopid(const char *); |
195 |
|
|
void print_sum(struct sum *, struct sum *); |
196 |
|
|
|
197 |
|
|
/* |
198 |
|
|
* uvm_map address tree implementation. |
199 |
|
|
*/ |
200 |
|
|
static int no_impl(const void *, const void *); |
201 |
|
|
static int |
202 |
|
|
no_impl(const void *p, const void *q) |
203 |
|
|
{ |
204 |
|
|
errx(1, "uvm_map address comparison not implemented"); |
205 |
|
|
return 0; |
206 |
|
|
} |
207 |
|
|
|
208 |
|
|
RBT_PROTOTYPE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl); |
209 |
|
|
RBT_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl); |
210 |
|
|
|
211 |
|
|
int |
212 |
|
|
main(int argc, char *argv[]) |
213 |
|
|
{ |
214 |
|
|
const char *errstr; |
215 |
|
|
char errbuf[_POSIX2_LINE_MAX], *kmem = NULL, *kernel = NULL; |
216 |
|
|
struct kinfo_proc *kproc; |
217 |
|
|
struct sum total_sum; |
218 |
|
|
int many, ch, rc; |
219 |
|
|
kvm_t *kd; |
220 |
|
|
pid_t pid = -1; |
221 |
|
|
gid_t gid; |
222 |
|
|
|
223 |
|
|
while ((ch = getopt(argc, argv, "AaD:dlmM:N:p:Prsvx")) != -1) { |
224 |
|
|
switch (ch) { |
225 |
|
|
case 'A': |
226 |
|
|
print_amap = 1; |
227 |
|
|
break; |
228 |
|
|
case 'a': |
229 |
|
|
print_all = 1; |
230 |
|
|
break; |
231 |
|
|
case 'd': |
232 |
|
|
print_ddb = 1; |
233 |
|
|
break; |
234 |
|
|
case 'D': |
235 |
|
|
debug = strtonum(optarg, 0, 0x1f, &errstr); |
236 |
|
|
if (errstr) |
237 |
|
|
errx(1, "invalid debug mask"); |
238 |
|
|
break; |
239 |
|
|
case 'l': |
240 |
|
|
print_maps = 1; |
241 |
|
|
break; |
242 |
|
|
case 'm': |
243 |
|
|
print_map = 1; |
244 |
|
|
break; |
245 |
|
|
case 'M': |
246 |
|
|
kmem = optarg; |
247 |
|
|
break; |
248 |
|
|
case 'N': |
249 |
|
|
kernel = optarg; |
250 |
|
|
break; |
251 |
|
|
case 'p': |
252 |
|
|
pid = strtopid(optarg); |
253 |
|
|
break; |
254 |
|
|
case 'P': |
255 |
|
|
pid = getpid(); |
256 |
|
|
break; |
257 |
|
|
case 's': |
258 |
|
|
print_solaris = 1; |
259 |
|
|
break; |
260 |
|
|
case 'v': |
261 |
|
|
verbose = 1; |
262 |
|
|
break; |
263 |
|
|
case 'r': |
264 |
|
|
case 'x': |
265 |
|
|
errx(1, "-%c option not implemented, sorry", ch); |
266 |
|
|
/*NOTREACHED*/ |
267 |
|
|
default: |
268 |
|
|
usage(); |
269 |
|
|
} |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
/* |
273 |
|
|
* Discard setgid privileges if not the running kernel so that bad |
274 |
|
|
* guys can't print interesting stuff from kernel memory. |
275 |
|
|
*/ |
276 |
|
|
gid = getgid(); |
277 |
|
|
if (kernel != NULL || kmem != NULL) |
278 |
|
|
if (setresgid(gid, gid, gid) == -1) |
279 |
|
|
err(1, "setresgid"); |
280 |
|
|
|
281 |
|
|
argc -= optind; |
282 |
|
|
argv += optind; |
283 |
|
|
|
284 |
|
|
/* more than one "process" to dump? */ |
285 |
|
|
many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0; |
286 |
|
|
|
287 |
|
|
/* apply default */ |
288 |
|
|
if (print_all + print_map + print_maps + print_solaris + |
289 |
|
|
print_ddb == 0) |
290 |
|
|
print_solaris = 1; |
291 |
|
|
|
292 |
|
|
/* start by opening libkvm */ |
293 |
|
|
kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf); |
294 |
|
|
|
295 |
|
|
if (kernel == NULL && kmem == NULL) |
296 |
|
|
if (setresgid(gid, gid, gid) == -1) |
297 |
|
|
err(1, "setresgid"); |
298 |
|
|
|
299 |
|
|
if (kd == NULL) |
300 |
|
|
errx(1, "%s", errbuf); |
301 |
|
|
|
302 |
|
|
/* get "bootstrap" addresses from kernel */ |
303 |
|
|
load_symbols(kd); |
304 |
|
|
|
305 |
|
|
memset(&total_sum, 0, sizeof(total_sum)); |
306 |
|
|
|
307 |
|
|
do { |
308 |
|
|
struct sum sum; |
309 |
|
|
|
310 |
|
|
memset(&sum, 0, sizeof(sum)); |
311 |
|
|
|
312 |
|
|
if (pid == -1) { |
313 |
|
|
if (argc == 0) |
314 |
|
|
pid = getppid(); |
315 |
|
|
else { |
316 |
|
|
pid = strtopid(argv[0]); |
317 |
|
|
argv++; |
318 |
|
|
argc--; |
319 |
|
|
} |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
/* find the process id */ |
323 |
|
|
if (pid == 0) |
324 |
|
|
kproc = NULL; |
325 |
|
|
else { |
326 |
|
|
kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, |
327 |
|
|
sizeof(struct kinfo_proc), &rc); |
328 |
|
|
if (kproc == NULL || rc == 0) { |
329 |
|
|
warnc(ESRCH, "%d", pid); |
330 |
|
|
pid = -1; |
331 |
|
|
continue; |
332 |
|
|
} |
333 |
|
|
} |
334 |
|
|
|
335 |
|
|
/* dump it */ |
336 |
|
|
if (many) { |
337 |
|
|
if (kproc) |
338 |
|
|
printf("process %d:\n", pid); |
339 |
|
|
else |
340 |
|
|
printf("kernel:\n"); |
341 |
|
|
} |
342 |
|
|
|
343 |
|
|
process_map(kd, pid, kproc, &sum); |
344 |
|
|
if (print_amap) |
345 |
|
|
print_sum(&sum, &total_sum); |
346 |
|
|
pid = -1; |
347 |
|
|
} while (argc > 0); |
348 |
|
|
|
349 |
|
|
if (print_amap) |
350 |
|
|
print_sum(&total_sum, NULL); |
351 |
|
|
|
352 |
|
|
/* done. go away. */ |
353 |
|
|
rc = kvm_close(kd); |
354 |
|
|
if (rc == -1) |
355 |
|
|
err(1, "kvm_close"); |
356 |
|
|
|
357 |
|
|
return (0); |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
void |
361 |
|
|
print_sum(struct sum *sum, struct sum *total_sum) |
362 |
|
|
{ |
363 |
|
|
const char *t = total_sum == NULL ? "total " : ""; |
364 |
|
|
printf("%samap mapped slots: %lu\n", t, sum->s_am_nslots); |
365 |
|
|
printf("%samap used slots: %lu\n", t, sum->s_am_nusedslots); |
366 |
|
|
|
367 |
|
|
if (total_sum) { |
368 |
|
|
total_sum->s_am_nslots += sum->s_am_nslots; |
369 |
|
|
total_sum->s_am_nusedslots += sum->s_am_nusedslots; |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
|
373 |
|
|
void |
374 |
|
|
process_map(kvm_t *kd, pid_t pid, struct kinfo_proc *proc, struct sum *sum) |
375 |
|
|
{ |
376 |
|
|
struct kbit kbit[3], *vmspace, *vm_map; |
377 |
|
|
struct vm_map_entry *vm_map_entry; |
378 |
|
|
size_t total = 0; |
379 |
|
|
char *thing; |
380 |
|
|
uid_t uid; |
381 |
|
|
int vmmap_flags; |
382 |
|
|
|
383 |
|
|
if ((uid = getuid())) { |
384 |
|
|
if (pid == 0) { |
385 |
|
|
warnx("kernel map is restricted"); |
386 |
|
|
return; |
387 |
|
|
} |
388 |
|
|
if (uid != proc->p_uid) { |
389 |
|
|
warnx("other users' process maps are restricted"); |
390 |
|
|
return; |
391 |
|
|
} |
392 |
|
|
} |
393 |
|
|
|
394 |
|
|
vmspace = &kbit[0]; |
395 |
|
|
vm_map = &kbit[1]; |
396 |
|
|
|
397 |
|
|
A(vmspace) = 0; |
398 |
|
|
A(vm_map) = 0; |
399 |
|
|
|
400 |
|
|
if (pid > 0) { |
401 |
|
|
A(vmspace) = (u_long)proc->p_vmspace; |
402 |
|
|
S(vmspace) = sizeof(struct vmspace); |
403 |
|
|
KDEREF(kd, vmspace); |
404 |
|
|
thing = "proc->p_vmspace.vm_map"; |
405 |
|
|
} else { |
406 |
|
|
A(vmspace) = 0; |
407 |
|
|
S(vmspace) = 0; |
408 |
|
|
thing = "kernel_map"; |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
if (pid > 0 && (debug & PRINT_VMSPACE)) { |
412 |
|
|
printf("proc->p_vmspace %p = {", P(vmspace)); |
413 |
|
|
printf(" vm_refcnt = %d,", D(vmspace, vmspace)->vm_refcnt); |
414 |
|
|
printf(" vm_shm = %p,\n", D(vmspace, vmspace)->vm_shm); |
415 |
|
|
printf(" vm_rssize = %d,", D(vmspace, vmspace)->vm_rssize); |
416 |
|
|
#if 0 |
417 |
|
|
printf(" vm_swrss = %d,", D(vmspace, vmspace)->vm_swrss); |
418 |
|
|
#endif |
419 |
|
|
printf(" vm_tsize = %d,", D(vmspace, vmspace)->vm_tsize); |
420 |
|
|
printf(" vm_dsize = %d,\n", D(vmspace, vmspace)->vm_dsize); |
421 |
|
|
printf(" vm_ssize = %d,", D(vmspace, vmspace)->vm_ssize); |
422 |
|
|
printf(" vm_taddr = %p,", D(vmspace, vmspace)->vm_taddr); |
423 |
|
|
printf(" vm_daddr = %p,\n", D(vmspace, vmspace)->vm_daddr); |
424 |
|
|
printf(" vm_maxsaddr = %p,", |
425 |
|
|
D(vmspace, vmspace)->vm_maxsaddr); |
426 |
|
|
printf(" vm_minsaddr = %p }\n", |
427 |
|
|
D(vmspace, vmspace)->vm_minsaddr); |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
S(vm_map) = sizeof(struct vm_map); |
431 |
|
|
if (pid > 0) { |
432 |
|
|
A(vm_map) = A(vmspace); |
433 |
|
|
memcpy(D(vm_map, vm_map), &D(vmspace, vmspace)->vm_map, |
434 |
|
|
S(vm_map)); |
435 |
|
|
} else { |
436 |
|
|
A(vm_map) = kernel_map_addr; |
437 |
|
|
KDEREF(kd, vm_map); |
438 |
|
|
} |
439 |
|
|
if (debug & PRINT_VM_MAP) { |
440 |
|
|
printf("%s %p = {", thing, P(vm_map)); |
441 |
|
|
|
442 |
|
|
printf(" pmap = %p,\n", D(vm_map, vm_map)->pmap); |
443 |
|
|
printf(" lock = <struct lock>\n"); |
444 |
|
|
printf(" size = %lx,", D(vm_map, vm_map)->size); |
445 |
|
|
printf(" ref_count = %d,", D(vm_map, vm_map)->ref_count); |
446 |
|
|
printf(" ref_lock = <struct simplelock>,\n"); |
447 |
|
|
printf(" min_offset-max_offset = 0x%lx-0x%lx\n", |
448 |
|
|
D(vm_map, vm_map)->min_offset, |
449 |
|
|
D(vm_map, vm_map)->max_offset); |
450 |
|
|
printf(" b_start-b_end = 0x%lx-0x%lx\n", |
451 |
|
|
D(vm_map, vm_map)->b_start, |
452 |
|
|
D(vm_map, vm_map)->b_end); |
453 |
|
|
printf(" s_start-s_end = 0x%lx-0x%lx\n", |
454 |
|
|
D(vm_map, vm_map)->s_start, |
455 |
|
|
D(vm_map, vm_map)->s_end); |
456 |
|
|
vmmap_flags = D(vm_map, vm_map)->flags; |
457 |
|
|
printf(" flags = %x <%s%s%s%s%s%s >,\n", |
458 |
|
|
vmmap_flags, |
459 |
|
|
vmmap_flags & VM_MAP_PAGEABLE ? " PAGEABLE" : "", |
460 |
|
|
vmmap_flags & VM_MAP_INTRSAFE ? " INTRSAFE" : "", |
461 |
|
|
vmmap_flags & VM_MAP_WIREFUTURE ? " WIREFUTURE" : "", |
462 |
|
|
vmmap_flags & VM_MAP_BUSY ? " BUSY" : "", |
463 |
|
|
vmmap_flags & VM_MAP_WANTLOCK ? " WANTLOCK" : "", |
464 |
|
|
#if VM_MAP_TOPDOWN > 0 |
465 |
|
|
vmmap_flags & VM_MAP_TOPDOWN ? " TOPDOWN" : |
466 |
|
|
#endif |
467 |
|
|
""); |
468 |
|
|
printf(" timestamp = %u }\n", D(vm_map, vm_map)->timestamp); |
469 |
|
|
} |
470 |
|
|
if (print_ddb) { |
471 |
|
|
printf("MAP %p: [0x%lx->0x%lx]\n", P(vm_map), |
472 |
|
|
D(vm_map, vm_map)->min_offset, |
473 |
|
|
D(vm_map, vm_map)->max_offset); |
474 |
|
|
printf("\tsz=%ld, ref=%d, version=%d, flags=0x%x\n", |
475 |
|
|
D(vm_map, vm_map)->size, |
476 |
|
|
D(vm_map, vm_map)->ref_count, |
477 |
|
|
D(vm_map, vm_map)->timestamp, |
478 |
|
|
D(vm_map, vm_map)->flags); |
479 |
|
|
printf("\tpmap=%p(resident=<unknown>)\n", |
480 |
|
|
D(vm_map, vm_map)->pmap); |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
/* headers */ |
484 |
|
|
#ifdef DISABLED_HEADERS |
485 |
|
|
if (print_map) |
486 |
|
|
printf("%-*s %-*s rwx RWX CPY NCP I W A\n", |
487 |
|
|
(int)sizeof(long) * 2 + 2, "Start", |
488 |
|
|
(int)sizeof(long) * 2 + 2, "End"); |
489 |
|
|
if (print_maps) |
490 |
|
|
printf("%-*s %-*s rwxp %-*s Dev Inode File\n", |
491 |
|
|
(int)sizeof(long) * 2 + 0, "Start", |
492 |
|
|
(int)sizeof(long) * 2 + 0, "End", |
493 |
|
|
(int)sizeof(long) * 2 + 0, "Offset"); |
494 |
|
|
if (print_solaris) |
495 |
|
|
printf("%-*s %*s Protection File\n", |
496 |
|
|
(int)sizeof(long) * 2 + 0, "Start", |
497 |
|
|
(int)sizeof(int) * 2 - 1, "Size "); |
498 |
|
|
#endif |
499 |
|
|
if (print_all) |
500 |
|
|
printf("%-*s %-*s %*s %-*s rwxpc RWX I/W/A Dev %*s - File\n", |
501 |
|
|
(int)sizeof(long) * 2, "Start", |
502 |
|
|
(int)sizeof(long) * 2, "End", |
503 |
|
|
(int)sizeof(int) * 2, "Size ", |
504 |
|
|
(int)sizeof(long) * 2, "Offset", |
505 |
|
|
(int)sizeof(int) * 2, "Inode"); |
506 |
|
|
|
507 |
|
|
/* these are the "sub entries" */ |
508 |
|
|
vm_map_entry = load_vm_map_entries(kd, |
509 |
|
|
RBT_ROOT(uvm_map_addr, &D(vm_map, vm_map)->addr), NULL); |
510 |
|
|
if (vm_map_entry != NULL) { |
511 |
|
|
/* RBTs point at rb_entries inside nodes */ |
512 |
|
|
D(vm_map, vm_map)->addr.rbh_root.rbt_root = |
513 |
|
|
&vm_map_entry->daddrs.addr_entry; |
514 |
|
|
} else |
515 |
|
|
RBT_INIT(uvm_map_addr, &D(vm_map, vm_map)->addr); |
516 |
|
|
|
517 |
|
|
RBT_FOREACH(vm_map_entry, uvm_map_addr, &D(vm_map, vm_map)->addr) |
518 |
|
|
total += dump_vm_map_entry(kd, vmspace, vm_map_entry, sum); |
519 |
|
|
unload_vm_map_entries(RBT_ROOT(uvm_map_addr, &D(vm_map, vm_map)->addr)); |
520 |
|
|
|
521 |
|
|
if (print_solaris) |
522 |
|
|
printf("%-*s %8luK\n", |
523 |
|
|
(int)sizeof(void *) * 2 - 2, " total", |
524 |
|
|
(unsigned long)total); |
525 |
|
|
if (print_all) |
526 |
|
|
printf("%-*s %9luk\n", |
527 |
|
|
(int)sizeof(void *) * 4 - 1, " total", |
528 |
|
|
(unsigned long)total); |
529 |
|
|
} |
530 |
|
|
|
531 |
|
|
void |
532 |
|
|
load_symbols(kvm_t *kd) |
533 |
|
|
{ |
534 |
|
|
int rc, i; |
535 |
|
|
|
536 |
|
|
rc = kvm_nlist(kd, &nl[0]); |
537 |
|
|
if (rc == -1) |
538 |
|
|
errx(1, "%s == %d", kvm_geterr(kd), rc); |
539 |
|
|
for (i = 0; i < sizeof(nl)/sizeof(nl[0]); i++) |
540 |
|
|
if (nl[i].n_value == 0 && nl[i].n_name) |
541 |
|
|
printf("%s not found\n", nl[i].n_name); |
542 |
|
|
|
543 |
|
|
uvm_vnodeops = (void*)nl[NL_UVM_VNODEOPS].n_value; |
544 |
|
|
uvm_deviceops = (void*)nl[NL_UVM_DEVICEOPS].n_value; |
545 |
|
|
aobj_pager = (void*)nl[NL_AOBJ_PAGER].n_value; |
546 |
|
|
|
547 |
|
|
nclruhead_addr = nl[NL_NCLRUHEAD].n_value; |
548 |
|
|
|
549 |
|
|
_KDEREF(kd, nl[NL_MAXSSIZ].n_value, &maxssiz, |
550 |
|
|
sizeof(maxssiz)); |
551 |
|
|
_KDEREF(kd, nl[NL_KERNEL_MAP].n_value, &kernel_map_addr, |
552 |
|
|
sizeof(kernel_map_addr)); |
553 |
|
|
} |
554 |
|
|
|
555 |
|
|
/* |
556 |
|
|
* Recreate the addr tree of vm_map in local memory. |
557 |
|
|
*/ |
558 |
|
|
struct vm_map_entry * |
559 |
|
|
load_vm_map_entries(kvm_t *kd, struct vm_map_entry *kptr, |
560 |
|
|
struct vm_map_entry *parent) |
561 |
|
|
{ |
562 |
|
|
static struct kbit map_ent; |
563 |
|
|
struct vm_map_entry *result, *ld; |
564 |
|
|
|
565 |
|
|
if (kptr == NULL) |
566 |
|
|
return NULL; |
567 |
|
|
|
568 |
|
|
A(&map_ent) = (u_long)kptr; |
569 |
|
|
S(&map_ent) = sizeof(struct vm_map_entry); |
570 |
|
|
KDEREF(kd, &map_ent); |
571 |
|
|
|
572 |
|
|
result = malloc(sizeof(*result)); |
573 |
|
|
if (result == NULL) |
574 |
|
|
err(1, "malloc"); |
575 |
|
|
memcpy(result, D(&map_ent, vm_map_entry), sizeof(struct vm_map_entry)); |
576 |
|
|
|
577 |
|
|
/* |
578 |
|
|
* Recurse to download rest of the tree. |
579 |
|
|
*/ |
580 |
|
|
|
581 |
|
|
/* RBTs point at rb_entries inside nodes */ |
582 |
|
|
ld = load_vm_map_entries(kd, RBT_LEFT(uvm_map_addr, result), result); |
583 |
|
|
result->daddrs.addr_entry.rbt_left = &ld->daddrs.addr_entry; |
584 |
|
|
ld = load_vm_map_entries(kd, RBT_RIGHT(uvm_map_addr, result), result); |
585 |
|
|
result->daddrs.addr_entry.rbt_right = &ld->daddrs.addr_entry; |
586 |
|
|
result->daddrs.addr_entry.rbt_parent = &parent->daddrs.addr_entry; |
587 |
|
|
|
588 |
|
|
return result; |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
/* |
592 |
|
|
* Release the addr tree of vm_map. |
593 |
|
|
*/ |
594 |
|
|
void |
595 |
|
|
unload_vm_map_entries(struct vm_map_entry *ent) |
596 |
|
|
{ |
597 |
|
|
if (ent == NULL) |
598 |
|
|
return; |
599 |
|
|
|
600 |
|
|
unload_vm_map_entries(RBT_LEFT(uvm_map_addr, ent)); |
601 |
|
|
unload_vm_map_entries(RBT_RIGHT(uvm_map_addr, ent)); |
602 |
|
|
free(ent); |
603 |
|
|
} |
604 |
|
|
|
605 |
|
|
size_t |
606 |
|
|
dump_vm_map_entry(kvm_t *kd, struct kbit *vmspace, |
607 |
|
|
struct vm_map_entry *vme, struct sum *sum) |
608 |
|
|
{ |
609 |
|
|
struct kbit kbit[5], *uvm_obj, *vp, *vfs, *amap, *uvn; |
610 |
|
|
ino_t inode = 0; |
611 |
|
|
dev_t dev = 0; |
612 |
|
|
size_t sz = 0; |
613 |
|
|
char *name; |
614 |
|
|
|
615 |
|
|
uvm_obj = &kbit[0]; |
616 |
|
|
vp = &kbit[1]; |
617 |
|
|
vfs = &kbit[2]; |
618 |
|
|
amap = &kbit[3]; |
619 |
|
|
uvn = &kbit[4]; |
620 |
|
|
|
621 |
|
|
A(uvm_obj) = 0; |
622 |
|
|
A(vp) = 0; |
623 |
|
|
A(vfs) = 0; |
624 |
|
|
A(uvn) = 0; |
625 |
|
|
|
626 |
|
|
if (debug & PRINT_VM_MAP_ENTRY) { |
627 |
|
|
printf("%s = {", "vm_map_entry"); |
628 |
|
|
printf(" start = %lx,", vme->start); |
629 |
|
|
printf(" end = %lx,", vme->end); |
630 |
|
|
printf(" fspace = %lx,\n", vme->fspace); |
631 |
|
|
printf(" object.uvm_obj/sub_map = %p,\n", |
632 |
|
|
vme->object.uvm_obj); |
633 |
|
|
printf(" offset = %lx,", (unsigned long)vme->offset); |
634 |
|
|
printf(" etype = %x <%s%s%s%s%s >,", vme->etype, |
635 |
|
|
vme->etype & UVM_ET_OBJ ? " OBJ" : "", |
636 |
|
|
vme->etype & UVM_ET_SUBMAP ? " SUBMAP" : "", |
637 |
|
|
vme->etype & UVM_ET_COPYONWRITE ? " COW" : "", |
638 |
|
|
vme->etype & UVM_ET_NEEDSCOPY ? " NEEDSCOPY" : "", |
639 |
|
|
vme->etype & UVM_ET_HOLE ? " HOLE" : ""); |
640 |
|
|
printf(" protection = %x,\n", vme->protection); |
641 |
|
|
printf(" max_protection = %x,", vme->max_protection); |
642 |
|
|
printf(" inheritance = %d,", vme->inheritance); |
643 |
|
|
printf(" wired_count = %d,\n", vme->wired_count); |
644 |
|
|
printf(" aref = <struct vm_aref>,"); |
645 |
|
|
printf(" advice = %d,", vme->advice); |
646 |
|
|
printf(" flags = %x <%s%s > }\n", vme->flags, |
647 |
|
|
vme->flags & UVM_MAP_STATIC ? " STATIC" : "", |
648 |
|
|
vme->flags & UVM_MAP_KMEM ? " KMEM" : ""); |
649 |
|
|
} |
650 |
|
|
|
651 |
|
|
A(vp) = 0; |
652 |
|
|
A(uvm_obj) = 0; |
653 |
|
|
|
654 |
|
|
if (vme->object.uvm_obj != NULL) { |
655 |
|
|
P(uvm_obj) = vme->object.uvm_obj; |
656 |
|
|
S(uvm_obj) = sizeof(struct uvm_object); |
657 |
|
|
KDEREF(kd, uvm_obj); |
658 |
|
|
if (UVM_ET_ISOBJ(vme) && |
659 |
|
|
UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) { |
660 |
|
|
P(uvn) = P(uvm_obj); |
661 |
|
|
S(uvn) = sizeof(struct uvm_vnode); |
662 |
|
|
KDEREF(kd, uvn); |
663 |
|
|
|
664 |
|
|
P(vp) = D(uvn, uvm_vnode)->u_vnode; |
665 |
|
|
S(vp) = sizeof(struct vnode); |
666 |
|
|
KDEREF(kd, vp); |
667 |
|
|
} |
668 |
|
|
} |
669 |
|
|
|
670 |
|
|
if (vme->aref.ar_amap != NULL) { |
671 |
|
|
P(amap) = vme->aref.ar_amap; |
672 |
|
|
S(amap) = sizeof(struct vm_amap); |
673 |
|
|
KDEREF(kd, amap); |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
A(vfs) = 0; |
677 |
|
|
|
678 |
|
|
if (P(vp) != NULL && D(vp, vnode)->v_mount != NULL) { |
679 |
|
|
P(vfs) = D(vp, vnode)->v_mount; |
680 |
|
|
S(vfs) = sizeof(struct mount); |
681 |
|
|
KDEREF(kd, vfs); |
682 |
|
|
D(vp, vnode)->v_mount = D(vfs, mount); |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
/* |
686 |
|
|
* dig out the device number and inode number from certain |
687 |
|
|
* file system types. |
688 |
|
|
*/ |
689 |
|
|
#define V_DATA_IS(vp, type, d, i) do { \ |
690 |
|
|
struct kbit data; \ |
691 |
|
|
P(&data) = D(vp, vnode)->v_data; \ |
692 |
|
|
S(&data) = sizeof(*D(&data, type)); \ |
693 |
|
|
KDEREF(kd, &data); \ |
694 |
|
|
dev = D(&data, type)->d; \ |
695 |
|
|
inode = D(&data, type)->i; \ |
696 |
|
|
} while (0/*CONSTCOND*/) |
697 |
|
|
|
698 |
|
|
if (A(vp) && |
699 |
|
|
D(vp, vnode)->v_type == VREG && |
700 |
|
|
D(vp, vnode)->v_data != NULL) { |
701 |
|
|
switch (D(vp, vnode)->v_tag) { |
702 |
|
|
case VT_UFS: |
703 |
|
|
case VT_EXT2FS: |
704 |
|
|
V_DATA_IS(vp, inode, i_dev, i_number); |
705 |
|
|
break; |
706 |
|
|
case VT_ISOFS: |
707 |
|
|
V_DATA_IS(vp, iso_node, i_dev, i_number); |
708 |
|
|
break; |
709 |
|
|
case VT_NON: |
710 |
|
|
case VT_NFS: |
711 |
|
|
case VT_MFS: |
712 |
|
|
case VT_MSDOSFS: |
713 |
|
|
default: |
714 |
|
|
break; |
715 |
|
|
} |
716 |
|
|
} |
717 |
|
|
|
718 |
|
|
name = findname(kd, vmspace, vme, vp, vfs, uvm_obj); |
719 |
|
|
|
720 |
|
|
if (print_map) { |
721 |
|
|
printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d", |
722 |
|
|
vme->start, vme->end, |
723 |
|
|
(vme->protection & PROT_READ) ? 'r' : '-', |
724 |
|
|
(vme->protection & PROT_WRITE) ? 'w' : '-', |
725 |
|
|
(vme->protection & PROT_EXEC) ? 'x' : '-', |
726 |
|
|
(vme->max_protection & PROT_READ) ? 'r' : '-', |
727 |
|
|
(vme->max_protection & PROT_WRITE) ? 'w' : '-', |
728 |
|
|
(vme->max_protection & PROT_EXEC) ? 'x' : '-', |
729 |
|
|
(vme->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW", |
730 |
|
|
(vme->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC", |
731 |
|
|
vme->inheritance, vme->wired_count, |
732 |
|
|
vme->advice); |
733 |
|
|
if (verbose) { |
734 |
|
|
if (inode) |
735 |
|
|
printf(" %d,%d %llu", |
736 |
|
|
major(dev), minor(dev), |
737 |
|
|
(unsigned long long)inode); |
738 |
|
|
if (name[0]) |
739 |
|
|
printf(" %s", name); |
740 |
|
|
} |
741 |
|
|
printf("\n"); |
742 |
|
|
} |
743 |
|
|
|
744 |
|
|
if (print_maps) |
745 |
|
|
printf("%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %llu %s\n", |
746 |
|
|
(int)sizeof(void *) * 2, vme->start, |
747 |
|
|
(int)sizeof(void *) * 2, vme->end, |
748 |
|
|
(vme->protection & PROT_READ) ? 'r' : '-', |
749 |
|
|
(vme->protection & PROT_WRITE) ? 'w' : '-', |
750 |
|
|
(vme->protection & PROT_EXEC) ? 'x' : '-', |
751 |
|
|
(vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', |
752 |
|
|
(int)sizeof(void *) * 2, |
753 |
|
|
(unsigned long)vme->offset, |
754 |
|
|
major(dev), minor(dev), (unsigned long long)inode, |
755 |
|
|
inode ? name : ""); |
756 |
|
|
|
757 |
|
|
if (print_ddb) { |
758 |
|
|
printf(" - <lost address>: 0x%lx->0x%lx: " |
759 |
|
|
"obj=%p/0x%lx, amap=%p/%d\n", |
760 |
|
|
vme->start, vme->end, |
761 |
|
|
vme->object.uvm_obj, (unsigned long)vme->offset, |
762 |
|
|
vme->aref.ar_amap, vme->aref.ar_pageoff); |
763 |
|
|
printf("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, " |
764 |
|
|
"wc=%d, adv=%d\n", |
765 |
|
|
(vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F', |
766 |
|
|
(vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F', |
767 |
|
|
(vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F', |
768 |
|
|
vme->protection, vme->max_protection, |
769 |
|
|
vme->inheritance, vme->wired_count, vme->advice); |
770 |
|
|
if (inode && verbose) |
771 |
|
|
printf("\t(dev=%d,%d ino=%llu [%s] [%p])\n", |
772 |
|
|
major(dev), minor(dev), (unsigned long long)inode, |
773 |
|
|
inode ? name : "", P(vp)); |
774 |
|
|
else if (name[0] == ' ' && verbose) |
775 |
|
|
printf("\t(%s)\n", &name[2]); |
776 |
|
|
} |
777 |
|
|
|
778 |
|
|
if (print_solaris) { |
779 |
|
|
char prot[30]; |
780 |
|
|
|
781 |
|
|
prot[0] = '\0'; |
782 |
|
|
prot[1] = '\0'; |
783 |
|
|
if (vme->protection & PROT_READ) |
784 |
|
|
strlcat(prot, "/read", sizeof(prot)); |
785 |
|
|
if (vme->protection & PROT_WRITE) |
786 |
|
|
strlcat(prot, "/write", sizeof(prot)); |
787 |
|
|
if (vme->protection & PROT_EXEC) |
788 |
|
|
strlcat(prot, "/exec", sizeof(prot)); |
789 |
|
|
|
790 |
|
|
sz = (size_t)((vme->end - vme->start) / 1024); |
791 |
|
|
printf("%0*lX %6luK %-15s %s\n", |
792 |
|
|
(int)sizeof(void *) * 2, (unsigned long)vme->start, |
793 |
|
|
(unsigned long)sz, &prot[1], name); |
794 |
|
|
} |
795 |
|
|
|
796 |
|
|
if (print_all) { |
797 |
|
|
sz = (size_t)((vme->end - vme->start) / 1024); |
798 |
|
|
printf("%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7llu - %s", |
799 |
|
|
(int)sizeof(void *) * 2, vme->start, (int)sizeof(void *) * 2, |
800 |
|
|
vme->end - (vme->start != vme->end ? 1 : 0), (unsigned long)sz, |
801 |
|
|
(int)sizeof(void *) * 2, (unsigned long)vme->offset, |
802 |
|
|
(vme->protection & PROT_READ) ? 'r' : '-', |
803 |
|
|
(vme->protection & PROT_WRITE) ? 'w' : '-', |
804 |
|
|
(vme->protection & PROT_EXEC) ? 'x' : '-', |
805 |
|
|
(vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's', |
806 |
|
|
(vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-', |
807 |
|
|
(vme->max_protection & PROT_READ) ? 'r' : '-', |
808 |
|
|
(vme->max_protection & PROT_WRITE) ? 'w' : '-', |
809 |
|
|
(vme->max_protection & PROT_EXEC) ? 'x' : '-', |
810 |
|
|
vme->inheritance, vme->wired_count, vme->advice, |
811 |
|
|
major(dev), minor(dev), (unsigned long long)inode, name); |
812 |
|
|
if (A(vp)) |
813 |
|
|
printf(" [%p]", P(vp)); |
814 |
|
|
printf("\n"); |
815 |
|
|
} |
816 |
|
|
|
817 |
|
|
if (print_amap && vme->aref.ar_amap) { |
818 |
|
|
printf(" amap - ref: %d fl: 0x%x nsl: %d nuse: %d\n", |
819 |
|
|
D(amap, vm_amap)->am_ref, |
820 |
|
|
D(amap, vm_amap)->am_flags, |
821 |
|
|
D(amap, vm_amap)->am_nslot, |
822 |
|
|
D(amap, vm_amap)->am_nused); |
823 |
|
|
if (sum) { |
824 |
|
|
sum->s_am_nslots += D(amap, vm_amap)->am_nslot; |
825 |
|
|
sum->s_am_nusedslots += D(amap, vm_amap)->am_nused; |
826 |
|
|
} |
827 |
|
|
} |
828 |
|
|
|
829 |
|
|
/* no access allowed, don't count space */ |
830 |
|
|
if ((vme->protection & rwx) == 0) |
831 |
|
|
sz = 0; |
832 |
|
|
|
833 |
|
|
return (sz); |
834 |
|
|
} |
835 |
|
|
|
836 |
|
|
char * |
837 |
|
|
findname(kvm_t *kd, struct kbit *vmspace, |
838 |
|
|
struct vm_map_entry *vme, struct kbit *vp, |
839 |
|
|
struct kbit *vfs, struct kbit *uvm_obj) |
840 |
|
|
{ |
841 |
|
|
static char buf[1024], *name; |
842 |
|
|
size_t l; |
843 |
|
|
|
844 |
|
|
if (UVM_ET_ISOBJ(vme)) { |
845 |
|
|
if (A(vfs)) { |
846 |
|
|
l = strlen(D(vfs, mount)->mnt_stat.f_mntonname); |
847 |
|
|
switch (search_cache(kd, vp, &name, buf, sizeof(buf))) { |
848 |
|
|
case 0: /* found something */ |
849 |
|
|
if (name - (1 + 11 + l) < buf) |
850 |
|
|
break; |
851 |
|
|
name--; |
852 |
|
|
*name = '/'; |
853 |
|
|
/*FALLTHROUGH*/ |
854 |
|
|
case 2: /* found nothing */ |
855 |
|
|
name -= 11; |
856 |
|
|
memcpy(name, " -unknown- ", (size_t)11); |
857 |
|
|
name -= l; |
858 |
|
|
memcpy(name, |
859 |
|
|
D(vfs, mount)->mnt_stat.f_mntonname, l); |
860 |
|
|
break; |
861 |
|
|
case 1: /* all is well */ |
862 |
|
|
if (name - (1 + l) < buf) |
863 |
|
|
break; |
864 |
|
|
name--; |
865 |
|
|
*name = '/'; |
866 |
|
|
if (l != 1) { |
867 |
|
|
name -= l; |
868 |
|
|
memcpy(name, |
869 |
|
|
D(vfs, mount)->mnt_stat.f_mntonname, l); |
870 |
|
|
} |
871 |
|
|
break; |
872 |
|
|
} |
873 |
|
|
} else if (UVM_OBJ_IS_DEVICE(D(uvm_obj, uvm_object))) { |
874 |
|
|
struct kbit kdev; |
875 |
|
|
dev_t dev; |
876 |
|
|
|
877 |
|
|
P(&kdev) = P(uvm_obj); |
878 |
|
|
S(&kdev) = sizeof(struct uvm_device); |
879 |
|
|
KDEREF(kd, &kdev); |
880 |
|
|
dev = D(&kdev, uvm_device)->u_device; |
881 |
|
|
name = devname(dev, S_IFCHR); |
882 |
|
|
if (name != NULL) |
883 |
|
|
snprintf(buf, sizeof(buf), "/dev/%s", name); |
884 |
|
|
else |
885 |
|
|
snprintf(buf, sizeof(buf), " [ device %d,%d ]", |
886 |
|
|
major(dev), minor(dev)); |
887 |
|
|
name = buf; |
888 |
|
|
} else if (UVM_OBJ_IS_AOBJ(D(uvm_obj, uvm_object))) |
889 |
|
|
name = " [ uvm_aobj ]"; |
890 |
|
|
else if (UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) |
891 |
|
|
name = " [ ?VNODE? ]"; |
892 |
|
|
else { |
893 |
|
|
snprintf(buf, sizeof(buf), " [ unknown (%p) ]", |
894 |
|
|
D(uvm_obj, uvm_object)->pgops); |
895 |
|
|
name = buf; |
896 |
|
|
} |
897 |
|
|
} else if (D(vmspace, vmspace)->vm_maxsaddr <= (caddr_t)vme->start && |
898 |
|
|
(D(vmspace, vmspace)->vm_maxsaddr + (size_t)maxssiz) >= |
899 |
|
|
(caddr_t)vme->end) { |
900 |
|
|
name = " [ stack ]"; |
901 |
|
|
} else if (UVM_ET_ISHOLE(vme)) |
902 |
|
|
name = " [ hole ]"; |
903 |
|
|
else |
904 |
|
|
name = " [ anon ]"; |
905 |
|
|
|
906 |
|
|
return (name); |
907 |
|
|
} |
908 |
|
|
|
909 |
|
|
int |
910 |
|
|
search_cache(kvm_t *kd, struct kbit *vp, char **name, char *buf, size_t blen) |
911 |
|
|
{ |
912 |
|
|
struct cache_entry *ce; |
913 |
|
|
struct kbit svp; |
914 |
|
|
char *o, *e; |
915 |
|
|
u_long cid; |
916 |
|
|
|
917 |
|
|
if (!namecache_loaded) |
918 |
|
|
load_name_cache(kd); |
919 |
|
|
|
920 |
|
|
P(&svp) = P(vp); |
921 |
|
|
S(&svp) = sizeof(struct vnode); |
922 |
|
|
cid = D(vp, vnode)->v_id; |
923 |
|
|
|
924 |
|
|
e = &buf[blen - 1]; |
925 |
|
|
o = e; |
926 |
|
|
do { |
927 |
|
|
LIST_FOREACH(ce, &lcache, ce_next) |
928 |
|
|
if (ce->ce_vp == P(&svp) && ce->ce_cid == cid) |
929 |
|
|
break; |
930 |
|
|
if (ce && ce->ce_vp == P(&svp) && ce->ce_cid == cid) { |
931 |
|
|
if (o != e) { |
932 |
|
|
if (o <= buf) |
933 |
|
|
break; |
934 |
|
|
*(--o) = '/'; |
935 |
|
|
} |
936 |
|
|
if (o - ce->ce_nlen <= buf) |
937 |
|
|
break; |
938 |
|
|
o -= ce->ce_nlen; |
939 |
|
|
memcpy(o, ce->ce_name, ce->ce_nlen); |
940 |
|
|
P(&svp) = ce->ce_pvp; |
941 |
|
|
cid = ce->ce_pcid; |
942 |
|
|
} else |
943 |
|
|
break; |
944 |
|
|
} while (1/*CONSTCOND*/); |
945 |
|
|
*e = '\0'; |
946 |
|
|
*name = o; |
947 |
|
|
|
948 |
|
|
if (e == o) |
949 |
|
|
return (2); |
950 |
|
|
|
951 |
|
|
KDEREF(kd, &svp); |
952 |
|
|
return (D(&svp, vnode)->v_flag & VROOT); |
953 |
|
|
} |
954 |
|
|
|
955 |
|
|
void |
956 |
|
|
load_name_cache(kvm_t *kd) |
957 |
|
|
{ |
958 |
|
|
struct namecache n, *tmp; |
959 |
|
|
struct namecache_head nchead; |
960 |
|
|
|
961 |
|
|
LIST_INIT(&lcache); |
962 |
|
|
_KDEREF(kd, nclruhead_addr, &nchead, sizeof(nchead)); |
963 |
|
|
tmp = TAILQ_FIRST(&nchead); |
964 |
|
|
while (tmp != NULL) { |
965 |
|
|
_KDEREF(kd, (u_long)tmp, &n, sizeof(n)); |
966 |
|
|
|
967 |
|
|
if (n.nc_nlen > 0) { |
968 |
|
|
if (n.nc_nlen > 2 || |
969 |
|
|
n.nc_name[0] != '.' || |
970 |
|
|
(n.nc_nlen != 1 && n.nc_name[1] != '.')) |
971 |
|
|
cache_enter(&n); |
972 |
|
|
} |
973 |
|
|
tmp = TAILQ_NEXT(&n, nc_lru); |
974 |
|
|
} |
975 |
|
|
|
976 |
|
|
namecache_loaded = 1; |
977 |
|
|
} |
978 |
|
|
|
979 |
|
|
void |
980 |
|
|
cache_enter(struct namecache *ncp) |
981 |
|
|
{ |
982 |
|
|
struct cache_entry *ce; |
983 |
|
|
|
984 |
|
|
if (debug & DUMP_NAMEI_CACHE) |
985 |
|
|
printf("ncp->nc_vp %10p, ncp->nc_dvp %10p, ncp->nc_nlen " |
986 |
|
|
"%3d [%.*s] (nc_dvpid=%lu, nc_vpid=%lu)\n", |
987 |
|
|
ncp->nc_vp, ncp->nc_dvp, |
988 |
|
|
ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name, |
989 |
|
|
ncp->nc_dvpid, ncp->nc_vpid); |
990 |
|
|
|
991 |
|
|
ce = malloc(sizeof(struct cache_entry)); |
992 |
|
|
if (ce == NULL) |
993 |
|
|
err(1, "cache_enter"); |
994 |
|
|
|
995 |
|
|
ce->ce_vp = ncp->nc_vp; |
996 |
|
|
ce->ce_pvp = ncp->nc_dvp; |
997 |
|
|
ce->ce_cid = ncp->nc_vpid; |
998 |
|
|
ce->ce_pcid = ncp->nc_dvpid; |
999 |
|
|
ce->ce_nlen = (unsigned)ncp->nc_nlen; |
1000 |
|
|
strlcpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name)); |
1001 |
|
|
|
1002 |
|
|
LIST_INSERT_HEAD(&lcache, ce, ce_next); |
1003 |
|
|
} |
1004 |
|
|
|
1005 |
|
|
static void __dead |
1006 |
|
|
usage(void) |
1007 |
|
|
{ |
1008 |
|
|
extern char *__progname; |
1009 |
|
|
fprintf(stderr, "usage: %s [-AadlmPsv] [-D number] " |
1010 |
|
|
"[-M core] [-N system] [-p pid] [pid ...]\n", |
1011 |
|
|
__progname); |
1012 |
|
|
exit(1); |
1013 |
|
|
} |
1014 |
|
|
|
1015 |
|
|
static pid_t |
1016 |
|
|
strtopid(const char *str) |
1017 |
|
|
{ |
1018 |
|
|
pid_t pid; |
1019 |
|
|
|
1020 |
|
|
errno = 0; |
1021 |
|
|
pid = (pid_t)strtonum(str, 0, INT_MAX, NULL); |
1022 |
|
|
if (errno != 0) |
1023 |
|
|
usage(); |
1024 |
|
|
return (pid); |
1025 |
|
|
} |