procmap.c revision 1.2
1/*	$OpenBSD: procmap.c,v 1.2 2004/02/16 08:57:58 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		default:
624			break;
625		}
626	}
627
628	name = findname(kd, vmspace, vm_map_entry, vp, vfs, uvm_obj);
629
630	if (print_map) {
631		printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d",
632		       vme->start, vme->end,
633		       (vme->protection & VM_PROT_READ) ? 'r' : '-',
634		       (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
635		       (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
636		       (vme->max_protection & VM_PROT_READ) ? 'r' : '-',
637		       (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-',
638		       (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
639		       (vme->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW",
640		       (vme->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC",
641		       vme->inheritance, vme->wired_count,
642		       vme->advice);
643		if (verbose) {
644			if (inode)
645				printf(" %d,%d %d",
646				       major(dev), minor(dev), inode);
647			if (name[0])
648				printf(" %s", name);
649		}
650		printf("\n");
651	}
652
653	if (print_maps)
654		printf("%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %d     %s\n",
655		       (int)sizeof(void *) * 2, vme->start,
656		       (int)sizeof(void *) * 2, vme->end,
657		       (vme->protection & VM_PROT_READ) ? 'r' : '-',
658		       (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
659		       (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
660		       (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
661		       (int)sizeof(void *) * 2,
662		       (unsigned long)vme->offset,
663		       major(dev), minor(dev), inode, inode ? name : "");
664
665	if (print_ddb) {
666		printf(" - %p: 0x%lx->0x%lx: obj=%p/0x%lx, amap=%p/%d\n",
667		       P(vm_map_entry), vme->start, vme->end,
668		       vme->object.uvm_obj, (unsigned long)vme->offset,
669		       vme->aref.ar_amap, vme->aref.ar_pageoff);
670		printf("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, "
671		       "wc=%d, adv=%d\n",
672		       (vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F',
673		       (vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F',
674		       (vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F',
675		       vme->protection, vme->max_protection,
676		       vme->inheritance, vme->wired_count, vme->advice);
677		if (inode && verbose)
678			printf("\t(dev=%d,%d ino=%d [%s] [%p])\n",
679			       major(dev), minor(dev), inode,
680			       inode ? name : "", P(vp));
681		else if (name[0] == ' ' && verbose)
682			printf("\t(%s)\n", &name[2]);
683	}
684
685	sz = 0;
686	if (print_solaris) {
687		char prot[30];
688
689		prot[0] = '\0';
690		prot[1] = '\0';
691		if (vme->protection & VM_PROT_READ)
692			strcat(prot, "/read");
693		if (vme->protection & VM_PROT_WRITE)
694			strcat(prot, "/write");
695		if (vme->protection & VM_PROT_EXECUTE)
696			strcat(prot, "/exec");
697
698		sz = (size_t)((vme->end - vme->start) / 1024);
699		printf("%0*lX %6luK %-15s   %s\n",
700		       (int)sizeof(void *) * 2,
701		       (unsigned long)vme->start,
702		       (unsigned long)sz,
703		       &prot[1],
704		       name);
705	}
706
707	if (print_all) {
708		sz = (size_t)((vme->end - vme->start) / 1024);
709		printf(A(vp) ?
710		       "%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7d - %s [%p]\n" :
711		       "%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7d - %s\n",
712		       (int)sizeof(void *) * 2,
713		       vme->start,
714		       (int)sizeof(void *) * 2,
715		       vme->end - (vme->start != vme->end ? 1 : 0),
716		       (unsigned long)sz,
717		       (int)sizeof(void *) * 2,
718		       (unsigned long)vme->offset,
719		       (vme->protection & VM_PROT_READ) ? 'r' : '-',
720		       (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
721		       (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
722		       (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
723		       (vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-',
724		       (vme->max_protection & VM_PROT_READ) ? 'r' : '-',
725		       (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-',
726		       (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
727		       vme->inheritance,
728		       vme->wired_count,
729		       vme->advice,
730		       major(dev), minor(dev), inode,
731		       name, P(vp));
732	}
733
734	/* no access allowed, don't count space */
735	if ((vme->protection & rwx) == 0)
736		sz = 0;
737
738	return (sz);
739}
740
741char*
742findname(kvm_t *kd, struct kbit *vmspace,
743	 struct kbit *vm_map_entry, struct kbit *vp,
744	 struct kbit *vfs, struct kbit *uvm_obj)
745{
746	static char buf[1024], *name;
747	struct vm_map_entry *vme;
748	size_t l;
749
750	vme = D(vm_map_entry, vm_map_entry);
751
752	if (UVM_ET_ISOBJ(vme)) {
753		if (A(vfs)) {
754			l = (unsigned)strlen(D(vfs, mount)->mnt_stat.f_mntonname);
755			switch (search_cache(kd, vp, &name, buf, sizeof(buf))) {
756			    case 0: /* found something */
757                                name--;
758                                *name = '/';
759				/*FALLTHROUGH*/
760			    case 2: /* found nothing */
761				name -= 6;
762				memcpy(name, " -??- ", (size_t)6);
763				name -= l;
764				memcpy(name,
765				       D(vfs, mount)->mnt_stat.f_mntonname, l);
766				break;
767			    case 1: /* all is well */
768				name--;
769				*name = '/';
770				if (l != 1) {
771					name -= l;
772					memcpy(name,
773					       D(vfs, mount)->mnt_stat.f_mntonname, l);
774				}
775				break;
776			}
777		}
778		else if (UVM_OBJ_IS_DEVICE(D(uvm_obj, uvm_object))) {
779			struct kbit kdev;
780			dev_t dev;
781
782			P(&kdev) = P(uvm_obj);
783			S(&kdev) = sizeof(struct uvm_device);
784			KDEREF(kd, &kdev);
785			dev = D(&kdev, uvm_device)->u_device;
786			name = devname(dev, S_IFCHR);
787			if (name != NULL)
788				snprintf(buf, sizeof(buf), "/dev/%s", name);
789			else
790				snprintf(buf, sizeof(buf), "  [ device %d,%d ]",
791					 major(dev), minor(dev));
792			name = buf;
793		}
794		else if (UVM_OBJ_IS_AOBJ(D(uvm_obj, uvm_object)))
795			name = "  [ uvm_aobj ]";
796#if 0
797		else if (UVM_OBJ_IS_UBCPAGER(D(uvm_obj, uvm_object)))
798			name = "  [ ubc_pager ]";
799#endif
800		else if (UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object)))
801			name = "  [ ?VNODE? ]";
802		else {
803			snprintf(buf, sizeof(buf), "  [ ?? %p ?? ]",
804				 D(uvm_obj, uvm_object)->pgops);
805			name = buf;
806		}
807	}
808
809	else if (D(vmspace, vmspace)->vm_maxsaddr <=
810		 (caddr_t)vme->start &&
811		 (D(vmspace, vmspace)->vm_maxsaddr + (size_t)maxssiz) >=
812		 (caddr_t)vme->end)
813		name = "  [ stack ]";
814
815	else if ((vme->protection & rwx) == rwx && !heapfound) {
816		/* XXX this could probably be done better */
817		heapfound = 1;
818		name = "  [ heap ]";
819	}
820
821	else
822		name = "  [ anon ]";
823
824	return (name);
825}
826
827int
828search_cache(kvm_t *kd, struct kbit *vp, char **name, char *buf, size_t blen)
829{
830	char *o, *e;
831	struct cache_entry *ce;
832	struct kbit svp;
833	u_long cid;
834
835	if (nchashtbl == NULL)
836		load_name_cache(kd);
837
838	P(&svp) = P(vp);
839	S(&svp) = sizeof(struct vnode);
840	cid = D(vp, vnode)->v_id;
841
842	e = &buf[blen - 1];
843	o = e;
844	do {
845		LIST_FOREACH(ce, &lcache, ce_next)
846			if (ce->ce_vp == P(&svp) && ce->ce_cid == cid)
847				break;
848		if (ce && ce->ce_vp == P(&svp) && ce->ce_cid == cid) {
849			if (o != e)
850				*(--o) = '/';
851			o -= ce->ce_nlen;
852			memcpy(o, ce->ce_name, (unsigned)ce->ce_nlen);
853			P(&svp) = ce->ce_pvp;
854			cid = ce->ce_pcid;
855		}
856		else
857			break;
858	} while (1/*CONSTCOND*/);
859	*e = '\0';
860	*name = o;
861
862	if (e == o)
863		return (2);
864
865	KDEREF(kd, &svp);
866	return (D(&svp, vnode)->v_flag & VROOT);
867}
868
869void
870load_name_cache(kvm_t *kd)
871{
872	struct namecache _ncp, *ncp, *oncp;
873	struct nchashhead _ncpp, *ncpp;
874	u_long nchash;
875	int i;
876
877	LIST_INIT(&lcache);
878
879	_KDEREF(kd, nchash_addr, &nchash, sizeof(nchash));
880	nchashtbl = malloc(sizeof(nchashtbl) * (int)nchash);
881	_KDEREF(kd, nchashtbl_addr, nchashtbl,
882		sizeof(nchashtbl) * (int)nchash);
883
884	ncpp = &_ncpp;
885
886	for (i = 0; i <= nchash; i++) {
887		ncpp = &nchashtbl[i];
888		oncp = NULL;
889		LIST_FOREACH(ncp, ncpp, nc_hash) {
890			if (ncp == oncp ||
891			    (void*)ncp < kernel_floor ||
892			    ncp == (void*)0xdeadbeef)
893				break;
894			oncp = ncp;
895			_KDEREF(kd, (u_long)ncp, &_ncp, sizeof(*ncp));
896			ncp = &_ncp;
897			if ((void*)ncp->nc_vp > kernel_floor &&
898			    ncp->nc_nlen > 0) {
899				if (ncp->nc_nlen > 2 ||
900				    ncp->nc_name[0] != '.' ||
901				    (ncp->nc_name[1] != '.' &&
902				     ncp->nc_nlen != 1))
903					cache_enter(ncp);
904			}
905		}
906	}
907}
908
909void
910cache_enter(struct namecache *ncp)
911{
912	struct cache_entry *ce;
913
914	if (debug & DUMP_NAMEI_CACHE)
915		printf("ncp->nc_vp %10p, ncp->nc_dvp %10p, ncp->nc_nlen "
916		       "%3d [%.*s] (nc_dvpid=%lu, nc_vpid=%lu)\n",
917		       ncp->nc_vp, ncp->nc_dvp,
918		       ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name,
919		       ncp->nc_dvpid, ncp->nc_vpid);
920
921	ce = malloc(sizeof(struct cache_entry));
922
923	ce->ce_vp = ncp->nc_vp;
924	ce->ce_pvp = ncp->nc_dvp;
925	ce->ce_cid = ncp->nc_vpid;
926	ce->ce_pcid = ncp->nc_dvpid;
927	ce->ce_nlen = ncp->nc_nlen;
928	strncpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name));
929	ce->ce_name[MIN(ce->ce_nlen, sizeof(ce->ce_name) - 1)] = '\0';
930
931	LIST_INSERT_HEAD(&lcache, ce, ce_next);
932}
933