1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2021 Facebook */
3#include <test_progs.h>
4#include <bpf/btf.h>
5#include "test_btf_decl_tag.skel.h"
6
7/* struct btf_type_tag_test is referenced in btf_type_tag.skel.h */
8struct btf_type_tag_test {
9        int **p;
10};
11#include "btf_type_tag.skel.h"
12#include "btf_type_tag_user.skel.h"
13#include "btf_type_tag_percpu.skel.h"
14
15static void test_btf_decl_tag(void)
16{
17	struct test_btf_decl_tag *skel;
18
19	skel = test_btf_decl_tag__open_and_load();
20	if (!ASSERT_OK_PTR(skel, "btf_decl_tag"))
21		return;
22
23	if (skel->rodata->skip_tests) {
24		printf("%s:SKIP: btf_decl_tag attribute not supported", __func__);
25		test__skip();
26	}
27
28	test_btf_decl_tag__destroy(skel);
29}
30
31static void test_btf_type_tag(void)
32{
33	struct btf_type_tag *skel;
34
35	skel = btf_type_tag__open_and_load();
36	if (!ASSERT_OK_PTR(skel, "btf_type_tag"))
37		return;
38
39	if (skel->rodata->skip_tests) {
40		printf("%s:SKIP: btf_type_tag attribute not supported", __func__);
41		test__skip();
42	}
43
44	btf_type_tag__destroy(skel);
45}
46
47/* loads vmlinux_btf as well as module_btf. If the caller passes NULL as
48 * module_btf, it will not load module btf.
49 *
50 * Returns 0 on success.
51 * Return -1 On error. In case of error, the loaded btf will be freed and the
52 * input parameters will be set to pointing to NULL.
53 */
54static int load_btfs(struct btf **vmlinux_btf, struct btf **module_btf,
55		     bool needs_vmlinux_tag)
56{
57	const char *module_name = "bpf_testmod";
58	__s32 type_id;
59
60	if (!env.has_testmod) {
61		test__skip();
62		return -1;
63	}
64
65	*vmlinux_btf = btf__load_vmlinux_btf();
66	if (!ASSERT_OK_PTR(*vmlinux_btf, "could not load vmlinux BTF"))
67		return -1;
68
69	if (!needs_vmlinux_tag)
70		goto load_module_btf;
71
72	/* skip the test if the vmlinux does not have __user tags */
73	type_id = btf__find_by_name_kind(*vmlinux_btf, "user", BTF_KIND_TYPE_TAG);
74	if (type_id <= 0) {
75		printf("%s:SKIP: btf_type_tag attribute not in vmlinux btf", __func__);
76		test__skip();
77		goto free_vmlinux_btf;
78	}
79
80load_module_btf:
81	/* skip loading module_btf, if not requested by caller */
82	if (!module_btf)
83		return 0;
84
85	*module_btf = btf__load_module_btf(module_name, *vmlinux_btf);
86	if (!ASSERT_OK_PTR(*module_btf, "could not load module BTF"))
87		goto free_vmlinux_btf;
88
89	/* skip the test if the module does not have __user tags */
90	type_id = btf__find_by_name_kind(*module_btf, "user", BTF_KIND_TYPE_TAG);
91	if (type_id <= 0) {
92		printf("%s:SKIP: btf_type_tag attribute not in %s", __func__, module_name);
93		test__skip();
94		goto free_module_btf;
95	}
96
97	return 0;
98
99free_module_btf:
100	btf__free(*module_btf);
101free_vmlinux_btf:
102	btf__free(*vmlinux_btf);
103
104	*vmlinux_btf = NULL;
105	if (module_btf)
106		*module_btf = NULL;
107	return -1;
108}
109
110static void test_btf_type_tag_mod_user(bool load_test_user1)
111{
112	struct btf *vmlinux_btf = NULL, *module_btf = NULL;
113	struct btf_type_tag_user *skel;
114	int err;
115
116	if (load_btfs(&vmlinux_btf, &module_btf, /*needs_vmlinux_tag=*/false))
117		return;
118
119	skel = btf_type_tag_user__open();
120	if (!ASSERT_OK_PTR(skel, "btf_type_tag_user"))
121		goto cleanup;
122
123	bpf_program__set_autoload(skel->progs.test_sys_getsockname, false);
124	if (load_test_user1)
125		bpf_program__set_autoload(skel->progs.test_user2, false);
126	else
127		bpf_program__set_autoload(skel->progs.test_user1, false);
128
129	err = btf_type_tag_user__load(skel);
130	ASSERT_ERR(err, "btf_type_tag_user");
131
132	btf_type_tag_user__destroy(skel);
133
134cleanup:
135	btf__free(module_btf);
136	btf__free(vmlinux_btf);
137}
138
139static void test_btf_type_tag_vmlinux_user(void)
140{
141	struct btf_type_tag_user *skel;
142	struct btf *vmlinux_btf = NULL;
143	int err;
144
145	if (load_btfs(&vmlinux_btf, NULL, /*needs_vmlinux_tag=*/true))
146		return;
147
148	skel = btf_type_tag_user__open();
149	if (!ASSERT_OK_PTR(skel, "btf_type_tag_user"))
150		goto cleanup;
151
152	bpf_program__set_autoload(skel->progs.test_user2, false);
153	bpf_program__set_autoload(skel->progs.test_user1, false);
154
155	err = btf_type_tag_user__load(skel);
156	ASSERT_ERR(err, "btf_type_tag_user");
157
158	btf_type_tag_user__destroy(skel);
159
160cleanup:
161	btf__free(vmlinux_btf);
162}
163
164static void test_btf_type_tag_mod_percpu(bool load_test_percpu1)
165{
166	struct btf *vmlinux_btf, *module_btf;
167	struct btf_type_tag_percpu *skel;
168	int err;
169
170	if (load_btfs(&vmlinux_btf, &module_btf, /*needs_vmlinux_tag=*/false))
171		return;
172
173	skel = btf_type_tag_percpu__open();
174	if (!ASSERT_OK_PTR(skel, "btf_type_tag_percpu"))
175		goto cleanup;
176
177	bpf_program__set_autoload(skel->progs.test_percpu_load, false);
178	bpf_program__set_autoload(skel->progs.test_percpu_helper, false);
179	if (load_test_percpu1)
180		bpf_program__set_autoload(skel->progs.test_percpu2, false);
181	else
182		bpf_program__set_autoload(skel->progs.test_percpu1, false);
183
184	err = btf_type_tag_percpu__load(skel);
185	ASSERT_ERR(err, "btf_type_tag_percpu");
186
187	btf_type_tag_percpu__destroy(skel);
188
189cleanup:
190	btf__free(module_btf);
191	btf__free(vmlinux_btf);
192}
193
194static void test_btf_type_tag_vmlinux_percpu(bool load_test)
195{
196	struct btf_type_tag_percpu *skel;
197	struct btf *vmlinux_btf = NULL;
198	int err;
199
200	if (load_btfs(&vmlinux_btf, NULL, /*needs_vmlinux_tag=*/true))
201		return;
202
203	skel = btf_type_tag_percpu__open();
204	if (!ASSERT_OK_PTR(skel, "btf_type_tag_percpu"))
205		goto cleanup;
206
207	bpf_program__set_autoload(skel->progs.test_percpu2, false);
208	bpf_program__set_autoload(skel->progs.test_percpu1, false);
209	if (load_test) {
210		bpf_program__set_autoload(skel->progs.test_percpu_helper, false);
211
212		err = btf_type_tag_percpu__load(skel);
213		ASSERT_ERR(err, "btf_type_tag_percpu_load");
214	} else {
215		bpf_program__set_autoload(skel->progs.test_percpu_load, false);
216
217		err = btf_type_tag_percpu__load(skel);
218		ASSERT_OK(err, "btf_type_tag_percpu_helper");
219	}
220
221	btf_type_tag_percpu__destroy(skel);
222
223cleanup:
224	btf__free(vmlinux_btf);
225}
226
227void test_btf_tag(void)
228{
229	if (test__start_subtest("btf_decl_tag"))
230		test_btf_decl_tag();
231	if (test__start_subtest("btf_type_tag"))
232		test_btf_type_tag();
233
234	if (test__start_subtest("btf_type_tag_user_mod1"))
235		test_btf_type_tag_mod_user(true);
236	if (test__start_subtest("btf_type_tag_user_mod2"))
237		test_btf_type_tag_mod_user(false);
238	if (test__start_subtest("btf_type_tag_sys_user_vmlinux"))
239		test_btf_type_tag_vmlinux_user();
240
241	if (test__start_subtest("btf_type_tag_percpu_mod1"))
242		test_btf_type_tag_mod_percpu(true);
243	if (test__start_subtest("btf_type_tag_percpu_mod2"))
244		test_btf_type_tag_mod_percpu(false);
245	if (test__start_subtest("btf_type_tag_percpu_vmlinux_load"))
246		test_btf_type_tag_vmlinux_percpu(true);
247	if (test__start_subtest("btf_type_tag_percpu_vmlinux_helper"))
248		test_btf_type_tag_vmlinux_percpu(false);
249}
250