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