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