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