[PATCH bpf-next v3 2/3] selftests/bpf: Dump data sections as part of btf_dump_test_case tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Modify `test_btf_dump_case` to test `btf_dump__dump_type_data`
alongside `btf_dump__dump_type`.

The `test_btf_dump_case` function provides a convenient way to test
`btf_dump__dump_type` behavior as test cases are specified in separate
C files and any differences are reported using `diff` utility. This
commit extends `test_btf_dump_case` to call `btf_dump__dump_type_data`
for each `BTF_KIND_DATASEC` object in the test case object file.

Signed-off-by: Eduard Zingerman <eddyz87@xxxxxxxxx>
---
 .../selftests/bpf/prog_tests/btf_dump.c       | 118 +++++++++++++++---
 1 file changed, 104 insertions(+), 14 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
index 24da335482d4..a0bdfc45660d 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf_dump.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <test_progs.h>
 #include <bpf/btf.h>
+#include <libelf.h>
+#include <gelf.h>
 
 static int duration = 0;
 
@@ -23,31 +25,104 @@ static struct btf_dump_test_case {
 	{"btf_dump: namespacing", "btf_dump_test_case_namespacing", false},
 };
 
-static int btf_dump_all_types(const struct btf *btf, void *ctx)
+static int btf_dump_all_types(const struct btf *btf, struct btf_dump *d)
 {
 	size_t type_cnt = btf__type_cnt(btf);
-	struct btf_dump *d;
 	int err = 0, id;
 
-	d = btf_dump__new(btf, btf_dump_printf, ctx, NULL);
-	err = libbpf_get_error(d);
-	if (err)
-		return err;
-
 	for (id = 1; id < type_cnt; id++) {
 		err = btf_dump__dump_type(d, id);
 		if (err)
-			goto done;
+			break;
+	}
+
+	return err;
+}
+
+/* Keep this as macro to retain __FILE__, __LINE__ values used by PRINT_FAIL */
+#define report_elf_error(fn)								\
+	({										\
+		int __err = elf_errno();						\
+		PRINT_FAIL("%s() failed %s(%d)\n", fn, elf_errmsg(__err), __err);	\
+		__err;									\
+	})
+
+static int btf_dump_datasec(Elf *elf, const struct btf *btf, struct btf_dump *d, __u32 id)
+{
+	const char *btf_sec, *elf_sec;
+	const struct btf_type *t;
+	Elf_Data *data = NULL;
+	Elf_Scn *scn = NULL;
+	size_t shstrndx;
+	GElf_Shdr sh;
+
+	if (elf_getshdrstrndx(elf, &shstrndx))
+		return report_elf_error("elf_getshdrstrndx");
+
+	t = btf__type_by_id(btf, id);
+	btf_sec = btf__str_by_offset(btf, t->name_off);
+
+	while ((scn = elf_nextscn(elf, scn)) != NULL) {
+		if (!gelf_getshdr(scn, &sh))
+			return report_elf_error("gelf_getshdr");
+		elf_sec = elf_strptr(elf, shstrndx, sh.sh_name);
+		if (!elf_sec)
+			return report_elf_error("elf_strptr");
+		if (strcmp(btf_sec, elf_sec) == 0) {
+			data = elf_getdata(scn, NULL);
+			if (!data)
+				return report_elf_error("elf_getdata");
+			break;
+		}
+	}
+
+	if (CHECK(!data, "btf_dump_datasec", "can't find ELF section %s\n", elf_sec))
+		return -1;
+
+	return btf_dump__dump_type_data(d, id, data->d_buf, data->d_size, NULL);
+}
+
+static int btf_dump_all_datasec(const struct btf *btf, struct btf_dump *d,
+				char *test_file, FILE *f)
+{
+	size_t type_cnt = btf__type_cnt(btf);
+	int err = 0, id, fd = 0;
+	Elf *elf = NULL;
+
+	fd = open(test_file, O_RDONLY | O_CLOEXEC);
+	if (CHECK(fd < 0, "open", "can't open %s for reading, %s(%d)\n",
+		  test_file, strerror(errno), errno)) {
+		err = errno;
+		goto done;
+	}
+
+	elf = elf_begin(fd, ELF_C_READ, NULL);
+	if (!elf) {
+		err = report_elf_error("elf_begin");
+		goto done;
+	}
+
+	for (id = 1; id < type_cnt; id++) {
+		if (!btf_is_datasec(btf__type_by_id(btf, id)))
+			continue;
+		err = btf_dump_datasec(elf, btf, d, id);
+		if (err)
+			break;
+		fprintf(f, "\n\n");
 	}
 
 done:
-	btf_dump__free(d);
+	if (fd)
+		close(fd);
+	if (elf)
+		elf_end(elf);
 	return err;
 }
 
 static int test_btf_dump_case(int n, struct btf_dump_test_case *t)
 {
 	char test_file[256], out_file[256], diff_cmd[1024];
+	struct btf_dump *d = NULL;
 	struct btf *btf = NULL;
 	int err = 0, fd = -1;
 	FILE *f = NULL;
@@ -86,12 +161,22 @@ static int test_btf_dump_case(int n, struct btf_dump_test_case *t)
 		goto done;
 	}
 
-	err = btf_dump_all_types(btf, f);
-	fclose(f);
-	close(fd);
-	if (CHECK(err, "btf_dump", "failure during C dumping: %d\n", err)) {
+	d = btf_dump__new(btf, btf_dump_printf, f, NULL);
+	err = libbpf_get_error(d);
+	if (CHECK(err, "btf_dump", "btf_dump__new failed: %d\n", err))
+		goto done;
+
+	err = btf_dump_all_types(btf, d);
+	if (CHECK(err, "btf_dump", "btf_dump_all_types failed: %d\n", err))
+		goto done;
+
+	err = btf_dump_all_datasec(btf, d, test_file, f);
+	if (CHECK(err, "btf_dump", "btf_dump_all_datasec failed: %d\n", err))
+		goto done;
+
+	if (CHECK(fflush(f), "btf_dump", "fflush() on %s failed: %s(%d)\n",
+		  test_file, strerror(errno), errno))
 		goto done;
-	}
 
 	snprintf(test_file, sizeof(test_file), "progs/%s.c", t->file);
 	if (access(test_file, R_OK) == -1)
@@ -122,6 +207,11 @@ static int test_btf_dump_case(int n, struct btf_dump_test_case *t)
 	remove(out_file);
 
 done:
+	if (f)
+		fclose(f);
+	if (fd >= 0)
+		close(fd);
+	btf_dump__free(d);
 	btf__free(btf);
 	return err;
 }
-- 
2.34.1




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux