forked from mirrors/linux
		
	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: Yonghong Song <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
		
							parent
							
								
									d7f5b5e051
								
							
						
					
					
						commit
						999d82cbc0
					
				
					 3 changed files with 136 additions and 13 deletions
				
			
		| 
						 | 
					@ -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 @@ static int file_has_btf_elf(const char *fn)
 | 
				
			||||||
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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue