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