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) */
-
}
}