bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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;
>   }
>   


  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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).