libbpf: Add layout encoding support

Support encoding of BTF layout data via btf__new_empty_opts().

Current supported opts are base_btf and add_layout.

Layout information is maintained in btf.c in the layouts[] array;
when BTF is created with the add_layout option it represents the
current view of supported BTF kinds.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260326145444.2076244-5-alan.maguire@oracle.com
This commit is contained in:
Alan Maguire
2026-03-26 14:54:39 +00:00
committed by Andrii Nakryiko
parent 2ecbe53e0e
commit d686d92c40
3 changed files with 83 additions and 2 deletions

View File

@@ -29,6 +29,36 @@
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.
*/
static struct btf_layout layouts[NR_BTF_KINDS] = {
/* singular element size vlen element(s) size flags */
[BTF_KIND_UNKN] = { 0, 0, 0 },
[BTF_KIND_INT] = { sizeof(__u32), 0, 0 },
[BTF_KIND_PTR] = { 0, 0, 0 },
[BTF_KIND_ARRAY] = { sizeof(struct btf_array), 0, 0 },
[BTF_KIND_STRUCT] = { 0, sizeof(struct btf_member), 0 },
[BTF_KIND_UNION] = { 0, sizeof(struct btf_member), 0 },
[BTF_KIND_ENUM] = { 0, sizeof(struct btf_enum), 0 },
[BTF_KIND_FWD] = { 0, 0, 0 },
[BTF_KIND_TYPEDEF] = { 0, 0, 0 },
[BTF_KIND_VOLATILE] = { 0, 0, 0 },
[BTF_KIND_CONST] = { 0, 0, 0 },
[BTF_KIND_RESTRICT] = { 0, 0, 0 },
[BTF_KIND_FUNC] = { 0, 0, 0 },
[BTF_KIND_FUNC_PROTO] = { 0, sizeof(struct btf_param), 0 },
[BTF_KIND_VAR] = { sizeof(struct btf_var), 0, 0 },
[BTF_KIND_DATASEC] = { 0, sizeof(struct btf_var_secinfo), 0 },
[BTF_KIND_FLOAT] = { 0, 0, 0 },
[BTF_KIND_DECL_TAG] = { sizeof(struct btf_decl_tag), 0, 0 },
[BTF_KIND_TYPE_TAG] = { 0, 0, 0 },
[BTF_KIND_ENUM64] = { 0, sizeof(struct btf_enum64), 0 },
};
struct btf {
/* raw BTF data in native endianness */
void *raw_data;
@@ -1179,8 +1209,10 @@ 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)
{
bool add_layout = OPTS_GET(opts, add_layout, false);
struct btf *base_btf = OPTS_GET(opts, base_btf, NULL);
struct btf_header *hdr;
struct btf *btf;
@@ -1205,6 +1237,8 @@ static struct btf *btf_new_empty(struct btf *base_btf)
/* +1 for empty string at offset 0 */
btf->raw_size = sizeof(struct btf_header) + (base_btf ? 0 : 1);
if (add_layout)
btf->raw_size += sizeof(layouts);
btf->raw_data = calloc(1, btf->raw_size);
if (!btf->raw_data) {
free(btf);
@@ -1219,6 +1253,19 @@ static struct btf *btf_new_empty(struct btf *base_btf)
btf->types_data = btf->raw_data + hdr->hdr_len;
btf->strs_data = btf->raw_data + hdr->hdr_len;
hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
if (add_layout) {
hdr->layout_len = sizeof(layouts);
btf->layout = layouts;
/*
* No need to swap endianness here as btf_get_raw_data()
* will do this for us if btf->swapped_endian is true.
*/
memcpy(btf->raw_data + hdr->hdr_len, layouts, sizeof(layouts));
btf->strs_data += sizeof(layouts);
hdr->str_off += sizeof(layouts);
}
memcpy(&btf->hdr, hdr, sizeof(*hdr));
return btf;
@@ -1231,7 +1278,19 @@ struct btf *btf__new_empty(void)
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)

View File

@@ -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_layout; /* add BTF layout information */
size_t:0;
};
#define btf_new_opts__last_field add_layout
/**
* @brief **btf__new_empty_opts()** creates an unpopulated BTF object with
* optional *base_btf* and BTF kind layout description if *add_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

View File

@@ -458,4 +458,6 @@ LIBBPF_1.7.0 {
} LIBBPF_1.6.0;
LIBBPF_1.8.0 {
global:
btf__new_empty_opts;
} LIBBPF_1.7.0;