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 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 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 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 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 */ 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 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