public inbox for dwarves@vger.kernel.org
 help / color / mirror / Atom feed
From: Ihor Solodrai <ihor.solodrai@linux.dev>
To: dwarves@vger.kernel.org, alan.maguire@oracle.com, acme@kernel.org
Cc: bpf@vger.kernel.org, andrii@kernel.org, ast@kernel.org,
	eddyz87@gmail.com, tj@kernel.org, kernel-team@meta.com
Subject: [PATCH dwarves v1 3/3] btf_encoder: support kfuncs with KF_MAGIC_ARGS flag
Date: Wed, 29 Oct 2025 12:02:49 -0700	[thread overview]
Message-ID: <20251029190249.3323752-4-ihor.solodrai@linux.dev> (raw)
In-Reply-To: <20251029190249.3323752-1-ihor.solodrai@linux.dev>

For BPF kernel functions marked with KF_MAGIC_ARGS flag we emit two
functions to BTF:
  * kfunc_impl() with prototype that matches kernel declaration
  * kfunc() with prototype that omits __magic arguments

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 btf_encoder.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 2 deletions(-)

diff --git a/btf_encoder.c b/btf_encoder.c
index b730280..7a10be3 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -48,6 +48,7 @@
 #define KF_ARENA_RET  (1 << 13)
 #define KF_ARENA_ARG1 (1 << 14)
 #define KF_ARENA_ARG2 (1 << 15)
+#define KF_MAGIC_ARGS (1 << 16)
 
 struct btf_id_and_flag {
 	uint32_t id;
@@ -1404,8 +1405,8 @@ static int32_t btf_encoder__add_func(struct btf_encoder *encoder,
 	return btf_fn_id;
 }
 
-static int btf_encoder__add_bpf_kfunc(struct btf_encoder *encoder,
-				      struct btf_encoder_func_state *state)
+static int btf_encoder__add_bpf_kfunc_instance(struct btf_encoder *encoder,
+					       struct btf_encoder_func_state *state)
 {
 	int btf_fn_id, err;
 
@@ -1426,6 +1427,122 @@ static int btf_encoder__add_bpf_kfunc(struct btf_encoder *encoder,
 	return 0;
 }
 
+static inline bool str_ends_with(const char *str, const char *suffix)
+{
+	int suffix_len = strlen(suffix);
+	int str_len = strlen(str);
+
+	if (str_len < suffix_len)
+		return false;
+
+	return strcmp(str + str_len - suffix_len, suffix) == 0;
+}
+
+#define BPF_KF_IMPL_SUFFIX "_impl"
+#define BPF_KF_ARG_MAGIC_SUFFIX "__magic"
+
+static inline bool btf__is_kf_magic_arg(const struct btf *btf, const struct btf_encoder_func_parm *p)
+{
+	const char *name;
+
+	name = btf__name_by_offset(btf, p->name_off);
+	if (!name)
+		return false;
+
+	return str_ends_with(name, BPF_KF_ARG_MAGIC_SUFFIX);
+}
+
+/*
+ * A kfunc with KF_MAGIC_ARGS flag has some number of arguments set implicitly by the BPF
+ * verifier. Such arguments are identified by __magic suffix in the argument name.
+ * process_kfunc_magic_args() checks the arguments from last to first, and returns the number of
+ * magic arguments. Note that *all* magic arguments must come after *all* normal arguments in the
+ * function signature. If this assumption is violated, or if no __magic arguments are found,
+ * process_kfunc_magic_args() returns an error.
+ */
+static int process_kfunc_magic_args(struct btf_encoder_func_state *state)
+{
+	const struct btf *btf = state->encoder->btf;
+	const struct btf_encoder_func_parm *p;
+	int cnt = 0, i;
+
+	for (i = state->nr_parms - 1; i >= 0; i--) {
+		p = &state->parms[i];
+		if (btf__is_kf_magic_arg(btf, p)) {
+			cnt++;
+			if (cnt != state->nr_parms - i)
+				goto out_err;
+		} else if (cnt == 0) {
+			goto out_err;
+		}
+	}
+
+	return cnt;
+
+out_err:
+	btf__log_err(btf, BTF_KIND_FUNC_PROTO, state->elf->name, true, 0,
+		     "return=%u Error emitting BTF func proto for KF_MAGIC_ARGS kfunc: unexpected kfunc signature",
+		     p->type_id);
+	return -1;
+}
+
+/*
+ * For KF_MAGIC_ARGS kfuncs we emit two BTF functions (and protos):
+ *   - bpf_foo_impl(<original kernel args>)
+ *   - bpf_foo(<bpf args w/o magic args>)
+ * We achieve this by creating a temporary btf_encoder_func_state-s
+ */
+static int btf_encoder__add_bpf_kfunc_with_magic_args(struct btf_encoder *encoder,
+						      struct btf_encoder_func_state *state)
+{
+	struct btf_encoder_func_annot tmp_annots[state->nr_annots];
+	struct btf_encoder_func_state tmp_state = *state;
+	struct elf_function tmp_elf = *state->elf;
+	char tmp_name[KSYM_NAME_LEN];
+	int err, i, j, nr_magic_args;
+
+	/* First, add kfunc_impl(), modifying only the name */
+	strcpy(tmp_name, state->elf->name);
+	strcat(tmp_name, BPF_KF_IMPL_SUFFIX);
+	tmp_elf.name = tmp_name;
+	tmp_state.elf = &tmp_elf;
+	err = btf_encoder__add_bpf_kfunc_instance(encoder, &tmp_state);
+	if (err < 0)
+		return -1;
+
+	/* Then add kfunc() with omitted magic arguments */
+	nr_magic_args = process_kfunc_magic_args(state);
+	if (nr_magic_args <= 0)
+		return -1;
+
+	tmp_state.elf = state->elf;
+	tmp_state.nr_parms -= nr_magic_args;
+	j = 0;
+	for (i = 0; i < state->nr_annots; i++) {
+		if (state->annots[i].component_idx < tmp_state.nr_parms)
+			tmp_annots[j++] = state->annots[i];
+	}
+	tmp_state.nr_annots = j;
+	tmp_state.annots = tmp_annots;
+	err = btf_encoder__add_bpf_kfunc_instance(encoder, &tmp_state);
+	if (err < 0)
+		return -1;
+
+	return 0;
+}
+
+static inline int btf_encoder__add_bpf_kfunc(struct btf_encoder *encoder,
+					     struct btf_encoder_func_state *state)
+{
+	uint32_t flags = state->elf->kfunc_flags;
+
+	if (KF_MAGIC_ARGS & flags)
+		return btf_encoder__add_bpf_kfunc_with_magic_args(encoder, state);
+
+	return btf_encoder__add_bpf_kfunc_instance(encoder, state);
+}
+
+
 static int elf_function__name_cmp(const void *_a, const void *_b)
 {
 	const struct elf_function *a = _a;
-- 
2.51.1


  parent reply	other threads:[~2025-10-29 19:03 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-29 19:02 [PATCH dwarves v1 0/3] btf_encoder: support for BPF magic kernel functions Ihor Solodrai
2025-10-29 19:02 ` [PATCH dwarves v1 1/3] btf_encoder: refactor btf_encoder__add_func_proto Ihor Solodrai
2025-10-30  0:34   ` Eduard Zingerman
2025-10-29 19:02 ` [PATCH dwarves v1 2/3] btf_encoder: factor out btf_encoder__add_bpf_kfunc() Ihor Solodrai
2025-10-29 19:02 ` Ihor Solodrai [this message]
2025-11-04 20:59 ` [PATCH dwarves v1 0/3] btf_encoder: support for BPF magic kernel functions Alan Maguire
2025-11-04 22:25   ` Ihor Solodrai
2025-11-04 22:33     ` Eduard Zingerman
2025-11-04 22:37       ` Ihor Solodrai
2025-11-14 18:33     ` 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=20251029190249.3323752-4-ihor.solodrai@linux.dev \
    --to=ihor.solodrai@linux.dev \
    --cc=acme@kernel.org \
    --cc=alan.maguire@oracle.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=dwarves@vger.kernel.org \
    --cc=eddyz87@gmail.com \
    --cc=kernel-team@meta.com \
    --cc=tj@kernel.org \
    /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