On Fri, Dec 30, 2011 at 02:42:18PM +0100, Ariane van der Steldt wrote:
> The huge diff included below is to replace vmmap for something that
> works a lot better. This is the second version I plan to commit.
> I have been running this on my laptop for months and have had no
> problems.
> 
> The current incarnation is:
>   vmmap_sys.diff.63

And this is the corresponding userspace counterpart of the diff, which
you'll need to compile userspace.

It's version is:
  vmmap_userland.diff.30
-- 
Ariane


Index: lib/libkvm/kvm_proc.c
===================================================================
RCS file: /cvs/src/lib/libkvm/kvm_proc.c,v
retrieving revision 1.42
diff -u -d -p -r1.42 kvm_proc.c
--- lib/libkvm/kvm_proc.c       12 Mar 2011 04:54:28 -0000      1.42
+++ lib/libkvm/kvm_proc.c       21 May 2011 13:38:58 -0000
@@ -131,7 +131,7 @@ static void ps_str_e(struct ps_strings *
 static char *
 _kvm_ureadm(kvm_t *kd, const struct miniproc *p, u_long va, u_long *cnt)
 {
-       u_long addr, head, offset, slot;
+       u_long addr, offset, slot;
        struct vm_anon *anonp, anon;
        struct vm_map_entry vme;
        struct vm_amap amap;
@@ -140,27 +140,28 @@ _kvm_ureadm(kvm_t *kd, const struct mini
        if (kd->swapspc == 0) {
                kd->swapspc = _kvm_malloc(kd, kd->nbpg);
                if (kd->swapspc == 0)
-                       return (0);
+                       return (NULL);
        }
 
        /*
         * Look through the address map for the memory object
         * that corresponds to the given virtual address.
-        * The header just has the entire valid range.
         */
-       head = (u_long)&p->p_vmspace->vm_map.header;
-       addr = head;
+       addr = (u_long)RB_ROOT(&p->p_vmspace->vm_map.addr);
        while (1) {
+               if (addr == 0)
+                       return (NULL);
                if (KREAD(kd, addr, &vme))
-                       return (0);
+                       return (NULL);
 
-               if (va >= vme.start && va < vme.end &&
-                   vme.aref.ar_amap != NULL)
+               if (va < vme.start)
+                       addr = (u_long)RB_LEFT(&vme, daddrs.addr_entry);
+               else if (va >= vme.end + vme.guard + vme.fspace)
+                       addr = (u_long)RB_RIGHT(&vme, daddrs.addr_entry);
+               else if (va >= vme.end)
+                       return (NULL);
+               else
                        break;
-
-               addr = (u_long)vme.next;
-               if (addr == head)
-                       return (0);
        }
 
        /*
Index: usr.sbin/procmap/procmap.c
===================================================================
RCS file: /cvs/src/usr.sbin/procmap/procmap.c,v
retrieving revision 1.38
diff -u -d -p -r1.38 procmap.c
--- usr.sbin/procmap/procmap.c  23 Apr 2011 01:01:34 -0000      1.38
+++ usr.sbin/procmap/procmap.c  21 May 2011 13:38:58 -0000
@@ -169,10 +169,13 @@ struct nlist nl[] = {
 
 void load_symbols(kvm_t *);
 void process_map(kvm_t *, pid_t, struct kinfo_proc *, struct sum *);
-size_t dump_vm_map_entry(kvm_t *, struct kbit *, struct kbit *, int,
+struct vm_map_entry *load_vm_map_entries(kvm_t *, struct vm_map_entry *,
+    struct vm_map_entry *);
+void unload_vm_map_entries(struct vm_map_entry *);
+size_t dump_vm_map_entry(kvm_t *, struct kbit *, struct vm_map_entry *,
     struct sum *);
-char *findname(kvm_t *, struct kbit *, struct kbit *, struct kbit *,
-           struct kbit *, struct kbit *);
+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);
 #if 0
 void load_name_cache(kvm_t *);
@@ -182,6 +185,19 @@ static void __dead usage(void);
 static pid_t strtopid(const char *);
 void print_sum(struct sum *, struct sum *);
 
+/*
+ * uvm_map address tree implementation.
+ */
+static int no_impl(void *, void *);
+static int
+no_impl(void *p, void *q)
+{
+       errx(1, "uvm_map address comparison not implemented");
+       return 0;
+}
+
+RB_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl);
+
 int
 main(int argc, char *argv[])
 {
@@ -347,12 +363,12 @@ print_sum(struct sum *sum, struct sum *t
 void
 process_map(kvm_t *kd, pid_t pid, struct kinfo_proc *proc, struct sum *sum)
 {
-       struct kbit kbit[4], *vmspace, *vm_map, *header, *vm_map_entry;
-       struct vm_map_entry *last;
-       u_long addr, next;
+       struct kbit kbit[3], *vmspace, *vm_map;
+       struct vm_map_entry *vm_map_entry;
        size_t total = 0;
        char *thing;
        uid_t uid;
+       int vmmap_flags;
 
        if ((uid = getuid())) {
                if (pid == 0) {
@@ -367,13 +383,9 @@ process_map(kvm_t *kd, pid_t pid, struct
 
        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) {
                A(vmspace) = (u_long)proc->p_vmspace;
@@ -416,34 +428,38 @@ process_map(kvm_t *kd, pid_t pid, struct
                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("    lock = <struct lock>\n");
                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" : 
"",
+               printf("    min_offset-max_offset = 0x%lx-0x%lx\n",
+                   D(vm_map, vm_map)->min_offset,
+                   D(vm_map, vm_map)->max_offset);
+               printf("    b_start-b_end = 0x%lx-0x%lx\n",
+                   D(vm_map, vm_map)->b_start,
+                   D(vm_map, vm_map)->b_end);
+               printf("    s_start-s_end = 0x%lx-0x%lx\n",
+                   D(vm_map, vm_map)->s_start,
+                   D(vm_map, vm_map)->s_end);
+               vmmap_flags = D(vm_map, vm_map)->flags;
+               printf("    flags = %x <%s%s%s%s%s%s >,\n",
+                   vmmap_flags,
+                   vmmap_flags & VM_MAP_PAGEABLE ? " PAGEABLE" : "",
+                   vmmap_flags & VM_MAP_INTRSAFE ? " INTRSAFE" : "",
+                   vmmap_flags & VM_MAP_WIREFUTURE ? " WIREFUTURE" : "",
+                   vmmap_flags & VM_MAP_BUSY ? " BUSY" : "",
+                   vmmap_flags & VM_MAP_WANTLOCK ? " WANTLOCK" : "",
 #if VM_MAP_TOPDOWN > 0
-                   D(vm_map, vm_map)->flags & VM_MAP_TOPDOWN ? " TOPDOWN" :
+                   vmmap_flags & VM_MAP_TOPDOWN ? " TOPDOWN" :
 #endif
                    "");
-               printf("    flags_lock = <struct simplelock>,");
-               printf(" timestamp = %u }\n", D(vm_map, vm_map)->timestamp);
+               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,
+               printf("\tsz=%ld, ref=%d, version=%d, flags=0x%x\n",
                    D(vm_map, vm_map)->size,
                    D(vm_map, vm_map)->ref_count,
                    D(vm_map, vm_map)->timestamp,
@@ -452,11 +468,6 @@ process_map(kvm_t *kd, pid_t pid, struct
                    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, sum);
-
        /* headers */
 #ifdef DISABLED_HEADERS
        if (print_map)
@@ -482,19 +493,12 @@ process_map(kvm_t *kd, pid_t pid, struct
                    (int)sizeof(int)  * 2, "Inode");
 
        /* these are the "sub entries" */
-       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);
+       RB_ROOT(&D(vm_map, vm_map)->addr) =
+           load_vm_map_entries(kd, RB_ROOT(&D(vm_map, vm_map)->addr), NULL);
+       RB_FOREACH(vm_map_entry, uvm_map_addr, &D(vm_map, vm_map)->addr)
+               total += dump_vm_map_entry(kd, vmspace, vm_map_entry, sum);
+       unload_vm_map_entries(RB_ROOT(&D(vm_map, vm_map)->addr));
 
-       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, sum);
-               next = (u_long)D(vm_map_entry, vm_map_entry)->next;
-       }
        if (print_solaris)
                printf("%-*s %8luK\n",
                    (int)sizeof(void *) * 2 - 2, " total",
@@ -527,12 +531,58 @@ load_symbols(kvm_t *kd)
            sizeof(kernel_map_addr));
 }
 
+/*
+ * Recreate the addr tree of vm_map in local memory.
+ */
+struct vm_map_entry *
+load_vm_map_entries(kvm_t *kd, struct vm_map_entry *kptr,
+    struct vm_map_entry *parent)
+{
+       static struct kbit map_ent;
+       struct vm_map_entry *result;
+
+       if (kptr == NULL)
+               return NULL;
+
+       A(&map_ent) = (u_long)kptr;
+       S(&map_ent) = sizeof(struct vm_map_entry);
+       KDEREF(kd, &map_ent);
+
+       result = malloc(sizeof(*result));
+       if (result == NULL)
+               err(1, "malloc");
+       memcpy(result, D(&map_ent, vm_map_entry), sizeof(struct vm_map_entry));
+
+       /*
+        * Recurse to download rest of the tree.
+        */
+       RB_LEFT(result, daddrs.addr_entry) = load_vm_map_entries(kd,
+           RB_LEFT(result, daddrs.addr_entry), result);
+       RB_RIGHT(result, daddrs.addr_entry) = load_vm_map_entries(kd,
+           RB_RIGHT(result, daddrs.addr_entry), result);
+       RB_PARENT(result, daddrs.addr_entry) = parent;
+       return result;
+}
+
+/*
+ * Release the addr tree of vm_map.
+ */
+void
+unload_vm_map_entries(struct vm_map_entry *ent)
+{
+       if (ent == NULL)
+               return;
+
+       unload_vm_map_entries(RB_LEFT(ent, daddrs.addr_entry));
+       unload_vm_map_entries(RB_RIGHT(ent, daddrs.addr_entry));
+       free(ent);
+}
+
 size_t
 dump_vm_map_entry(kvm_t *kd, struct kbit *vmspace,
-    struct kbit *vm_map_entry, int ishead, struct sum *sum)
+    struct vm_map_entry *vme, struct sum *sum)
 {
        struct kbit kbit[4], *uvm_obj, *vp, *vfs, *amap;
-       struct vm_map_entry *vme;
        ino_t inode = 0;
        dev_t dev = 0;
        size_t sz = 0;
@@ -547,15 +597,9 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
        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);
+       if (debug & PRINT_VM_MAP_ENTRY) {
+               printf("%s = {", "vm_map_entry");
+               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);
@@ -576,9 +620,6 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    vme->flags & UVM_MAP_KMEM ? " KMEM" : "");
        }
 
-       if (ishead)
-               return (0);
-
        A(vp) = 0;
        A(uvm_obj) = 0;
 
@@ -643,7 +684,7 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                }
        }
 
-       name = findname(kd, vmspace, vm_map_entry, vp, vfs, uvm_obj);
+       name = findname(kd, vmspace, vme, vp, vfs, uvm_obj);
 
        if (print_map) {
                printf("0x%lx 0x%lx %c%c%c %c%c%c %s %s %d %d %d",
@@ -681,8 +722,9 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
                    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,
+               printf(" - <lost address>: 0x%lx->0x%lx: "
+                   "obj=%p/0x%lx, amap=%p/%d\n",
+                   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, "
@@ -761,15 +803,12 @@ dump_vm_map_entry(kvm_t *kd, struct kbit
 
 char *
 findname(kvm_t *kd, struct kbit *vmspace,
-    struct kbit *vm_map_entry, struct kbit *vp,
+    struct vm_map_entry *vme, 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 = strlen(D(vfs, mount)->mnt_stat.f_mntonname);
@@ -828,9 +867,7 @@ findname(kvm_t *kd, struct kbit *vmspace
            (caddr_t)vme->end) {
                name = "  [ stack ]";
        } else if (D(vmspace, vmspace)->vm_daddr <= (caddr_t)vme->start &&
-           D(vmspace, vmspace)->vm_daddr + BRKSIZ >= (caddr_t)vme->end &&
-           D(vmspace, vmspace)->vm_dsize * getpagesize() / 2 <
-           (vme->end - vme->start)) {
+           D(vmspace, vmspace)->vm_daddr + BRKSIZ >= (caddr_t)vme->end) {
                name = "  [ heap ]";
        } else if (UVM_ET_ISHOLE(vme))
                name = "  [ hole ]";

Reply via email to