This re-introduces the vnode-to-filename mapping code with adaptions to the new namecache layout.
For example, running procmap -a 1 now prints the .text, .data, and .rodata segments of init(1) as below, if /sbin/init is in the name cache: 104ccb700000-104ccb73dfff 248k 00000 r-xp+ (rwx) 1/0/0 04:00 42 - /sbin/init [0xffffff043c977898] 104ccb83d000-104ccb847fff 44k 3d000 r--p+ (rwx) 1/0/0 04:00 42 - /sbin/init [0xffffff043c977898] 104ccbb48000-104ccbb48fff 4k 48000 rw-p+ (rwx) 1/0/0 04:00 42 - /sbin/init [0xffffff043c977898] ok? Index: usr.sbin/procmap/procmap.1 =================================================================== RCS file: /cvs/src/usr.sbin/procmap/procmap.1,v retrieving revision 1.20 diff -u -p -r1.20 procmap.1 --- usr.sbin/procmap/procmap.1 13 Mar 2015 19:58:41 -0000 1.20 +++ usr.sbin/procmap/procmap.1 26 May 2016 08:02:58 -0000 @@ -90,6 +90,8 @@ dump the process's vm_map structure dump the vm_map.header structure .It Cm 8 dump each vm_map_entry in its entirety +.It Cm 16 +dump the namei cache as it is traversed .El .It Fl d Dumps the vm_map and vm_map_entry structures in a style similar to Index: usr.sbin/procmap/procmap.c =================================================================== RCS file: /cvs/src/usr.sbin/procmap/procmap.c,v retrieving revision 1.61 diff -u -p -r1.61 procmap.c --- usr.sbin/procmap/procmap.c 25 May 2016 15:45:53 -0000 1.61 +++ usr.sbin/procmap/procmap.c 26 May 2016 08:02:58 -0000 @@ -38,6 +38,7 @@ #include <sys/vnode.h> #include <sys/mount.h> #include <sys/uio.h> +#include <sys/namei.h> #include <sys/sysctl.h> /* XXX until uvm gets cleaned up */ @@ -79,6 +80,7 @@ typedef int boolean_t; #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; @@ -89,8 +91,10 @@ struct cache_entry { }; LIST_HEAD(cache_head, cache_entry) lcache; +TAILQ_HEAD(namecache_head, namecache) nclruhead; +int namecache_loaded; void *uvm_vnodeops, *uvm_deviceops, *aobj_pager; -u_long kernel_map_addr; +u_long kernel_map_addr, nclruhead_addr; int debug, verbose; int print_all, print_map, print_maps, print_solaris, print_ddb, print_amap; int rwx = PROT_READ | PROT_WRITE | PROT_EXEC; @@ -165,6 +169,8 @@ struct nlist nl[] = { #define NL_AOBJ_PAGER 3 { "_kernel_map" }, #define NL_KERNEL_MAP 4 + { "_nclruhead" }, +#define NL_NCLRUHEAD 5 { NULL } }; @@ -178,6 +184,8 @@ size_t dump_vm_map_entry(kvm_t *, struct char *findname(kvm_t *, struct kbit *, struct vm_map_entry *, 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 *); static void __dead usage(void); static pid_t strtopid(const char *); void print_sum(struct sum *, struct sum *); @@ -219,7 +227,7 @@ main(int argc, char *argv[]) print_ddb = 1; break; case 'D': - debug = strtonum(optarg, 0, 0xf, &errstr); + debug = strtonum(optarg, 0, 0x1f, &errstr); if (errstr) errx(1, "invalid debug mask"); break; @@ -524,6 +532,8 @@ load_symbols(kvm_t *kd) uvm_deviceops = (void*)nl[NL_UVM_DEVICEOPS].n_value; aobj_pager = (void*)nl[NL_AOBJ_PAGER].n_value; + nclruhead_addr = nl[NL_NCLRUHEAD].n_value; + _KDEREF(kd, nl[NL_MAXSSIZ].n_value, &maxssiz, sizeof(maxssiz)); _KDEREF(kd, nl[NL_KERNEL_MAP].n_value, &kernel_map_addr, @@ -889,6 +899,9 @@ search_cache(kvm_t *kd, struct kbit *vp, char *o, *e; u_long cid; + if (!namecache_loaded) + load_name_cache(kd); + P(&svp) = P(vp); S(&svp) = sizeof(struct vnode); cid = D(vp, vnode)->v_id; @@ -900,8 +913,11 @@ search_cache(kvm_t *kd, struct kbit *vp, 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) + if (o != e) { + if (o <= buf) + break; *(--o) = '/'; + } if (o - ce->ce_nlen <= buf) break; o -= ce->ce_nlen; @@ -919,6 +935,56 @@ search_cache(kvm_t *kd, struct kbit *vp, KDEREF(kd, &svp); return (D(&svp, vnode)->v_flag & VROOT); +} + +void +load_name_cache(kvm_t *kd) +{ + struct namecache n, *tmp; + struct namecache_head nchead; + + LIST_INIT(&lcache); + _KDEREF(kd, nclruhead_addr, &nchead, sizeof(nchead)); + tmp = TAILQ_FIRST(&nchead); + while (tmp != NULL) { + _KDEREF(kd, (u_long)tmp, &n, sizeof(n)); + + if (n.nc_nlen > 0) { + if (n.nc_nlen > 2 || + n.nc_name[0] != '.' || + (n.nc_nlen != 1 && n.nc_name[1] != '.')) + cache_enter(&n); + } + tmp = TAILQ_NEXT(&n, nc_lru); + } + + namecache_loaded = 1; +} + +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)); + if (ce == NULL) + err(1, "cache_enter"); + + 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 = (unsigned)ncp->nc_nlen; + strlcpy(ce->ce_name, ncp->nc_name, sizeof(ce->ce_name)); + + LIST_INSERT_HEAD(&lcache, ce, ce_next); } static void __dead