All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andriin@fb.com>
To: <bpf@vger.kernel.org>, <netdev@vger.kernel.org>, <ast@fb.com>,
	<daniel@iogearbox.net>
Cc: <andrii.nakryiko@gmail.com>, <kernel-team@fb.com>,
	Andrii Nakryiko <andriin@fb.com>
Subject: [PATCH bpf-next 3/4] selftests/bpf: add checking of raw type dump in BTF writer APIs selftests
Date: Tue, 29 Sep 2020 16:28:42 -0700	[thread overview]
Message-ID: <20200929232843.1249318-4-andriin@fb.com> (raw)
In-Reply-To: <20200929232843.1249318-1-andriin@fb.com>

Cross-validate raw BTF dump and writable BTF in a single selftest. Raw type
dump checks also serve as a good self-documentation.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
 .../selftests/bpf/prog_tests/btf_write.c      | 67 ++++++++++++++++++-
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_write.c b/tools/testing/selftests/bpf/prog_tests/btf_write.c
index 314e1e7c36df..bbf842fc8f48 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_write.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_write.c
@@ -1,22 +1,49 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2020 Facebook */
+#define _GNU_SOURCE
 #include <test_progs.h>
 #include <bpf/btf.h>
 
 static int duration = 0;
 
+static char *dump_buf;
+static size_t dump_buf_sz;
+static FILE *dump_buf_file;
+
+static void dump_fn(void *ctx, const char *fmt, va_list args)
+{
+	vfprintf(dump_buf_file, fmt, args);
+}
+
+static void check_type_dump(struct btf_dump *d, int type_id, const char *exp)
+{
+	fseek(dump_buf_file, 0, SEEK_SET);
+	btf_dump__dump_type_raw(d, type_id);
+	fflush(dump_buf_file);
+	dump_buf[dump_buf_sz] = 0; /* some libc implementations don't do this */
+	ASSERT_STREQ(dump_buf, exp, "type_raw_dump");
+}
+
 void test_btf_write() {
 	const struct btf_var_secinfo *vi;
 	const struct btf_type *t;
 	const struct btf_member *m;
 	const struct btf_enum *v;
 	const struct btf_param *p;
-	struct btf *btf;
+	struct btf *btf = NULL;
+	struct btf_dump *d = NULL;
 	int id, err, str_off;
 
+	dump_buf_file = open_memstream(&dump_buf, &dump_buf_sz);
+	if (CHECK(!dump_buf_file, "dump_memstream", "failed: %d\n", errno))
+		return;
+
 	btf = btf__new_empty();
 	if (CHECK(IS_ERR(btf), "new_empty", "failed: %ld\n", PTR_ERR(btf)))
-		return;
+		goto err_out;
+	d = btf_dump__new(btf, NULL, NULL, dump_fn);
+	if (!ASSERT_OK(libbpf_get_error(d), "btf_dump__new"))
+		goto err_out;
 
 	str_off = btf__find_str(btf, "int");
 	ASSERT_EQ(str_off, -ENOENT, "int_str_missing_off");
@@ -39,6 +66,7 @@ void test_btf_write() {
 	ASSERT_EQ(t->size, 4, "int_sz");
 	ASSERT_EQ(btf_int_encoding(t), BTF_INT_SIGNED, "int_enc");
 	ASSERT_EQ(btf_int_bits(t), 32, "int_bits");
+	check_type_dump(d, 1, "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED");
 
 	/* invalid int size */
 	id = btf__add_int(btf, "bad sz int", 7, 0);
@@ -59,24 +87,28 @@ void test_btf_write() {
 	t = btf__type_by_id(btf, 2);
 	ASSERT_EQ(btf_kind(t), BTF_KIND_PTR, "ptr_kind");
 	ASSERT_EQ(t->type, 1, "ptr_type");
+	check_type_dump(d, 2, "[2] PTR '(anon)' type_id=1");
 
 	id = btf__add_const(btf, 5); /* points forward to restrict */
 	ASSERT_EQ(id, 3, "const_id");
 	t = btf__type_by_id(btf, 3);
 	ASSERT_EQ(btf_kind(t), BTF_KIND_CONST, "const_kind");
 	ASSERT_EQ(t->type, 5, "const_type");
+	check_type_dump(d, 3, "[3] CONST '(anon)' type_id=5");
 
 	id = btf__add_volatile(btf, 3);
 	ASSERT_EQ(id, 4, "volatile_id");
 	t = btf__type_by_id(btf, 4);
 	ASSERT_EQ(btf_kind(t), BTF_KIND_VOLATILE, "volatile_kind");
 	ASSERT_EQ(t->type, 3, "volatile_type");
+	check_type_dump(d, 4, "[4] VOLATILE '(anon)' type_id=3");
 
 	id = btf__add_restrict(btf, 4);
 	ASSERT_EQ(id, 5, "restrict_id");
 	t = btf__type_by_id(btf, 5);
 	ASSERT_EQ(btf_kind(t), BTF_KIND_RESTRICT, "restrict_kind");
 	ASSERT_EQ(t->type, 4, "restrict_type");
+	check_type_dump(d, 5, "[5] RESTRICT '(anon)' type_id=4");
 
 	/* ARRAY */
 	id = btf__add_array(btf, 1, 2, 10); /* int *[10] */
@@ -86,6 +118,7 @@ void test_btf_write() {
 	ASSERT_EQ(btf_array(t)->index_type, 1, "array_index_type");
 	ASSERT_EQ(btf_array(t)->type, 2, "array_elem_type");
 	ASSERT_EQ(btf_array(t)->nelems, 10, "array_nelems");
+	check_type_dump(d, 6, "[6] ARRAY '(anon)' type_id=2 index_type_id=1 nr_elems=10");
 
 	/* STRUCT */
 	err = btf__add_field(btf, "field", 1, 0, 0);
@@ -113,6 +146,10 @@ void test_btf_write() {
 	ASSERT_EQ(m->type, 1, "f2_type");
 	ASSERT_EQ(btf_member_bit_offset(t, 1), 32, "f2_bit_off");
 	ASSERT_EQ(btf_member_bitfield_size(t, 1), 16, "f2_bit_sz");
+	check_type_dump(d, 7,
+			"[7] STRUCT 's1' size=8 vlen=2\n"
+			"\t'f1' type_id=1 bits_offset=0\n"
+			"\t'f2' type_id=1 bits_offset=32 bitfield_size=16");
 
 	/* UNION */
 	id = btf__add_union(btf, "u1", 8);
@@ -136,6 +173,9 @@ void test_btf_write() {
 	ASSERT_EQ(m->type, 1, "f1_type");
 	ASSERT_EQ(btf_member_bit_offset(t, 0), 0, "f1_bit_off");
 	ASSERT_EQ(btf_member_bitfield_size(t, 0), 16, "f1_bit_sz");
+	check_type_dump(d, 8,
+			"[8] UNION 'u1' size=8 vlen=1\n"
+			"\t'f1' type_id=1 bits_offset=0 bitfield_size=16");
 
 	/* ENUM */
 	id = btf__add_enum(btf, "e1", 4);
@@ -156,6 +196,10 @@ void test_btf_write() {
 	v = btf_enum(t) + 1;
 	ASSERT_STREQ(btf__str_by_offset(btf, v->name_off), "v2", "v2_name");
 	ASSERT_EQ(v->val, 2, "v2_val");
+	check_type_dump(d, 9,
+			"[9] ENUM 'e1' size=4 vlen=2\n"
+			"\t'v1' val=1\n"
+			"\t'v2' val=2");
 
 	/* FWDs */
 	id = btf__add_fwd(btf, "struct_fwd", BTF_FWD_STRUCT);
@@ -164,6 +208,7 @@ void test_btf_write() {
 	ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "struct_fwd", "fwd_name");
 	ASSERT_EQ(btf_kind(t), BTF_KIND_FWD, "fwd_kind");
 	ASSERT_EQ(btf_kflag(t), 0, "fwd_kflag");
+	check_type_dump(d, 10, "[10] FWD 'struct_fwd' fwd_kind=struct");
 
 	id = btf__add_fwd(btf, "union_fwd", BTF_FWD_UNION);
 	ASSERT_EQ(id, 11, "union_fwd_id");
@@ -171,6 +216,7 @@ void test_btf_write() {
 	ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "union_fwd", "fwd_name");
 	ASSERT_EQ(btf_kind(t), BTF_KIND_FWD, "fwd_kind");
 	ASSERT_EQ(btf_kflag(t), 1, "fwd_kflag");
+	check_type_dump(d, 11, "[11] FWD 'union_fwd' fwd_kind=union");
 
 	id = btf__add_fwd(btf, "enum_fwd", BTF_FWD_ENUM);
 	ASSERT_EQ(id, 12, "enum_fwd_id");
@@ -179,6 +225,7 @@ void test_btf_write() {
 	ASSERT_EQ(btf_kind(t), BTF_KIND_ENUM, "enum_fwd_kind");
 	ASSERT_EQ(btf_vlen(t), 0, "enum_fwd_kind");
 	ASSERT_EQ(t->size, 4, "enum_fwd_sz");
+	check_type_dump(d, 12, "[12] ENUM 'enum_fwd' size=4 vlen=0");
 
 	/* TYPEDEF */
 	id = btf__add_typedef(btf, "typedef1", 1);
@@ -187,6 +234,7 @@ void test_btf_write() {
 	ASSERT_STREQ(btf__str_by_offset(btf, t->name_off), "typedef1", "typedef_name");
 	ASSERT_EQ(btf_kind(t), BTF_KIND_TYPEDEF, "typedef_kind");
 	ASSERT_EQ(t->type, 1, "typedef_type");
+	check_type_dump(d, 13, "[13] TYPEDEF 'typedef1' type_id=1");
 
 	/* FUNC & FUNC_PROTO */
 	id = btf__add_func(btf, "func1", BTF_FUNC_GLOBAL, 15);
@@ -196,6 +244,7 @@ void test_btf_write() {
 	ASSERT_EQ(t->type, 15, "func_type");
 	ASSERT_EQ(btf_kind(t), BTF_KIND_FUNC, "func_kind");
 	ASSERT_EQ(btf_vlen(t), BTF_FUNC_GLOBAL, "func_vlen");
+	check_type_dump(d, 14, "[14] FUNC 'func1' type_id=15 linkage=global");
 
 	id = btf__add_func_proto(btf, 1);
 	ASSERT_EQ(id, 15, "func_proto_id");
@@ -214,6 +263,10 @@ void test_btf_write() {
 	p = btf_params(t) + 1;
 	ASSERT_STREQ(btf__str_by_offset(btf, p->name_off), "p2", "p2_name");
 	ASSERT_EQ(p->type, 2, "p2_type");
+	check_type_dump(d, 15,
+			"[15] FUNC_PROTO '(anon)' ret_type_id=1 vlen=2\n"
+			"\t'p1' type_id=1\n"
+			"\t'p2' type_id=2");
 
 	/* VAR */
 	id = btf__add_var(btf, "var1", BTF_VAR_GLOBAL_ALLOCATED, 1);
@@ -223,6 +276,7 @@ void test_btf_write() {
 	ASSERT_EQ(btf_kind(t), BTF_KIND_VAR, "var_kind");
 	ASSERT_EQ(t->type, 1, "var_type");
 	ASSERT_EQ(btf_var(t)->linkage, BTF_VAR_GLOBAL_ALLOCATED, "var_type");
+	check_type_dump(d, 16, "[16] VAR 'var1' type_id=1, linkage=global-alloc");
 
 	/* DATASECT */
 	id = btf__add_datasec(btf, "datasec1", 12);
@@ -239,6 +293,13 @@ void test_btf_write() {
 	ASSERT_EQ(vi->type, 1, "v1_type");
 	ASSERT_EQ(vi->offset, 4, "v1_off");
 	ASSERT_EQ(vi->size, 8, "v1_sz");
-
+	check_type_dump(d, 17,
+			"[17] DATASEC 'datasec1' size=12 vlen=1\n"
+			"\ttype_id=1 offset=4 size=8");
+
+err_out:
+	fclose(dump_buf_file);
+	free(dump_buf);
+	btf_dump__free(d);
 	btf__free(btf);
 }
-- 
2.24.1


  parent reply	other threads:[~2020-09-29 23:29 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-29 23:28 [PATCH bpf-next 0/4] libbpf: add raw BTF type dumping Andrii Nakryiko
2020-09-29 23:28 ` [PATCH bpf-next 1/4] libbpf: make btf_dump work with modifiable BTF Andrii Nakryiko
2020-09-29 23:28 ` [PATCH bpf-next 2/4] libbpf: add raw dumping of BTF types Andrii Nakryiko
2020-09-29 23:28 ` Andrii Nakryiko [this message]
2020-09-29 23:28 ` [PATCH bpf-next 4/4] selftests/bpf: test "incremental" btf_dump in C format Andrii Nakryiko
2020-09-30  0:03 ` [PATCH bpf-next 0/4] libbpf: add raw BTF type dumping Alexei Starovoitov
2020-09-30  0:44   ` Andrii Nakryiko
2020-09-30  3:18     ` Alexei Starovoitov
2020-09-30 18:22       ` Andrii Nakryiko
2020-09-30 21:29         ` Alexei Starovoitov
2020-09-30 22:47           ` Andrii Nakryiko

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=20200929232843.1249318-4-andriin@fb.com \
    --to=andriin@fb.com \
    --cc=andrii.nakryiko@gmail.com \
    --cc=ast@fb.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=netdev@vger.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.