BPF List
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Eduard Zingerman <eddyz87@gmail.com>,
	kernel-team@fb.com
Subject: [PATCH bpf-next 11/12] selftests/bpf: Cover tracing on >8 and <=16 byte return targets
Date: Wed,  8 Jul 2026 13:10:36 -0700	[thread overview]
Message-ID: <20260708201036.2162000-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260708200939.2153664-1-yonghong.song@linux.dev>

Tracing attach types differ in whether they need the target's return value
preserved across the BPF trampoline, which saves and restores only 8 bytes
of it. fentry runs before the target returns and never observes the return
value, so it can attach to a function returning a >8 byte value; fexit,
fmod_ret and fsession read the return value and must keep rejecting such a
target.

Add fentry, fexit, fentry_multi and fexit_multi tests that attach to
functions returning a >8 and <=16 byte value (a 16-byte struct and an
__int128).

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
 .../selftests/bpf/prog_tests/aggregate_ret.c  | 128 ++++++++++++++++++
 .../selftests/bpf/progs/aggregate_ret_trace.c |  44 ++++++
 .../selftests/bpf/test_kmods/bpf_testmod.c    |  32 +++++
 .../selftests/bpf/test_kmods/bpf_testmod.h    |   5 +
 4 files changed, 209 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/aggregate_ret_trace.c

diff --git a/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c b/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
index 2f1e5c704959..7caf815a2c06 100644
--- a/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
+++ b/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
@@ -8,6 +8,7 @@
 #include "aggregate_ret_run.skel.h"
 #include "aggregate_ret_func.skel.h"
 #include "aggregate_ret_kfunc.skel.h"
+#include "aggregate_ret_trace.skel.h"
 
 /*
  * Run one program and check its result. The program returns 0 on success, or
@@ -37,6 +38,131 @@ static void run_prog(struct bpf_program *prog, bool may_skip)
 	ASSERT_EQ(topts.retval, 0, "aggregate_ret_result");
 }
 
+/*
+ * Multi-attach (BPF_TRACE_*_MULTI) requires CONFIG_HAVE_SINGLE_FTRACE_DIRECT_OPS,
+ * which today only x86_64 selects. Otherwise bpf_tracing_multi_attach() returns
+ * -EOPNOTSUPP unconditionally.
+ */
+static bool tracing_multi_supported(struct bpf_program *prog)
+{
+	const char *small_pat = "bpf_testmod:bpf_testmod_trampoline_count_test";
+	struct bpf_link *link;
+
+	link = bpf_program__attach_tracing_multi(prog, small_pat, NULL);
+	if (libbpf_get_error(link) == -EOPNOTSUPP)
+		return false;
+	bpf_link__destroy(link);
+	return true;
+}
+
+static void test_tracing_attach_types(void)
+{
+	const char *i128_pat = "bpf_testmod:bpf_testmod_aggregate_ret_i128_fn";
+	int err;
+
+	if (test__start_subtest("trace_fentry")) {
+		struct aggregate_ret_trace *trace = NULL;
+
+		trace = aggregate_ret_trace__open();
+		if (!ASSERT_OK_PTR(trace, "trace_fentry_open"))
+			return;
+
+		bpf_program__set_autoload(trace->progs.fexit_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fentry_multi, false);
+		bpf_program__set_autoload(trace->progs.fexit_multi, false);
+
+		err = aggregate_ret_trace__load(trace);
+		if (!ASSERT_OK(err, "trace_fentry_load"))
+			goto destroy_trace_fentry;
+
+		err = aggregate_ret_trace__attach(trace);
+		if (!ASSERT_OK(err, "trace_fentry_attach"))
+			goto destroy_trace_fentry;
+
+		ASSERT_OK(trigger_module_test_read(1), "trace_fentry_trigger");
+		ASSERT_EQ(trace->bss->fentry_hit, 1, "trace_fentry_hit");
+
+destroy_trace_fentry:
+		aggregate_ret_trace__destroy(trace);
+	}
+
+	if (test__start_subtest("trace_fexit_reject")) {
+		struct aggregate_ret_trace *trace = NULL;
+
+		trace = aggregate_ret_trace__open();
+		if (!ASSERT_OK_PTR(trace, "trace_fexit_open"))
+			return;
+
+		bpf_program__set_autoload(trace->progs.fentry_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fentry_multi, false);
+		bpf_program__set_autoload(trace->progs.fexit_multi, false);
+
+		err = aggregate_ret_trace__load(trace);
+		ASSERT_EQ(err, -EOPNOTSUPP, "trace_fexit_load");
+
+		aggregate_ret_trace__destroy(trace);
+	}
+
+	if (test__start_subtest("trace_fentry_multi")) {
+		struct aggregate_ret_trace *trace = NULL;
+		struct bpf_link *link;
+
+		trace = aggregate_ret_trace__open();
+		if (!ASSERT_OK_PTR(trace, "trace_fentry_multi_open"))
+			return;
+
+		bpf_program__set_autoload(trace->progs.fentry_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fexit_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fexit_multi, false);
+
+		if (!ASSERT_OK(aggregate_ret_trace__load(trace), "trace_fentry_multi_load"))
+			goto destroy_fentry_multi;
+
+		if (!tracing_multi_supported(trace->progs.fentry_multi)) {
+			test__skip();
+			goto destroy_fentry_multi;
+		}
+
+		link = bpf_program__attach_tracing_multi(trace->progs.fentry_multi, i128_pat, NULL);
+		if (!ASSERT_OK_PTR(link, "trace_fentry_multi_attach"))
+			goto destroy_fentry_multi;
+
+		ASSERT_OK(trigger_module_test_read(1), "trace_fentry_multi_trigger");
+		ASSERT_EQ(trace->bss->fentry_multi_hit, 1, "trace_fentry_multi_hit");
+
+		bpf_link__destroy(link);
+destroy_fentry_multi:
+		aggregate_ret_trace__destroy(trace);
+	}
+
+	if (test__start_subtest("trace_fexit_multi_reject")) {
+		struct aggregate_ret_trace *trace = NULL;
+		struct bpf_link *link;
+
+		trace = aggregate_ret_trace__open();
+		if (!ASSERT_OK_PTR(trace, "trace_fexit_multi_open"))
+			return;
+
+		bpf_program__set_autoload(trace->progs.fentry_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fexit_bpf_testmod_aggregate_ret_fn, false);
+		bpf_program__set_autoload(trace->progs.fentry_multi, false);
+
+		if (!ASSERT_OK(aggregate_ret_trace__load(trace), "trace_fexit_multi_load"))
+			goto destroy_fexit_multi;
+
+		if (!tracing_multi_supported(trace->progs.fexit_multi)) {
+			test__skip();
+			goto destroy_fexit_multi;
+		}
+
+		link = bpf_program__attach_tracing_multi(trace->progs.fexit_multi, i128_pat, NULL);
+		ASSERT_EQ(libbpf_get_error(link), -EOPNOTSUPP, "trace_fexit_multi_reject");
+		bpf_link__destroy(link);
+destroy_fexit_multi:
+		aggregate_ret_trace__destroy(trace);
+	}
+}
+
 void test_aggregate_ret(void)
 {
 	struct aggregate_ret_struct_c *skel_struct_c;
@@ -118,4 +244,6 @@ void test_aggregate_ret(void)
 
 	RUN_TESTS(aggregate_ret_func);
 	RUN_TESTS(aggregate_ret_kfunc);
+
+	test_tracing_attach_types();
 }
diff --git a/tools/testing/selftests/bpf/progs/aggregate_ret_trace.c b/tools/testing/selftests/bpf/progs/aggregate_ret_trace.c
new file mode 100644
index 000000000000..ff9fd4036121
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/aggregate_ret_trace.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+struct bpf_testmod_aggregate_ret {
+	__u64 lo;
+	__u64 hi;
+};
+
+int fentry_hit;
+int fexit_hit;
+int fentry_multi_hit;
+
+SEC("fentry/bpf_testmod:bpf_testmod_aggregate_ret_fn")
+int BPF_PROG2(fentry_bpf_testmod_aggregate_ret_fn, __u64, lo, __u64, hi)
+{
+	fentry_hit++;
+	return 0;
+}
+
+SEC("fexit/bpf_testmod:bpf_testmod_aggregate_ret_fn")
+int BPF_PROG2(fexit_bpf_testmod_aggregate_ret_fn, __u64, lo, __u64, hi,
+	      struct bpf_testmod_aggregate_ret, ret)
+{
+	fexit_hit += ret.lo == lo && ret.hi == hi;
+	return 0;
+}
+
+SEC("fentry.multi/bpf_testmod:bpf_testmod_aggregate_ret_i128_fn")
+int BPF_PROG(fentry_multi)
+{
+	fentry_multi_hit++;
+	return 0;
+}
+
+SEC("fexit.multi/bpf_testmod:bpf_testmod_aggregate_ret_i128_fn")
+int BPF_PROG(fexit_multi)
+{
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index c9e211d8a719..b558c538400e 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -469,12 +469,34 @@ noinline void bpf_testmod_stacktrace_test_1(void)
 }
 
 int bpf_testmod_fentry_ok;
+u64 bpf_testmod_aggregate_ret_seen;
 
 noinline int bpf_testmod_trampoline_count_test(void)
 {
 	return 0;
 }
 
+__noclone noinline struct bpf_testmod_aggregate_ret
+bpf_testmod_aggregate_ret_fn(u64 lo, u64 hi)
+{
+	struct bpf_testmod_aggregate_ret ret = {
+		.lo = lo,
+		.hi = hi,
+	};
+
+	bpf_testmod_aggregate_ret_seen += lo + hi;
+	return ret;
+}
+
+__noclone noinline __int128
+bpf_testmod_aggregate_ret_i128_fn(u64 lo, u64 hi)
+{
+	__int128 ret = ((__int128)hi << 64) | lo;
+
+	bpf_testmod_aggregate_ret_seen += lo + hi;
+	return ret;
+}
+
 noinline ssize_t
 bpf_testmod_test_read(struct file *file, struct kobject *kobj,
 		      const struct bin_attribute *bin_attr,
@@ -492,6 +514,8 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
 	struct bpf_testmod_struct_arg_5 struct_arg5 = {23, 24, 25, 26};
 	union bpf_testmod_union_arg_1 union_arg1 = { .arg = {1} };
 	union bpf_testmod_union_arg_2 union_arg2 = { .arg = {2, 3} };
+	struct bpf_testmod_aggregate_ret agg_ret;
+	__int128 agg_i128;
 	int i = 1;
 
 	while (bpf_testmod_return_ptr(i))
@@ -534,6 +558,14 @@ bpf_testmod_test_read(struct file *file, struct kobject *kobj,
 
 	trace_bpf_testmod_test_nullable_bare_tp(NULL);
 
+	agg_ret = bpf_testmod_aggregate_ret_fn(len, off);
+	if (agg_ret.lo == U64_MAX && agg_ret.hi == U64_MAX)
+		goto out;
+
+	agg_i128 = bpf_testmod_aggregate_ret_i128_fn(len, off);
+	if (agg_i128 == (__int128)-1)
+		goto out;
+
 	/* Magic number to enable writable tp */
 	if (len == 64) {
 		struct bpf_testmod_test_writable_ctx writable = {
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
index 863fd10f1619..4dcbfd64de62 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.h
@@ -25,6 +25,11 @@ struct bpf_testmod_test_writable_ctx {
 	int val;
 };
 
+struct bpf_testmod_aggregate_ret {
+	__u64 lo;
+	__u64 hi;
+};
+
 /* BPF iter that returns *value* *n* times in a row */
 struct bpf_iter_testmod_seq {
 	s64 value;
-- 
2.53.0-Meta


  parent reply	other threads:[~2026-07-08 20:10 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 20:09 [PATCH bpf-next 00/12] bpf: Support 16-byte return values in the R0:R2 register pair Yonghong Song
2026-07-08 20:09 ` [PATCH bpf-next 01/12] bpf: Factor check_global_ret_scalar_reg() out of the global return check Yonghong Song
2026-07-08 20:09 ` [PATCH bpf-next 02/12] bpf: Add verifier support for 16-byte returns in R0:R2 Yonghong Song
2026-07-08 21:17   ` bot+bpf-ci
2026-07-09 16:40     ` Yonghong Song
2026-07-09 22:21   ` Eduard Zingerman
2026-07-10  4:57     ` Yonghong Song
2026-07-08 20:09 ` [PATCH bpf-next 03/12] bpf: Wire up JIT support for 16-byte kfunc returns Yonghong Song
2026-07-10  0:06   ` Eduard Zingerman
2026-07-08 20:10 ` [PATCH bpf-next 04/12] bpf: Track R2 of register-pair returns in precision backtracking Yonghong Song
2026-07-08 21:10   ` bot+bpf-ci
2026-07-09 16:41     ` Yonghong Song
2026-07-10  0:31   ` Eduard Zingerman
2026-07-08 20:10 ` [PATCH bpf-next 05/12] bpf: Account R2 of register-pair returns in live register analysis Yonghong Song
2026-07-08 21:10   ` bot+bpf-ci
2026-07-09 21:07   ` Eduard Zingerman
2026-07-10  5:06     ` Yonghong Song
2026-07-08 20:10 ` [PATCH bpf-next 06/12] bpf: Force JIT for programs using the R0:R2 register pair Yonghong Song
2026-07-08 21:10   ` bot+bpf-ci
2026-07-09  3:15   ` Leon Hwang
2026-07-09 16:44     ` Yonghong Song
2026-07-09 20:30   ` Eduard Zingerman
2026-07-10  5:07     ` Yonghong Song
2026-07-09 22:27   ` Eduard Zingerman
2026-07-10  5:09     ` Yonghong Song
2026-07-08 20:10 ` [PATCH bpf-next 07/12] bpf: Reject >8 byte return values on return-reading trampoline paths Yonghong Song
2026-07-09  3:16   ` Leon Hwang
2026-07-09 16:52     ` Yonghong Song
2026-07-10  2:01       ` Leon Hwang
2026-07-09 23:08   ` Eduard Zingerman
2026-07-10  2:02     ` Leon Hwang
2026-07-10  5:27       ` Yonghong Song
2026-07-10  5:12     ` Yonghong Song
2026-07-08 20:10 ` [PATCH bpf-next 08/12] bpf: Enable 16-byte aggregate return types Yonghong Song
2026-07-08 20:28   ` sashiko-bot
2026-07-09 19:40     ` Yonghong Song
2026-07-10  0:45   ` Eduard Zingerman
2026-07-10  5:29     ` Yonghong Song
2026-07-08 20:10 ` [PATCH bpf-next 09/12] selftests/bpf: Add C tests for 16-byte returns in R0:R2 Yonghong Song
2026-07-08 20:24   ` sashiko-bot
2026-07-09 19:51     ` Yonghong Song
2026-07-08 21:10   ` bot+bpf-ci
2026-07-09 19:54     ` Yonghong Song
2026-07-10  1:19   ` Eduard Zingerman
2026-07-10  5:32     ` Yonghong Song
2026-07-08 20:10 ` [PATCH bpf-next 10/12] selftests/bpf: Add inline-asm and subprog tests for R0:R2 returns Yonghong Song
2026-07-08 20:28   ` sashiko-bot
2026-07-09 19:57     ` Yonghong Song
2026-07-10  1:38   ` Eduard Zingerman
2026-07-10  5:35     ` Yonghong Song
2026-07-08 20:10 ` Yonghong Song [this message]
2026-07-08 20:10 ` [PATCH bpf-next 12/12] Documentation/bpf: Document 16-byte kfunc return values in R0:R2 Yonghong Song
2026-07-10  0:56 ` [PATCH bpf-next 00/12] bpf: Support 16-byte return values in the R0:R2 register pair Eduard Zingerman
2026-07-10  6:00   ` Yonghong Song
2026-07-10  6:13     ` Eduard Zingerman
2026-07-10 15:18       ` Yonghong Song

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=20260708201036.2162000-1-yonghong.song@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=kernel-team@fb.com \
    /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