]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
libbpf: Add layout encoding support
authorAlan Maguire <alan.maguire@oracle.com>
Thu, 26 Mar 2026 14:54:39 +0000 (14:54 +0000)
committerAndrii Nakryiko <andrii@kernel.org>
Thu, 26 Mar 2026 20:53:56 +0000 (13:53 -0700)
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
tools/lib/bpf/btf.c
tools/lib/bpf/btf.h
tools/lib/bpf/libbpf.map

index 291691171ca7a5645ae683bf1971014a392535b5..35b7fb85e1bb4336e4b7f6be20db91b87c870733 100644 (file)
 
 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)
index b30008c267c0d8a0471425a3869ce2028bc2d980..a1f8deca2603395c8f36b3a85671678074924c61 100644 (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
index 5828040f178a8959b1ef4901db3f357dcc1b6731..346fd346666bfc6d927cb40728f25fde6202bd54 100644 (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;