Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add CO-RE relo test for TYPE_ID_LOCAL/TYPE_ID_TARGET

Add tests for BTF type ID relocations. To allow testing this, enhance
core_relo.c test runner to allow dynamic initialization of test inputs.
If Clang doesn't have necessary support for new functionality, test is
skipped.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20200819194519.3375898-4-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
4836bf5e 124a892d

+323 -19
+163 -5
tools/testing/selftests/bpf/prog_tests/core_reloc.c
··· 3 3 #include "progs/core_reloc_types.h" 4 4 #include <sys/mman.h> 5 5 #include <sys/syscall.h> 6 + #include <bpf/btf.h> 7 + 8 + static int duration = 0; 6 9 7 10 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name) 8 11 ··· 272 269 .fails = true, \ 273 270 } 274 271 272 + #define TYPE_ID_CASE_COMMON(name) \ 273 + .case_name = #name, \ 274 + .bpf_obj_file = "test_core_reloc_type_id.o", \ 275 + .btf_src_file = "btf__core_reloc_" #name ".o" \ 276 + 277 + #define TYPE_ID_CASE(name, setup_fn) { \ 278 + TYPE_ID_CASE_COMMON(name), \ 279 + .output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {}, \ 280 + .output_len = sizeof(struct core_reloc_type_id_output), \ 281 + .setup = setup_fn, \ 282 + } 283 + 284 + #define TYPE_ID_ERR_CASE(name) { \ 285 + TYPE_ID_CASE_COMMON(name), \ 286 + .fails = true, \ 287 + } 288 + 289 + struct core_reloc_test_case; 290 + 291 + typedef int (*setup_test_fn)(struct core_reloc_test_case *test); 292 + 275 293 struct core_reloc_test_case { 276 294 const char *case_name; 277 295 const char *bpf_obj_file; ··· 304 280 bool fails; 305 281 bool relaxed_core_relocs; 306 282 bool direct_raw_tp; 283 + setup_test_fn setup; 307 284 }; 285 + 286 + static int find_btf_type(const struct btf *btf, const char *name, __u32 kind) 287 + { 288 + int id; 289 + 290 + id = btf__find_by_name_kind(btf, name, kind); 291 + if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id)) 292 + return -1; 293 + 294 + return id; 295 + } 296 + 297 + static int setup_type_id_case_local(struct core_reloc_test_case *test) 298 + { 299 + struct core_reloc_type_id_output *exp = (void *)test->output; 300 + struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL); 301 + struct btf *targ_btf = btf__parse(test->btf_src_file, NULL); 302 + const struct btf_type *t; 303 + const char *name; 304 + int i; 305 + 306 + if (CHECK(IS_ERR(local_btf), "local_btf", "failed: %ld\n", PTR_ERR(local_btf)) || 307 + CHECK(IS_ERR(targ_btf), "targ_btf", "failed: %ld\n", PTR_ERR(targ_btf))) { 308 + btf__free(local_btf); 309 + btf__free(targ_btf); 310 + return -EINVAL; 311 + } 312 + 313 + exp->local_anon_struct = -1; 314 + exp->local_anon_union = -1; 315 + exp->local_anon_enum = -1; 316 + exp->local_anon_func_proto_ptr = -1; 317 + exp->local_anon_void_ptr = -1; 318 + exp->local_anon_arr = -1; 319 + 320 + for (i = 1; i <= btf__get_nr_types(local_btf); i++) 321 + { 322 + t = btf__type_by_id(local_btf, i); 323 + /* we are interested only in anonymous types */ 324 + if (t->name_off) 325 + continue; 326 + 327 + if (btf_is_struct(t) && btf_vlen(t) && 328 + (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) && 329 + strcmp(name, "marker_field") == 0) { 330 + exp->local_anon_struct = i; 331 + } else if (btf_is_union(t) && btf_vlen(t) && 332 + (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) && 333 + strcmp(name, "marker_field") == 0) { 334 + exp->local_anon_union = i; 335 + } else if (btf_is_enum(t) && btf_vlen(t) && 336 + (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) && 337 + strcmp(name, "MARKER_ENUM_VAL") == 0) { 338 + exp->local_anon_enum = i; 339 + } else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) { 340 + if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) && 341 + btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) && 342 + strcmp(name, "_Bool") == 0) { 343 + /* ptr -> func_proto -> _Bool */ 344 + exp->local_anon_func_proto_ptr = i; 345 + } else if (btf_is_void(t)) { 346 + /* ptr -> void */ 347 + exp->local_anon_void_ptr = i; 348 + } 349 + } else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) && 350 + btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) && 351 + strcmp(name, "_Bool") == 0) { 352 + /* _Bool[] */ 353 + exp->local_anon_arr = i; 354 + } 355 + } 356 + 357 + exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT); 358 + exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION); 359 + exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM); 360 + exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT); 361 + exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF); 362 + exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF); 363 + exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF); 364 + 365 + btf__free(local_btf); 366 + btf__free(targ_btf); 367 + return 0; 368 + } 369 + 370 + static int setup_type_id_case_success(struct core_reloc_test_case *test) { 371 + struct core_reloc_type_id_output *exp = (void *)test->output; 372 + struct btf *targ_btf = btf__parse(test->btf_src_file, NULL); 373 + int err; 374 + 375 + err = setup_type_id_case_local(test); 376 + if (err) 377 + return err; 378 + 379 + targ_btf = btf__parse(test->btf_src_file, NULL); 380 + 381 + exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT); 382 + exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION); 383 + exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM); 384 + exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT); 385 + exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF); 386 + exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF); 387 + exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF); 388 + 389 + btf__free(targ_btf); 390 + return 0; 391 + } 392 + 393 + static int setup_type_id_case_failure(struct core_reloc_test_case *test) 394 + { 395 + struct core_reloc_type_id_output *exp = (void *)test->output; 396 + int err; 397 + 398 + err = setup_type_id_case_local(test); 399 + if (err) 400 + return err; 401 + 402 + exp->targ_struct = 0; 403 + exp->targ_union = 0; 404 + exp->targ_enum = 0; 405 + exp->targ_int = 0; 406 + exp->targ_struct_typedef = 0; 407 + exp->targ_func_proto_typedef = 0; 408 + exp->targ_arr_typedef = 0; 409 + 410 + return 0; 411 + } 308 412 309 413 static struct core_reloc_test_case test_cases[] = { 310 414 /* validate we can find kernel image and use its BTF for relocs */ ··· 682 530 .struct_exists = 1, 683 531 .struct_sz = sizeof(struct a_struct), 684 532 }), 533 + 534 + /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */ 535 + TYPE_ID_CASE(type_id, setup_type_id_case_success), 536 + TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure), 685 537 }; 686 538 687 539 struct data { ··· 707 551 struct bpf_object_load_attr load_attr = {}; 708 552 struct core_reloc_test_case *test_case; 709 553 const char *tp_name, *probe_name; 710 - int err, duration = 0, i, equal; 554 + int err, i, equal; 711 555 struct bpf_link *link = NULL; 712 556 struct bpf_map *data_map; 713 557 struct bpf_program *prog; ··· 723 567 if (!test__start_subtest(test_case->case_name)) 724 568 continue; 725 569 726 - DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, 727 - .relaxed_core_relocs = test_case->relaxed_core_relocs, 728 - ); 570 + if (test_case->setup) { 571 + err = test_case->setup(test_case); 572 + if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err)) 573 + continue; 574 + } 729 575 730 - obj = bpf_object__open_file(test_case->bpf_obj_file, &opts); 576 + obj = bpf_object__open_file(test_case->bpf_obj_file, NULL); 731 577 if (CHECK(IS_ERR(obj), "obj_open", "failed to open '%s': %ld\n", 732 578 test_case->bpf_obj_file, PTR_ERR(obj))) 733 579 continue;
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_type_id.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_type_id x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_type_id___missing_targets.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_type_id___missing_targets x) {}
+41
tools/testing/selftests/bpf/progs/core_reloc_types.h
··· 1034 1034 func_proto_typedef___fn_wrong_arg_cnt1 f6; 1035 1035 func_proto_typedef___fn_wrong_arg_cnt2 f7; 1036 1036 }; 1037 + 1038 + /* 1039 + * TYPE ID MAPPING (LOCAL AND TARGET) 1040 + */ 1041 + struct core_reloc_type_id_output { 1042 + int local_anon_struct; 1043 + int local_anon_union; 1044 + int local_anon_enum; 1045 + int local_anon_func_proto_ptr; 1046 + int local_anon_void_ptr; 1047 + int local_anon_arr; 1048 + 1049 + int local_struct; 1050 + int local_union; 1051 + int local_enum; 1052 + int local_int; 1053 + int local_struct_typedef; 1054 + int local_func_proto_typedef; 1055 + int local_arr_typedef; 1056 + 1057 + int targ_struct; 1058 + int targ_union; 1059 + int targ_enum; 1060 + int targ_int; 1061 + int targ_struct_typedef; 1062 + int targ_func_proto_typedef; 1063 + int targ_arr_typedef; 1064 + }; 1065 + 1066 + struct core_reloc_type_id { 1067 + struct a_struct f1; 1068 + union a_union f2; 1069 + enum an_enum f3; 1070 + named_struct_typedef f4; 1071 + func_proto_typedef f5; 1072 + arr_typedef f6; 1073 + }; 1074 + 1075 + struct core_reloc_type_id___missing_targets { 1076 + /* nothing */ 1077 + };
-14
tools/testing/selftests/bpf/progs/test_core_reloc_type_based.c
··· 48 48 49 49 typedef char arr_typedef[20]; 50 50 51 - struct core_reloc_type_based { 52 - struct a_struct f1; 53 - union a_union f2; 54 - enum an_enum f3; 55 - named_struct_typedef f4; 56 - anon_struct_typedef f5; 57 - struct_ptr_typedef f6; 58 - int_typedef f7; 59 - enum_typedef f8; 60 - void_ptr_typedef f9; 61 - func_proto_typedef f10; 62 - arr_typedef f11; 63 - }; 64 - 65 51 struct core_reloc_type_based_output { 66 52 bool struct_exists; 67 53 bool union_exists;
+113
tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2020 Facebook 3 + 4 + #include <linux/bpf.h> 5 + #include <stdint.h> 6 + #include <stdbool.h> 7 + #include <bpf/bpf_helpers.h> 8 + #include <bpf/bpf_core_read.h> 9 + 10 + char _license[] SEC("license") = "GPL"; 11 + 12 + struct { 13 + char in[256]; 14 + char out[256]; 15 + bool skip; 16 + } data = {}; 17 + 18 + /* some types are shared with test_core_reloc_type_based.c */ 19 + struct a_struct { 20 + int x; 21 + }; 22 + 23 + union a_union { 24 + int y; 25 + int z; 26 + }; 27 + 28 + enum an_enum { 29 + AN_ENUM_VAL1 = 1, 30 + AN_ENUM_VAL2 = 2, 31 + AN_ENUM_VAL3 = 3, 32 + }; 33 + 34 + typedef struct a_struct named_struct_typedef; 35 + 36 + typedef int (*func_proto_typedef)(long); 37 + 38 + typedef char arr_typedef[20]; 39 + 40 + struct core_reloc_type_id_output { 41 + int local_anon_struct; 42 + int local_anon_union; 43 + int local_anon_enum; 44 + int local_anon_func_proto_ptr; 45 + int local_anon_void_ptr; 46 + int local_anon_arr; 47 + 48 + int local_struct; 49 + int local_union; 50 + int local_enum; 51 + int local_int; 52 + int local_struct_typedef; 53 + int local_func_proto_typedef; 54 + int local_arr_typedef; 55 + 56 + int targ_struct; 57 + int targ_union; 58 + int targ_enum; 59 + int targ_int; 60 + int targ_struct_typedef; 61 + int targ_func_proto_typedef; 62 + int targ_arr_typedef; 63 + }; 64 + 65 + /* preserve types even if Clang doesn't support built-in */ 66 + struct a_struct t1 = {}; 67 + union a_union t2 = {}; 68 + enum an_enum t3 = 0; 69 + named_struct_typedef t4 = {}; 70 + func_proto_typedef t5 = 0; 71 + arr_typedef t6 = {}; 72 + 73 + SEC("raw_tracepoint/sys_enter") 74 + int test_core_type_id(void *ctx) 75 + { 76 + /* We use __builtin_btf_type_id() in this tests, but up until the time 77 + * __builtin_preserve_type_info() was added it contained a bug that 78 + * would make this test fail. The bug was fixed with addition of 79 + * __builtin_preserve_type_info(), though, so that's what we are using 80 + * to detect whether this test has to be executed, however strange 81 + * that might look like. 82 + */ 83 + #if __has_builtin(__builtin_preserve_type_info) 84 + struct core_reloc_type_id_output *out = (void *)&data.out; 85 + 86 + out->local_anon_struct = bpf_core_type_id_local(struct { int marker_field; }); 87 + out->local_anon_union = bpf_core_type_id_local(union { int marker_field; }); 88 + out->local_anon_enum = bpf_core_type_id_local(enum { MARKER_ENUM_VAL = 123 }); 89 + out->local_anon_func_proto_ptr = bpf_core_type_id_local(_Bool(*)(int)); 90 + out->local_anon_void_ptr = bpf_core_type_id_local(void *); 91 + out->local_anon_arr = bpf_core_type_id_local(_Bool[47]); 92 + 93 + out->local_struct = bpf_core_type_id_local(struct a_struct); 94 + out->local_union = bpf_core_type_id_local(union a_union); 95 + out->local_enum = bpf_core_type_id_local(enum an_enum); 96 + out->local_int = bpf_core_type_id_local(int); 97 + out->local_struct_typedef = bpf_core_type_id_local(named_struct_typedef); 98 + out->local_func_proto_typedef = bpf_core_type_id_local(func_proto_typedef); 99 + out->local_arr_typedef = bpf_core_type_id_local(arr_typedef); 100 + 101 + out->targ_struct = bpf_core_type_id_kernel(struct a_struct); 102 + out->targ_union = bpf_core_type_id_kernel(union a_union); 103 + out->targ_enum = bpf_core_type_id_kernel(enum an_enum); 104 + out->targ_int = bpf_core_type_id_kernel(int); 105 + out->targ_struct_typedef = bpf_core_type_id_kernel(named_struct_typedef); 106 + out->targ_func_proto_typedef = bpf_core_type_id_kernel(func_proto_typedef); 107 + out->targ_arr_typedef = bpf_core_type_id_kernel(arr_typedef); 108 + #else 109 + data.skip = true; 110 + #endif 111 + 112 + return 0; 113 + }