root/tools/testing/selftests/bpf/progs/test_core_reloc_type_id.c
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Facebook

#include <linux/bpf.h>
#include <stdint.h>
#include <stdbool.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>

char _license[] SEC("license") = "GPL";

struct {
        char in[256];
        char out[256];
        bool skip;
} data = {};

/* some types are shared with test_core_reloc_type_based.c */
struct a_struct {
        int x;
};

union a_union {
        int y;
        int z;
};

enum an_enum {
        AN_ENUM_VAL1 = 1,
        AN_ENUM_VAL2 = 2,
        AN_ENUM_VAL3 = 3,
};

typedef struct a_struct named_struct_typedef;

typedef int (*func_proto_typedef)(long);

typedef char arr_typedef[20];

struct core_reloc_type_id_output {
        int local_anon_struct;
        int local_anon_union;
        int local_anon_enum;
        int local_anon_func_proto_ptr;
        int local_anon_void_ptr;
        int local_anon_arr;

        int local_struct;
        int local_union;
        int local_enum;
        int local_int;
        int local_struct_typedef;
        int local_func_proto_typedef;
        int local_arr_typedef;

        int targ_struct;
        int targ_union;
        int targ_enum;
        int targ_int;
        int targ_struct_typedef;
        int targ_func_proto_typedef;
        int targ_arr_typedef;
};

/* preserve types even if Clang doesn't support built-in */
struct a_struct t1 = {};
union a_union t2 = {};
enum an_enum t3 = 0;
named_struct_typedef t4 = {};
func_proto_typedef t5 = 0;
arr_typedef t6 = {};

SEC("raw_tracepoint/sys_enter")
int test_core_type_id(void *ctx)
{
        /* We use __builtin_btf_type_id() in this tests, but up until the time
         * __builtin_preserve_type_info() was added it contained a bug that
         * would make this test fail. The bug was fixed ([0]) with addition of
         * __builtin_preserve_type_info(), though, so that's what we are using
         * to detect whether this test has to be executed, however strange
         * that might look like.
         *
         *   [0] https://github.com/llvm/llvm-project/commit/00602ee7ef0bf6c68d690a2bd729c12b95c95c99
         */
#if __has_builtin(__builtin_preserve_type_info)
        struct core_reloc_type_id_output *out = (void *)&data.out;

        out->local_anon_struct = bpf_core_type_id_local(struct { int marker_field; });
        out->local_anon_union = bpf_core_type_id_local(union { int marker_field; });
        out->local_anon_enum = bpf_core_type_id_local(enum { MARKER_ENUM_VAL = 123 });
        out->local_anon_func_proto_ptr = bpf_core_type_id_local(_Bool(*)(int));
        out->local_anon_void_ptr = bpf_core_type_id_local(void *);
        out->local_anon_arr = bpf_core_type_id_local(_Bool[47]);

        out->local_struct = bpf_core_type_id_local(struct a_struct);
        out->local_union = bpf_core_type_id_local(union a_union);
        out->local_enum = bpf_core_type_id_local(enum an_enum);
        out->local_int = bpf_core_type_id_local(int);
        out->local_struct_typedef = bpf_core_type_id_local(named_struct_typedef);
        out->local_func_proto_typedef = bpf_core_type_id_local(func_proto_typedef);
        out->local_arr_typedef = bpf_core_type_id_local(arr_typedef);

        out->targ_struct = bpf_core_type_id_kernel(struct a_struct);
        out->targ_union = bpf_core_type_id_kernel(union a_union);
        out->targ_enum = bpf_core_type_id_kernel(enum an_enum);
        out->targ_int = bpf_core_type_id_kernel(int);
        out->targ_struct_typedef = bpf_core_type_id_kernel(named_struct_typedef);
        out->targ_func_proto_typedef = bpf_core_type_id_kernel(func_proto_typedef);
        out->targ_arr_typedef = bpf_core_type_id_kernel(arr_typedef);
#else
        data.skip = true;
#endif

        return 0;
}