[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