[PATCH v6 bpf-next 04/10] libbpf: Add kind layout encoding support

Alan Maguire
2025-12-10T20:34:19Z

Support encoding of BTF kind layout data via btf__new_empty_opts().

Current supported opts are base_btf and add_kind_layout.

Kind layout information is maintained in btf.c in the
kind_layouts[] array; when BTF is created with the
add_kind_layout option it represents the current view
of supported BTF kinds.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
tools/lib/bpf/btf.c | 61 ++++++++++++++++++++++++++++++++++++++--
tools/lib/bpf/btf.h | 20 +++++++++++++
tools/lib/bpf/libbpf.map | 1 +
3 files changed, 79 insertions(+), 3 deletions(-)

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 4eb0704a0309..2133e976cb9c 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -29,6 +29,35 @@

static struct btf_type btf_void;

+/* Describe how kinds are laid out; some have a singular element following the "struct btf_type",
+ * some have BTF_INFO_VLEN(t->info) elements. Specify sizes for both. Flags are currently unused.
+ * Kind layout can be optionally added to the BTF representation in a dedicated section to
+ * facilitate parsing. New kinds must be added here.
+ */
+struct btf_kind_layout kind_layouts[NR_BTF_KINDS] = {
+/* singular element size vlen element(s) size */
+{ 0, 0 }, /* _UNKN */
+{ sizeof(__u32), 0 }, /* _INT */
+{ 0, 0 }, /* _PTR */
+{ sizeof(struct btf_array), 0 }, /* _ARRAY */
+{ 0, sizeof(struct btf_member) }, /* _STRUCT */
+{ 0, sizeof(struct btf_member) }, /* _UNION */
+{ 0, sizeof(struct btf_enum) }, /* _ENUM */
+{ 0, 0 }, /* _FWD */
+{ 0, 0 }, /* _TYPEDEF */
+{ 0, 0 }, /* _VOLATILE */
+{ 0, 0 }, /* _CONST */
+{ 0, 0 }, /* _RESTRICT */
+{ 0, 0 }, /* _FUNC */
+{ 0, sizeof(struct btf_param) }, /* _FUNC_PROTO */
+{ sizeof(struct btf_var), 0 }, /* _VAR */
+{ 0, sizeof(struct btf_var_secinfo) }, /* _DATASEC */
+{ 0, 0 }, /* _FLOAT */
+{ sizeof(struct btf_decl_tag), 0 }, /* _DECL_TAG */
+{ 0, 0 }, /* _TYPE_TAG */
+{ 0, sizeof(struct btf_enum64) }, /* _ENUM64 */
+};
+
struct btf {
/* raw BTF data in native endianness */
void *raw_data;
@@ -1067,8 +1096,9 @@ void btf__free(struct btf *btf)
free(btf);
}

-static struct btf *btf_new_empty(struct btf *base_btf)
+static struct btf *btf_new_empty(struct btf_new_opts *opts)
{
+ struct btf *base_btf = OPTS_GET(opts, base_btf, NULL);
struct btf_header *hdr;
struct btf *btf;

@@ -1111,6 +1141,17 @@ static struct btf *btf_new_empty(struct btf *base_btf)
free(btf);
return ERR_PTR(-ENOMEM);
}
+
+ if (opts->add_kind_layout) {
+ hdr->kind_layout_len = sizeof(kind_layouts);
+ btf->kind_layout = malloc(hdr->kind_layout_len);
+ if (!btf->kind_layout) {
+ free(btf->hdr);
+ free(btf);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(btf->kind_layout, kind_layouts, sizeof(kind_layouts));
+ }
memcpy(btf->hdr, hdr, sizeof(*hdr));

return btf;
@@ -1118,12 +1159,26 @@ static struct btf *btf_new_empty(struct btf *base_btf)

struct btf *btf__new_empty(void)
{
- return libbpf_ptr(btf_new_empty(NULL));
+ LIBBPF_OPTS(btf_new_opts, opts);
+
+ return libbpf_ptr(btf_new_empty(&opts));
}

struct btf *btf__new_empty_split(struct btf *base_btf)
{
- return libbpf_ptr(btf_new_empty(base_btf));
+ LIBBPF_OPTS(btf_new_opts, opts);
+
+ opts.base_btf = base_btf;
+
+ return libbpf_ptr(btf_new_empty(&opts));
+}
+
+struct btf *btf__new_empty_opts(struct btf_new_opts *opts)
+{
+ if (!OPTS_VALID(opts, btf_new_opts))
+ return libbpf_err_ptr(-EINVAL);
+
+ return libbpf_ptr(btf_new_empty(opts));
}

static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, bool is_mmap)
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index cc01494d6210..dcc166834937 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -109,6 +109,26 @@ LIBBPF_API struct btf *btf__new_empty(void);
*/
LIBBPF_API struct btf *btf__new_empty_split(struct btf *base_btf);

+struct btf_new_opts {
+ size_t sz;
+ struct btf *base_btf; /* optional base BTF */
+ bool add_kind_layout; /* add BTF kind layout information */
+ size_t:0;
+};
+#define btf_new_opts__last_field add_kind_layout
+
+/**
+ * @brief **btf__new_empty_opts()** creates an unpopulated BTF object with
+ * optional *base_btf* and BTF kind layout description if *add_kind_layout*
+ * is set
+ * @return new BTF object instance which has to be eventually freed with
+ * **btf__free()**
+ *
+ * On error, NULL is returned and the thread-local `errno` variable is
+ * set to the error code.
+ */
+LIBBPF_API struct btf *btf__new_empty_opts(struct btf_new_opts *opts);
+
/**
* @brief **btf__distill_base()** creates new versions of the split BTF
* *src_btf* and its base BTF. The new base BTF will only contain the types
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 84fb90a016c9..0fb9a1f70e72 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -453,4 +453,5 @@ LIBBPF_1.7.0 {
bpf_map__exclusive_program;
bpf_prog_assoc_struct_ops;
bpf_program__assoc_struct_ops;
+ btf__new_empty_opts;
} LIBBPF_1.6.0;
--
2.43.5