public inbox for dwarves@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers
@ 2025-02-12 20:15 Ihor Solodrai
  2025-02-12 20:15 ` [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs() Ihor Solodrai
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-12 20:15 UTC (permalink / raw)
  To: dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, eddyz87, mykolal, kernel-team

This patch series implements emitting appropriate BTF type tags for
argument and return types of kfuncs marked with KF_ARENA_* flags.

For additional context see the description of BPF patch
"bpf: define KF_ARENA_* flags for bpf_arena kfuncs" [1].

The feature depends on recent changes in libbpf [2].

[1] https://lore.kernel.org/bpf/20250206003148.2308659-1-ihor.solodrai@linux.dev/
[2] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@linux.dev/

v1->v2:
  * Rewrite patch #1 refactoring btf_encoder__tag_kfuncs(): now the
    post-processing step is removed entirely, and kfuncs are tagged in
    btf_encoder__add_func().
  * Nits and renames in patch #2
  * Add patch #4 editing man pages

v1: https://lore.kernel.org/dwarves/20250207021442.155703-1-ihor.solodrai@linux.dev/

Ihor Solodrai (4):
  btf_encoder: refactor btf_encoder__tag_kfuncs()
  btf_encoder: emit type tags for bpf_arena pointers
  pahole: introduce --btf_feature=attributes
  man-pages: describe attributes and remove reproducible_build

 btf_encoder.c      | 282 +++++++++++++++++++++++----------------------
 dwarves.h          |   1 +
 man-pages/pahole.1 |   7 +-
 pahole.c           |  11 ++
 4 files changed, 161 insertions(+), 140 deletions(-)

-- 
2.48.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs()
  2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
@ 2025-02-12 20:15 ` Ihor Solodrai
  2025-02-19  3:25   ` Eduard Zingerman
  2025-02-12 20:15 ` [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-12 20:15 UTC (permalink / raw)
  To: dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, eddyz87, mykolal, kernel-team

btf_encoder__tag_kfuncs() is a post-processing step of BTF encoding,
executed right before BTF is deduped and dumped to the output.

Rewrite btf_encoder__tag_kfuncs() into btf_encoder__collect_kfuncs().
Now it only reads the .BTF_ids section of the ELF, collecting kfunc
information and adding it to corresponding elf_function structs. It is
executed in btf_encoder__new() if tag_kfuncs flag is set. This way
kfunc information is available within entire lifetime of the
btf_encoder.

BTF decl tags for kfuncs are added immediately after the function is
added to BTF in btf_encoder__add_func(). It's done by btf__tag_kfunc()
factored out from the btf_encoder__tag_kfunc().

As a result btf_encoder__tag_kfuncs(), its subroutines and struct
btf_func type are deleted, as they are no longer necessary.

Link: https://lore.kernel.org/dwarves/3782640a577e6945c86d6330bc8a05018a1e5c52.camel@gmail.com/

Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 btf_encoder.c | 192 +++++++++++++++-----------------------------------
 1 file changed, 57 insertions(+), 135 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 511c1ea..965e8f0 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -89,6 +89,8 @@ struct elf_function {
 	const char	*name;
 	char		*alias;
 	size_t		prefixlen;
+	bool		kfunc;
+	uint32_t	kfunc_flags;
 };
 
 struct elf_secinfo {
@@ -145,11 +147,6 @@ struct btf_encoder {
 	struct list_head elf_functions_list;
 };
 
-struct btf_func {
-	const char *name;
-	int	    type_id;
-};
-
 /* Half open interval representing range of addresses containing kfuncs */
 struct btf_kfunc_set_range {
 	uint64_t start;
@@ -1178,6 +1175,39 @@ out:
 	return err;
 }
 
+static int btf__add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const char *kfunc)
+{
+	int err = btf__add_decl_tag(btf, tag, id, -1);
+
+	if (err < 0) {
+		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
+			__func__, kfunc, err);
+		return err;
+	}
+	return 0;
+}
+
+static int btf__tag_kfunc(struct btf *btf, struct elf_function *kfunc, __u32 btf_fn_id)
+{
+	int err;
+
+	/* Note we are unconditionally adding the btf_decl_tag even
+	 * though vmlinux may already contain btf_decl_tags for kfuncs.
+	 * We are ok to do this b/c we will later btf__dedup() to remove
+	 * any duplicates.
+	 */
+	err = btf__add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, btf_fn_id, kfunc->name);
+	if (err < 0)
+		return err;
+
+	if (kfunc->kfunc_flags & KF_FASTCALL) {
+		err = btf__add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, btf_fn_id, kfunc->name);
+		if (err < 0)
+			return err;
+	}
+	return 0;
+}
+
 static int32_t btf_encoder__add_func(struct btf_encoder *encoder,
 				     struct btf_encoder_func_state *state)
 {
@@ -1188,6 +1218,7 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder,
 	const char *value;
 	char tmp_value[KSYM_NAME_LEN];
 	uint16_t idx;
+	int err;
 
 	btf_fnproto_id = btf_encoder__add_func_proto(encoder, NULL, state);
 	name = func->alias ?: func->name;
@@ -1199,6 +1230,16 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder,
 		       name, btf_fnproto_id < 0 ? "proto" : "func");
 		return -1;
 	}
+
+	if (func->kfunc && encoder->tag_kfuncs && !encoder->skip_encoding_decl_tag) {
+		err = btf__tag_kfunc(encoder->btf, func, btf_fn_id);
+		if (err < 0) {
+			fprintf(stderr, "%s: failed to tag kfunc '%s': %d\n",
+				__func__, func->name, err);
+			return err;
+		}
+	}
+
 	if (state->nr_annots == 0)
 		return 0;
 
@@ -1771,116 +1812,10 @@ static char *get_func_name(const char *sym)
 	return func;
 }
 
-static int btf_func_cmp(const void *_a, const void *_b)
-{
-	const struct btf_func *a = _a;
-	const struct btf_func *b = _b;
-
-	return strcmp(a->name, b->name);
-}
-
-/*
- * Collects all functions described in BTF.
- * Returns non-zero on error.
- */
-static int btf_encoder__collect_btf_funcs(struct btf_encoder *encoder, struct gobuffer *funcs)
-{
-	struct btf *btf = encoder->btf;
-	int nr_types, type_id;
-	int err = -1;
-
-	/* First collect all the func entries into an array */
-	nr_types = btf__type_cnt(btf);
-	for (type_id = 1; type_id < nr_types; type_id++) {
-		const struct btf_type *type;
-		struct btf_func func = {};
-		const char *name;
-
-		type = btf__type_by_id(btf, type_id);
-		if (!type) {
-			fprintf(stderr, "%s: malformed BTF, can't resolve type for ID %d\n",
-				__func__, type_id);
-			err = -EINVAL;
-			goto out;
-		}
-
-		if (!btf_is_func(type))
-			continue;
-
-		name = btf__name_by_offset(btf, type->name_off);
-		if (!name) {
-			fprintf(stderr, "%s: malformed BTF, can't resolve name for ID %d\n",
-				__func__, type_id);
-			err = -EINVAL;
-			goto out;
-		}
-
-		func.name = name;
-		func.type_id = type_id;
-		err = gobuffer__add(funcs, &func, sizeof(func));
-		if (err < 0)
-			goto out;
-	}
-
-	/* Now that we've collected funcs, sort them by name */
-	gobuffer__sort(funcs, sizeof(struct btf_func), btf_func_cmp);
-
-	err = 0;
-out:
-	return err;
-}
-
-static int btf__add_kfunc_decl_tag(struct btf *btf, const char *tag, __u32 id, const char *kfunc)
-{
-	int err = btf__add_decl_tag(btf, tag, id, -1);
-
-	if (err < 0) {
-		fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n",
-			__func__, kfunc, err);
-		return err;
-	}
-	return 0;
-}
-
-static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, struct gobuffer *funcs, const char *kfunc, __u32 flags)
-{
-	struct btf_func key = { .name = kfunc };
-	struct btf *btf = encoder->btf;
-	struct btf_func *target;
-	const void *base;
-	unsigned int cnt;
-	int err;
-
-	base = gobuffer__entries(funcs);
-	cnt = gobuffer__nr_entries(funcs);
-	target = bsearch(&key, base, cnt, sizeof(key), btf_func_cmp);
-	if (!target) {
-		fprintf(stderr, "%s: failed to find kfunc '%s' in BTF\n", __func__, kfunc);
-		return -1;
-	}
-
-	/* Note we are unconditionally adding the btf_decl_tag even
-	 * though vmlinux may already contain btf_decl_tags for kfuncs.
-	 * We are ok to do this b/c we will later btf__dedup() to remove
-	 * any duplicates.
-	 */
-	err = btf__add_kfunc_decl_tag(btf, BTF_KFUNC_TYPE_TAG, target->type_id, kfunc);
-	if (err < 0)
-		return err;
-	if (flags & KF_FASTCALL) {
-		err = btf__add_kfunc_decl_tag(btf, BTF_FASTCALL_TAG, target->type_id, kfunc);
-		if (err < 0)
-			return err;
-	}
-
-	return 0;
-}
-
-static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
+static int btf_encoder__collect_kfuncs(struct btf_encoder *encoder)
 {
 	const char *filename = encoder->source_filename;
 	struct gobuffer btf_kfunc_ranges = {};
-	struct gobuffer btf_funcs = {};
 	Elf_Data *symbols = NULL;
 	Elf_Data *idlist = NULL;
 	Elf_Scn *symscn = NULL;
@@ -1977,12 +1912,6 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 	}
 	nr_syms = shdr.sh_size / shdr.sh_entsize;
 
-	err = btf_encoder__collect_btf_funcs(encoder, &btf_funcs);
-	if (err) {
-		fprintf(stderr, "%s: failed to collect BTF funcs\n", __func__);
-		goto out;
-	}
-
 	/* First collect all kfunc set ranges.
 	 *
 	 * Note we choose not to sort these ranges and accept a linear
@@ -2015,12 +1944,12 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 	for (i = 0; i < nr_syms; i++) {
 		const struct btf_kfunc_set_range *ranges;
 		const struct btf_id_and_flag *pair;
+		struct elf_function *elf_fn;
 		unsigned int ranges_cnt;
 		char *func, *name;
 		ptrdiff_t off;
 		GElf_Sym sym;
 		bool found;
-		int err;
 		int j;
 
 		if (!gelf_getsym(symbols, i, &sym)) {
@@ -2061,18 +1990,16 @@ static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder)
 			continue;
 		}
 
-		err = btf_encoder__tag_kfunc(encoder, &btf_funcs, func, pair->flags);
-		if (err) {
-			fprintf(stderr, "%s: failed to tag kfunc '%s'\n", __func__, func);
-			free(func);
-			goto out;
+		elf_fn = btf_encoder__find_function(encoder, func, 0);
+		if (elf_fn) {
+			elf_fn->kfunc = true;
+			elf_fn->kfunc_flags = pair->flags;
 		}
 		free(func);
 	}
 
 	err = 0;
 out:
-	__gobuffer__delete(&btf_funcs);
 	__gobuffer__delete(&btf_kfunc_ranges);
 	if (elf)
 		elf_end(elf);
@@ -2083,7 +2010,6 @@ out:
 
 int btf_encoder__encode(struct btf_encoder *encoder, struct conf_load *conf)
 {
-	bool should_tag_kfuncs;
 	int err;
 	size_t shndx;
 
@@ -2099,15 +2025,6 @@ int btf_encoder__encode(struct btf_encoder *encoder, struct conf_load *conf)
 	if (btf__type_cnt(encoder->btf) == 1)
 		return 0;
 
-	/* Note vmlinux may already contain btf_decl_tag's for kfuncs. So
-	 * take care to call this before btf_dedup().
-	 */
-	should_tag_kfuncs = encoder->tag_kfuncs && !encoder->skip_encoding_decl_tag;
-	if (should_tag_kfuncs && btf_encoder__tag_kfuncs(encoder)) {
-		fprintf(stderr, "%s: failed to tag kfuncs!\n", __func__);
-		return -1;
-	}
-
 	if (btf__dedup(encoder->btf, NULL)) {
 		fprintf(stderr, "%s: btf__dedup failed!\n", __func__);
 		return -1;
@@ -2496,6 +2413,11 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		if (!found_percpu && encoder->verbose)
 			printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION);
 
+		if (encoder->tag_kfuncs) {
+			if (btf_encoder__collect_kfuncs(encoder))
+				goto out_delete;
+		}
+
 		if (encoder->verbose)
 			printf("File %s:\n", cu->filename);
 	}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers
  2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
  2025-02-12 20:15 ` [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs() Ihor Solodrai
@ 2025-02-12 20:15 ` Ihor Solodrai
  2025-02-19  4:36   ` Eduard Zingerman
  2025-02-12 20:15 ` [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes Ihor Solodrai
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-12 20:15 UTC (permalink / raw)
  To: dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, eddyz87, mykolal, kernel-team

When adding a kfunc prototype to BTF, check for the flags indicating
bpf_arena pointers and emit a type tag encoding
__attribute__((address_space(1))) for them. This also requires
updating BTF type ids in the btf_encoder_func_state, which is done as
a side effect in the tagging functions.

This feature depends on recent update in libbpf, supporting arbitrarty
attribute encoding [1].

[1] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@linux.dev/

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
---
 btf_encoder.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 965e8f0..3cec106 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -40,7 +40,13 @@
 #define BTF_SET8_KFUNCS		(1 << 0)
 #define BTF_KFUNC_TYPE_TAG	"bpf_kfunc"
 #define BTF_FASTCALL_TAG       "bpf_fastcall"
-#define KF_FASTCALL            (1 << 12)
+#define BPF_ARENA_ATTR         "address_space(1)"
+
+/* kfunc flags, see include/linux/btf.h in the kernel source */
+#define KF_FASTCALL   (1 << 12)
+#define KF_ARENA_RET  (1 << 13)
+#define KF_ARENA_ARG1 (1 << 14)
+#define KF_ARENA_ARG2 (1 << 15)
 
 struct btf_id_and_flag {
 	uint32_t id;
@@ -731,6 +737,78 @@ static int32_t btf_encoder__tag_type(struct btf_encoder *encoder, uint32_t tag_t
 	return encoder->type_id_off + tag_type;
 }
 
+#if LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 6
+static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
+{
+	const struct btf_type *ptr;
+	int tagged_type_id;
+
+	ptr = btf__type_by_id(btf, ptr_id);
+	if (!btf_is_ptr(ptr))
+		return -EINVAL;
+
+	tagged_type_id = btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr->type);
+	if (tagged_type_id < 0)
+		return tagged_type_id;
+
+	return btf__add_ptr(btf, tagged_type_id);
+}
+
+static int btf__tag_bpf_arena_arg(struct btf *btf, struct btf_encoder_func_state *state, int idx)
+{
+	int id;
+
+	if (state->nr_parms <= idx)
+		return -EINVAL;
+
+	id = btf__tag_bpf_arena_ptr(btf, state->parms[idx].type_id);
+	if (id < 0) {
+		btf__log_err(btf, BTF_KIND_TYPE_TAG, BPF_ARENA_ATTR, true, id,
+			"Error adding BPF_ARENA_ATTR for an argument of kfunc '%s'", state->elf->name);
+		return id;
+	}
+	state->parms[idx].type_id = id;
+
+	return id;
+}
+
+static int btf__add_bpf_arena_type_tags(struct btf *btf, struct btf_encoder_func_state *state)
+{
+	uint32_t flags = state->elf->kfunc_flags;
+	int ret_type_id;
+	int err;
+
+	if (KF_ARENA_RET & flags) {
+		ret_type_id = btf__tag_bpf_arena_ptr(btf, state->ret_type_id);
+		if (ret_type_id < 0) {
+			btf__log_err(btf, BTF_KIND_TYPE_TAG, BPF_ARENA_ATTR, true, ret_type_id,
+				"Error adding BPF_ARENA_ATTR for return type of kfunc '%s'", state->elf->name);
+			return ret_type_id;
+		}
+		state->ret_type_id = ret_type_id;
+	}
+
+	if (KF_ARENA_ARG1 & flags) {
+		err = btf__tag_bpf_arena_arg(btf, state, 0);
+		if (err < 0)
+			return err;
+	}
+
+	if (KF_ARENA_ARG2 & flags) {
+		err = btf__tag_bpf_arena_arg(btf, state, 1);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+#endif // LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 6
+
+static inline bool is_kfunc_state(struct btf_encoder_func_state *state)
+{
+	return state && state->elf && state->elf->kfunc;
+}
+
 static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct ftype *ftype,
 					   struct btf_encoder_func_state *state)
 {
@@ -744,6 +822,12 @@ static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct f
 
 	assert(ftype != NULL || state != NULL);
 
+#if LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 6
+	if (is_kfunc_state(state) && encoder->tag_kfuncs)
+		if (btf__add_bpf_arena_type_tags(encoder->btf, state) < 0)
+			return -1;
+#endif
+
 	/* add btf_type for func_proto */
 	if (ftype) {
 		btf = encoder->btf;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes
  2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
  2025-02-12 20:15 ` [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs() Ihor Solodrai
  2025-02-12 20:15 ` [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
@ 2025-02-12 20:15 ` Ihor Solodrai
  2025-02-19  5:30   ` Eduard Zingerman
  2025-02-12 20:15 ` [PATCH v2 dwarves 4/4] man-pages: describe attributes and remove reproducible_build Ihor Solodrai
  2025-02-13 13:16 ` [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Jiri Olsa
  4 siblings, 1 reply; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-12 20:15 UTC (permalink / raw)
  To: dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, eddyz87, mykolal, kernel-team

Add a feature flag "attributes" (default: false) controlling whether
pahole is allowed to generate BTF attributes: type tags and decl tags
with kind_flag = 1.

This is necessary for backward compatibility, as BPF verifier does not
recognize tags with kind_flag = 1 prior to (at least) 6.14-rc1 [1].

[1] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@linux.dev/

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
---
 btf_encoder.c |  6 ++++--
 dwarves.h     |  1 +
 pahole.c      | 11 +++++++++++
 3 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index 3cec106..fc99ad2 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -136,7 +136,8 @@ struct btf_encoder {
 			  gen_floats,
 			  skip_encoding_decl_tag,
 			  tag_kfuncs,
-			  gen_distilled_base;
+			  gen_distilled_base,
+			  encode_attributes;
 	uint32_t	  array_index_id;
 	struct elf_secinfo *secinfo;
 	size_t             seccnt;
@@ -823,7 +824,7 @@ static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct f
 	assert(ftype != NULL || state != NULL);
 
 #if LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 6
-	if (is_kfunc_state(state) && encoder->tag_kfuncs)
+	if (is_kfunc_state(state) && encoder->tag_kfuncs && encoder->encode_attributes)
 		if (btf__add_bpf_arena_type_tags(encoder->btf, state) < 0)
 			return -1;
 #endif
@@ -2417,6 +2418,7 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
 		encoder->skip_encoding_decl_tag	 = conf_load->skip_encoding_btf_decl_tag;
 		encoder->tag_kfuncs	 = conf_load->btf_decl_tag_kfuncs;
 		encoder->gen_distilled_base = conf_load->btf_gen_distilled_base;
+		encoder->encode_attributes = conf_load->btf_attributes;
 		encoder->verbose	 = verbose;
 		encoder->has_index_type  = false;
 		encoder->need_index_type = false;
diff --git a/dwarves.h b/dwarves.h
index 8234e1a..99ed783 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -89,6 +89,7 @@ struct conf_load {
 	bool			reproducible_build;
 	bool			btf_decl_tag_kfuncs;
 	bool			btf_gen_distilled_base;
+	bool			btf_attributes;
 	uint8_t			hashtable_bits;
 	uint8_t			max_hashtable_bits;
 	uint16_t		kabi_prefix_len;
diff --git a/pahole.c b/pahole.c
index af3e1cf..0bda249 100644
--- a/pahole.c
+++ b/pahole.c
@@ -1152,6 +1152,7 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
 #define ARG_padding_ge		   347
 #define ARG_padding		   348
 #define ARGP_with_embedded_flexible_array 349
+#define ARGP_btf_attributes	   350
 
 /* --btf_features=feature1[,feature2,..] allows us to specify
  * a list of requested BTF features or "default" to enable all default
@@ -1210,6 +1211,9 @@ struct btf_feature {
 	BTF_NON_DEFAULT_FEATURE(distilled_base, btf_gen_distilled_base, false),
 #endif
 	BTF_NON_DEFAULT_FEATURE(global_var, encode_btf_global_vars, false),
+#if LIBBPF_MAJOR_VERSION >= 1 && LIBBPF_MINOR_VERSION >= 6
+	BTF_NON_DEFAULT_FEATURE(attributes, btf_attributes, false),
+#endif
 };
 
 #define BTF_MAX_FEATURE_STR	1024
@@ -1785,6 +1789,11 @@ static const struct argp_option pahole__options[] = {
 		.key = ARGP_running_kernel_vmlinux,
 		.doc = "Search for, possibly getting from a debuginfo server, a vmlinux matching the running kernel build-id (from /sys/kernel/notes)"
 	},
+	{
+		.name = "btf_attributes",
+		.key  = ARGP_btf_attributes,
+		.doc  = "Allow generation of attributes in BTF. Attributes are the type tags and decl tags with the kind_flag set to 1.",
+	},
 	{
 		.name = NULL,
 	}
@@ -1979,6 +1988,8 @@ static error_t pahole__options_parser(int key, char *arg,
 		show_supported_btf_features(stdout);	exit(0);
 	case ARGP_btf_features_strict:
 		parse_btf_features(arg, true);		break;
+	case ARGP_btf_attributes:
+		conf_load.btf_attributes = true;	break;
 	default:
 		return ARGP_ERR_UNKNOWN;
 	}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 dwarves 4/4] man-pages: describe attributes and remove reproducible_build
  2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
                   ` (2 preceding siblings ...)
  2025-02-12 20:15 ` [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes Ihor Solodrai
@ 2025-02-12 20:15 ` Ihor Solodrai
  2025-02-13 13:16 ` [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Jiri Olsa
  4 siblings, 0 replies; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-12 20:15 UTC (permalink / raw)
  To: dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, eddyz87, mykolal, kernel-team

Add a description of the new --btf_feature=attributes.

Also remove reproducible_build description, as it is now a moot
feature flag.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 man-pages/pahole.1 | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/man-pages/pahole.1 b/man-pages/pahole.1
index 39e7b46..3125de3 100644
--- a/man-pages/pahole.1
+++ b/man-pages/pahole.1
@@ -327,9 +327,10 @@ Encode BTF using the specified feature list, or specify 'default' for all standa
 Supported non-standard features (not enabled for 'default')
 
 .nf
-	reproducible_build Ensure generated BTF is consistent every time;
-	                   without this parallel BTF encoding can result in
-	                   inconsistent BTF ids.
+	attributes         Allow generation of decl_tags and type_tags with
+	                   kind_flag = 1. These tags can be used to encode
+	                   arbitrary compiler attributes in BTF, but are
+	                   backward incompatible.
 	decl_tag_kfuncs    Inject a BTF_KIND_DECL_TAG for each discovered kfunc.
 	distilled_base     For split BTF, generate a distilled version of
 	                   the associated base BTF to support later relocation
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers
  2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
                   ` (3 preceding siblings ...)
  2025-02-12 20:15 ` [PATCH v2 dwarves 4/4] man-pages: describe attributes and remove reproducible_build Ihor Solodrai
@ 2025-02-13 13:16 ` Jiri Olsa
  4 siblings, 0 replies; 11+ messages in thread
From: Jiri Olsa @ 2025-02-13 13:16 UTC (permalink / raw)
  To: Ihor Solodrai
  Cc: dwarves, bpf, acme, alan.maguire, ast, andrii, eddyz87, mykolal,
	kernel-team

On Wed, Feb 12, 2025 at 12:15:48PM -0800, Ihor Solodrai wrote:
> This patch series implements emitting appropriate BTF type tags for
> argument and return types of kfuncs marked with KF_ARENA_* flags.
> 
> For additional context see the description of BPF patch
> "bpf: define KF_ARENA_* flags for bpf_arena kfuncs" [1].
> 
> The feature depends on recent changes in libbpf [2].
> 
> [1] https://lore.kernel.org/bpf/20250206003148.2308659-1-ihor.solodrai@linux.dev/
> [2] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@linux.dev/
> 
> v1->v2:
>   * Rewrite patch #1 refactoring btf_encoder__tag_kfuncs(): now the
>     post-processing step is removed entirely, and kfuncs are tagged in
>     btf_encoder__add_func().
>   * Nits and renames in patch #2
>   * Add patch #4 editing man pages

lgtm

Reviewed-by: Jiri Olsa <jolsa@kernel.org>

thanks,
jirka

> 
> v1: https://lore.kernel.org/dwarves/20250207021442.155703-1-ihor.solodrai@linux.dev/
> 
> Ihor Solodrai (4):
>   btf_encoder: refactor btf_encoder__tag_kfuncs()
>   btf_encoder: emit type tags for bpf_arena pointers
>   pahole: introduce --btf_feature=attributes
>   man-pages: describe attributes and remove reproducible_build
> 
>  btf_encoder.c      | 282 +++++++++++++++++++++++----------------------
>  dwarves.h          |   1 +
>  man-pages/pahole.1 |   7 +-
>  pahole.c           |  11 ++
>  4 files changed, 161 insertions(+), 140 deletions(-)
> 
> -- 
> 2.48.1
> 
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs()
  2025-02-12 20:15 ` [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs() Ihor Solodrai
@ 2025-02-19  3:25   ` Eduard Zingerman
  0 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2025-02-19  3:25 UTC (permalink / raw)
  To: Ihor Solodrai, dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, mykolal, kernel-team

On Wed, 2025-02-12 at 12:15 -0800, Ihor Solodrai wrote:
> btf_encoder__tag_kfuncs() is a post-processing step of BTF encoding,
> executed right before BTF is deduped and dumped to the output.
> 
> Rewrite btf_encoder__tag_kfuncs() into btf_encoder__collect_kfuncs().
> Now it only reads the .BTF_ids section of the ELF, collecting kfunc
> information and adding it to corresponding elf_function structs. It is
> executed in btf_encoder__new() if tag_kfuncs flag is set. This way
> kfunc information is available within entire lifetime of the
> btf_encoder.
> 
> BTF decl tags for kfuncs are added immediately after the function is
> added to BTF in btf_encoder__add_func(). It's done by btf__tag_kfunc()
> factored out from the btf_encoder__tag_kfunc().
> 
> As a result btf_encoder__tag_kfuncs(), its subroutines and struct

Nit: btf_encoder__collect_btf_funcs() is the one removed,
     btf_encoder__tag_kfuncs is renamed.

> btf_func type are deleted, as they are no longer necessary.
> 
> Link: https://lore.kernel.org/dwarves/3782640a577e6945c86d6330bc8a05018a1e5c52.camel@gmail.com/
> 
> Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>

[...]

>  btf_encoder.c | 192 +++++++++++++++-----------------------------------
>  1 file changed, 57 insertions(+), 135 deletions(-)
> 
> diff --git a/btf_encoder.c b/btf_encoder.c
> index 511c1ea..965e8f0 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c

[...]

> @@ -1199,6 +1230,16 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder,
>  		       name, btf_fnproto_id < 0 ? "proto" : "func");
>  		return -1;
>  	}
> +
> +	if (func->kfunc && encoder->tag_kfuncs && !encoder->skip_encoding_decl_tag) {
> +		err = btf__tag_kfunc(encoder->btf, func, btf_fn_id);
> +		if (err < 0) {
> +			fprintf(stderr, "%s: failed to tag kfunc '%s': %d\n",
> +				__func__, func->name, err);

Nit: btf__tag_kfunc() already prints to stderr in case of an error,
     this printf is unnecessary.

> +			return err;
> +		}
> +	}
> +
>  	if (state->nr_annots == 0)
>  		return 0;
>  

[...]


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers
  2025-02-12 20:15 ` [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
@ 2025-02-19  4:36   ` Eduard Zingerman
  2025-02-19  5:45     ` Eduard Zingerman
  0 siblings, 1 reply; 11+ messages in thread
From: Eduard Zingerman @ 2025-02-19  4:36 UTC (permalink / raw)
  To: Ihor Solodrai, dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, mykolal, kernel-team

On Wed, 2025-02-12 at 12:15 -0800, Ihor Solodrai wrote:

[...]

> diff --git a/btf_encoder.c b/btf_encoder.c
> index 965e8f0..3cec106 100644
> --- a/btf_encoder.c
> +++ b/btf_encoder.c

[...]

> +static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
> +{
> +	const struct btf_type *ptr;
> +	int tagged_type_id;
> +
> +	ptr = btf__type_by_id(btf, ptr_id);
> +	if (!btf_is_ptr(ptr))
> +		return -EINVAL;
> +
> +	tagged_type_id = btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr->type);
> +	if (tagged_type_id < 0)
> +		return tagged_type_id;
> +
> +	return btf__add_ptr(btf, tagged_type_id);
> +}

I might be confused, but this is a bit strange.
The type constructed here is: ptr -> type_tag -> t.
However, address_space is an attribute of a pointer, not a pointed type.
I think that correct sequence should be: type_tag -> ptr -> t.
This would make libbpf emit C declaration as follows:

  void * __attribute__((address_space(1))) ptr;

Instead of current:

  void __attribute__((address_space(1))) * ptr;

clang generates identical IR for both declarations:

  @ptr = dso_local global ptr addrspace(1) null, align 8

Thus, imo, this function should be simplified as below:

  static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
  {
	const struct btf_type *ptr;

	ptr = btf__type_by_id(btf, ptr_id);
	if (!btf_is_ptr(ptr))
		return -EINVAL;

	return btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr_id);
  }

[...]


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes
  2025-02-12 20:15 ` [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes Ihor Solodrai
@ 2025-02-19  5:30   ` Eduard Zingerman
  0 siblings, 0 replies; 11+ messages in thread
From: Eduard Zingerman @ 2025-02-19  5:30 UTC (permalink / raw)
  To: Ihor Solodrai, dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, mykolal, kernel-team

On Wed, 2025-02-12 at 12:15 -0800, Ihor Solodrai wrote:
> Add a feature flag "attributes" (default: false) controlling whether
> pahole is allowed to generate BTF attributes: type tags and decl tags
> with kind_flag = 1.
> 
> This is necessary for backward compatibility, as BPF verifier does not
> recognize tags with kind_flag = 1 prior to (at least) 6.14-rc1 [1].
> 
> [1] https://lore.kernel.org/bpf/20250130201239.1429648-1-ihor.solodrai@linux.dev/
> 
> Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
> Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
> ---

Acked-by: Eduard Zingerman <eddyz87@gmail.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers
  2025-02-19  4:36   ` Eduard Zingerman
@ 2025-02-19  5:45     ` Eduard Zingerman
  2025-02-19 18:03       ` Ihor Solodrai
  0 siblings, 1 reply; 11+ messages in thread
From: Eduard Zingerman @ 2025-02-19  5:45 UTC (permalink / raw)
  To: Ihor Solodrai, dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, mykolal, kernel-team

On Tue, 2025-02-18 at 20:36 -0800, Eduard Zingerman wrote:
> On Wed, 2025-02-12 at 12:15 -0800, Ihor Solodrai wrote:
> 
> [...]
> 
> > diff --git a/btf_encoder.c b/btf_encoder.c
> > index 965e8f0..3cec106 100644
> > --- a/btf_encoder.c
> > +++ b/btf_encoder.c
> 
> [...]
> 
> > +static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
> > +{
> > +	const struct btf_type *ptr;
> > +	int tagged_type_id;
> > +
> > +	ptr = btf__type_by_id(btf, ptr_id);
> > +	if (!btf_is_ptr(ptr))
> > +		return -EINVAL;
> > +
> > +	tagged_type_id = btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr->type);
> > +	if (tagged_type_id < 0)
> > +		return tagged_type_id;
> > +
> > +	return btf__add_ptr(btf, tagged_type_id);
> > +}
> 
> I might be confused, but this is a bit strange.
> The type constructed here is: ptr -> type_tag -> t.
> However, address_space is an attribute of a pointer, not a pointed type.
> I think that correct sequence should be: type_tag -> ptr -> t.
> This would make libbpf emit C declaration as follows:
> 
>   void * __attribute__((address_space(1))) ptr;
> 
> Instead of current:
> 
>   void __attribute__((address_space(1))) * ptr;
> 
> clang generates identical IR for both declarations:
> 
>   @ptr = dso_local global ptr addrspace(1) null, align 8
> 
> Thus, imo, this function should be simplified as below:
> 
>   static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
>   {
> 	const struct btf_type *ptr;
> 
> 	ptr = btf__type_by_id(btf, ptr_id);
> 	if (!btf_is_ptr(ptr))
> 		return -EINVAL;
> 
> 	return btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr_id);
>   }
> 
> [...]
>

Ok, this comment can be ignored.
The following C code:

int foo(void * __attribute__((address_space(1))) ptr) {
  return ptr != 0;
}

does not compile, with the following error reported:

test3.c:1:49: error: parameter may not be qualified with an address space
    1 | int foo(void *__attribute__((address_space(1))) ptr) {
      |

While the following works:

int foo(void __attribute__((address_space(1))) *ptr) {
  return ptr != 0;
}

With the following IR generated:

define dso_local i32 @foo(ptr addrspace(1) noundef %0) #0 { ... }

Strange.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers
  2025-02-19  5:45     ` Eduard Zingerman
@ 2025-02-19 18:03       ` Ihor Solodrai
  0 siblings, 0 replies; 11+ messages in thread
From: Ihor Solodrai @ 2025-02-19 18:03 UTC (permalink / raw)
  To: Eduard Zingerman, dwarves, bpf
  Cc: acme, alan.maguire, ast, andrii, mykolal, kernel-team

On 2/18/25 9:45 PM, Eduard Zingerman wrote:
> On Tue, 2025-02-18 at 20:36 -0800, Eduard Zingerman wrote:
>> On Wed, 2025-02-12 at 12:15 -0800, Ihor Solodrai wrote:
>>
>> [...]
>>
>>> diff --git a/btf_encoder.c b/btf_encoder.c
>>> index 965e8f0..3cec106 100644
>>> --- a/btf_encoder.c
>>> +++ b/btf_encoder.c
>>
>> [...]
>>
>>> +static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
>>> +{
>>> +	const struct btf_type *ptr;
>>> +	int tagged_type_id;
>>> +
>>> +	ptr = btf__type_by_id(btf, ptr_id);
>>> +	if (!btf_is_ptr(ptr))
>>> +		return -EINVAL;
>>> +
>>> +	tagged_type_id = btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr->type);
>>> +	if (tagged_type_id < 0)
>>> +		return tagged_type_id;
>>> +
>>> +	return btf__add_ptr(btf, tagged_type_id);
>>> +}
>>
>> I might be confused, but this is a bit strange.
>> The type constructed here is: ptr -> type_tag -> t.
>> However, address_space is an attribute of a pointer, not a pointed type.
>> I think that correct sequence should be: type_tag -> ptr -> t.
>> This would make libbpf emit C declaration as follows:
>>
>>   void * __attribute__((address_space(1))) ptr;
>>
>> Instead of current:
>>
>>   void __attribute__((address_space(1))) * ptr;

I was also confused about this.

The goal I had in mind is reproducing bpf_arena_* function
declarations, which are:

    void __arena* bpf_arena_alloc_pages(void *map, void __arena *addr, __u32 page_cnt,
    				    int node_id, __u64 flags) __ksym __weak;
    void bpf_arena_free_pages(void *map, void __arena *ptr, __u32 page_cnt) __ksym __weak;

AFAIU this is by design. From BTF documentation[1]:

    Currently, BTF_KIND_TYPE_TAG is only emitted for pointer types. It has
    the following btf type chain:

    ptr -> [type_tag]*
        -> [const | volatile | restrict | typedef]*
        -> base_type

    Basically, a pointer type points to zero or more type_tag, then zero
    or more const/volatile/restrict/typedef and finally the base type. The
    base type is one of int, ptr, array, struct, union, enum, func_proto
    and float types.

So yeah, unintuitively a tagged pointer in BTF is actually a pointer
to a tagged type. My guess is, it is so because of how C compilers
interpret type attributes, as evident by an example you've tested.

[1] https://docs.kernel.org/bpf/btf.html#btf-kind-type-tag

>>
>> clang generates identical IR for both declarations:
>>
>>   @ptr = dso_local global ptr addrspace(1) null, align 8
>>
>> Thus, imo, this function should be simplified as below:
>>
>>   static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
>>   {
>> 	const struct btf_type *ptr;
>>
>> 	ptr = btf__type_by_id(btf, ptr_id);
>> 	if (!btf_is_ptr(ptr))
>> 		return -EINVAL;
>>
>> 	return btf__add_type_attr(btf, BPF_ARENA_ATTR, ptr_id);
>>   }
>>
>> [...]
>>
>
> Ok, this comment can be ignored.
> The following C code:
>
> int foo(void * __attribute__((address_space(1))) ptr) {
>   return ptr != 0;
> }
>
> does not compile, with the following error reported:
>
> test3.c:1:49: error: parameter may not be qualified with an address space
>     1 | int foo(void *__attribute__((address_space(1))) ptr) {
>       |
>
> While the following works:
>
> int foo(void __attribute__((address_space(1))) *ptr) {
>   return ptr != 0;
> }
>
> With the following IR generated:
>
> define dso_local i32 @foo(ptr addrspace(1) noundef %0) #0 { ... }
>
> Strange.
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-02-19 18:03 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-12 20:15 [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
2025-02-12 20:15 ` [PATCH v2 dwarves 1/4] btf_encoder: refactor btf_encoder__tag_kfuncs() Ihor Solodrai
2025-02-19  3:25   ` Eduard Zingerman
2025-02-12 20:15 ` [PATCH v2 dwarves 2/4] btf_encoder: emit type tags for bpf_arena pointers Ihor Solodrai
2025-02-19  4:36   ` Eduard Zingerman
2025-02-19  5:45     ` Eduard Zingerman
2025-02-19 18:03       ` Ihor Solodrai
2025-02-12 20:15 ` [PATCH v2 dwarves 3/4] pahole: introduce --btf_feature=attributes Ihor Solodrai
2025-02-19  5:30   ` Eduard Zingerman
2025-02-12 20:15 ` [PATCH v2 dwarves 4/4] man-pages: describe attributes and remove reproducible_build Ihor Solodrai
2025-02-13 13:16 ` [PATCH v2 dwarves 0/4] btf_encoder: emit type tags for bpf_arena pointers Jiri Olsa

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox