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