[DTrace-devel] [PATCH 2/8] btf: always load BTF (if available)
Eugene Loh
eugene.loh at oracle.com
Thu Apr 4 21:49:19 UTC 2024
I'm missing something. I think HAVE_LIBCTF is false on OL7. So the
libdtrace/Build change means we'll start compiling dt_btf.c on OL7. For
me, that means build problems because I do not know what ctf_dict_t is.
What is supposed to be happening on OL7?
On 4/3/24 11:26, Kris Van Hees via DTrace-devel wrote:
> Upcoming work will make use of BPF features that depend on BTF data.
> Load it if available, and generate CTF from it if no CTF archive is
> found.
>
> Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
> ---
> libdtrace/Build | 5 +--
> libdtrace/dt_btf.c | 88 ++++++++++++++++++++++++++++---------------
> libdtrace/dt_btf.h | 6 ++-
> libdtrace/dt_impl.h | 3 +-
> libdtrace/dt_module.c | 70 ++++++++++++++++++++++------------
> 5 files changed, 111 insertions(+), 61 deletions(-)
>
> diff --git a/libdtrace/Build b/libdtrace/Build
> index 4ed04fdf..9733a17b 100644
> --- a/libdtrace/Build
> +++ b/libdtrace/Build
> @@ -13,6 +13,7 @@ libdtrace-build_DIR := $(current-dir)
> libdtrace-build_SOURCES = dt_aggregate.c \
> dt_as.c \
> dt_bpf.c \
> + dt_btf.c \
> dt_buf.c \
> dt_cc.c \
> dt_cg.c \
> @@ -71,10 +72,6 @@ libdtrace-build_SOURCES = dt_aggregate.c \
> dt_work.c \
> dt_xlator.c
>
> -ifdef HAVE_LIBCTF
> -libdtrace-build_SOURCES += dt_btf.c
> -endif
> -
> libdtrace-build_SRCDEPS := dt_grammar.h $(objdir)/dt_git_version.h
>
> SHLIBS += libdtrace
> diff --git a/libdtrace/dt_btf.c b/libdtrace/dt_btf.c
> index 59126dd1..3f713632 100644
> --- a/libdtrace/dt_btf.c
> +++ b/libdtrace/dt_btf.c
> @@ -37,7 +37,7 @@ struct dt_btf {
> ctf_id_t *ctfids; /* matching CTF type ids */
> };
>
> -static const char *
> +const char *
> dt_btf_errmsg(int err)
> {
> return strerror(err);
> @@ -362,11 +362,11 @@ dt_btf_add_to_ctf(dtrace_hdl_t *dtp, dt_btf_t *btf, ctf_dict_t *ctf,
> * If we are not constructing shared_ctf, we may be looking for a type
> * in shared_ctf.
> */
> - if (dtp->dt_btf && btf != dtp->dt_btf) {
> - if (type_id < dtp->dt_btf->type_cnt)
> - return dtp->dt_btf->ctfids[type_id];
> + if (dtp->dt_shared_btf && btf != dtp->dt_shared_btf) {
> + if (type_id < dtp->dt_shared_btf->type_cnt)
> + return dtp->dt_shared_btf->ctfids[type_id];
>
> - type_id -= dtp->dt_btf->type_cnt - 1;
> + type_id -= dtp->dt_shared_btf->type_cnt - 1;
> }
>
> assert(type_id < btf->type_cnt);
> @@ -668,7 +668,7 @@ dt_btf_add_to_ctf(dtrace_hdl_t *dtp, dt_btf_t *btf, ctf_dict_t *ctf,
> assert(0);
> }
>
> -ctf_dict_t *
> +static ctf_dict_t *
> dt_btf_to_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp, dt_btf_t *btf)
> {
> int i, base = 0;
> @@ -695,9 +695,12 @@ dt_btf_to_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp, dt_btf_t *btf)
> ctf_setspecific(ctf, dmp);
>
> if (strcmp(dmp->dm_name, "vmlinux") == 0)
> - return ctf;
> + goto out;
> }
>
> + if (!btf)
> + goto out;
> +
> btf->ctfids = dt_calloc(dtp, btf->type_cnt, sizeof(ctf_id_t));
> for (i = 1; i < btf->type_cnt; i++)
> btf->ctfids[i] = CTF_ERR;
> @@ -715,13 +718,13 @@ dt_btf_to_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp, dt_btf_t *btf)
>
> /*
> * Any module other than 'vmlinux' inherits the types from 'vmlinux'.
> - * The shared types are 1 through (base = dtp->dt_btf->type_cnt - 1).
> + * Shared types are 1 through (base = dtp->dt_shared_btf->type_cnt - 1).
> * A module's types are base through (base + btf->type_cnt - 1), but
> * the types are stored in the BTF types array with indexes 1 through
> * (btf->type_cnt - 1).
> */
> - if (dtp->dt_btf)
> - base = dtp->dt_btf->type_cnt - 1;
> + if (btf != dtp->dt_shared_btf)
> + base = dtp->dt_shared_btf->type_cnt - 1;
>
> for (i = 1; i < btf->type_cnt; i++) {
> int type_id = i + base;
> @@ -733,13 +736,14 @@ dt_btf_to_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp, dt_btf_t *btf)
> }
> }
>
> +out:
> if (ctf_update(ctf) == CTF_ERR)
> return NULL;
>
> return ctf;
> }
>
> -ctf_dict_t *
> +dt_btf_t *
> dt_btf_load_module(dtrace_hdl_t *dtp, dt_module_t *dmp)
> {
> char fn[PATH_MAX + 1];
> @@ -747,36 +751,59 @@ dt_btf_load_module(dtrace_hdl_t *dtp, dt_module_t *dmp)
>
> snprintf(fn, sizeof(fn), "/sys/kernel/btf/%s", dmp->dm_name);
> btf = dt_btf_load_file(dtp, fn);
> - if (btf == NULL)
> - return NULL;
>
> - if (strcmp(dmp->dm_name, "vmlinux") == 0) {
> - dtp->dt_shared_ctf = dt_btf_to_ctf(dtp, NULL, btf);
> - dtp->dt_btf = btf;
> + if (btf && strcmp(dmp->dm_name, "vmlinux") == 0)
> + dtp->dt_shared_btf = btf;
>
> - dt_dprintf("Generated shared CTF from BTF (%d types).\n",
> - btf->type_cnt);
> + return btf;
> +}
>
> - return dtp->dt_shared_ctf;
> - }
> +ctf_dict_t *
> +dt_btf_module_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> +{
> + ctf_dict_t *ctf;
> + dt_btf_t *btf = dmp->dm_btf;
> +
> + /* If we already have CTF data, return it. */
> + if (dmp->dm_ctfp)
> + return dmp->dm_ctfp;
> +
> + /*
> + * If the module is 'vmlinux', we are creating the shared CTF.
> + * If the module uses the shared BTF, we create CTF for a NULL BTF.
> + * Otherwise, convert the module BTF.
> + */
> + if (strcmp(dmp->dm_name, "vmlinux") == 0)
> + ctf = dt_btf_to_ctf(dtp, NULL, btf);
> + else if (btf == dtp->dt_shared_btf)
> + ctf = dt_btf_to_ctf(dtp, dmp, NULL);
> + else
> + ctf = dt_btf_to_ctf(dtp, dmp, btf);
> +
> + /*
> + * If generating CTF data for the main kernel, store it as the shared
> + * CTF.
> + */
> + if (!dtp->dt_shared_ctf && dtp->dt_shared_btf && btf == dtp->dt_shared_btf)
> + dtp->dt_shared_ctf = ctf;
>
> dt_dprintf("Generated %s CTF from BTF (%d types).\n", dmp->dm_name,
> btf->type_cnt);
>
> - return dt_btf_to_ctf(dtp, dmp, btf);
> + return ctf;
> }
>
> const char *
> dt_btf_get_string(dtrace_hdl_t *dtp, dt_btf_t *btf, uint32_t off)
> {
> - if (dtp->dt_btf == NULL)
> + if (dtp->dt_shared_btf == NULL)
> goto ok;
>
> /* Check if the offset is within the base BTF string area. */
> - if (btf == dtp->dt_btf || off < dtp->dt_btf->hdr->str_len)
> - return dtp->dt_btf->sdata + off;
> + if (btf == dtp->dt_shared_btf || off < dtp->dt_shared_btf->hdr->str_len)
> + return dtp->dt_shared_btf->sdata + off;
>
> - off -= dtp->dt_btf->hdr->str_len;
> + off -= dtp->dt_shared_btf->hdr->str_len;
> ok:
> if (off < btf->hdr->str_len)
> return btf->sdata + off;
> @@ -799,11 +826,11 @@ dt_btf_lookup_name_kind(dtrace_hdl_t *dtp, dt_btf_t *btf, const char *name,
> * Ensure the shared BTF is loaded, and if no BTF is given, use the
> * shared one.
> */
> - if (!dtp->dt_btf) {
> + if (!dtp->dt_shared_btf) {
> dt_btf_load_module(dtp, dtp->dt_exec);
>
> if (!btf)
> - btf = dtp->dt_btf;
> + btf = dtp->dt_shared_btf;
> }
>
> if (!btf)
> @@ -816,8 +843,8 @@ dt_btf_lookup_name_kind(dtrace_hdl_t *dtp, dt_btf_t *btf, const char *name,
> * the types are stored in the BTF types array with indexes 1 through
> * (btf->type_cnt - 1).
> */
> - if (btf != dtp->dt_btf)
> - base = dtp->dt_btf->type_cnt - 1;
> + if (btf != dtp->dt_shared_btf)
> + base = dtp->dt_shared_btf->type_cnt - 1;
>
>
> for (i = 1; i < btf->type_cnt; i++) {
> @@ -833,7 +860,8 @@ dt_btf_lookup_name_kind(dtrace_hdl_t *dtp, dt_btf_t *btf, const char *name,
> }
>
> if (base > 0)
> - return dt_btf_lookup_name_kind(dtp, dtp->dt_btf, name, kind);
> + return dt_btf_lookup_name_kind(dtp, dtp->dt_shared_btf,
> + name, kind);
>
> return -ENOENT;
> }
> diff --git a/libdtrace/dt_btf.h b/libdtrace/dt_btf.h
> index 863fa470..85ae315e 100644
> --- a/libdtrace/dt_btf.h
> +++ b/libdtrace/dt_btf.h
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -16,7 +16,9 @@ extern "C" {
>
> typedef struct dt_btf dt_btf_t;
>
> -extern ctf_dict_t *dt_btf_load_module(dtrace_hdl_t *, dt_module_t *);
> +extern const char *dt_btf_errmsg(int);
> +extern dt_btf_t *dt_btf_load_module(dtrace_hdl_t *, dt_module_t *);
> +extern ctf_dict_t *dt_btf_module_ctf(dtrace_hdl_t *, dt_module_t *);
> extern const char *dt_btf_get_string(dtrace_hdl_t *, dt_btf_t *, uint32_t);
>
> #ifdef __cplusplus
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 2dfb64d6..3f258376 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -159,6 +159,7 @@ typedef struct dt_module {
> ctf_sect_t dm_ctdata; /* CTF data for module */
> ctf_sect_t dm_symtab; /* symbol table */
> ctf_sect_t dm_strtab; /* string table */
> + struct dt_btf *dm_btf; /* BTF data for module */
>
> /*
> * Kernel modules only.
> @@ -337,7 +338,7 @@ struct dtrace_hdl {
> dt_htab_t *dt_kernsyms; /* htab of kernel symbol names */
> char *dt_ctfa_path; /* path to vmlinux.ctfa */
> ctf_archive_t *dt_ctfa; /* ctf archive for the entire kernel tree */
> - struct dt_btf *dt_btf; /* BTF data for the kernel */
> + struct dt_btf *dt_shared_btf; /* BTF data for the kernel (shared) */
> ctf_file_t *dt_shared_ctf; /* Handle to the shared CTF */
> dt_htab_t *dt_kernpaths; /* hash table of dt_kern_path_t's */
> dt_module_t *dt_exec; /* pointer to executable module */
> diff --git a/libdtrace/dt_module.c b/libdtrace/dt_module.c
> index 1e730426..3182f388 100644
> --- a/libdtrace/dt_module.c
> +++ b/libdtrace/dt_module.c
> @@ -1,6 +1,6 @@
> /*
> * Oracle Linux DTrace.
> - * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
> * Licensed under the Universal Permissive License v 1.0 as shown at
> * http://oss.oracle.com/licenses/upl.
> */
> @@ -41,6 +41,9 @@ dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp);
> static void
> dt_module_shuffle_to_start(dtrace_hdl_t *dtp, const char *name);
>
> +static void
> +dt_kern_module_find_btf(dtrace_hdl_t *dtp, dt_module_t *dmp);
> +
> static void
> dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp);
>
> @@ -392,6 +395,9 @@ dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp)
> if (dmp->dm_flags & DT_DM_LOADED)
> return 0; /* module is already loaded */
>
> + /* Load BTF data for the module. */
> + dt_kern_module_find_btf(dtp, dmp);
> +
> /*
> * First find out where the module is, and preliminarily load its CTF.
> * If this fails, we don't care: the problem will be detected in
> @@ -610,6 +616,10 @@ dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> static void
> dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
> {
> + if (dmp->dm_btf != dtp->dt_shared_btf)
> + dt_free(dtp, dmp->dm_btf);
> + dmp->dm_btf = NULL;
> +
> if (dmp->dm_ctfp != dtp->dt_shared_ctf)
> ctf_close(dmp->dm_ctfp);
> dmp->dm_ctfp = NULL;
> @@ -834,17 +844,11 @@ dt_kern_module_init(dtrace_hdl_t *dtp, dt_module_t *dmp)
> static void
> dt_kern_module_ctf_from_btf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> {
> - /*
> - * The first module for which we need to collect data must be the
> - * 'vmlinux' module. It will be used to initialize the shared_ctf
> - * data.
> - */
> - if (dtp->dt_btf == NULL)
> - assert(strcmp(dmp->dm_name, "vmlinux") == 0);
> + assert(dmp->dm_btf != NULL);
>
> dt_dprintf("Generating CTF for module %s from BTF.\n", dmp->dm_name);
>
> - dmp->dm_ctfp = dt_btf_load_module(dtp, dmp);
> + dmp->dm_ctfp = dt_btf_module_ctf(dtp, dmp);
> if (dmp->dm_ctfp == NULL)
> dt_dprintf("Cannot generate CTF for module %s from BTF: %s; "
> "looking for out-of-tree module.\n",
> @@ -854,6 +858,33 @@ dt_kern_module_ctf_from_btf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> }
> #endif
>
> +/*
> + * Load BTF data for a kernel module (vmlinux is treated as its own module as
> + * well), if available and not already loaded.
> + */
> +static void
> +dt_kern_module_find_btf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> +{
> + /*
> + * The first module for which we need to collect BTF data must be the
> + * 'vmlinux' module.
> + */
> + if (dtp->dt_shared_btf == NULL)
> + assert(strcmp(dmp->dm_name, "vmlinux") == 0);
> +
> + dt_dprintf("Loading BTF for module %s.\n", dmp->dm_name);
> +
> + dmp->dm_btf = dt_btf_load_module(dtp, dmp);
> +
> + /*
> + * If no module specific BTF was found, we assume it is a builtin
> + * module and we assign the shared BTF to it. That is the fallback
> + * anyway for type lookups in modules, so it is safe.
> + */
> + if (dmp->dm_btf == NULL)
> + dmp->dm_btf = dtp->dt_shared_btf;
> +}
> +
> /*
> * Determine the location of a kernel module's CTF data.
> *
> @@ -872,18 +903,6 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> dt_kern_module_init(dtp, dmp);
> }
>
> -#ifdef HAVE_LIBCTF
> - /*
> - * If we already know that our CTF data is derived from BTF data (i.e.
> - * there is no CTF archive for the runtime kernel), there is no point
> - * in trying to load CTF data. Go directly to BTF-based processing.
> - */
> - if (dtp->dt_btf) {
> - dt_kern_module_ctf_from_btf(dtp, dmp);
> - return;
> - }
> -#endif
> -
> /*
> * Kernel modules' CTF can be in one of two places: the CTF archive or
> * linked into the module (for out-of-tree modules). The corresponding
> @@ -899,7 +918,7 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> *
> * Check for a CTF archive containing the specified module.
> */
> - if (dtp->dt_ctfa == NULL) {
> + if (dtp->dt_ctfa == NULL && dtp->dt_shared_ctf == NULL) {
> char *ctfa_name;
> char *to;
>
> @@ -931,6 +950,8 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> }
> } else {
> #ifdef HAVE_LIBCTF
> + dt_module_t *mod;
> +
> dt_dprintf("Cannot open CTF archive %s: %s; "
> "trying BTF.\n",
> ctfa_name, ctf_errmsg(dtp->dt_ctferr));
> @@ -939,8 +960,9 @@ dt_kern_module_find_ctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
> * Try to load the vmlinux BTF data to generate the CTF
> * data for shared_ctf from.
> */
> - dt_kern_module_ctf_from_btf(dtp,
> - dt_module_lookup_by_name(dtp, "vmlinux"));
> + mod = dt_module_lookup_by_name(dtp, "vmlinux");
> + dt_kern_module_ctf_from_btf(dtp, mod);
> + dtp->dt_shared_ctf = mod->dm_ctfp;
> #else
> dt_dprintf("Cannot open CTF archive %s: %s; "
> "looking for in-module CTF instead.\n",
More information about the DTrace-devel
mailing list