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