1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <test_progs.h> 4 #include "progs/core_reloc_types.h" 5 #include "bpf_testmod/bpf_testmod.h" 6 #include <linux/limits.h> 7 #include <sys/mman.h> 8 #include <sys/syscall.h> 9 #include <bpf/btf.h> 10 11 static int duration = 0; 12 13 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name) 14 15 #define MODULES_CASE(name, pg_name, tp_name) { \ 16 .case_name = name, \ 17 .bpf_obj_file = "test_core_reloc_module.bpf.o", \ 18 .btf_src_file = NULL, /* find in kernel module BTFs */ \ 19 .input = "", \ 20 .input_len = 0, \ 21 .output = STRUCT_TO_CHAR_PTR(core_reloc_module_output) { \ 22 .read_ctx_sz = sizeof(struct bpf_testmod_test_read_ctx),\ 23 .read_ctx_exists = true, \ 24 .buf_exists = true, \ 25 .len_exists = true, \ 26 .off_exists = true, \ 27 .len = 123, \ 28 .off = 0, \ 29 .comm = "test_progs", \ 30 .comm_len = sizeof("test_progs"), \ 31 }, \ 32 .output_len = sizeof(struct core_reloc_module_output), \ 33 .prog_name = pg_name, \ 34 .raw_tp_name = tp_name, \ 35 .trigger = __trigger_module_test_read, \ 36 .needs_testmod = true, \ 37 } 38 39 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 40 .a = 42, \ 41 .b = 0xc001, \ 42 .c = 0xbeef, \ 43 } 44 45 #define FLAVORS_CASE_COMMON(name) \ 46 .case_name = #name, \ 47 .bpf_obj_file = "test_core_reloc_flavors.bpf.o", \ 48 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 49 .raw_tp_name = "sys_enter", \ 50 .prog_name = "test_core_flavors" \ 51 52 #define FLAVORS_CASE(name) { \ 53 FLAVORS_CASE_COMMON(name), \ 54 .input = FLAVORS_DATA(core_reloc_##name), \ 55 .input_len = sizeof(struct core_reloc_##name), \ 56 .output = FLAVORS_DATA(core_reloc_flavors), \ 57 .output_len = sizeof(struct core_reloc_flavors), \ 58 } 59 60 #define FLAVORS_ERR_CASE(name) { \ 61 FLAVORS_CASE_COMMON(name), \ 62 .fails = true, \ 63 } 64 65 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 66 .a = { .a = { .a = 42 } }, \ 67 .b = { .b = { .b = 0xc001 } }, \ 68 } 69 70 #define NESTING_CASE_COMMON(name) \ 71 .case_name = #name, \ 72 .bpf_obj_file = "test_core_reloc_nesting.bpf.o", \ 73 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 74 .raw_tp_name = "sys_enter", \ 75 .prog_name = "test_core_nesting" \ 76 77 #define NESTING_CASE(name) { \ 78 NESTING_CASE_COMMON(name), \ 79 .input = NESTING_DATA(core_reloc_##name), \ 80 .input_len = sizeof(struct core_reloc_##name), \ 81 .output = NESTING_DATA(core_reloc_nesting), \ 82 .output_len = sizeof(struct core_reloc_nesting) \ 83 } 84 85 #define NESTING_ERR_CASE(name) { \ 86 NESTING_CASE_COMMON(name), \ 87 .fails = true, \ 88 .run_btfgen_fails = true, \ 89 } 90 91 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 92 .a = { [2] = 1 }, \ 93 .b = { [1] = { [2] = { [3] = 2 } } }, \ 94 .c = { [1] = { .c = 3 } }, \ 95 .d = { [0] = { [0] = { .d = 4 } } }, \ 96 } 97 98 #define ARRAYS_CASE_COMMON(name) \ 99 .case_name = #name, \ 100 .bpf_obj_file = "test_core_reloc_arrays.bpf.o", \ 101 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 102 .raw_tp_name = "sys_enter", \ 103 .prog_name = "test_core_arrays" \ 104 105 #define ARRAYS_CASE(name) { \ 106 ARRAYS_CASE_COMMON(name), \ 107 .input = ARRAYS_DATA(core_reloc_##name), \ 108 .input_len = sizeof(struct core_reloc_##name), \ 109 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \ 110 .a2 = 1, \ 111 .b123 = 2, \ 112 .c1c = 3, \ 113 .d00d = 4, \ 114 .f10c = 0, \ 115 }, \ 116 .output_len = sizeof(struct core_reloc_arrays_output) \ 117 } 118 119 #define ARRAYS_ERR_CASE(name) { \ 120 ARRAYS_CASE_COMMON(name), \ 121 .fails = true, \ 122 } 123 124 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 125 .a = 1, \ 126 .b = 2, \ 127 .c = 3, \ 128 .d = (void *)4, \ 129 .f = (void *)5, \ 130 } 131 132 #define PRIMITIVES_CASE_COMMON(name) \ 133 .case_name = #name, \ 134 .bpf_obj_file = "test_core_reloc_primitives.bpf.o", \ 135 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 136 .raw_tp_name = "sys_enter", \ 137 .prog_name = "test_core_primitives" \ 138 139 #define PRIMITIVES_CASE(name) { \ 140 PRIMITIVES_CASE_COMMON(name), \ 141 .input = PRIMITIVES_DATA(core_reloc_##name), \ 142 .input_len = sizeof(struct core_reloc_##name), \ 143 .output = PRIMITIVES_DATA(core_reloc_primitives), \ 144 .output_len = sizeof(struct core_reloc_primitives), \ 145 } 146 147 #define PRIMITIVES_ERR_CASE(name) { \ 148 PRIMITIVES_CASE_COMMON(name), \ 149 .fails = true, \ 150 } 151 152 #define MODS_CASE(name) { \ 153 .case_name = #name, \ 154 .bpf_obj_file = "test_core_reloc_mods.bpf.o", \ 155 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 156 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) { \ 157 .a = 1, \ 158 .b = 2, \ 159 .c = (void *)3, \ 160 .d = (void *)4, \ 161 .e = { [2] = 5 }, \ 162 .f = { [1] = 6 }, \ 163 .g = { .x = 7 }, \ 164 .h = { .y = 8 }, \ 165 }, \ 166 .input_len = sizeof(struct core_reloc_##name), \ 167 .output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) { \ 168 .a = 1, .b = 2, .c = 3, .d = 4, \ 169 .e = 5, .f = 6, .g = 7, .h = 8, \ 170 }, \ 171 .output_len = sizeof(struct core_reloc_mods_output), \ 172 .raw_tp_name = "sys_enter", \ 173 .prog_name = "test_core_mods", \ 174 } 175 176 #define PTR_AS_ARR_CASE(name) { \ 177 .case_name = #name, \ 178 .bpf_obj_file = "test_core_reloc_ptr_as_arr.bpf.o", \ 179 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 180 .input = (const char *)&(struct core_reloc_##name []){ \ 181 { .a = 1 }, \ 182 { .a = 2 }, \ 183 { .a = 3 }, \ 184 }, \ 185 .input_len = 3 * sizeof(struct core_reloc_##name), \ 186 .output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) { \ 187 .a = 3, \ 188 }, \ 189 .output_len = sizeof(struct core_reloc_ptr_as_arr), \ 190 .raw_tp_name = "sys_enter", \ 191 .prog_name = "test_core_ptr_as_arr", \ 192 } 193 194 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 195 .u8_field = 1, \ 196 .s8_field = 2, \ 197 .u16_field = 3, \ 198 .s16_field = 4, \ 199 .u32_field = 5, \ 200 .s32_field = 6, \ 201 .u64_field = 7, \ 202 .s64_field = 8, \ 203 } 204 205 #define INTS_CASE_COMMON(name) \ 206 .case_name = #name, \ 207 .bpf_obj_file = "test_core_reloc_ints.bpf.o", \ 208 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 209 .raw_tp_name = "sys_enter", \ 210 .prog_name = "test_core_ints" 211 212 #define INTS_CASE(name) { \ 213 INTS_CASE_COMMON(name), \ 214 .input = INTS_DATA(core_reloc_##name), \ 215 .input_len = sizeof(struct core_reloc_##name), \ 216 .output = INTS_DATA(core_reloc_ints), \ 217 .output_len = sizeof(struct core_reloc_ints), \ 218 } 219 220 #define INTS_ERR_CASE(name) { \ 221 INTS_CASE_COMMON(name), \ 222 .fails = true, \ 223 } 224 225 #define FIELD_EXISTS_CASE_COMMON(name) \ 226 .case_name = #name, \ 227 .bpf_obj_file = "test_core_reloc_existence.bpf.o", \ 228 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 229 .raw_tp_name = "sys_enter", \ 230 .prog_name = "test_core_existence" 231 232 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \ 233 .case_name = test_name_prefix#name, \ 234 .bpf_obj_file = objfile, \ 235 .btf_src_file = "btf__core_reloc_" #name ".bpf.o" 236 237 #define BITFIELDS_CASE(name, ...) { \ 238 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \ 239 "probed:", name), \ 240 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \ 241 .input_len = sizeof(struct core_reloc_##name), \ 242 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \ 243 __VA_ARGS__, \ 244 .output_len = sizeof(struct core_reloc_bitfields_output), \ 245 .raw_tp_name = "sys_enter", \ 246 .prog_name = "test_core_bitfields", \ 247 }, { \ 248 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \ 249 "direct:", name), \ 250 .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \ 251 .input_len = sizeof(struct core_reloc_##name), \ 252 .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \ 253 __VA_ARGS__, \ 254 .output_len = sizeof(struct core_reloc_bitfields_output), \ 255 .prog_name = "test_core_bitfields_direct", \ 256 } 257 258 259 #define BITFIELDS_ERR_CASE(name) { \ 260 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.bpf.o", \ 261 "probed:", name), \ 262 .fails = true, \ 263 .run_btfgen_fails = true, \ 264 .raw_tp_name = "sys_enter", \ 265 .prog_name = "test_core_bitfields", \ 266 }, { \ 267 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.bpf.o", \ 268 "direct:", name), \ 269 .fails = true, \ 270 .run_btfgen_fails = true, \ 271 .prog_name = "test_core_bitfields_direct", \ 272 } 273 274 #define SIZE_CASE_COMMON(name) \ 275 .case_name = #name, \ 276 .bpf_obj_file = "test_core_reloc_size.bpf.o", \ 277 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 278 .raw_tp_name = "sys_enter", \ 279 .prog_name = "test_core_size" 280 281 #define SIZE_OUTPUT_DATA(type) \ 282 STRUCT_TO_CHAR_PTR(core_reloc_size_output) { \ 283 .int_sz = sizeof(((type *)0)->int_field), \ 284 .int_off = offsetof(type, int_field), \ 285 .struct_sz = sizeof(((type *)0)->struct_field), \ 286 .struct_off = offsetof(type, struct_field), \ 287 .union_sz = sizeof(((type *)0)->union_field), \ 288 .union_off = offsetof(type, union_field), \ 289 .arr_sz = sizeof(((type *)0)->arr_field), \ 290 .arr_off = offsetof(type, arr_field), \ 291 .arr_elem_sz = sizeof(((type *)0)->arr_field[1]), \ 292 .arr_elem_off = offsetof(type, arr_field[1]), \ 293 .ptr_sz = 8, /* always 8-byte pointer for BPF */ \ 294 .ptr_off = offsetof(type, ptr_field), \ 295 .enum_sz = sizeof(((type *)0)->enum_field), \ 296 .enum_off = offsetof(type, enum_field), \ 297 .float_sz = sizeof(((type *)0)->float_field), \ 298 .float_off = offsetof(type, float_field), \ 299 } 300 301 #define SIZE_CASE(name) { \ 302 SIZE_CASE_COMMON(name), \ 303 .input_len = 0, \ 304 .output = SIZE_OUTPUT_DATA(struct core_reloc_##name), \ 305 .output_len = sizeof(struct core_reloc_size_output), \ 306 } 307 308 #define SIZE_ERR_CASE(name) { \ 309 SIZE_CASE_COMMON(name), \ 310 .fails = true, \ 311 .run_btfgen_fails = true, \ 312 } 313 314 #define TYPE_BASED_CASE_COMMON(name) \ 315 .case_name = #name, \ 316 .bpf_obj_file = "test_core_reloc_type_based.bpf.o", \ 317 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 318 .raw_tp_name = "sys_enter", \ 319 .prog_name = "test_core_type_based" 320 321 #define TYPE_BASED_CASE(name, ...) { \ 322 TYPE_BASED_CASE_COMMON(name), \ 323 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output) \ 324 __VA_ARGS__, \ 325 .output_len = sizeof(struct core_reloc_type_based_output), \ 326 } 327 328 #define TYPE_BASED_ERR_CASE(name) { \ 329 TYPE_BASED_CASE_COMMON(name), \ 330 .fails = true, \ 331 } 332 333 #define TYPE_ID_CASE_COMMON(name) \ 334 .case_name = #name, \ 335 .bpf_obj_file = "test_core_reloc_type_id.bpf.o", \ 336 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 337 .raw_tp_name = "sys_enter", \ 338 .prog_name = "test_core_type_id" 339 340 #define TYPE_ID_CASE(name, setup_fn) { \ 341 TYPE_ID_CASE_COMMON(name), \ 342 .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \ 343 .output_len = sizeof(struct core_reloc_type_id_output), \ 344 .setup = setup_fn, \ 345 } 346 347 #define TYPE_ID_ERR_CASE(name) { \ 348 TYPE_ID_CASE_COMMON(name), \ 349 .fails = true, \ 350 } 351 352 #define ENUMVAL_CASE_COMMON(name) \ 353 .case_name = #name, \ 354 .bpf_obj_file = "test_core_reloc_enumval.bpf.o", \ 355 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 356 .raw_tp_name = "sys_enter", \ 357 .prog_name = "test_core_enumval" 358 359 #define ENUMVAL_CASE(name, ...) { \ 360 ENUMVAL_CASE_COMMON(name), \ 361 .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \ 362 __VA_ARGS__, \ 363 .output_len = sizeof(struct core_reloc_enumval_output), \ 364 } 365 366 #define ENUMVAL_ERR_CASE(name) { \ 367 ENUMVAL_CASE_COMMON(name), \ 368 .fails = true, \ 369 } 370 371 #define ENUM64VAL_CASE_COMMON(name) \ 372 .case_name = #name, \ 373 .bpf_obj_file = "test_core_reloc_enum64val.bpf.o", \ 374 .btf_src_file = "btf__core_reloc_" #name ".bpf.o", \ 375 .raw_tp_name = "sys_enter", \ 376 .prog_name = "test_core_enum64val" 377 378 #define ENUM64VAL_CASE(name, ...) { \ 379 ENUM64VAL_CASE_COMMON(name), \ 380 .output = STRUCT_TO_CHAR_PTR(core_reloc_enum64val_output) \ 381 __VA_ARGS__, \ 382 .output_len = sizeof(struct core_reloc_enum64val_output), \ 383 } 384 385 #define ENUM64VAL_ERR_CASE(name) { \ 386 ENUM64VAL_CASE_COMMON(name), \ 387 .fails = true, \ 388 } 389 390 struct core_reloc_test_case; 391 392 typedef int (*setup_test_fn)(struct core_reloc_test_case *test); 393 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test); 394 395 struct core_reloc_test_case { 396 const char *case_name; 397 const char *bpf_obj_file; 398 const char *btf_src_file; 399 const char *input; 400 int input_len; 401 const char *output; 402 int output_len; 403 bool fails; 404 bool run_btfgen_fails; 405 bool needs_testmod; 406 bool relaxed_core_relocs; 407 const char *prog_name; 408 const char *raw_tp_name; 409 setup_test_fn setup; 410 trigger_test_fn trigger; 411 }; 412 find_btf_type(const struct btf * btf,const char * name,__u32 kind)413 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind) 414 { 415 int id; 416 417 id = btf__find_by_name_kind(btf, name, kind); 418 if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id)) 419 return -1; 420 421 return id; 422 } 423 setup_type_id_case_local(struct core_reloc_test_case * test)424 static int setup_type_id_case_local(struct core_reloc_test_case *test) 425 { 426 struct core_reloc_type_id_output *exp = (void *)test->output; 427 struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL); 428 struct btf *targ_btf = btf__parse(test->btf_src_file, NULL); 429 const struct btf_type *t; 430 const char *name; 431 int i; 432 433 if (!ASSERT_OK_PTR(local_btf, "local_btf") || !ASSERT_OK_PTR(targ_btf, "targ_btf")) { 434 btf__free(local_btf); 435 btf__free(targ_btf); 436 return -EINVAL; 437 } 438 439 exp->local_anon_struct = -1; 440 exp->local_anon_union = -1; 441 exp->local_anon_enum = -1; 442 exp->local_anon_func_proto_ptr = -1; 443 exp->local_anon_void_ptr = -1; 444 exp->local_anon_arr = -1; 445 446 for (i = 1; i < btf__type_cnt(local_btf); i++) 447 { 448 t = btf__type_by_id(local_btf, i); 449 /* we are interested only in anonymous types */ 450 if (t->name_off) 451 continue; 452 453 if (btf_is_struct(t) && btf_vlen(t) && 454 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) && 455 strcmp(name, "marker_field") == 0) { 456 exp->local_anon_struct = i; 457 } else if (btf_is_union(t) && btf_vlen(t) && 458 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) && 459 strcmp(name, "marker_field") == 0) { 460 exp->local_anon_union = i; 461 } else if (btf_is_enum(t) && btf_vlen(t) && 462 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) && 463 strcmp(name, "MARKER_ENUM_VAL") == 0) { 464 exp->local_anon_enum = i; 465 } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) { 466 if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) && 467 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) && 468 strcmp(name, "_Bool") == 0) { 469 /* ptr -> func_proto -> _Bool */ 470 exp->local_anon_func_proto_ptr = i; 471 } else if (btf_is_void(t)) { 472 /* ptr -> void */ 473 exp->local_anon_void_ptr = i; 474 } 475 } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) && 476 btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) && 477 strcmp(name, "_Bool") == 0) { 478 /* _Bool[] */ 479 exp->local_anon_arr = i; 480 } 481 } 482 483 exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT); 484 exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION); 485 exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM); 486 exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT); 487 exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF); 488 exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF); 489 exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF); 490 491 btf__free(local_btf); 492 btf__free(targ_btf); 493 return 0; 494 } 495 setup_type_id_case_success(struct core_reloc_test_case * test)496 static int setup_type_id_case_success(struct core_reloc_test_case *test) { 497 struct core_reloc_type_id_output *exp = (void *)test->output; 498 struct btf *targ_btf; 499 int err; 500 501 err = setup_type_id_case_local(test); 502 if (err) 503 return err; 504 505 targ_btf = btf__parse(test->btf_src_file, NULL); 506 507 exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT); 508 exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION); 509 exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM); 510 exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT); 511 exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF); 512 exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF); 513 exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF); 514 515 btf__free(targ_btf); 516 return 0; 517 } 518 setup_type_id_case_failure(struct core_reloc_test_case * test)519 static int setup_type_id_case_failure(struct core_reloc_test_case *test) 520 { 521 struct core_reloc_type_id_output *exp = (void *)test->output; 522 int err; 523 524 err = setup_type_id_case_local(test); 525 if (err) 526 return err; 527 528 exp->targ_struct = 0; 529 exp->targ_union = 0; 530 exp->targ_enum = 0; 531 exp->targ_int = 0; 532 exp->targ_struct_typedef = 0; 533 exp->targ_func_proto_typedef = 0; 534 exp->targ_arr_typedef = 0; 535 536 return 0; 537 } 538 __trigger_module_test_read(const struct core_reloc_test_case * test)539 static int __trigger_module_test_read(const struct core_reloc_test_case *test) 540 { 541 struct core_reloc_module_output *exp = (void *)test->output; 542 543 trigger_module_test_read(exp->len); 544 return 0; 545 } 546 547 static const struct core_reloc_test_case test_cases[] = { 548 /* validate we can find kernel image and use its BTF for relocs */ 549 { 550 .case_name = "kernel", 551 .bpf_obj_file = "test_core_reloc_kernel.bpf.o", 552 .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */ 553 .input = "", 554 .input_len = 0, 555 .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) { 556 .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, 557 .comm = "test_progs", 558 .comm_len = sizeof("test_progs"), 559 .local_task_struct_matches = true, 560 }, 561 .output_len = sizeof(struct core_reloc_kernel_output), 562 .raw_tp_name = "sys_enter", 563 .prog_name = "test_core_kernel", 564 }, 565 566 /* validate we can find kernel module BTF types for relocs/attach */ 567 MODULES_CASE("module_probed", "test_core_module_probed", "bpf_testmod_test_read"), 568 MODULES_CASE("module_direct", "test_core_module_direct", NULL), 569 570 /* validate BPF program can use multiple flavors to match against 571 * single target BTF type 572 */ 573 FLAVORS_CASE(flavors), 574 575 FLAVORS_ERR_CASE(flavors__err_wrong_name), 576 577 /* various struct/enum nesting and resolution scenarios */ 578 NESTING_CASE(nesting), 579 NESTING_CASE(nesting___anon_embed), 580 NESTING_CASE(nesting___struct_union_mixup), 581 NESTING_CASE(nesting___extra_nesting), 582 NESTING_CASE(nesting___dup_compat_types), 583 584 NESTING_ERR_CASE(nesting___err_missing_field), 585 NESTING_ERR_CASE(nesting___err_array_field), 586 NESTING_ERR_CASE(nesting___err_missing_container), 587 NESTING_ERR_CASE(nesting___err_nonstruct_container), 588 NESTING_ERR_CASE(nesting___err_array_container), 589 NESTING_ERR_CASE(nesting___err_dup_incompat_types), 590 NESTING_ERR_CASE(nesting___err_partial_match_dups), 591 NESTING_ERR_CASE(nesting___err_too_deep), 592 593 /* various array access relocation scenarios */ 594 ARRAYS_CASE(arrays), 595 ARRAYS_CASE(arrays___diff_arr_dim), 596 ARRAYS_CASE(arrays___diff_arr_val_sz), 597 ARRAYS_CASE(arrays___equiv_zero_sz_arr), 598 ARRAYS_CASE(arrays___fixed_arr), 599 600 ARRAYS_ERR_CASE(arrays___err_too_small), 601 ARRAYS_ERR_CASE(arrays___err_too_shallow), 602 ARRAYS_ERR_CASE(arrays___err_non_array), 603 ARRAYS_ERR_CASE(arrays___err_wrong_val_type), 604 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr), 605 606 /* enum/ptr/int handling scenarios */ 607 PRIMITIVES_CASE(primitives), 608 PRIMITIVES_CASE(primitives___diff_enum_def), 609 PRIMITIVES_CASE(primitives___diff_func_proto), 610 PRIMITIVES_CASE(primitives___diff_ptr_type), 611 612 PRIMITIVES_ERR_CASE(primitives___err_non_enum), 613 PRIMITIVES_ERR_CASE(primitives___err_non_int), 614 PRIMITIVES_ERR_CASE(primitives___err_non_ptr), 615 616 /* const/volatile/restrict and typedefs scenarios */ 617 MODS_CASE(mods), 618 MODS_CASE(mods___mod_swap), 619 MODS_CASE(mods___typedefs), 620 621 /* handling "ptr is an array" semantics */ 622 PTR_AS_ARR_CASE(ptr_as_arr), 623 PTR_AS_ARR_CASE(ptr_as_arr___diff_sz), 624 625 /* int signedness/sizing/bitfield handling */ 626 INTS_CASE(ints), 627 INTS_CASE(ints___bool), 628 INTS_CASE(ints___reverse_sign), 629 630 /* validate edge cases of capturing relocations */ 631 { 632 .case_name = "misc", 633 .bpf_obj_file = "test_core_reloc_misc.bpf.o", 634 .btf_src_file = "btf__core_reloc_misc.bpf.o", 635 .input = (const char *)&(struct core_reloc_misc_extensible[]){ 636 { .a = 1 }, 637 { .a = 2 }, /* not read */ 638 { .a = 3 }, 639 }, 640 .input_len = 4 * sizeof(int), 641 .output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) { 642 .a = 1, 643 .b = 1, 644 .c = 0, /* BUG in clang, should be 3 */ 645 }, 646 .output_len = sizeof(struct core_reloc_misc_output), 647 .raw_tp_name = "sys_enter", 648 .prog_name = "test_core_misc", 649 }, 650 651 /* validate field existence checks */ 652 { 653 FIELD_EXISTS_CASE_COMMON(existence), 654 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) { 655 .a = 1, 656 .b = 2, 657 .c = 3, 658 .arr = { 4 }, 659 .s = { .x = 5 }, 660 }, 661 .input_len = sizeof(struct core_reloc_existence), 662 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) { 663 .a_exists = 1, 664 .b_exists = 1, 665 .c_exists = 1, 666 .arr_exists = 1, 667 .s_exists = 1, 668 .a_value = 1, 669 .b_value = 2, 670 .c_value = 3, 671 .arr_value = 4, 672 .s_value = 5, 673 }, 674 .output_len = sizeof(struct core_reloc_existence_output), 675 }, 676 { 677 FIELD_EXISTS_CASE_COMMON(existence___minimal), 678 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) { 679 .a = 42, 680 }, 681 .input_len = sizeof(struct core_reloc_existence___minimal), 682 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) { 683 .a_exists = 1, 684 .b_exists = 0, 685 .c_exists = 0, 686 .arr_exists = 0, 687 .s_exists = 0, 688 .a_value = 42, 689 .b_value = 0xff000002u, 690 .c_value = 0xff000003u, 691 .arr_value = 0xff000004u, 692 .s_value = 0xff000005u, 693 }, 694 .output_len = sizeof(struct core_reloc_existence_output), 695 }, 696 { 697 FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs), 698 .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) { 699 }, 700 .input_len = sizeof(struct core_reloc_existence___wrong_field_defs), 701 .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) { 702 .a_exists = 0, 703 .b_exists = 0, 704 .c_exists = 0, 705 .arr_exists = 0, 706 .s_exists = 0, 707 .a_value = 0xff000001u, 708 .b_value = 0xff000002u, 709 .c_value = 0xff000003u, 710 .arr_value = 0xff000004u, 711 .s_value = 0xff000005u, 712 }, 713 .output_len = sizeof(struct core_reloc_existence_output), 714 }, 715 716 /* bitfield relocation checks */ 717 BITFIELDS_CASE(bitfields, { 718 .ub1 = 1, 719 .ub2 = 2, 720 .ub7 = 96, 721 .sb4 = -7, 722 .sb20 = -0x76543, 723 .u32 = 0x80000000, 724 .s32 = -0x76543210, 725 }), 726 BITFIELDS_CASE(bitfields___bit_sz_change, { 727 .ub1 = 6, 728 .ub2 = 0xABCDE, 729 .ub7 = 1, 730 .sb4 = -1, 731 .sb20 = -0x17654321, 732 .u32 = 0xBEEF, 733 .s32 = -0x3FEDCBA987654321LL, 734 }), 735 BITFIELDS_CASE(bitfields___bitfield_vs_int, { 736 .ub1 = 0xFEDCBA9876543210LL, 737 .ub2 = 0xA6, 738 .ub7 = -0x7EDCBA987654321LL, 739 .sb4 = -0x6123456789ABCDELL, 740 .sb20 = 0xD00DLL, 741 .u32 = -0x76543, 742 .s32 = 0x0ADEADBEEFBADB0BLL, 743 }), 744 BITFIELDS_CASE(bitfields___just_big_enough, { 745 .ub1 = 0xFLL, 746 .ub2 = 0x0812345678FEDCBALL, 747 }), 748 BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield), 749 750 /* field size and offset relocation checks */ 751 SIZE_CASE(size), 752 SIZE_CASE(size___diff_sz), 753 SIZE_CASE(size___diff_offs), 754 SIZE_ERR_CASE(size___err_ambiguous), 755 756 /* validate type existence, match, and size relocations */ 757 TYPE_BASED_CASE(type_based, { 758 .struct_exists = 1, 759 .complex_struct_exists = 1, 760 .union_exists = 1, 761 .enum_exists = 1, 762 .typedef_named_struct_exists = 1, 763 .typedef_anon_struct_exists = 1, 764 .typedef_struct_ptr_exists = 1, 765 .typedef_int_exists = 1, 766 .typedef_enum_exists = 1, 767 .typedef_void_ptr_exists = 1, 768 .typedef_restrict_ptr_exists = 1, 769 .typedef_func_proto_exists = 1, 770 .typedef_arr_exists = 1, 771 772 .struct_matches = 1, 773 .complex_struct_matches = 1, 774 .union_matches = 1, 775 .enum_matches = 1, 776 .typedef_named_struct_matches = 1, 777 .typedef_anon_struct_matches = 1, 778 .typedef_struct_ptr_matches = 1, 779 .typedef_int_matches = 1, 780 .typedef_enum_matches = 1, 781 .typedef_void_ptr_matches = 1, 782 .typedef_restrict_ptr_matches = 1, 783 .typedef_func_proto_matches = 1, 784 .typedef_arr_matches = 1, 785 786 .struct_sz = sizeof(struct a_struct), 787 .union_sz = sizeof(union a_union), 788 .enum_sz = sizeof(enum an_enum), 789 .typedef_named_struct_sz = sizeof(named_struct_typedef), 790 .typedef_anon_struct_sz = sizeof(anon_struct_typedef), 791 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef), 792 .typedef_int_sz = sizeof(int_typedef), 793 .typedef_enum_sz = sizeof(enum_typedef), 794 .typedef_void_ptr_sz = sizeof(void_ptr_typedef), 795 .typedef_func_proto_sz = sizeof(func_proto_typedef), 796 .typedef_arr_sz = sizeof(arr_typedef), 797 }), 798 TYPE_BASED_CASE(type_based___all_missing, { 799 /* all zeros */ 800 }), 801 TYPE_BASED_CASE(type_based___diff, { 802 .struct_exists = 1, 803 .complex_struct_exists = 1, 804 .union_exists = 1, 805 .enum_exists = 1, 806 .typedef_named_struct_exists = 1, 807 .typedef_anon_struct_exists = 1, 808 .typedef_struct_ptr_exists = 1, 809 .typedef_int_exists = 1, 810 .typedef_enum_exists = 1, 811 .typedef_void_ptr_exists = 1, 812 .typedef_func_proto_exists = 1, 813 .typedef_arr_exists = 1, 814 815 .struct_matches = 1, 816 .complex_struct_matches = 1, 817 .union_matches = 1, 818 .enum_matches = 1, 819 .typedef_named_struct_matches = 1, 820 .typedef_anon_struct_matches = 1, 821 .typedef_struct_ptr_matches = 1, 822 .typedef_int_matches = 0, 823 .typedef_enum_matches = 1, 824 .typedef_void_ptr_matches = 1, 825 .typedef_func_proto_matches = 0, 826 .typedef_arr_matches = 0, 827 828 .struct_sz = sizeof(struct a_struct___diff), 829 .union_sz = sizeof(union a_union___diff), 830 .enum_sz = sizeof(enum an_enum___diff), 831 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff), 832 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff), 833 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff), 834 .typedef_int_sz = sizeof(int_typedef___diff), 835 .typedef_enum_sz = sizeof(enum_typedef___diff), 836 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff), 837 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff), 838 .typedef_arr_sz = sizeof(arr_typedef___diff), 839 }), 840 TYPE_BASED_CASE(type_based___diff_sz, { 841 .struct_exists = 1, 842 .union_exists = 1, 843 .enum_exists = 1, 844 .typedef_named_struct_exists = 1, 845 .typedef_anon_struct_exists = 1, 846 .typedef_struct_ptr_exists = 1, 847 .typedef_int_exists = 1, 848 .typedef_enum_exists = 1, 849 .typedef_void_ptr_exists = 1, 850 .typedef_func_proto_exists = 1, 851 .typedef_arr_exists = 1, 852 853 .struct_matches = 0, 854 .union_matches = 0, 855 .enum_matches = 0, 856 .typedef_named_struct_matches = 0, 857 .typedef_anon_struct_matches = 0, 858 .typedef_struct_ptr_matches = 1, 859 .typedef_int_matches = 0, 860 .typedef_enum_matches = 0, 861 .typedef_void_ptr_matches = 1, 862 .typedef_func_proto_matches = 0, 863 .typedef_arr_matches = 0, 864 865 .struct_sz = sizeof(struct a_struct___diff_sz), 866 .union_sz = sizeof(union a_union___diff_sz), 867 .enum_sz = sizeof(enum an_enum___diff_sz), 868 .typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz), 869 .typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz), 870 .typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz), 871 .typedef_int_sz = sizeof(int_typedef___diff_sz), 872 .typedef_enum_sz = sizeof(enum_typedef___diff_sz), 873 .typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz), 874 .typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz), 875 .typedef_arr_sz = sizeof(arr_typedef___diff_sz), 876 }), 877 TYPE_BASED_CASE(type_based___incompat, { 878 .enum_exists = 1, 879 .enum_matches = 1, 880 .enum_sz = sizeof(enum an_enum), 881 }), 882 TYPE_BASED_CASE(type_based___fn_wrong_args, { 883 .struct_exists = 1, 884 .struct_matches = 1, 885 .struct_sz = sizeof(struct a_struct), 886 }), 887 888 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */ 889 TYPE_ID_CASE(type_id, setup_type_id_case_success), 890 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure), 891 892 /* Enumerator value existence and value relocations */ 893 ENUMVAL_CASE(enumval, { 894 .named_val1_exists = true, 895 .named_val2_exists = true, 896 .named_val3_exists = true, 897 .anon_val1_exists = true, 898 .anon_val2_exists = true, 899 .anon_val3_exists = true, 900 .named_val1 = 1, 901 .named_val2 = 2, 902 .anon_val1 = 0x10, 903 .anon_val2 = 0x20, 904 }), 905 ENUMVAL_CASE(enumval___diff, { 906 .named_val1_exists = true, 907 .named_val2_exists = true, 908 .named_val3_exists = true, 909 .anon_val1_exists = true, 910 .anon_val2_exists = true, 911 .anon_val3_exists = true, 912 .named_val1 = 101, 913 .named_val2 = 202, 914 .anon_val1 = 0x11, 915 .anon_val2 = 0x22, 916 }), 917 ENUMVAL_CASE(enumval___val3_missing, { 918 .named_val1_exists = true, 919 .named_val2_exists = true, 920 .named_val3_exists = false, 921 .anon_val1_exists = true, 922 .anon_val2_exists = true, 923 .anon_val3_exists = false, 924 .named_val1 = 111, 925 .named_val2 = 222, 926 .anon_val1 = 0x111, 927 .anon_val2 = 0x222, 928 }), 929 ENUMVAL_ERR_CASE(enumval___err_missing), 930 931 /* 64bit enumerator value existence and value relocations */ 932 ENUM64VAL_CASE(enum64val, { 933 .unsigned_val1_exists = true, 934 .unsigned_val2_exists = true, 935 .unsigned_val3_exists = true, 936 .signed_val1_exists = true, 937 .signed_val2_exists = true, 938 .signed_val3_exists = true, 939 .unsigned_val1 = 0x1ffffffffULL, 940 .unsigned_val2 = 0x2, 941 .signed_val1 = 0x1ffffffffLL, 942 .signed_val2 = -2, 943 }), 944 ENUM64VAL_CASE(enum64val___diff, { 945 .unsigned_val1_exists = true, 946 .unsigned_val2_exists = true, 947 .unsigned_val3_exists = true, 948 .signed_val1_exists = true, 949 .signed_val2_exists = true, 950 .signed_val3_exists = true, 951 .unsigned_val1 = 0x101ffffffffULL, 952 .unsigned_val2 = 0x202ffffffffULL, 953 .signed_val1 = -101, 954 .signed_val2 = -202, 955 }), 956 ENUM64VAL_CASE(enum64val___val3_missing, { 957 .unsigned_val1_exists = true, 958 .unsigned_val2_exists = true, 959 .unsigned_val3_exists = false, 960 .signed_val1_exists = true, 961 .signed_val2_exists = true, 962 .signed_val3_exists = false, 963 .unsigned_val1 = 0x111ffffffffULL, 964 .unsigned_val2 = 0x222, 965 .signed_val1 = 0x111ffffffffLL, 966 .signed_val2 = -222, 967 }), 968 ENUM64VAL_ERR_CASE(enum64val___err_missing), 969 }; 970 971 struct data { 972 char in[256]; 973 char out[256]; 974 bool skip; 975 uint64_t my_pid_tgid; 976 }; 977 roundup_page(size_t sz)978 static size_t roundup_page(size_t sz) 979 { 980 long page_size = sysconf(_SC_PAGE_SIZE); 981 return (sz + page_size - 1) / page_size * page_size; 982 } 983 run_btfgen(const char * src_btf,const char * dst_btf,const char * objpath)984 static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objpath) 985 { 986 char command[4096]; 987 int n; 988 989 n = snprintf(command, sizeof(command), 990 "./bpftool gen min_core_btf %s %s %s", 991 src_btf, dst_btf, objpath); 992 if (n < 0 || n >= sizeof(command)) 993 return -1; 994 995 return system(command); 996 } 997 run_core_reloc_tests(bool use_btfgen)998 static void run_core_reloc_tests(bool use_btfgen) 999 { 1000 const size_t mmap_sz = roundup_page(sizeof(struct data)); 1001 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1002 struct core_reloc_test_case *test_case, test_case_copy; 1003 const char *tp_name, *probe_name; 1004 int err, i, equal, fd; 1005 struct bpf_link *link = NULL; 1006 struct bpf_map *data_map; 1007 struct bpf_program *prog; 1008 struct bpf_object *obj; 1009 uint64_t my_pid_tgid; 1010 struct data *data; 1011 void *mmap_data = NULL; 1012 1013 my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32); 1014 1015 for (i = 0; i < ARRAY_SIZE(test_cases); i++) { 1016 char btf_file[] = "/tmp/core_reloc.btf.XXXXXX"; 1017 1018 test_case_copy = test_cases[i]; 1019 test_case = &test_case_copy; 1020 1021 if (!test__start_subtest(test_case->case_name)) 1022 continue; 1023 1024 if (test_case->needs_testmod && !env.has_testmod) { 1025 test__skip(); 1026 continue; 1027 } 1028 1029 /* generate a "minimal" BTF file and use it as source */ 1030 if (use_btfgen) { 1031 1032 if (!test_case->btf_src_file || test_case->run_btfgen_fails) { 1033 test__skip(); 1034 continue; 1035 } 1036 1037 fd = mkstemp(btf_file); 1038 if (!ASSERT_GE(fd, 0, "btf_tmp")) 1039 continue; 1040 close(fd); /* we only need the path */ 1041 err = run_btfgen(test_case->btf_src_file, btf_file, 1042 test_case->bpf_obj_file); 1043 if (!ASSERT_OK(err, "run_btfgen")) 1044 continue; 1045 1046 test_case->btf_src_file = btf_file; 1047 } 1048 1049 if (test_case->setup) { 1050 err = test_case->setup(test_case); 1051 if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err)) 1052 continue; 1053 } 1054 1055 if (test_case->btf_src_file) { 1056 err = access(test_case->btf_src_file, R_OK); 1057 if (!ASSERT_OK(err, "btf_src_file")) 1058 continue; 1059 } 1060 1061 open_opts.btf_custom_path = test_case->btf_src_file; 1062 obj = bpf_object__open_file(test_case->bpf_obj_file, &open_opts); 1063 if (!ASSERT_OK_PTR(obj, "obj_open")) 1064 goto cleanup; 1065 1066 probe_name = test_case->prog_name; 1067 tp_name = test_case->raw_tp_name; /* NULL for tp_btf */ 1068 prog = bpf_object__find_program_by_name(obj, probe_name); 1069 if (CHECK(!prog, "find_probe", 1070 "prog '%s' not found\n", probe_name)) 1071 goto cleanup; 1072 1073 err = bpf_object__load(obj); 1074 if (err) { 1075 if (!test_case->fails) 1076 ASSERT_OK(err, "obj_load"); 1077 goto cleanup; 1078 } 1079 1080 data_map = bpf_object__find_map_by_name(obj, ".bss"); 1081 if (CHECK(!data_map, "find_data_map", "data map not found\n")) 1082 goto cleanup; 1083 1084 mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, 1085 MAP_SHARED, bpf_map__fd(data_map), 0); 1086 if (CHECK(mmap_data == MAP_FAILED, "mmap", 1087 ".bss mmap failed: %d", errno)) { 1088 mmap_data = NULL; 1089 goto cleanup; 1090 } 1091 data = mmap_data; 1092 1093 memset(mmap_data, 0, sizeof(*data)); 1094 if (test_case->input_len) 1095 memcpy(data->in, test_case->input, test_case->input_len); 1096 data->my_pid_tgid = my_pid_tgid; 1097 1098 link = bpf_program__attach_raw_tracepoint(prog, tp_name); 1099 if (!ASSERT_OK_PTR(link, "attach_raw_tp")) 1100 goto cleanup; 1101 1102 /* trigger test run */ 1103 if (test_case->trigger) { 1104 if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger")) 1105 goto cleanup; 1106 } else { 1107 usleep(1); 1108 } 1109 1110 if (data->skip) { 1111 test__skip(); 1112 goto cleanup; 1113 } 1114 1115 if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail")) 1116 goto cleanup; 1117 1118 equal = memcmp(data->out, test_case->output, 1119 test_case->output_len) == 0; 1120 if (CHECK(!equal, "check_result", 1121 "input/output data don't match\n")) { 1122 int j; 1123 1124 for (j = 0; j < test_case->input_len; j++) { 1125 printf("input byte #%d: 0x%02hhx\n", 1126 j, test_case->input[j]); 1127 } 1128 for (j = 0; j < test_case->output_len; j++) { 1129 printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n", 1130 j, test_case->output[j], data->out[j]); 1131 } 1132 goto cleanup; 1133 } 1134 1135 cleanup: 1136 if (mmap_data) { 1137 CHECK_FAIL(munmap(mmap_data, mmap_sz)); 1138 mmap_data = NULL; 1139 } 1140 if (use_btfgen) 1141 remove(test_case->btf_src_file); 1142 bpf_link__destroy(link); 1143 link = NULL; 1144 bpf_object__close(obj); 1145 } 1146 } 1147 test_core_reloc(void)1148 void test_core_reloc(void) 1149 { 1150 run_core_reloc_tests(false); 1151 } 1152 test_core_reloc_btfgen(void)1153 void test_core_reloc_btfgen(void) 1154 { 1155 run_core_reloc_tests(true); 1156 } 1157