summaryrefslogtreecommitdiff
path: root/usr.sbin/procmap/procmap.c
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2004-02-16 08:54:35 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2004-02-16 08:54:35 +0000
commit94a57b7e2666c361b0315791be5e8906e0ae4d47 (patch)
treec155bd963228e47f2985dcbfc2f31eabeb77dee0 /usr.sbin/procmap/procmap.c
parent43c231ad54f7e602c698f73720b108be8f1b6395 (diff)
rough cut of netbsd's pmap process memory map inspector.
initially from drahn@, renamed to procmap to avoid conflict with unrelated pmap(9). works more or less as advertised, could definitely use some work though. would be really nice if somebody made it use sysctl and not kmem. more or less ok deraadt@ drahn@
Diffstat (limited to 'usr.sbin/procmap/procmap.c')
-rw-r--r--usr.sbin/procmap/procmap.c931
1 files changed, 931 insertions, 0 deletions
diff --git a/usr.sbin/procmap/procmap.c b/usr.sbin/procmap/procmap.c
new file mode 100644
index 00000000000..7eefc118fc4
--- /dev/null
+++ b/usr.sbin/procmap/procmap.c
@@ -0,0 +1,931 @@
+/* $OpenBSD: procmap.c,v 1.1 2004/02/16 08:54:34 tedu Exp $ */
+/* $NetBSD: pmap.c,v 1.1 2002/09/01 20:32:44 atatat Exp $ */
+
+/*
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/exec.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <sys/namei.h>
+#include <sys/sysctl.h>
+
+#include <uvm/uvm.h>
+#include <uvm/uvm_device.h>
+
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#undef doff_t
+#undef IN_ACCESS
+#undef i_size
+#undef i_devvp
+#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/cd9660_node.h>
+
+#include <kvm.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+/*
+ * stolen (and munged) from #include <uvm/uvm_object.h>
+ */
+#define UVM_OBJ_IS_VNODE(uobj) ((uobj)->pgops == uvm_vnodeops)
+#define UVM_OBJ_IS_AOBJ(uobj) ((uobj)->pgops == aobj_pager)
+#define UVM_OBJ_IS_DEVICE(uobj) ((uobj)->pgops == uvm_deviceops)
+#if 0
+#define UVM_OBJ_IS_UBCPAGER(uobj) ((uobj)->pgops == ubc_pager)
+#endif
+
+#define PRINT_VMSPACE 0x00000001
+#define PRINT_VM_MAP 0x00000002
+#define PRINT_VM_MAP_HEADER 0x00000004
+#define PRINT_VM_MAP_ENTRY 0x00000008
+#define DUMP_NAMEI_CACHE 0x00000010
+
+struct cache_entry {
+ LIST_ENTRY(cache_entry) ce_next;
+ struct vnode *ce_vp, *ce_pvp;
+ u_long ce_cid, ce_pcid;
+ int ce_nlen;
+ char ce_name[256];
+};
+
+LIST_HEAD(cache_head, cache_entry) lcache;
+LIST_HEAD(nchashhead, namecache) *nchashtbl = NULL;
+void *uvm_vnodeops, *uvm_deviceops, *aobj_pager;
+#if 0
+void *ubc_pager;
+#endif
+void *kernel_floor;
+u_long nchash_addr, nchashtbl_addr, kernel_map_addr;
+int debug, verbose;
+int print_all, print_map, print_maps, print_solaris, print_ddb;
+int rwx = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, heapfound;
+rlim_t maxssiz;
+
+struct kbit {
+ /*
+ * size of data chunk
+ */
+ size_t k_size;
+
+ /*
+ * something for printf() and something for kvm_read()
+ */
+ union {
+ void *k_addr_p;
+ u_long k_addr_ul;
+ } k_addr;
+
+ /*
+ * where we actually put the "stuff"
+ */
+ union {
+ char data[1];
+ struct vmspace vmspace;
+ struct vm_map vm_map;
+ struct vm_map_entry vm_map_entry;
+ struct vnode vnode;
+ struct uvm_object uvm_object;
+ struct mount mount;
+ struct namecache namecache;
+ struct inode inode;
+ struct iso_node iso_node;
+ struct uvm_device uvm_device;
+ } k_data;
+};
+
+/* the size of the object in the kernel */
+#define S(x) ((x)->k_size)
+/* the address of the object in kernel, two forms */
+#define A(x) ((x)->k_addr.k_addr_ul)
+#define P(x) ((x)->k_addr.k_addr_p)
+/* the data from the kernel */
+#define D(x,d) (&((x)->k_data.d))
+
+/* suck the data from the kernel */
+#define _KDEREF(kd, addr, dst, sz) do { \
+ ssize_t len; \
+ len = kvm_read((kd), (addr), (dst), (sz)); \
+ if (len != (sz)) \
+ errx(1, "%s == %ld vs. %lu @ %lx", \
+ kvm_geterr(kd), (long)len, (unsigned long)(sz), (addr)); \
+} while (0/*CONSTCOND*/)
+
+/* suck the data using the structure */
+#define KDEREF(kd, item) _KDEREF((kd), A(item), D(item, data), S(item))
+
+struct nlist nl[] = {
+ { "_maxsmap" },
+#define NL_MAXSSIZ 0
+ { "_uvm_vnodeops" },
+#define NL_UVM_VNODEOPS 1
+ { "_uvm_deviceops" },
+#define NL_UVM_DEVICEOPS 2
+ { "_aobj_pager" },
+#define NL_AOBJ_PAGER 3
+ { "_kernel_map" },
+#define NL_KERNEL_MAP 4
+ { "_nchashtbl" },
+#define NL_NCHASHTBL 5
+ { "_nchash" },
+#define NL_NCHASH 6
+ { "_kernel_text" },
+#define NL_KENTER 7
+#if 0
+ { "_ubc_pager" },
+#define NL_UBC_PAGER 8
+#endif
+ { NULL }
+};
+
+void load_symbols(kvm_t *);
+void process_map(kvm_t *, pid_t, struct kinfo_proc *);
+size_t dump_vm_map_entry(kvm_t *, struct kbit *, struct kbit *, int);
+char *findname(kvm_t *, struct kbit *, struct kbit *, struct kbit *,
+ struct kbit *, struct kbit *);
+int search_cache(kvm_t *, struct kbit *, char **, char *, size_t);
+void load_name_cache(kvm_t *);
+void cache_enter(struct namecache *);
+
+int
+main(int argc, char *argv[])
+{
+ kvm_t *kd;
+ pid_t pid;
+ int many, ch, rc;
+ char errbuf[_POSIX2_LINE_MAX + 1];
+ /* u_long addr, next; */
+ struct kinfo_proc *kproc;
+ /* struct proc proc; */
+ char *kmem, *kernel;
+ extern char *__progname;
+
+ pid = -1;
+ verbose = debug = 0;
+ print_all = print_map = print_maps = print_solaris = print_ddb = 0;
+ kmem = kernel = NULL;
+
+ while ((ch = getopt(argc, argv, "aD:dlmM:N:p:Prsvx")) != -1) {
+ switch (ch) {
+ case 'a':
+ print_all = 1;
+ break;
+ case 'd':
+ print_ddb = 1;
+ break;
+ case 'D':
+ debug = atoi(optarg);
+ break;
+ case 'l':
+ print_maps = 1;
+ break;
+ case 'm':
+ print_map = 1;
+ break;
+ case 'M':
+ kmem = optarg;
+ break;
+ case 'N':
+ kernel = optarg;
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'P':
+ pid = getpid();
+ break;
+ case 's':
+ print_solaris = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'r':
+ case 'x':
+ errx(1, "-%c option not implemented, sorry", optopt);
+ /*NOTREACHED*/
+ case '?':
+ default:
+ fprintf(stderr, "usage: %s [-adlmPsv] [-D number] "
+ "[-M core] [-N system] [-p pid] [pid ...]\n",
+ __progname);
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* more than one "process" to dump? */
+ many = (argc > 1 - (pid == -1 ? 0 : 1)) ? 1 : 0;
+
+ /* apply default */
+ if (print_all + print_map + print_maps + print_solaris +
+ print_ddb == 0)
+ print_solaris = 1;
+
+ /* start by opening libkvm */
+ kd = kvm_openfiles(kernel, kmem, NULL, O_RDONLY, errbuf);
+ errbuf[_POSIX2_LINE_MAX] = '\0';
+ if (kd == NULL)
+ errx(1, "%s", errbuf);
+
+ /* get "bootstrap" addresses from kernel */
+ load_symbols(kd);
+
+ do {
+ if (pid == -1) {
+ if (argc == 0)
+ pid = getppid();
+ else {
+ pid = atoi(argv[0]);
+ argv++;
+ argc--;
+ }
+ }
+
+ /* find the process id */
+ if (pid == 0)
+ kproc = NULL;
+ else {
+ kproc = kvm_getprocs(kd, KERN_PROC_PID, pid, &rc);
+ if (kproc == NULL || rc == 0) {
+ errno = ESRCH;
+ warn("%d", pid);
+ pid = -1;
+ continue;
+ }
+ }
+
+ /* dump it */
+ if (many) {
+ if (kproc)
+ printf("process %d:\n", pid);
+ else
+ printf("kernel:\n");
+ }
+
+ process_map(kd, pid, kproc);
+ pid = -1;
+ } while (argc > 0);
+
+ /* done. go away. */
+ rc = kvm_close(kd);
+ if (rc == -1)
+ err(1, "kvm_close");
+
+ return (0);
+}
+
+void
+process_map(kvm_t *kd, pid_t pid, struct kinfo_proc *proc)
+{
+ struct kbit kbit[4];
+ struct kbit *vmspace, *vm_map, *header, *vm_map_entry;
+ struct vm_map_entry *last;
+ size_t total;
+ u_long addr, next;
+ char *thing;
+
+ vmspace = &kbit[0];
+ vm_map = &kbit[1];
+ header = &kbit[2];
+ vm_map_entry = &kbit[3];
+
+ A(vmspace) = 0;
+ A(vm_map) = 0;
+ A(header) = 0;
+ A(vm_map_entry) = 0;
+
+ if (pid > 0) {
+ heapfound = 0;
+ A(vmspace) = (u_long)proc->kp_proc.p_vmspace;
+ S(vmspace) = sizeof(struct vmspace);
+ KDEREF(kd, vmspace);
+ thing = "proc->p_vmspace.vm_map";
+ } else {
+ heapfound = 1; /* but really, do kernels have a heap? */
+ A(vmspace) = 0;
+ S(vmspace) = 0;
+ thing = "kernel_map";
+ }
+
+ if (pid > 0 && (debug & PRINT_VMSPACE)) {
+ printf("proc->p_vmspace %p = {", P(vmspace));
+ printf(" vm_refcnt = %d,", D(vmspace, vmspace)->vm_refcnt);
+ printf(" vm_shm = %p,\n", D(vmspace, vmspace)->vm_shm);
+ printf(" vm_rssize = %d,", D(vmspace, vmspace)->vm_rssize);
+ printf(" vm_swrss = %d,", D(vmspace, vmspace)->vm_swrss);
+ printf(" vm_tsize = %d,", D(vmspace, vmspace)->vm_tsize);
+ printf(" vm_dsize = %d,\n", D(vmspace, vmspace)->vm_dsize);
+ printf(" vm_ssize = %d,", D(vmspace, vmspace)->vm_ssize);
+ printf(" vm_taddr = %p,", D(vmspace, vmspace)->vm_taddr);
+ printf(" vm_daddr = %p,\n", D(vmspace, vmspace)->vm_daddr);
+ printf(" vm_maxsaddr = %p,",
+ D(vmspace, vmspace)->vm_maxsaddr);
+ printf(" vm_minsaddr = %p }\n",
+ D(vmspace, vmspace)->vm_minsaddr);
+ }
+
+ S(vm_map) = sizeof(struct vm_map);
+ if (pid > 0) {
+ A(vm_map) = A(vmspace);
+ memcpy(D(vm_map, vm_map), &D(vmspace, vmspace)->vm_map,
+ S(vm_map));
+ } else {
+ A(vm_map) = kernel_map_addr;
+ KDEREF(kd, vm_map);
+ }
+ if (debug & PRINT_VM_MAP) {
+ printf("%s %p = {", thing, P(vm_map));
+
+ printf(" pmap = %p,\n", D(vm_map, vm_map)->pmap);
+ printf(" lock = <struct lock>,");
+ printf(" header = <struct vm_map_entry>,");
+ printf(" nentries = %d,\n", D(vm_map, vm_map)->nentries);
+ printf(" size = %lx,", D(vm_map, vm_map)->size);
+ printf(" ref_count = %d,", D(vm_map, vm_map)->ref_count);
+ printf(" ref_lock = <struct simplelock>,\n");
+ printf(" hint = %p,", D(vm_map, vm_map)->hint);
+ printf(" hint_lock = <struct simplelock>,\n");
+ printf(" first_free = %p,", D(vm_map, vm_map)->first_free);
+ printf(" flags = %x <%s%s%s%s%s%s >,\n", D(vm_map, vm_map)->flags,
+ D(vm_map, vm_map)->flags & VM_MAP_PAGEABLE ? " PAGEABLE" : "",
+ D(vm_map, vm_map)->flags & VM_MAP_INTRSAFE ? " INTRSAFE" : "",
+ D(vm_map, vm_map)->flags & VM_MAP_WIREFUTURE ? " WIREFUTURE" : "",
+ D(vm_map, vm_map)->flags & VM_MAP_BUSY ? " BUSY" : "",
+ D(vm_map, vm_map)->flags & VM_MAP_WANTLOCK ? " WANTLOCK" : "",
+#if VM_MAP_TOPDOWN > 0
+ D(vm_map, vm_map)->flags & VM_MAP_TOPDOWN ? " TOPDOWN" :
+#endif
+ "");
+ printf(" flags_lock = <struct simplelock>,");
+ printf(" timestamp = %u }\n", D(vm_map, vm_map)->timestamp);
+ }
+ if (print_ddb) {
+ printf("MAP %p: [0x%lx->0x%lx]\n", P(vm_map),
+ D(vm_map, vm_map)->min_offset, D(vm_map, vm_map)->max_offset);
+ printf("\t#ent=%d, sz=%ld, ref=%d, version=%d, flags=0x%x\n",
+ D(vm_map, vm_map)->nentries, D(vm_map, vm_map)->size,
+ D(vm_map, vm_map)->ref_count, D(vm_map, vm_map)->timestamp,
+ D(vm_map, vm_map)->flags);
+ printf("\tpmap=%p(resident=<unknown>)\n", D(vm_map, vm_map)->pmap);
+ }
+
+ A(header) = A(vm_map) + offsetof(struct vm_map, header);
+ S(header) = sizeof(struct vm_map_entry);
+ memcpy(D(header, vm_map_entry), &D(vm_map, vm_map)->header, S(header));
+ dump_vm_map_entry(kd, vmspace, header, 1);
+
+ /* headers */
+#ifdef DISABLED_HEADERS
+ if (print_map)
+ printf("%-*s %-*s rwx RWX CPY NCP I W A\n",
+ (int)sizeof(long) * 2 + 2, "Start",
+ (int)sizeof(long) * 2 + 2, "End");
+ if (print_maps)
+ printf("%-*s %-*s rwxp %-*s Dev Inode File\n",
+ (int)sizeof(long) * 2 + 0, "Start",
+ (int)sizeof(long) * 2 + 0, "End",
+ (int)sizeof(long) * 2 + 0, "Offset");
+ if (print_solaris)
+ printf("%-*s %*s Protection File\n",
+ (int)sizeof(long) * 2 + 0, "Start",
+ (int)sizeof(int) * 2 - 1, "Size ");
+#endif
+ if (print_all)
+ printf("%-*s %-*s %*s %-*s rwxpc RWX I/W/A Dev %*s - File\n",
+ (int)sizeof(long) * 2, "Start",
+ (int)sizeof(long) * 2, "End",
+ (int)sizeof(int) * 2, "Size ",
+ (int)sizeof(long) * 2, "Offset",
+ (int)sizeof(int) * 2, "Inode");
+
+ /* these are the "sub entries" */
+ total = 0;
+ next = (u_long)D(header, vm_map_entry)->next;
+ D(vm_map_entry, vm_map_entry)->next =
+ D(header, vm_map_entry)->next + 1;
+ last = P(header);
+
+ while (next != 0 && D(vm_map_entry, vm_map_entry)->next != last) {
+ addr = next;
+ A(vm_map_entry) = addr;
+ S(vm_map_entry) = sizeof(struct vm_map_entry);
+ KDEREF(kd, vm_map_entry);
+ total += dump_vm_map_entry(kd, vmspace, vm_map_entry, 0);
+ next = (u_long)D(vm_map_entry, vm_map_entry)->next;
+ }
+ if (print_solaris)
+ printf("%-*s %8luK\n",
+ (int)sizeof(void *) * 2 - 2, " total",
+ (unsigned long)total);
+ if (print_all)
+ printf("%-*s %9luk\n",
+ (int)sizeof(void *) * 4 - 1, " total",
+ (unsigned long)total);
+}
+
+void
+load_symbols(kvm_t *kd)
+{
+ int rc;
+ int i;
+
+ rc = kvm_nlist(kd, &nl[0]);
+ if (rc == -1)
+ errx(1, "%s == %d", kvm_geterr(kd), rc);
+ for (i = 0; i < sizeof(nl)/sizeof(nl[0]); i++)
+ if (nl[i].n_value == 0)
+ printf("%s\n", nl[i].n_name);
+
+ uvm_vnodeops = (void*)nl[NL_UVM_VNODEOPS].n_value;
+ uvm_deviceops = (void*)nl[NL_UVM_DEVICEOPS].n_value;
+ aobj_pager = (void*)nl[NL_AOBJ_PAGER].n_value;
+#if 0
+ ubc_pager = (void*)nl[NL_UBC_PAGER].n_value;
+#endif
+
+ kernel_floor = (void*)nl[NL_KENTER].n_value;
+ nchash_addr = nl[NL_NCHASH].n_value;
+
+ _KDEREF(kd, nl[NL_MAXSSIZ].n_value, &maxssiz,
+ sizeof(maxssiz));
+ _KDEREF(kd, nl[NL_NCHASHTBL].n_value, &nchashtbl_addr,
+ sizeof(nchashtbl_addr));
+ _KDEREF(kd, nl[NL_KERNEL_MAP].n_value, &kernel_map_addr,
+ sizeof(kernel_map_addr));
+}
+
+size_t
+dump_vm_map_entry(kvm_t *kd, struct kbit *vmspace,
+ struct kbit *vm_map_entry,
+ int ishead)
+{
+ struct kbit kbit[3];
+ struct kbit *uvm_obj, *vp, *vfs;
+ struct vm_map_entry *vme;
+ size_t sz;
+ char *name;
+ dev_t dev;
+ ino_t inode;
+
+ uvm_obj = &kbit[0];
+ vp = &kbit[1];
+ vfs = &kbit[2];
+
+ A(uvm_obj) = 0;
+ A(vp) = 0;
+ A(vfs) = 0;
+
+ vme = D(vm_map_entry, vm_map_entry);
+
+ if ((ishead && (debug & PRINT_VM_MAP_HEADER)) ||
+ (!ishead && (debug & PRINT_VM_MAP_ENTRY))) {
+ printf("%s %p = {", ishead ? "vm_map.header" : "vm_map_entry",
+ P(vm_map_entry));
+ printf(" prev = %p,", vme->prev);
+ printf(" next = %p,\n", vme->next);
+ printf(" start = %lx,", vme->start);
+ printf(" end = %lx,", vme->end);
+ printf(" object.uvm_obj/sub_map = %p,\n", vme->object.uvm_obj);
+ printf(" offset = %lx,", (unsigned long)vme->offset);
+ printf(" etype = %x <%s%s%s%s >,", vme->etype,
+ vme->etype & UVM_ET_OBJ ? " OBJ" : "",
+ vme->etype & UVM_ET_SUBMAP ? " SUBMAP" : "",
+ vme->etype & UVM_ET_COPYONWRITE ? " COW" : "",
+ vme->etype & UVM_ET_NEEDSCOPY ? " NEEDSCOPY" : "");
+ printf(" protection = %x,\n", vme->protection);
+ printf(" max_protection = %x,", vme->max_protection);
+ printf(" inheritance = %d,", vme->inheritance);
+ printf(" wired_count = %d,\n", vme->wired_count);
+ printf(" aref = <struct vm_aref>,");
+ printf(" advice = %d,", vme->advice);
+ printf(" flags = %x <%s%s > }\n", vme->flags,
+ vme->flags & UVM_MAP_STATIC ? " STATIC" : "",
+ vme->flags & UVM_MAP_KMEM ? " KMEM" : "");
+ }
+
+ if (ishead)
+ return (0);
+
+ A(vp) = 0;
+ A(uvm_obj) = 0;
+
+ if (vme->object.uvm_obj != NULL) {
+ P(uvm_obj) = vme->object.uvm_obj;
+ S(uvm_obj) = sizeof(struct uvm_object);
+ KDEREF(kd, uvm_obj);
+ if (UVM_ET_ISOBJ(vme) &&
+ UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object))) {
+ P(vp) = P(uvm_obj);
+ S(vp) = sizeof(struct vnode);
+ KDEREF(kd, vp);
+ }
+ }
+
+ A(vfs) = NULL;
+
+ if (P(vp) != NULL && D(vp, vnode)->v_mount != NULL) {
+ P(vfs) = D(vp, vnode)->v_mount;
+ S(vfs) = sizeof(struct mount);
+ KDEREF(kd, vfs);
+ D(vp, vnode)->v_mount = D(vfs, mount);
+ }
+
+ /*
+ * dig out the device number and inode number from certain
+ * file system types.
+ */
+#define V_DATA_IS(vp, type, d, i) do { \
+ struct kbit data; \
+ P(&data) = D(vp, vnode)->v_data; \
+ S(&data) = sizeof(*D(&data, type)); \
+ KDEREF(kd, &data); \
+ dev = D(&data, type)->d; \
+ inode = D(&data, type)->i; \
+} while (0/*CONSTCOND*/)
+
+ dev = 0;
+ inode = 0;
+
+ if (A(vp) &&
+ D(vp, vnode)->v_type == VREG &&
+ D(vp, vnode)->v_data != NULL) {
+ switch (D(vp, vnode)->v_tag) {
+ case VT_UFS:
+ case VT_LFS:
+ case VT_EXT2FS:
+ V_DATA_IS(vp, inode, i_dev, i_number);
+ break;
+ case VT_ISOFS:
+ V_DATA_IS(vp, iso_node, i_dev, i_number);
+ break;
+ case VT_NON:
+ case VT_NFS:
+ case VT_MFS:
+ case VT_MSDOSFS:
+ case VT_LOFS:
+ case VT_FDESC:
+ case VT_PORTAL:
+ case VT_NULL:
+ case VT_UMAP:
+ case VT_KERNFS:
+ case VT_PROCFS:
+ case VT_AFS:
+ case VT_UNION:
+ case VT_ADOSFS:
+ break;
+ }
+ }
+
+ name = findname(kd, vmspace, vm_map_entry, vp, vfs, uvm_obj);
+
+ if (print_map) {
+ printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d",
+ vme->start, vme->end,
+ (vme->protection & VM_PROT_READ) ? 'r' : '-',
+ (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
+ (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ (vme->max_protection & VM_PROT_READ) ? 'r' : '-',
+ (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-',
+ (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ (vme->etype & UVM_ET_COPYONWRITE) ? "COW" : "NCOW",
+ (vme->etype & UVM_ET_NEEDSCOPY) ? "NC" : "NNC",
+ vme->inheritance, vme->wired_count,
+ vme->advice);
+ if (verbose) {
+ if (inode)
+ printf(" %d,%d %d",
+ major(dev), minor(dev), inode);
+ if (name[0])
+ printf(" %s", name);
+ }
+ printf("\n");
+ }
+
+ if (print_maps)
+ printf("%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %d %s\n",
+ (int)sizeof(void *) * 2, vme->start,
+ (int)sizeof(void *) * 2, vme->end,
+ (vme->protection & VM_PROT_READ) ? 'r' : '-',
+ (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
+ (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
+ (int)sizeof(void *) * 2,
+ (unsigned long)vme->offset,
+ major(dev), minor(dev), inode, inode ? name : "");
+
+ if (print_ddb) {
+ printf(" - %p: 0x%lx->0x%lx: obj=%p/0x%lx, amap=%p/%d\n",
+ P(vm_map_entry), vme->start, vme->end,
+ vme->object.uvm_obj, (unsigned long)vme->offset,
+ vme->aref.ar_amap, vme->aref.ar_pageoff);
+ printf("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, "
+ "wc=%d, adv=%d\n",
+ (vme->etype & UVM_ET_SUBMAP) ? 'T' : 'F',
+ (vme->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F',
+ (vme->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F',
+ vme->protection, vme->max_protection,
+ vme->inheritance, vme->wired_count, vme->advice);
+ if (inode && verbose)
+ printf("\t(dev=%d,%d ino=%d [%s] [%p])\n",
+ major(dev), minor(dev), inode,
+ inode ? name : "", P(vp));
+ else if (name[0] == ' ' && verbose)
+ printf("\t(%s)\n", &name[2]);
+ }
+
+ sz = 0;
+ if (print_solaris) {
+ char prot[30];
+
+ prot[0] = '\0';
+ prot[1] = '\0';
+ if (vme->protection & VM_PROT_READ)
+ strcat(prot, "/read");
+ if (vme->protection & VM_PROT_WRITE)
+ strcat(prot, "/write");
+ if (vme->protection & VM_PROT_EXECUTE)
+ strcat(prot, "/exec");
+
+ sz = (size_t)((vme->end - vme->start) / 1024);
+ printf("%0*lX %6luK %-15s %s\n",
+ (int)sizeof(void *) * 2,
+ (unsigned long)vme->start,
+ (unsigned long)sz,
+ &prot[1],
+ name);
+ }
+
+ if (print_all) {
+ sz = (size_t)((vme->end - vme->start) / 1024);
+ printf(A(vp) ?
+ "%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7d - %s [%p]\n" :
+ "%0*lx-%0*lx %7luk %0*lx %c%c%c%c%c (%c%c%c) %d/%d/%d %02d:%02d %7d - %s\n",
+ (int)sizeof(void *) * 2,
+ vme->start,
+ (int)sizeof(void *) * 2,
+ vme->end - (vme->start != vme->end ? 1 : 0),
+ (unsigned long)sz,
+ (int)sizeof(void *) * 2,
+ (unsigned long)vme->offset,
+ (vme->protection & VM_PROT_READ) ? 'r' : '-',
+ (vme->protection & VM_PROT_WRITE) ? 'w' : '-',
+ (vme->protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ (vme->etype & UVM_ET_COPYONWRITE) ? 'p' : 's',
+ (vme->etype & UVM_ET_NEEDSCOPY) ? '+' : '-',
+ (vme->max_protection & VM_PROT_READ) ? 'r' : '-',
+ (vme->max_protection & VM_PROT_WRITE) ? 'w' : '-',
+ (vme->max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
+ vme->inheritance,
+ vme->wired_count,
+ vme->advice,
+ major(dev), minor(dev), inode,
+ name, P(vp));
+ }
+
+ /* no access allowed, don't count space */
+ if ((vme->protection & rwx) == 0)
+ sz = 0;
+
+ return (sz);
+}
+
+char*
+findname(kvm_t *kd, struct kbit *vmspace,
+ struct kbit *vm_map_entry, struct kbit *vp,
+ struct kbit *vfs, struct kbit *uvm_obj)
+{
+ static char buf[1024], *name;
+ struct vm_map_entry *vme;
+ size_t l;
+
+ vme = D(vm_map_entry, vm_map_entry);
+
+ if (UVM_ET_ISOBJ(vme)) {
+ if (A(vfs)) {
+ l = (unsigned)strlen(D(vfs, mount)->mnt_stat.f_mntonname);
+ switch (search_cache(kd, vp, &name, buf, sizeof(buf))) {
+ case 0: /* found something */
+ name--;
+ *name = '/';
+ /*FALLTHROUGH*/
+ case 2: /* found nothing */
+ name -= 6;
+ memcpy(name, " -??- ", (size_t)6);
+ name -= l;
+ memcpy(name,
+ D(vfs, mount)->mnt_stat.f_mntonname, l);
+ break;
+ case 1: /* all is well */
+ name--;
+ *name = '/';
+ if (l != 1) {
+ name -= l;
+ memcpy(name,
+ D(vfs, mount)->mnt_stat.f_mntonname, l);
+ }
+ break;
+ }
+ }
+ else if (UVM_OBJ_IS_DEVICE(D(uvm_obj, uvm_object))) {
+ struct kbit kdev;
+ dev_t dev;
+
+ P(&kdev) = P(uvm_obj);
+ S(&kdev) = sizeof(struct uvm_device);
+ KDEREF(kd, &kdev);
+ dev = D(&kdev, uvm_device)->u_device;
+ name = devname(dev, S_IFCHR);
+ if (name != NULL)
+ snprintf(buf, sizeof(buf), "/dev/%s", name);
+ else
+ snprintf(buf, sizeof(buf), " [ device %d,%d ]",
+ major(dev), minor(dev));
+ name = buf;
+ }
+ else if (UVM_OBJ_IS_AOBJ(D(uvm_obj, uvm_object)))
+ name = " [ uvm_aobj ]";
+#if 0
+ else if (UVM_OBJ_IS_UBCPAGER(D(uvm_obj, uvm_object)))
+ name = " [ ubc_pager ]";
+#endif
+ else if (UVM_OBJ_IS_VNODE(D(uvm_obj, uvm_object)))
+ name = " [ ?VNODE? ]";
+ else {
+ snprintf(buf, sizeof(buf), " [ ?? %p ?? ]",
+ D(uvm_obj, uvm_object)->pgops);
+ name = buf;
+ }
+ }
+
+ else if (D(vmspace, vmspace)->vm_maxsaddr <=
+ (caddr_t)vme->start &&
+ (D(vmspace, vmspace)->vm_maxsaddr + (size_t)maxssiz) >=
+ (caddr_t)vme->end)
+ name = " [ stack ]";
+
+ else if ((vme->protection & rwx) == rwx && !heapfound) {
+ /* XXX this could probably be done better */
+ heapfound = 1;
+ name = " [ heap ]";
+ }
+
+ else
+ name = " [ anon ]";
+
+ return (name);
+}
+
+int
+search_cache(kvm_t *kd, struct kbit *vp, char **name, char *buf, size_t blen)
+{
+ char *o, *e;
+ struct cache_entry *ce;
+ struct kbit svp;
+ u_long cid;
+
+ if (nchashtbl == NULL)
+ load_name_cache(kd);
+
+ P(&svp) = P(vp);
+ S(&svp) = sizeof(struct vnode);
+ cid = D(vp, vnode)->v_id;
+
+ e = &buf[blen - 1];
+ o = e;
+ do {
+ LIST_FOREACH(ce, &lcache, ce_next)
+ if (ce->ce_vp == P(&svp) && ce->ce_cid == cid)
+ break;
+ if (ce && ce->ce_vp == P(&svp) && ce->ce_cid == cid) {
+ if (o != e)
+ *(--o) = '/';
+ o -= ce->ce_nlen;
+ memcpy(o, ce->ce_name, (unsigned)ce->ce_nlen);
+ P(&svp) = ce->ce_pvp;
+ cid = ce->ce_pcid;
+ }
+ else
+ break;
+ } while (1/*CONSTCOND*/);
+ *e = '\0';
+ *name = o;
+
+ if (e == o)
+ return (2);
+
+ KDEREF(kd, &svp);
+ return (D(&svp, vnode)->v_flag & VROOT);
+}
+
+void
+load_name_cache(kvm_t *kd)
+{
+ struct namecache _ncp, *ncp, *oncp;
+ struct nchashhead _ncpp, *ncpp;
+ u_long nchash;
+ int i;
+
+ LIST_INIT(&lcache);
+
+ _KDEREF(kd, nchash_addr, &nchash, sizeof(nchash));
+ nchashtbl = malloc(sizeof(nchashtbl) * (int)nchash);
+ _KDEREF(kd, nchashtbl_addr, nchashtbl,
+ sizeof(nchashtbl) * (int)nchash);
+
+ ncpp = &_ncpp;
+
+ for (i = 0; i <= nchash; i++) {
+ ncpp = &nchashtbl[i];
+ oncp = NULL;
+ LIST_FOREACH(ncp, ncpp, nc_hash) {
+ if (ncp == oncp ||
+ (void*)ncp < kernel_floor ||
+ ncp == (void*)0xdeadbeef)
+ break;
+ oncp = ncp;
+ _KDEREF(kd, (u_long)ncp, &_ncp, sizeof(*ncp));
+ ncp = &_ncp;
+ if ((void*)ncp->nc_vp > kernel_floor &&
+ ncp->nc_nlen > 0) {
+ if (ncp->nc_nlen > 2 ||
+ ncp->nc_name[0] != '.' ||
+ (ncp->nc_name[1] != '.' &&
+ ncp->nc_nlen != 1))
+ cache_enter(ncp);
+ }
+ }
+ }
+}
+
+void
+cache_enter(struct namecache *ncp)
+{
+ struct cache_entry *ce;
+
+ if (debug & DUMP_NAMEI_CACHE)
+ printf("ncp->nc_vp %10p, ncp->nc_dvp %10p, ncp->nc_nlen "
+ "%3d [%.*s] (nc_dvpid=%lu, nc_vpid=%lu)\n",
+ ncp->nc_vp, ncp->nc_dvp,
+ ncp->nc_nlen, ncp->nc_nlen, ncp->nc_name,
+ ncp->nc_dvpid, ncp->nc_vpid);
+
+ ce = malloc(sizeof(struct cache_entry));
+
+ ce->ce_vp = ncp->nc_vp;
+ ce->ce_pvp = ncp->nc_dvp;
+ ce->ce_cid = ncp->nc_vpid;
+ ce->ce_pcid = ncp->nc_dvpid;
+ ce->ce_nlen = ncp->nc_nlen;
+ strncpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name));
+ ce->ce_name[MIN(ce->ce_nlen, sizeof(ce->ce_name) - 1)] = '\0';
+
+ LIST_INSERT_HEAD(&lcache, ce, ce_next);
+}