BPF List
 help / color / mirror / Atom feed
From: Anton Protopopov <aspsk@isovalent.com>
To: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Jiri Olsa <jolsa@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Stanislav Fomichev <sdf@google.com>,
	Yonghong Song <yonghong.song@linux.dev>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Quentin Monnet <quentin@isovalent.com>,
	bpf@vger.kernel.org
Cc: Anton Protopopov <aspsk@isovalent.com>
Subject: [PATCH v1 bpf-next 4/9] selftests/bpf: Add tests for instructions mappings
Date: Fri,  2 Feb 2024 16:28:08 +0000	[thread overview]
Message-ID: <20240202162813.4184616-5-aspsk@isovalent.com> (raw)
In-Reply-To: <20240202162813.4184616-1-aspsk@isovalent.com>

Add several self-tests to test the instructions mappings from xlated
to original:

    * check that mappings work for a program without patches
    * same for a program with patches to insns
    * same for a program with patches to insns and bpf-to-bpf calls
    * same for a program with patches and deletions
    * same for a program with patches, deletions, and bpf-to-bpf calls

Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
---
 .../bpf/prog_tests/bpf_insns_mappings.c       | 156 ++++++++++++++++++
 .../selftests/bpf/progs/bpf_insns_mappings.c  | 155 +++++++++++++++++
 2 files changed, 311 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/bpf_insns_mappings.c
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_insns_mappings.c

diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_insns_mappings.c b/tools/testing/selftests/bpf/prog_tests/bpf_insns_mappings.c
new file mode 100644
index 000000000000..2a7b53231080
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_insns_mappings.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2024 Isovalent */
+
+#include <test_progs.h>
+#include "bpf_insns_mappings.skel.h"
+
+#define MAX_INSNS 4096
+
+static struct bpf_prog_info *prog_info_and_mappings(int prog_fd)
+{
+	static __thread struct bpf_prog_info prog_info;
+	static __thread char xlated_insns[MAX_INSNS];
+	static __thread __u32 orig_idx[MAX_INSNS];
+	__u32 prog_info_len;
+	__u32 orig_idx_len;
+	int err;
+
+	prog_info_len = sizeof(prog_info);
+
+	memset(&prog_info, 0, sizeof(prog_info));
+	err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
+	if (!ASSERT_GE(err, 0, "bpf_prog_get_info_by_fd"))
+		return NULL;
+
+	orig_idx_len = prog_info.orig_idx_len;
+	memset(&prog_info, 0, sizeof(prog_info));
+
+	if (orig_idx_len) {
+		prog_info.orig_idx_len = orig_idx_len;
+		prog_info.orig_idx = ptr_to_u64(orig_idx);
+	}
+
+	prog_info.xlated_prog_insns = ptr_to_u64(xlated_insns);
+	prog_info.xlated_prog_len = sizeof(xlated_insns);
+
+	err = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
+	if (!ASSERT_GE(err, 0, "bpf_prog_get_info_by_fd"))
+		return NULL;
+
+	return &prog_info;
+}
+
+static int beef_search_original(const struct bpf_insn *insns, int n_insns, int *idx, int n_max)
+{
+	int i, n_found = 0;
+
+	for (i = 0; i < n_insns; i++) {
+		if (insns[i].imm == 0xbeef) {
+			if (!ASSERT_LT(n_found, n_max, "beef"))
+				return -1;
+			idx[n_found++] = i;
+		}
+	}
+
+	return n_found;
+}
+
+static int beef_search_xlated(struct bpf_prog_info *info, int *idx, int len)
+{
+	struct bpf_insn *insns = u64_to_ptr(info->xlated_prog_insns);
+	int tot = info->xlated_prog_len / 8;
+	int i, n = 0;
+
+	for (i = 0; i < tot; i++) {
+		if (insns[i].imm == 0xbeef) {
+			if (!ASSERT_LT(n, len, "beef"))
+				return -1;
+			idx[n++] = ((__u32 *)u64_to_ptr(info->orig_idx))[i];
+		}
+	}
+
+	return n;
+}
+
+static void beef_check(const struct bpf_program *prog, int n_expected)
+{
+	struct bpf_prog_info *prog_info;
+	int idx_expected[MAX_INSNS];
+	int idx[MAX_INSNS];
+	int prog_fd;
+	int n, i;
+
+	/*
+	 * Find all beef instructions in the original program
+	 */
+
+	n = beef_search_original(bpf_program__insns(prog),
+				 bpf_program__insn_cnt(prog),
+				 idx_expected, MAX_INSNS);
+	if (!ASSERT_EQ(n, n_expected, "search original insns"))
+		return;
+
+	/*
+	 * Now find all the beef instructions in the xlated program and extract
+	 * corresponding orig_idx mappings
+	 */
+	prog_fd = bpf_program__fd(prog);
+	if (!ASSERT_GE(prog_fd, 0, "bpf_program__fd"))
+		return;
+
+	prog_info = prog_info_and_mappings(prog_fd);
+	if (!ASSERT_OK_PTR(prog_info, "prog_info_and_mappings"))
+		return;
+
+	if (!ASSERT_EQ(beef_search_xlated(prog_info, idx, n), n, "total # of beef"))
+		return;
+
+	/*
+	 * Check that the orig_idx points to the correct original indexes
+	 */
+	for (i = 0; i < n; i++)
+		ASSERT_EQ(idx[i], idx_expected[i], "beef index");
+}
+
+static void check_prog(const struct bpf_program *prog, int n_expected)
+{
+	struct bpf_link *link;
+
+	link = bpf_program__attach(prog);
+	if (!ASSERT_OK_PTR(link, "link"))
+		return;
+
+	beef_check(prog, n_expected);
+
+	bpf_link__destroy(link);
+}
+
+void test_bpf_insns_mappings(void)
+{
+	struct bpf_insns_mappings *skel;
+
+	skel = bpf_insns_mappings__open();
+	if (!ASSERT_OK_PTR(skel, "bpf_insns_mappings__open"))
+		return;
+
+	if (!ASSERT_OK(bpf_insns_mappings__load(skel),
+		  "bpf_insns_mappings__load"))
+		return;
+
+	if (test__start_subtest("check_trivial_prog"))
+		check_prog(skel->progs.check_trivial_prog, 3);
+
+	if (test__start_subtest("check_simple_prog"))
+		check_prog(skel->progs.check_simple_prog, 3);
+
+	if (test__start_subtest("check_bpf_to_bpf"))
+		check_prog(skel->progs.check_bpf_to_bpf, 6);
+
+	if (test__start_subtest("check_prog_dead_code"))
+		check_prog(skel->progs.check_prog_dead_code, 13);
+
+	if (test__start_subtest("check_prog_dead_code_bpf_to_bpf"))
+		check_prog(skel->progs.check_prog_dead_code_bpf_to_bpf, 26);
+
+	bpf_insns_mappings__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_insns_mappings.c b/tools/testing/selftests/bpf/progs/bpf_insns_mappings.c
new file mode 100644
index 000000000000..f6ff690801ea
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpf_insns_mappings.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2024 Isovalent */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__uint(max_entries, 1);
+	__type(key, u32);
+	__type(value, u64);
+} just_a_map SEC(".maps");
+
+static inline void beef(void)
+{
+	asm volatile("r8 = 0xbeef" ::: "r8");
+}
+
+static inline void cafe(void)
+{
+	asm volatile("r7 = 0xcafe" ::: "r7");
+}
+
+/*
+ * Trivial program: every insn maps to the original index
+ */
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int check_trivial_prog(void *ctx)
+{
+	beef();
+	cafe();
+	beef();
+	cafe();
+	beef();
+
+	return 0;
+}
+
+/* Some random instructions which will be patched for sure */
+static inline void beefify(void)
+{
+	__u32 key = 0;
+	__u64 *x;
+
+	beef();
+	bpf_printk("%llx", bpf_jiffies64());
+	beef();
+
+	key = !!bpf_jiffies64();
+	x = bpf_map_lookup_elem(&just_a_map, &key);
+	if (!x)
+		return;
+
+	beef();
+}
+
+/*
+ * Simple program: one section, no bpf-to-bpf calls, some patches
+ */
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int check_simple_prog(void *ctx)
+{
+	beefify();
+	return 0;
+}
+
+int __noinline foobar(int x)
+{
+	beefify();
+	return x;
+}
+
+/*
+ * Same simple program + a bpf-to-bpf call
+ */
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int check_bpf_to_bpf(void *ctx)
+{
+	beefify();
+
+	return foobar(0);
+}
+
+static inline void dead_code1(void)
+{
+	asm volatile("goto +0");
+}
+
+static inline void dead_code100(void)
+{
+#	if defined(__clang__)
+#		pragma clang loop unroll_count(100)
+#	elif defined(__GNUC__)
+#		pragma GCC unroll 100
+#	else
+#		error "unroll this loop, please"
+#	endif
+	for (int i = 0; i < 100; i++)
+		asm volatile("goto +0");
+}
+
+/*
+ * Some beef instructions, patches, plus dead code
+ */
+static __always_inline void dead_beef(void)
+{
+	beef();		/* 1 beef */
+	dead_code1();
+	beef();		/* 1 beef */
+	dead_code1();
+	beef();		/* 1 beef */
+	dead_code100();
+	beef();		/* 1 beef */
+
+	dead_code100();
+	beefify();	/* 3 beef */
+	dead_code100();
+	beefify();	/* 3 beef */
+	dead_code1();
+	beefify();	/* 3 beef */
+
+	/* 13 beef insns total */
+}
+
+/*
+ * A program with some nops to be removed
+ */
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int check_prog_dead_code(void *ctx)
+{
+	dead_beef();
+
+	return 0;
+}
+
+int __noinline foobar2(int x)
+{
+	dead_beef();
+
+	return x;
+}
+
+/*
+ * A program with some nops to be removed + a bpf-to-bpf call to a similar func
+ */
+SEC("fentry/" SYS_PREFIX "sys_nanosleep")
+int check_prog_dead_code_bpf_to_bpf(void *ctx)
+{
+	dead_beef();
+
+	return foobar2(0);
+}
+
+char _license[] SEC("license") = "GPL";
-- 
2.34.1


  parent reply	other threads:[~2024-02-02 16:34 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-02 16:28 [PATCH v1 bpf-next 0/9] BPF static branches Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 1/9] bpf: fix potential error return Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 2/9] bpf: keep track of and expose xlated insn offsets Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 3/9] bpf: expose how xlated insns map to jitted insns Anton Protopopov
2024-02-06  1:09   ` Alexei Starovoitov
2024-02-06 10:02     ` Anton Protopopov
2024-02-07  2:26       ` Alexei Starovoitov
2024-02-08 11:05         ` Anton Protopopov
2024-02-15  6:48           ` Alexei Starovoitov
2024-02-16 13:57             ` Anton Protopopov
2024-02-21  1:09               ` Alexei Starovoitov
2024-03-06 10:44                 ` Anton Protopopov
2024-03-14  1:56                   ` Alexei Starovoitov
2024-03-14  9:03                     ` Anton Protopopov
2024-03-14 17:07                       ` Alexei Starovoitov
2024-03-14 20:06                         ` Andrii Nakryiko
2024-03-14 21:41                           ` Alexei Starovoitov
2024-03-15 13:11                             ` Anton Protopopov
2024-03-15 16:32                             ` Andrii Nakryiko
2024-03-15 17:22                               ` Alexei Starovoitov
2024-03-15 17:29                                 ` Andrii Nakryiko
2024-03-28 16:37                                   ` Anton Protopopov
2024-03-29 22:44                                     ` Andrii Nakryiko
2024-04-01  9:47                                       ` Anton Protopopov
2024-02-02 16:28 ` Anton Protopopov [this message]
2024-02-02 16:28 ` [PATCH v1 bpf-next 5/9] bpftool: dump new fields of bpf prog info Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 6/9] bpf: add support for an extended JA instruction Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 7/9] bpf: Add kernel/bpftool asm support for new instructions Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 8/9] bpf: add BPF_STATIC_BRANCH_UPDATE syscall Anton Protopopov
2024-02-02 16:28 ` [PATCH v1 bpf-next 9/9] selftests/bpf: Add tests for new ja* instructions Anton Protopopov
2024-02-02 22:39 ` [PATCH v1 bpf-next 0/9] BPF static branches Andrii Nakryiko
2024-02-04 16:05   ` Anton Protopopov

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=20240202162813.4184616-5-aspsk@isovalent.com \
    --to=aspsk@isovalent.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=quentin@isovalent.com \
    --cc=sdf@google.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