In gmane.os.openbsd.misc, you wrote:
> On Fri, Jun 03, 2011 at 03:27:37PM +0200, David Coppa wrote:
>> On Thu, Jun 2, 2011 at 7:14 PM, Antoine Jacoutot <[email protected]> 
>> wrote:
>> 
>> > I guess you are not current enough to build lsof.
>> 
>> >> dproc.c: In function 'process_text':
>> >> dproc.c:539: error: 'struct vm_map' has no member named 'nentries'
>> >> dproc.c:545: error: 'struct vm_map' has no member named 'header'
>> >> dproc.c:547: error: 'struct vm_map_entry' has no member named 'next'
>> >> *** Error code 1
>> 
>> I'm current (done a "make build" this morning) and I confirm lsof is
>> broken due to vmmap.
>> 
>> Ariane, please, can you help shedding some light?
>
> This is the same as procmap (from base) and libgtop (from ports) do.
> They traversed the map using a linked list (in the old allocator this
> list existed). The new allocator only has a tree.
>
> The easiest way to traverse a map from userspace is to recreate the tree
> in userspace, then use RB_FOREACH to traverse it. This is what is done
> to make libgtop2 work properly.
> See /usr/ports/devel/libgtop2/files/procmap.c for sample code; the
> load_vmmap_entries and unload_vmmap_entries code can be copied verbatim
> and adapted to lsofs idea of kvm_read.
>
>         RB_INIT(&root);
>         nentries = load_vmmap_entries(server,
>             (unsigned long) RB_ROOT(&vmspace.vm_map.addr),
>             &RB_ROOT(&root), NULL);
>         if (nentries == -1) {
>                 unload_vmmap_entries(RB_ROOT(&root));
>                 glibtop_error_io_r (server, "kvm_read (entry)");
>         }
>
>         RB_FOREACH(entry, uvm_map_addr, &root) {
>                 /*
>                  * funky code goes here
>                  */
>         }
>
>         unload_vmmap_entries(RB_ROOT(&root));
>
> The load_vmmap_entries function performs copy from kernel to userland.
> The unload_vmmap_entries is a recursive free() (and must be called if
> the copy fails).
> -- 
> Ariane
>
>

Trying the diff below but I'm getting this when linking. Any clues
as to what I'm missing?

./lib/liblsof.a(dvch.o)(.text+0x4fe): In function `dcpath':
: warning: strcpy() is almost always misused, please use strlcpy()
dproc.o(.text+0x531): In function `gather_proc_info':
: undefined reference to `uvm_map_addr_RB_MINMAX'
dproc.o(.text+0x64e): In function `gather_proc_info':
: undefined reference to `uvm_map_addr_RB_NEXT'
collect2: ld returned 1 exit status
*** Error code 1

$OpenBSD$
--- dialects/n+obsd/dproc.c.orig        Wed May 11 13:54:00 2005
+++ dialects/n+obsd/dproc.c     Fri Jun  3 18:35:26 2011
@@ -93,7 +93,88 @@ ckkv(d, er, ev, ea)
 }
 
 
+
 /*
+ * Download vmmap_entries from the kernel into our address space.
+ * We fix up the addr tree while downloading.
+ *
+ * Returns: the size of the tree on succes, or -1 on failure.
+ * On failure, *rptr needs to be passed to unload_vmmap_entries to free
+ * the lot.
+ */
+ssize_t
+load_vmmap_entries(unsigned long kptr,
+    struct vm_map_entry **rptr, struct vm_map_entry *parent)
+{
+       struct vm_map_entry *entry;
+       unsigned long left_kptr, right_kptr;
+       ssize_t left_sz;
+       ssize_t right_sz;
+
+       if (kptr == 0)
+               return 0;
+
+       /* Need space. */
+       entry = malloc(sizeof(*entry));
+       if (entry == NULL)
+               return -1;
+
+       /* Download entry at kptr. */
+       if (kvm_read (Kd, kptr,
+           (char *)entry, sizeof(*entry)) != sizeof(*entry)) {
+               free(entry);
+               return -1;
+       }
+
+       /*
+        * Update addr pointers to have sane values in this address space.
+        * We save the kernel pointers in {left,right}_kptr, so we have them
+        * available to download children.
+        */
+       left_kptr = (unsigned long) RB_LEFT(entry, daddrs.addr_entry);
+       right_kptr = (unsigned long) RB_RIGHT(entry, daddrs.addr_entry);
+       RB_LEFT(entry, daddrs.addr_entry) =
+           RB_RIGHT(entry, daddrs.addr_entry) = NULL;
+       /* Fill in parent pointer. */
+       RB_PARENT(entry, daddrs.addr_entry) = parent;
+
+       /*
+        * Consistent state reached, fill in *rptr.
+        */
+       *rptr = entry;
+
+       /*
+        * Download left, right.
+        * On failure, our map is in a state that can be handled by
+        * unload_vmmap_entries.
+        */
+       left_sz = load_vmmap_entries(left_kptr,
+           &RB_LEFT(entry, daddrs.addr_entry), entry);
+       if (left_sz == -1)
+               return -1;
+       right_sz = load_vmmap_entries(right_kptr,
+           &RB_RIGHT(entry, daddrs.addr_entry), entry);
+       if (right_sz == -1)
+               return -1;
+
+       return 1 + left_sz + right_sz;
+}
+
+/*
+ * Free the vmmap entries in the given tree.
+ */
+void
+unload_vmmap_entries(struct vm_map_entry *entry)
+{
+       if (entry == NULL)
+               return;
+
+       unload_vmmap_entries(RB_LEFT(entry, daddrs.addr_entry));
+       unload_vmmap_entries(RB_RIGHT(entry, daddrs.addr_entry));
+       free(entry);
+}
+
+/*
  * enter_vn_text() - enter a vnode text reference
  */
 
@@ -515,13 +596,10 @@ process_text(vm)
        KA_T ka;
        int n = 0;
        struct vm_map_entry vmme, *e;
+       struct uvm_map_addr root;
        struct vmspace vmsp;
+       ssize_t nentries;
 
-#if    !defined(UVM)
-       struct pager_struct pg;
-       struct vm_object vmo;
-#endif /* !defined(UVM) */
-
 /*
  * Read the vmspace structure for the process.
  */
@@ -531,54 +609,25 @@ process_text(vm)
  * Read the vm_map structure.  Search its vm_map_entry structure list.
  */
 
-#if    !defined(UVM)
-       if (!vmsp.vm_map.is_main_map)
-           return;
-#endif /* !defined(UVM) */
+       RB_INIT(&root);
+       nentries = load_vmmap_entries(
+           (unsigned long) RB_ROOT(&vmsp.vm_map.addr),
+           &RB_ROOT(&root), NULL);
+       if (nentries == -1) {
+               unload_vmmap_entries(RB_ROOT(&root));
+               (void) fprintf(stderr, "%s: kvm_read (entry)", Pn);
+               Exit(1);
+       }
 
-       for (i = 0; i < vmsp.vm_map.nentries; i++) {
-
-       /*
-        * Read the next vm_map_entry.
-        */
-           if (!i)
-               e = &vmsp.vm_map.header;
-           else {
-               if (!(ka = (KA_T)e->next))
-                   return;
-               e = &vmme;
+       RB_FOREACH(e, uvm_map_addr, &root) {
                if (kread(ka, (char *)e, sizeof(vmme)))
                    return;
-           }
 
-#if    defined(UVM)
        /*
         * Process the uvm_obj pointer of a UVM map entry with a UVM_ET_OBJ
         * type as a vnode pointer.
         */
            if ((e->etype > UVM_ET_OBJ) && e->object.uvm_obj)
                (void) enter_vn_text((KA_T)e->object.uvm_obj, &n);
-#else  /* !defined(UVM) */
-       /*
-        * Read the map entry's object and the object's shadow.
-        * Look for a PG_VNODE pager handle.
-        */
-           if (e->is_a_map || e->is_sub_map)
-               continue;
-           for (j = 0, ka = (KA_T)e->object.vm_object;
-                j < 2 && ka;
-                j++, ka = (KA_T)vmo.shadow)
-           {
-               if (kread(ka, (char *)&vmo, sizeof(vmo)))
-                   break;
-               if (!(ka = (KA_T)vmo.pager)
-               ||   kread(ka, (char *)&pg, sizeof(pg)))
-                   continue;
-               if (!pg.pg_handle || pg.pg_type != PG_VNODE)
-                   continue;
-               (void) enter_vn_text((KA_T)pg.pg_handle, &n);
-           }
-#endif /* defined(UVM) */
-
        }
 }

Reply via email to