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