Hi,
Needs an RB_GENERATE, see devel/libgtop2/files/procmap.c used this at
end of file. Adding this builds, but I get a Seg fault when attempting
running built lsof on amd64.
/*
* Don't implement address comparison.
*/
static __inline int
no_impl(void *p, void *q)
{
abort(); /* Should not be called. */
return 0;
}
RB_GENERATE(uvm_map_addr, vm_map_entry, daddrs.addr_entry, no_impl);
Regards
Nigel Taylor
On 06/03/11 18:41, Stuart Henderson wrote:
> 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) */
> -
> }
> }