BPF List
 help / color / mirror / Atom feed
From: Ihor Solodrai <ihor.solodrai@linux.dev>
To: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Eduard Zingerman <eddyz87@gmail.com>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>,
	Quentin Monnet <qmo@kernel.org>
Cc: bpf@vger.kernel.org
Subject: [PATCH bpf-next v1 2/4] selftests/bpf: Add tests for bpftool btf dump format c
Date: Wed, 19 Aug 2026 17:06:25 -0700	[thread overview]
Message-ID: <20260820000627.3826188-3-ihor.solodrai@linux.dev> (raw)
In-Reply-To: <20260820000627.3826188-1-ihor.solodrai@linux.dev>

"bpftool btf dump format c" generates the vmlinux.h that BPF programs
are built against, and it has no test coverage at all. The only
in-tree consumers are build systems, and none of them diff the result.

Building against the header only catches what a compiler rejects.
Missing macros, a missing preserve_access_index pragma and the wrong
padding width all compile.

Add a test for those three, over both sort orderings.

Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
---
 .../bpf/prog_tests/bpftool_btf_dump.c         | 151 ++++++++++++++++++
 1 file changed, 151 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/bpftool_btf_dump.c

diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_btf_dump.c b/tools/testing/selftests/bpf/prog_tests/bpftool_btf_dump.c
new file mode 100644
index 000000000000..53bb7065b3ca
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/bpftool_btf_dump.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <bpftool_helpers.h>
+#include <bpf/btf.h>
+#include <unistd.h>
+
+#define DUMP_BUF_SZ	(16 * 1024)
+
+static int btf_to_tmpfile(struct btf *btf, char *path, size_t path_sz)
+{
+	const void *raw;
+	ssize_t written;
+	__u32 sz;
+	int fd;
+
+	raw = btf__raw_data(btf, &sz);
+	if (!ASSERT_OK_PTR(raw, "raw_data"))
+		return -1;
+
+	snprintf(path, path_sz, "/tmp/bpftool_btf_dump.XXXXXX");
+	fd = mkstemp(path);
+	if (!ASSERT_OK_FD(fd, "mkstemp"))
+		return -1;
+
+	written = write(fd, raw, sz);
+	close(fd);
+	if (!ASSERT_EQ(written, sz, "write_btf")) {
+		unlink(path);
+		return -1;
+	}
+	return 0;
+}
+
+static char *dump_c(const char *path, bool sorted)
+{
+	char args[MAX_BPFTOOL_CMD_LEN];
+	char *buf;
+	int err;
+
+	buf = malloc(DUMP_BUF_SZ);
+	if (!ASSERT_OK_PTR(buf, "alloc"))
+		return NULL;
+
+	snprintf(args, sizeof(args), "btf dump file %s format c%s",
+		 path, sorted ? "" : " unsorted");
+	err = get_bpftool_command_output(args, buf, DUMP_BUF_SZ);
+	if (!ASSERT_OK(err, "dump")) {
+		free(buf);
+		return NULL;
+	}
+	return buf;
+}
+
+/*
+ * struct holey { int c; <32 bit hole> int tail; };
+ *
+ * One record with a hole, and a 4-byte long to pad it with. How records
+ * themselves are rendered is already covered by the build, so the fixture does
+ * not need to be more elaborate than that.
+ */
+static struct btf *mk_btf(void)
+{
+	struct btf *btf;
+	int id, err;
+
+	btf = btf__new_empty();
+	if (!ASSERT_OK_PTR(btf, "new_empty"))
+		return NULL;
+
+	id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
+	if (!ASSERT_EQ(id, 1, "int"))
+		goto err_out;
+
+	id = btf__add_int(btf, "long int", 4, BTF_INT_SIGNED);
+	if (!ASSERT_GT(id, 0, "long"))
+		goto err_out;
+
+	id = btf__add_struct(btf, "holey", 16);
+	if (!ASSERT_GT(id, 0, "struct_holey"))
+		goto err_out;
+
+	err = btf__add_field(btf, "c", 1, 0, 0);
+	if (!ASSERT_OK(err, "holey_c"))
+		goto err_out;
+
+	err = btf__add_field(btf, "tail", 1, 96, 0);
+	if (!ASSERT_OK(err, "holey_tail"))
+		goto err_out;
+
+	btf__set_pointer_size(btf, 4);
+
+	return btf;
+err_out:
+	btf__free(btf);
+	return NULL;
+}
+
+/*
+ * Check only what the selftests build cannot:
+ *   - bpf_helpers.h defines __ksym and __weak as well, and no program uses
+ *     __bpf_fastcall, so losing the macro block changes nothing;
+ *   - building without the preserve_access_index pragma is a supported mode
+ *     (BPF_NO_PRESERVE_ACCESS_INDEX), so losing it only costs CO-RE;
+ *   - the padding width comes from the BTF's pointer size, and a native build
+ *     never runs the host bpftool over a differently sized target's BTF.
+ */
+static void test_dump(const char *path, bool sorted)
+{
+	char *buf;
+
+	buf = dump_c(path, sorted);
+	if (!buf)
+		return;
+
+	ASSERT_HAS_SUBSTR(buf, "#define __ksym __attribute__((section(\".ksyms\")))",
+			  "ksym");
+	ASSERT_HAS_SUBSTR(buf, "#define __weak __attribute__((weak))", "weak");
+	ASSERT_HAS_SUBSTR(buf, "#define __bpf_fastcall __attribute__((bpf_fastcall))",
+			  "bpf_fastcall");
+
+	ASSERT_HAS_SUBSTR(buf, "#ifndef BPF_NO_PRESERVE_ACCESS_INDEX", "pai_guard");
+	ASSERT_HAS_SUBSTR(buf,
+			  "#pragma clang attribute push (__attribute__((preserve_access_index)), apply_to = record)",
+			  "pai_push");
+	ASSERT_HAS_SUBSTR(buf, "#pragma clang attribute pop", "pai_pop");
+
+	ASSERT_HAS_SUBSTR(buf, "long: 32;", "target_ptr_size");
+
+	free(buf);
+}
+
+void test_bpftool_btf_dump(void)
+{
+	char path[PATH_MAX];
+	struct btf *btf;
+
+	btf = mk_btf();
+	if (!btf)
+		return;
+	if (btf_to_tmpfile(btf, path, sizeof(path)))
+		goto out;
+
+	if (test__start_subtest("c_sorted"))
+		test_dump(path, true);
+	if (test__start_subtest("c_unsorted"))
+		test_dump(path, false);
+
+	unlink(path);
+out:
+	btf__free(btf);
+}
-- 
2.55.0


  parent reply	other threads:[~2026-08-20  0:06 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20  0:06 [PATCH bpf-next v1 0/4] bpftool, selftests: Add tests for C dump and fix a dropped type Ihor Solodrai
2026-08-20  0:06 ` [PATCH bpf-next v1 1/4] selftests/bpf: NUL-terminate bpftool command output Ihor Solodrai
2026-08-20  0:06 ` Ihor Solodrai [this message]
2026-08-20  0:16   ` [PATCH bpf-next v1 2/4] selftests/bpf: Add tests for bpftool btf dump format c sashiko-bot
2026-08-20  0:51   ` bot+bpf-ci
2026-08-20  0:06 ` [PATCH bpf-next v1 3/4] bpftool: Don't drop a type in the sorted C dump Ihor Solodrai
2026-08-20  0:06 ` [PATCH bpf-next v1 4/4] selftests/bpf: Check that sorting preserves types in bpftool dump Ihor Solodrai

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=20260820000627.3826188-3-ihor.solodrai@linux.dev \
    --to=ihor.solodrai@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=memxor@gmail.com \
    --cc=qmo@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