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