On Sat, May 30, 2026 at 3:13 PM Richard Henderson <
[email protected]> wrote:

> Use kinfo_getvmmap from -luser.
>
> Signed-off-by: Richard Henderson <[email protected]>
> ---
>  common-user/selfmap.c   | 41 ++++++++++++++++++++++++++++++++++++++++-
>  common-user/meson.build |  5 +++++
>  2 files changed, 45 insertions(+), 1 deletion(-)
>
> diff --git a/common-user/selfmap.c b/common-user/selfmap.c
> index a1b88dee66..151d066801 100644
> --- a/common-user/selfmap.c
> +++ b/common-user/selfmap.c
> @@ -9,6 +9,10 @@
>  #include "qemu/osdep.h"
>  #include "qemu/cutils.h"
>  #include "user/selfmap.h"
> +#ifdef __FreeBSD__
> +#include <libutil.h>
> +#include <sys/user.h>
> +#endif
>
>  IntervalTreeRoot *read_self_maps(void)
>  {
> @@ -80,9 +84,44 @@ IntervalTreeRoot *read_self_maps(void)
>      g_strfreev(lines);
>      g_free(maps);
>
> +    return root;
> +#elif defined(__FreeBSD__)
> +    int n = 0;
> +    struct kinfo_vmentry *entries = kinfo_getvmmap(getpid(), &n);
>

So I had the following to use the sysctl interface. The extra bit is
paranoia
for the general case where we're multi-threaded. I'm not entirely sure it's
needed, but it won't hurt since we free this memory at the end anyway.
It's up to you to see if you think the -lutil addition is better or this
slightly
longer code is better.

    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
    size_t len;
    char *buf, *p;

    if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
        return NULL;
    }

    /* Add some slack in case mappings change between calls. */
    len = len * 4 / 3;
    buf = g_malloc(len);
    if (sysctl(mib, 4, buf, &len, NULL, 0) < 0) {
        g_free(buf);
        return NULL;
    }



> +    IntervalTreeRoot *root;
> +
> +    if (!entries) {
> +        return NULL;
> +    }
> +    root = g_new0(IntervalTreeRoot, 1);
> +
> +    for (int i = 0; i < n; ++i) {
> +        struct kinfo_vmentry *k = &entries[i];
> +        size_t path_len = strnlen(k->kve_path, sizeof(k->kve_path)) + 1;
>

This is shorter than what I had in blitz.


> +        MapInfo *e = g_malloc0(sizeof(*e) + path_len);
>
>
My version did the following only if
      if (kve->kve_type != KVME_TYPE_GUARD &&
            kve->kve_type != KVME_TYPE_DEAD) {

though now I see my version would have been better with the
contrapositive and continue.


> +        e->itree.start = k->kve_start;
> +        e->itree.last = k->kve_end - 1;
> +
> +        /* ??? The rest of these fields are only used in linux-user. */
> +        e->dev = k->kve_vn_fsid_freebsd11;
> +        e->inode = k->kve_vn_fileid;
> +        e->offset = k->kve_offset;
> +        e->is_read = k->kve_protection & KVME_PROT_READ;
> +        e->is_write = k->kve_protection & KVME_PROT_WRITE;
> +        e->is_exec = k->kve_protection & KVME_PROT_EXEC;
> +        e->is_priv = k->kve_flags & KVME_FLAG_COW;
> +        if (path_len) {
> +            e->path = memcpy(e + 1, k->kve_path, path_len);
> +        }
> +
> +        interval_tree_insert(&e->itree, root);
> +    }
> +
> +    free(entries);
>

I had g_free() here, but I am a 'cargo cult' glib user...


>      return root;
>  #else
> -    return NULL;
> +# error
>  #endif
>  }
>
> diff --git a/common-user/meson.build b/common-user/meson.build
> index 831a7273fb..5e041de55e 100644
> --- a/common-user/meson.build
> +++ b/common-user/meson.build
> @@ -10,3 +10,8 @@ user_ss.add(files(
>    'safe-syscall-error.c',
>    'selfmap.c',
>  ))
> +
> +if host_os == 'freebsd'
> +  libutil = cc.find_library('util', required: true)
> +  user_ss.add(libutil)
> +endif
>

This dependency is likely fine, but as I said in my other mail using the
sysctl obviates the need for this.

And thank you so much for writing this, even though there's a small
collision here. I do very much
appreciate it.

Warner


> --
> 2.43.0
>
>

Reply via email to