diff options
Diffstat (limited to 'usr.sbin/procmap/procmap.c')
| -rw-r--r-- | usr.sbin/procmap/procmap.c | 931 |
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); +} |
