@@ -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;
}
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@gmail.com> --- .../selftests/bpf/prog_tests/btf_dump.c | 118 +++++++++++++++--- 1 file changed, 104 insertions(+), 14 deletions(-)