From: Mykyta Yatsenko <mykyta.yatsenko5@gmail.com>
To: Alan Maguire <alan.maguire@oracle.com>,
andrii@kernel.org, ast@kernel.org
Cc: daniel@iogearbox.net, martin.lau@linux.dev, eddyz87@gmail.com,
song@kernel.org, yonghong.song@linux.dev,
john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
haoluo@google.com, jolsa@kernel.org, qmo@kernel.org,
ihor.solodrai@linux.dev, dwarves@vger.kernel.org,
bpf@vger.kernel.org, ttreyer@meta.com
Subject: Re: [PATCH v6 bpf-next 02/10] libbpf: Support kind layout section handling in BTF
Date: Sat, 13 Dec 2025 03:37:03 +0000 [thread overview]
Message-ID: <562aa38b-2cf0-490c-98df-0b42e1d5a599@gmail.com> (raw)
In-Reply-To: <20251210203243.814529-3-alan.maguire@oracle.com>
On 12/10/25 20:32, Alan Maguire wrote:
> Support reading in kind layout fixing endian issues on reading;
> also support writing kind layout section to raw BTF object.
> There is not yet an API to populate the kind layout with meaningful
> information.
>
> As part of this, we need to consider multiple valid BTF header
> sizes; the original or the kind layout-extended headers.
> So to support this, the "struct btf" representation is modified
> to always allocate a "struct btf_header" and copy the valid
> portion from the raw data to it; this means we can always safely
> check fields like btf->hdr->kind_layout_len.
>
> Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
> ---
> tools/lib/bpf/btf.c | 200 ++++++++++++++++++++++++++++++--------------
> 1 file changed, 139 insertions(+), 61 deletions(-)
>
> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
> index b136572e889a..737adc560818 100644
> --- a/tools/lib/bpf/btf.c
> +++ b/tools/lib/bpf/btf.c
> @@ -40,42 +40,53 @@ struct btf {
>
> /*
> * When BTF is loaded from an ELF or raw memory it is stored
> - * in a contiguous memory block. The hdr, type_data, and, strs_data
> + * in a contiguous memory block. The type_data, and, strs_data
> * point inside that memory region to their respective parts of BTF
> * representation:
> *
> - * +--------------------------------+
> - * | Header | Types | Strings |
> - * +--------------------------------+
> - * ^ ^ ^
> - * | | |
> - * hdr | |
> - * types_data-+ |
> - * strs_data------------+
> + * +--------------------------------+---------------------+
> + * | Header | Types | Strings |Optional kind layout |
> + * +--------------------------------+---------------------+
> + * ^ ^ ^ ^
> + * | | | |
> + * raw_data | | |
> + * types_data-+ | |
> + * strs_data------------+ |
> + * kind_layout----------------------+
> + *
> + * A separate struct btf_header is allocated for btf->hdr,
> + * and header information is copied into it. This allows us
> + * to handle header data for various header formats; the original,
> + * the extended header with kind layout, etc.
> *
> * If BTF data is later modified, e.g., due to types added or
> * removed, BTF deduplication performed, etc, this contiguous
> - * representation is broken up into three independently allocated
> - * memory regions to be able to modify them independently.
> + * representation is broken up into four independent memory
> + * regions.
> + *
> * raw_data is nulled out at that point, but can be later allocated
> * and cached again if user calls btf__raw_data(), at which point
> - * raw_data will contain a contiguous copy of header, types, and
> - * strings:
> + * raw_data will contain a contiguous copy of header, types, strings
> + * and optionally kind_layout. kind_layout optionally points to a
> + * kind_layout array - this allows us to encode information about
> + * the kinds known at encoding time. If kind_layout is NULL no
> + * kind information is encoded.
> *
> - * +----------+ +---------+ +-----------+
> - * | Header | | Types | | Strings |
> - * +----------+ +---------+ +-----------+
> - * ^ ^ ^
> - * | | |
> - * hdr | |
> - * types_data----+ |
> - * strset__data(strs_set)-----+
> + * +----------+ +---------+ +-----------+ +-----------+
> + * | Header | | Types | | Strings | |kind_layout|
> + * +----------+ +---------+ +-----------+ +-----------+
> + * ^ ^ ^ ^
> + * | | | |
> + * hdr | | |
> + * types_data----+ | |
> + * strset__data(strs_set)-----+ |
> + * kind_layout--------------------------------+
> *
> - * +----------+---------+-----------+
> - * | Header | Types | Strings |
> - * raw_data----->+----------+---------+-----------+
> + * +----------+---------+-----------+---------------------+
> + * | Header | Types | Strings | Optional kind layout|
> + * raw_data----->+----------+---------+-----------+---------------------+
> */
> - struct btf_header *hdr;
> + struct btf_header *hdr; /* separately-allocated header data */
>
> void *types_data;
> size_t types_data_cap; /* used size stored in hdr->type_len */
> @@ -123,6 +134,13 @@ struct btf {
> /* whether raw_data is a (read-only) mmap */
> bool raw_data_is_mmap;
>
> + /* is BTF modifiable? i.e. is it split into separate sections as described above? */
> + bool modifiable;
> + /* Points either at raw kind layout data in parsed BTF (if present), or
> + * at an allocated kind layout array when BTF is modifiable.
> + */
> + void *kind_layout;
> +
> /* BTF object FD, if loaded into kernel */
> int fd;
>
> @@ -214,7 +232,7 @@ static int btf_add_type_idx_entry(struct btf *btf, __u32 type_off)
> return 0;
> }
>
> -static void btf_bswap_hdr(struct btf_header *h)
> +static void btf_bswap_hdr(struct btf_header *h, __u32 hdr_len)
> {
> h->magic = bswap_16(h->magic);
> h->hdr_len = bswap_32(h->hdr_len);
> @@ -222,50 +240,68 @@ static void btf_bswap_hdr(struct btf_header *h)
> h->type_len = bswap_32(h->type_len);
> h->str_off = bswap_32(h->str_off);
> h->str_len = bswap_32(h->str_len);
> + /* May be operating on raw data with hdr_len that does not include below fields */
> + if (hdr_len >= sizeof(struct btf_header)) {
> + h->kind_layout_off = bswap_32(h->kind_layout_off);
> + h->kind_layout_len = bswap_32(h->kind_layout_len);
> + }
> }
>
> static int btf_parse_hdr(struct btf *btf)
> {
> - struct btf_header *hdr = btf->hdr;
> + struct btf_header *hdr = btf->raw_data;
> + __u32 hdr_len = hdr->hdr_len;
> __u32 meta_left;
>
> - if (btf->raw_size < sizeof(struct btf_header)) {
> + if (btf->raw_size < offsetofend(struct btf_header, str_len)) {
> pr_debug("BTF header not found\n");
> return -EINVAL;
> }
>
> if (hdr->magic == bswap_16(BTF_MAGIC)) {
> btf->swapped_endian = true;
> - if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) {
> + hdr_len = bswap_32(hdr->hdr_len);
> + if (hdr_len < offsetofend(struct btf_header, str_len)) {
> pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n",
> - bswap_32(hdr->hdr_len));
> + hdr_len);
> return -ENOTSUP;
> }
> - btf_bswap_hdr(hdr);
> } else if (hdr->magic != BTF_MAGIC) {
> pr_debug("Invalid BTF magic: %x\n", hdr->magic);
> return -EINVAL;
> }
>
> - if (btf->raw_size < hdr->hdr_len) {
> + if (btf->raw_size < hdr_len) {
> pr_debug("BTF header len %u larger than data size %u\n",
> - hdr->hdr_len, btf->raw_size);
> + hdr_len, btf->raw_size);
> return -EINVAL;
> }
>
> - meta_left = btf->raw_size - hdr->hdr_len;
> - if (meta_left < (long long)hdr->str_off + hdr->str_len) {
> + /* At this point, we have basic header information, so allocate btf->hdr */
> + btf->hdr = calloc(1, sizeof(struct btf_header));
> + if (!btf->hdr) {
> + pr_debug("BTF header allocation failed\n");
> + return -ENOMEM;
> + }
> + if (btf->swapped_endian)
> + btf_bswap_hdr(hdr, hdr_len);
> + memcpy(btf->hdr, hdr, hdr_len < sizeof(struct btf_header) ? hdr_len :
> + sizeof(struct btf_header));
can we simplify this a little bit: memcpy(btf->hdr, hdr, min(hdr_len,
sizeof(struct btf_header));?
min macro is available in libbpf_internal.h
> +
> + meta_left = btf->raw_size - hdr_len;
> + if (meta_left < (long long)btf->hdr->str_off + btf->hdr->str_len) {
> pr_debug("Invalid BTF total size: %u\n", btf->raw_size);
> return -EINVAL;
> }
>
> - if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) {
> + if ((long long)btf->hdr->type_off + btf->hdr->type_len > btf->hdr->str_off) {
> pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n",
> - hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len);
> + btf->hdr->type_off, btf->hdr->type_len, btf->hdr->str_off,
> + btf->hdr->str_len);
> return -EINVAL;
> }
>
> - if (hdr->type_off % 4) {
> + if (btf->hdr->type_off % 4) {
> pr_debug("BTF type section is not aligned to 4 bytes\n");
> return -EINVAL;
> }
> @@ -292,6 +328,22 @@ static int btf_parse_str_sec(struct btf *btf)
> return 0;
> }
>
> +static int btf_parse_kind_layout_sec(struct btf *btf)
> +{
> + const struct btf_header *hdr = btf->hdr;
> +
> + if (!hdr->kind_layout_off || !hdr->kind_layout_len)
> + return 0;
> +
> + if (hdr->kind_layout_len % sizeof(struct btf_kind_layout) != 0) {
> + pr_debug("Invalid BTF kind layout section\n");
> + return -EINVAL;
> + }
> + btf->kind_layout = btf->raw_data + btf->hdr->hdr_len + btf->hdr->kind_layout_off;
> +
> + return 0;
> +}
> +
> static int btf_type_size(const struct btf_type *t)
> {
> const int base_size = sizeof(struct btf_type);
> @@ -951,7 +1003,8 @@ __s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name,
>
> static bool btf_is_modifiable(const struct btf *btf)
> {
> - return (void *)btf->hdr != btf->raw_data;
> + /* BTF is modifiable if split into multiple sections */
> + return btf->modifiable;
> }
>
> static void btf_free_raw_data(struct btf *btf)
> @@ -980,10 +1033,11 @@ void btf__free(struct btf *btf)
> * might still have a cached contiguous raw data present,
> * which will be unconditionally freed below.
> */
> - free(btf->hdr);
> free(btf->types_data);
> strset__free(btf->strs_set);
> + free(btf->kind_layout);
> }
> + free(btf->hdr);
> btf_free_raw_data(btf);
> free(btf->raw_data_swapped);
> free(btf->type_offs);
> @@ -994,6 +1048,7 @@ void btf__free(struct btf *btf)
>
> static struct btf *btf_new_empty(struct btf *base_btf)
> {
> + struct btf_header *hdr;
> struct btf *btf;
>
> btf = calloc(1, sizeof(*btf));
> @@ -1022,14 +1077,20 @@ static struct btf *btf_new_empty(struct btf *base_btf)
> return ERR_PTR(-ENOMEM);
> }
>
> - btf->hdr = btf->raw_data;
> - btf->hdr->hdr_len = sizeof(struct btf_header);
> - btf->hdr->magic = BTF_MAGIC;
> - btf->hdr->version = BTF_VERSION;
> + hdr = btf->raw_data;
> + hdr->hdr_len = sizeof(struct btf_header);
> + hdr->magic = BTF_MAGIC;
> + hdr->version = BTF_VERSION;
>
> - btf->types_data = btf->raw_data + btf->hdr->hdr_len;
> - btf->strs_data = btf->raw_data + btf->hdr->hdr_len;
> - btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */
> + 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 */
> + btf->hdr = calloc(1, sizeof(struct btf_header));
> + if (!btf->hdr) {
> + free(btf);
> + return ERR_PTR(-ENOMEM);
> + }
> + memcpy(btf->hdr, hdr, sizeof(*hdr));
>
> return btf;
> }
> @@ -1078,7 +1139,6 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b
>
> btf->raw_size = size;
>
> - btf->hdr = btf->raw_data;
> err = btf_parse_hdr(btf);
> if (err)
> goto done;
> @@ -1087,6 +1147,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b
> btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off;
>
> err = btf_parse_str_sec(btf);
> + err = err ?: btf_parse_kind_layout_sec(btf);
> err = err ?: btf_parse_type_sec(btf);
> err = err ?: btf_sanity_check(btf);
> if (err)
> @@ -1550,6 +1611,11 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi
> }
>
> data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len;
> + if (btf->kind_layout) {
> + data_sz = roundup(data_sz, 4);
> + data_sz += hdr->kind_layout_len;
> + hdr->kind_layout_off = roundup(hdr->type_len + hdr->str_len, 4);
> + }
> data = calloc(1, data_sz);
> if (!data)
> return NULL;
> @@ -1557,7 +1623,7 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi
>
> memcpy(p, hdr, hdr->hdr_len);
> if (swap_endian)
> - btf_bswap_hdr(p);
> + btf_bswap_hdr(p, hdr->hdr_len);
> p += hdr->hdr_len;
>
> memcpy(p, btf->types_data, hdr->type_len);
> @@ -1576,7 +1642,11 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi
> p += hdr->type_len;
>
> memcpy(p, btf_strs_data(btf), hdr->str_len);
> - p += hdr->str_len;
> +
> + if (btf->kind_layout) {
> + p = data + hdr->hdr_len + hdr->kind_layout_off;
> + memcpy(p, btf->kind_layout, hdr->kind_layout_len);
> + }
>
> *size = data_sz;
> return data;
> @@ -1717,13 +1787,13 @@ static void btf_invalidate_raw_data(struct btf *btf)
> }
> }
>
> -/* Ensure BTF is ready to be modified (by splitting into a three memory
> - * regions for header, types, and strings). Also invalidate cached
> - * raw_data, if any.
> +/* Ensure BTF is ready to be modified (by splitting into memory regions
> + * for types and strings, with kind layout section if needed (btf->hdr
> + * is already a separate region). Also invalidate cached raw_data, if any.
> */
> static int btf_ensure_modifiable(struct btf *btf)
> {
> - void *hdr, *types;
> + void *types, *kind_layout = NULL;
> struct strset *set = NULL;
> int err = -ENOMEM;
>
> @@ -1733,15 +1803,20 @@ static int btf_ensure_modifiable(struct btf *btf)
> return 0;
> }
>
> - /* split raw data into three memory regions */
> - hdr = malloc(btf->hdr->hdr_len);
> + /* split raw data into memory regions; btf->hdr is done already. */
> types = malloc(btf->hdr->type_len);
> - if (!hdr || !types)
> + if (!types)
> goto err_out;
> -
> - memcpy(hdr, btf->hdr, btf->hdr->hdr_len);
> memcpy(types, btf->types_data, btf->hdr->type_len);
>
> + if (btf->hdr->kind_layout_len && btf->hdr->kind_layout_off) {
> + kind_layout = malloc(btf->hdr->kind_layout_len);
> + if (!kind_layout)
> + goto err_out;
> + memcpy(kind_layout, btf->raw_data + btf->hdr->hdr_len + btf->hdr->kind_layout_off,
> + btf->hdr->kind_layout_len);
> + }
> +
> /* build lookup index for all strings */
> set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len);
> if (IS_ERR(set)) {
> @@ -1750,11 +1825,12 @@ static int btf_ensure_modifiable(struct btf *btf)
> }
>
> /* only when everything was successful, update internal state */
> - btf->hdr = hdr;
> btf->types_data = types;
> btf->types_data_cap = btf->hdr->type_len;
> btf->strs_data = NULL;
> btf->strs_set = set;
> + if (kind_layout)
> + btf->kind_layout = kind_layout;
> /* if BTF was created from scratch, all strings are guaranteed to be
> * unique and deduplicated
> */
> @@ -1766,12 +1842,14 @@ static int btf_ensure_modifiable(struct btf *btf)
> /* invalidate raw_data representation */
> btf_invalidate_raw_data(btf);
>
> + btf->modifiable = true;
> +
> return 0;
>
> err_out:
> strset__free(set);
> - free(hdr);
> free(types);
> + free(kind_layout);
> return err;
> }
>
next prev parent reply other threads:[~2025-12-13 3:37 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-10 20:32 [PATCH v6 bpf-next 00/10] Add kind layout to BTF Alan Maguire
2025-12-10 20:32 ` [PATCH v6 bpf-next 01/10] btf: add kind layout encoding to UAPI Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-13 2:52 ` Mykyta Yatsenko
2025-12-10 20:32 ` [PATCH v6 bpf-next 02/10] libbpf: Support kind layout section handling in BTF Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-11 8:31 ` Alan Maguire
2025-12-13 3:37 ` Mykyta Yatsenko [this message]
2025-12-10 20:32 ` [PATCH v6 bpf-next 03/10] libbpf: use kind layout to compute an unknown kind size Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-11 8:33 ` Alan Maguire
2025-12-13 3:51 ` Mykyta Yatsenko
2025-12-10 20:32 ` [PATCH v6 bpf-next 04/10] libbpf: Add kind layout encoding support Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-11 8:36 ` Alan Maguire
2025-12-11 10:23 ` Alan Maguire
2025-12-10 20:32 ` [PATCH v6 bpf-next 05/10] libbpf: BTF validation can use kind layout for unknown kinds Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-10 20:32 ` [PATCH v6 bpf-next 06/10] btf: support kernel parsing of BTF with kind layout Alan Maguire
2025-12-10 20:32 ` [PATCH v6 bpf-next 07/10] selftests/bpf: test kind encoding/decoding Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-10 20:32 ` [PATCH v6 bpf-next 08/10] bpftool: add BTF dump "format meta" to dump header/metadata Alan Maguire
2025-12-10 20:55 ` bot+bpf-ci
2025-12-10 20:32 ` [PATCH v6 bpf-next 09/10] bpftool: Update doc to describe bpftool btf dump .. format metadata Alan Maguire
2025-12-10 20:32 ` [PATCH v6 bpf-next 10/10] kbuild, bpf: Specify "kind_layout" optional feature Alan Maguire
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=562aa38b-2cf0-490c-98df-0b42e1d5a599@gmail.com \
--to=mykyta.yatsenko5@gmail.com \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dwarves@vger.kernel.org \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=martin.lau@linux.dev \
--cc=qmo@kernel.org \
--cc=sdf@fomichev.me \
--cc=song@kernel.org \
--cc=ttreyer@meta.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.