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