Commit 999d82cb authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov
Browse files

tools/bpf: enhance test_btf file testing to test func info



Change the bpf programs test_btf_haskv.c and test_btf_nokv.c to
have two sections, and enhance test_btf.c test_file feature
to test btf func_info returned by the kernel.

Signed-off-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent d7f5b5e0
Loading
Loading
Loading
Loading
+108 −9
Original line number Original line Diff line number Diff line
@@ -2434,13 +2434,13 @@ static struct btf_file_test file_tests[] = {
},
},
};
};


static int file_has_btf_elf(const char *fn)
static int file_has_btf_elf(const char *fn, bool *has_btf_ext)
{
{
	Elf_Scn *scn = NULL;
	Elf_Scn *scn = NULL;
	GElf_Ehdr ehdr;
	GElf_Ehdr ehdr;
	int ret = 0;
	int elf_fd;
	int elf_fd;
	Elf *elf;
	Elf *elf;
	int ret;


	if (CHECK(elf_version(EV_CURRENT) == EV_NONE,
	if (CHECK(elf_version(EV_CURRENT) == EV_NONE,
		  "elf_version(EV_CURRENT) == EV_NONE"))
		  "elf_version(EV_CURRENT) == EV_NONE"))
@@ -2472,14 +2472,12 @@ static int file_has_btf_elf(const char *fn)
		}
		}


		sh_name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
		sh_name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
		if (!strcmp(sh_name, BTF_ELF_SEC)) {
		if (!strcmp(sh_name, BTF_ELF_SEC))
			ret = 1;
			ret = 1;
			goto done;
		if (!strcmp(sh_name, BTF_EXT_ELF_SEC))
		}
			*has_btf_ext = true;
	}
	}


	ret = 0;

done:
done:
	close(elf_fd);
	close(elf_fd);
	elf_end(elf);
	elf_end(elf);
@@ -2489,15 +2487,24 @@ done:
static int do_test_file(unsigned int test_num)
static int do_test_file(unsigned int test_num)
{
{
	const struct btf_file_test *test = &file_tests[test_num - 1];
	const struct btf_file_test *test = &file_tests[test_num - 1];
	const char *expected_fnames[] = {"_dummy_tracepoint",
					 "test_long_fname_1",
					 "test_long_fname_2"};
	struct bpf_prog_info info = {};
	struct bpf_object *obj = NULL;
	struct bpf_object *obj = NULL;
	struct bpf_func_info *finfo;
	struct bpf_program *prog;
	struct bpf_program *prog;
	__u32 info_len, rec_size;
	bool has_btf_ext = false;
	struct btf *btf = NULL;
	void *func_info = NULL;
	struct bpf_map *map;
	struct bpf_map *map;
	int err;
	int i, err, prog_fd;


	fprintf(stderr, "BTF libbpf test[%u] (%s): ", test_num,
	fprintf(stderr, "BTF libbpf test[%u] (%s): ", test_num,
		test->file);
		test->file);


	err = file_has_btf_elf(test->file);
	err = file_has_btf_elf(test->file, &has_btf_ext);
	if (err == -1)
	if (err == -1)
		return err;
		return err;


@@ -2525,6 +2532,7 @@ static int do_test_file(unsigned int test_num)
	err = bpf_object__load(obj);
	err = bpf_object__load(obj);
	if (CHECK(err < 0, "bpf_object__load: %d", err))
	if (CHECK(err < 0, "bpf_object__load: %d", err))
		goto done;
		goto done;
	prog_fd = bpf_program__fd(prog);


	map = bpf_object__find_map_by_name(obj, "btf_map");
	map = bpf_object__find_map_by_name(obj, "btf_map");
	if (CHECK(!map, "btf_map not found")) {
	if (CHECK(!map, "btf_map not found")) {
@@ -2539,9 +2547,100 @@ static int do_test_file(unsigned int test_num)
		  test->btf_kv_notfound))
		  test->btf_kv_notfound))
		goto done;
		goto done;


	if (!jit_enabled || !has_btf_ext)
		goto skip_jit;

	/* get necessary program info */
	info_len = sizeof(struct bpf_prog_info);
	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);

	if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) {
		fprintf(stderr, "%s\n", btf_log_buf);
		err = -1;
		goto done;
	}
	if (CHECK(info.func_info_cnt != 3,
		  "incorrect info.func_info_cnt (1st) %d",
		  info.func_info_cnt)) {
		err = -1;
		goto done;
	}
	rec_size = info.func_info_rec_size;
	if (CHECK(rec_size < 4,
		  "incorrect info.func_info_rec_size (1st) %d\n", rec_size)) {
		err = -1;
		goto done;
	}

	func_info = malloc(info.func_info_cnt * rec_size);
	if (CHECK(!func_info, "out of memeory")) {
		err = -1;
		goto done;
	}

	/* reset info to only retrieve func_info related data */
	memset(&info, 0, sizeof(info));
	info.func_info_cnt = 3;
	info.func_info_rec_size = rec_size;
	info.func_info = ptr_to_u64(func_info);

	err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);

	if (CHECK(err == -1, "invalid get info (2nd) errno:%d", errno)) {
		fprintf(stderr, "%s\n", btf_log_buf);
		err = -1;
		goto done;
	}
	if (CHECK(info.func_info_cnt != 3,
		  "incorrect info.func_info_cnt (2nd) %d",
		  info.func_info_cnt)) {
		err = -1;
		goto done;
	}
	if (CHECK(info.func_info_rec_size != rec_size,
		  "incorrect info.func_info_rec_size (2nd) %d",
		  info.func_info_rec_size)) {
		err = -1;
		goto done;
	}

	err = btf_get_from_id(info.btf_id, &btf);
	if (CHECK(err, "cannot get btf from kernel, err: %d", err))
		goto done;

	/* check three functions */
	finfo = func_info;
	for (i = 0; i < 3; i++) {
		const struct btf_type *t;
		const char *fname;

		t = btf__type_by_id(btf, finfo->type_id);
		if (CHECK(!t, "btf__type_by_id failure: id %u",
			  finfo->type_id)) {
			err = -1;
			goto done;
		}

		fname = btf__name_by_offset(btf, t->name_off);
		err = strcmp(fname, expected_fnames[i]);
		/* for the second and third functions in .text section,
		 * the compiler may order them either way.
		 */
		if (i && err)
			err = strcmp(fname, expected_fnames[3 - i]);
		if (CHECK(err, "incorrect fname %s", fname ? : "")) {
			err = -1;
			goto done;
		}

		finfo = (void *)finfo + rec_size;
	}

skip_jit:
	fprintf(stderr, "OK");
	fprintf(stderr, "OK");


done:
done:
	free(func_info);
	bpf_object__close(obj);
	bpf_object__close(obj);
	return err;
	return err;
}
}
+14 −2
Original line number Original line Diff line number Diff line
@@ -24,8 +24,8 @@ struct dummy_tracepoint_args {
	struct sock *sock;
	struct sock *sock;
};
};


SEC("dummy_tracepoint")
__attribute__((noinline))
int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
static int test_long_fname_2(struct dummy_tracepoint_args *arg)
{
{
	struct ipv_counts *counts;
	struct ipv_counts *counts;
	int key = 0;
	int key = 0;
@@ -42,4 +42,16 @@ int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
	return 0;
	return 0;
}
}


__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg)
{
	return test_long_fname_2(arg);
}

SEC("dummy_tracepoint")
int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
{
	return test_long_fname_1(arg);
}

char _license[] SEC("license") = "GPL";
char _license[] SEC("license") = "GPL";
+14 −2
Original line number Original line Diff line number Diff line
@@ -22,8 +22,8 @@ struct dummy_tracepoint_args {
	struct sock *sock;
	struct sock *sock;
};
};


SEC("dummy_tracepoint")
__attribute__((noinline))
int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
static int test_long_fname_2(struct dummy_tracepoint_args *arg)
{
{
	struct ipv_counts *counts;
	struct ipv_counts *counts;
	int key = 0;
	int key = 0;
@@ -40,4 +40,16 @@ int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
	return 0;
	return 0;
}
}


__attribute__((noinline))
static int test_long_fname_1(struct dummy_tracepoint_args *arg)
{
	return test_long_fname_2(arg);
}

SEC("dummy_tracepoint")
int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
{
	return test_long_fname_1(arg);
}

char _license[] SEC("license") = "GPL";
char _license[] SEC("license") = "GPL";