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