xref: /linux/tools/testing/selftests/bpf/prog_tests/resolve_btfids.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/err.h>
4 #include <string.h>
5 #include <bpf/btf.h>
6 #include <bpf/libbpf.h>
7 #include <linux/btf.h>
8 #include <linux/kernel.h>
9 #define CONFIG_DEBUG_INFO_BTF
10 #include <linux/btf_ids.h>
11 #include "test_progs.h"
12 
13 #define BTF_DATA_FILE "resolve_btfids.test.o.BTF"
14 
15 #define DECL_TAG_FASTCALL "bpf_fastcall"
16 #define DECL_TAG_KFUNC "bpf_kfunc"
17 #define TYPE_ATTR_ARENA "address_space(1)"
18 #define ARENA_ARG(n) (1U << (n))
19 
20 #ifndef KF_FASTCALL
21 #define KF_FASTCALL (1 << 12)
22 #endif
23 #ifndef KF_ARENA_RET
24 #define KF_ARENA_RET  (1 << 13)
25 #endif
26 #ifndef KF_ARENA_ARG1
27 #define KF_ARENA_ARG1 (1 << 14)
28 #endif
29 #ifndef KF_ARENA_ARG2
30 #define KF_ARENA_ARG2 (1 << 15)
31 #endif
32 
33 struct symbol {
34 	const char	*name;
35 	int		 type;
36 	int		 id;
37 };
38 
39 struct symbol test_symbols[] = {
40 	{ "unused",  BTF_KIND_UNKN,     0 },
41 	{ "S",       BTF_KIND_TYPEDEF, -1 },
42 	{ "T",       BTF_KIND_TYPEDEF, -1 },
43 	{ "U",       BTF_KIND_TYPEDEF, -1 },
44 	{ "S",       BTF_KIND_STRUCT,  -1 },
45 	{ "U",       BTF_KIND_UNION,   -1 },
46 	{ "func",    BTF_KIND_FUNC,    -1 },
47 };
48 
49 struct kfunc_symbol {
50 	const char	*name;
51 	s32		 id;
52 	u32		 flags;
53 	u32		 arena_args;
54 	bool		 arena_ret;
55 };
56 
57 static struct kfunc_symbol kfunc_symbols[] = {
58 	{ "kfunc_a", -1, 0, 0, false },
59 	{ "kfunc_b", -1, KF_FASTCALL, 0, false },
60 	{ "kfunc_c", -1, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2,
61 	  ARENA_ARG(0) | ARENA_ARG(1), true },
62 	{ "kfunc_d", -1, KF_ARENA_ARG2, ARENA_ARG(1), false },
63 	{ "kfunc_e", -1, 0, ARENA_ARG(0) | ARENA_ARG(1) | ARENA_ARG(2) |
64 	  ARENA_ARG(3) | ARENA_ARG(4), false },
65 	{ "kfunc_f", -1, 0, ARENA_ARG(1), false },
66 	{ "kfunc_g", -1, KF_ARENA_RET, ARENA_ARG(0) | ARENA_ARG(1), true },
67 };
68 
69 /* Align the .BTF_ids section to 4 bytes */
70 asm (
71 ".pushsection " BTF_IDS_SECTION " ,\"a\"; \n"
72 ".balign 4, 0;                            \n"
73 ".popsection;                             \n");
74 
75 /*
76  * test_list_local, test_set and test_kfunc_set are .local symbols placed
77  * in .BTF_ids by inline asm, and are read here directly by C name. To the
78  * compiler they are plain, default-visibility extern objects.
79  *
80  * When test_progs is linked as a position-independent executable (PIE),
81  * taking the address of such an extern is routed through the GOT. The
82  * GNU assembler on aarch64 unconditionally converts references to .local
83  * symbols into section + addend form (".BTF_ids + <offset>"), but a GOT
84  * slot cannot carry an addend (the AArch64 ELF spec mandates zero), so
85  * the linker resolves it to the .BTF_ids base.
86  *
87  * Mark them hidden so the compiler treats them as non-interposable and
88  * emits a direct, addend-preserving PC-relative access instead of a GOT
89  * load, in both PIE and non-PIE builds. test_list_global is .globl and
90  * not affected, so it is left at default visibility.
91  */
92 #pragma GCC visibility push(hidden)
93 BTF_ID_LIST(test_list_local)
94 BTF_ID_UNUSED
95 BTF_ID(typedef, S)
96 BTF_ID(typedef, T)
97 BTF_ID(typedef, U)
98 BTF_ID(struct,  S)
99 BTF_ID(union,   U)
100 BTF_ID(func,    func)
101 
102 BTF_SET_START(test_set)
103 BTF_ID(typedef, S)
104 BTF_ID(typedef, T)
105 BTF_ID(typedef, U)
106 BTF_ID(struct,  S)
107 BTF_ID(union,   U)
108 BTF_ID(func,    func)
109 BTF_SET_END(test_set)
110 
111 BTF_KFUNCS_START(test_kfunc_set)
112 BTF_ID_FLAGS(func, kfunc_a)
113 BTF_ID_FLAGS(func, kfunc_b, KF_FASTCALL)
114 BTF_ID_FLAGS(func, kfunc_c, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2)
115 BTF_ID_FLAGS(func, kfunc_d, KF_ARENA_ARG2)
116 BTF_ID_FLAGS(func, kfunc_e)
117 BTF_ID_FLAGS(func, kfunc_f)
118 BTF_ID_FLAGS(func, kfunc_g, KF_ARENA_RET)
119 BTF_KFUNCS_END(test_kfunc_set)
120 
121 /*
122  * Same kfuncs in reverse declaration order, so resolve_btfids has to
123  * actually sort at least one of the two sets.
124  */
125 BTF_KFUNCS_START(test_kfunc_set_rev)
126 BTF_ID_FLAGS(func, kfunc_g, KF_ARENA_RET)
127 BTF_ID_FLAGS(func, kfunc_f)
128 BTF_ID_FLAGS(func, kfunc_e)
129 BTF_ID_FLAGS(func, kfunc_d, KF_ARENA_ARG2)
130 BTF_ID_FLAGS(func, kfunc_c, KF_ARENA_RET | KF_ARENA_ARG1 | KF_ARENA_ARG2)
131 BTF_ID_FLAGS(func, kfunc_b, KF_FASTCALL)
132 BTF_ID_FLAGS(func, kfunc_a)
133 BTF_KFUNCS_END(test_kfunc_set_rev)
134 #pragma GCC visibility pop
135 
136 extern __u32 test_list_global[];
137 BTF_ID_LIST_GLOBAL(test_list_global, 1)
138 BTF_ID_UNUSED
BTF_ID(typedef,S)139 BTF_ID(typedef, S)
140 BTF_ID(typedef, T)
141 BTF_ID(typedef, U)
142 BTF_ID(struct,  S)
143 BTF_ID(union,   U)
144 BTF_ID(func,    func)
145 
146 static int
147 __resolve_symbol(struct btf *btf, int type_id)
148 {
149 	const struct btf_type *type;
150 	const char *str;
151 	unsigned int i;
152 
153 	type = btf__type_by_id(btf, type_id);
154 	if (!ASSERT_OK_PTR(type, "btf__type_by_id"))
155 		return -1;
156 
157 	str = btf__name_by_offset(btf, type->name_off);
158 
159 	for (i = 0; i < ARRAY_SIZE(test_symbols); i++) {
160 		if (test_symbols[i].id >= 0)
161 			continue;
162 
163 		if (BTF_INFO_KIND(type->info) != test_symbols[i].type)
164 			continue;
165 
166 		if (!strcmp(str, test_symbols[i].name))
167 			test_symbols[i].id = type_id;
168 	}
169 
170 	if (!btf_is_func(type))
171 		return 0;
172 
173 	for (i = 0; i < ARRAY_SIZE(kfunc_symbols); i++) {
174 		if (kfunc_symbols[i].id >= 0)
175 			continue;
176 		if (!strcmp(str, kfunc_symbols[i].name))
177 			kfunc_symbols[i].id = type_id;
178 	}
179 
180 	return 0;
181 }
182 
resolve_symbols(struct btf * btf)183 static int resolve_symbols(struct btf *btf)
184 {
185 	__u32 nr = btf__type_cnt(btf);
186 	int type_id;
187 
188 	for (type_id = 1; type_id < nr; type_id++) {
189 		if (__resolve_symbol(btf, type_id))
190 			return -1;
191 	}
192 	return 0;
193 }
194 
btf_has_decl_tag(struct btf * btf,const char * tag_name,s32 target_id)195 static bool btf_has_decl_tag(struct btf *btf, const char *tag_name, s32 target_id)
196 {
197 	const struct btf_type *t;
198 	const char *name;
199 	int nr, id;
200 
201 	nr = btf__type_cnt(btf);
202 	for (id = 1; id < nr; id++) {
203 		t = btf__type_by_id(btf, id);
204 		if (!btf_is_decl_tag(t))
205 			continue;
206 		if (t->type != (__u32)target_id)
207 			continue;
208 		if (btf_decl_tag(t)->component_idx != -1)
209 			continue;
210 		name = btf__name_by_offset(btf, t->name_off);
211 		if (strcmp(name, tag_name) == 0)
212 			return true;
213 	}
214 	return false;
215 }
216 
check_kfunc_set(struct btf_id_set8 * set)217 static void check_kfunc_set(struct btf_id_set8 *set)
218 {
219 	unsigned int i, j;
220 
221 	ASSERT_EQ(set->flags, BTF_SET8_KFUNCS, "kfunc_set_flags");
222 	ASSERT_EQ(set->cnt, ARRAY_SIZE(kfunc_symbols), "kfunc_set_cnt");
223 
224 	for (i = 0; i < set->cnt; i++) {
225 		for (j = 0; j < ARRAY_SIZE(kfunc_symbols); j++) {
226 			if (kfunc_symbols[j].id == (s32)set->pairs[i].id) {
227 				ASSERT_EQ(set->pairs[i].flags,
228 					  kfunc_symbols[j].flags, "kfunc_flags_check");
229 				break;
230 			}
231 		}
232 
233 		ASSERT_TRUE(j < ARRAY_SIZE(kfunc_symbols), "kfunc_id_found");
234 
235 		if (i > 0) {
236 			ASSERT_LE(set->pairs[i - 1].id,
237 				  set->pairs[i].id, "kfunc_sort_check");
238 		}
239 	}
240 }
241 
242 /* True if @id is PTR -> TYPE_TAG(kflag=1, "address_space(1)") -> pointee */
is_arena_tagged_ptr(struct btf * btf,__u32 id)243 static bool is_arena_tagged_ptr(struct btf *btf, __u32 id)
244 {
245 	const struct btf_type *ptr, *tag;
246 	const char *name;
247 
248 	ptr = btf__type_by_id(btf, id);
249 	if (!btf_is_ptr(ptr))
250 		return false;
251 	tag = btf__type_by_id(btf, ptr->type);
252 	if (!btf_is_type_tag(tag) || !btf_kflag(tag))
253 		return false;
254 	name = btf__name_by_offset(btf, tag->name_off);
255 	return strcmp(name, TYPE_ATTR_ARENA) == 0;
256 }
257 
test_resolve_btfids(void)258 void test_resolve_btfids(void)
259 {
260 	__u32 *test_list, *test_lists[] = { test_list_local, test_list_global };
261 	unsigned int i, j;
262 	struct btf *btf;
263 
264 	btf = btf__parse_raw(BTF_DATA_FILE);
265 	if (!ASSERT_OK_PTR(btf, "btf_parse"))
266 		return;
267 
268 	if (resolve_symbols(btf))
269 		goto out;
270 
271 	/* Check BTF_ID_LIST(test_list_local) and
272 	 * BTF_ID_LIST_GLOBAL(test_list_global) IDs
273 	 */
274 	for (j = 0; j < ARRAY_SIZE(test_lists); j++) {
275 		test_list = test_lists[j];
276 		for (i = 0; i < ARRAY_SIZE(test_symbols); i++)
277 			ASSERT_EQ(test_list[i], test_symbols[i].id, test_symbols[i].name);
278 	}
279 
280 	/* Check BTF_SET_START(test_set) IDs */
281 	for (i = 0; i < test_set.cnt; i++) {
282 		bool found = false;
283 
284 		for (j = 0; j < ARRAY_SIZE(test_symbols); j++) {
285 			if (test_symbols[j].id != test_set.ids[i])
286 				continue;
287 			found = true;
288 			break;
289 		}
290 
291 		if (!ASSERT_TRUE(found, "id_in_test_symbols"))
292 			break;
293 
294 		if (i > 0)
295 			ASSERT_LE(test_set.ids[i - 1], test_set.ids[i], "sort_check");
296 	}
297 
298 	check_kfunc_set(&test_kfunc_set);
299 	check_kfunc_set(&test_kfunc_set_rev);
300 
301 	/* Check resolve_btfids emitted a bpf_kfunc decl_tag for each kfunc */
302 	for (i = 0; i < ARRAY_SIZE(kfunc_symbols); i++) {
303 		ASSERT_TRUE(btf_has_decl_tag(btf, DECL_TAG_KFUNC,
304 					     kfunc_symbols[i].id),
305 			    kfunc_symbols[i].name);
306 	}
307 
308 	/* Check resolve_btfids emitted bpf_fastcall for KF_FASTCALL kfuncs */
309 	for (i = 0; i < ARRAY_SIZE(kfunc_symbols); i++) {
310 		if (kfunc_symbols[i].flags & KF_FASTCALL) {
311 			ASSERT_TRUE(btf_has_decl_tag(btf, DECL_TAG_FASTCALL,
312 						     kfunc_symbols[i].id),
313 				    kfunc_symbols[i].name);
314 		}
315 	}
316 
317 	/*
318 	 * Check resolve_btfids wrapped exactly the arena-flagged or suffixed
319 	 * return/args with the address_space(1) type attribute, and left other
320 	 * pointers/returns untouched.
321 	 */
322 	for (i = 0; i < ARRAY_SIZE(kfunc_symbols); i++) {
323 		const struct btf_type *fn, *proto;
324 		const struct btf_param *params;
325 		const char *name = kfunc_symbols[i].name;
326 		u32 arena_args = kfunc_symbols[i].arena_args;
327 		__u32 nr;
328 
329 		fn = btf__type_by_id(btf, kfunc_symbols[i].id);
330 		if (!ASSERT_TRUE(btf_is_func(fn), name))
331 			continue;
332 		proto = btf__type_by_id(btf, fn->type);
333 		if (!ASSERT_TRUE(btf_is_func_proto(proto), name))
334 			continue;
335 		params = btf_params(proto);
336 		nr = btf_vlen(proto);
337 
338 		ASSERT_EQ(is_arena_tagged_ptr(btf, proto->type),
339 			  kfunc_symbols[i].arena_ret, name);
340 		for (j = 0; j < nr; j++)
341 			ASSERT_EQ(is_arena_tagged_ptr(btf, params[j].type),
342 				  !!(arena_args & ARENA_ARG(j)), name);
343 	}
344 
345 out:
346 	btf__free(btf);
347 }
348