Commit c1447efd authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'type-and-enum-value-relos'

Andrii Nakryiko says:

====================
This patch set adds libbpf support for two new classes of CO-RE relocations:
type-based (TYPE_EXISTS/TYPE_SIZE/TYPE_ID_LOCAL/TYPE_ID_TARGET) and enum
value-vased (ENUMVAL_EXISTS/ENUMVAL_VALUE):
  - TYPE_EXISTS allows to detect presence in kernel BTF of a locally-recorded
    BTF type. Useful for feature detection (new functionality often comes with
    new internal kernel types), as well as handling type renames and bigger
    refactorings.
  - TYPE_SIZE allows to get the real size (in bytes) of a specified kernel
    type. Useful for dumping internal structure as-is through perfbuf or
    ringbuf.
  - TYPE_ID_LOCAL/TYPE_ID_TARGET allow to capture BTF type ID of a BTF type in
    program's BTF or kernel BTF, respectively. These could be used for
    high-performance and space-efficient generic data dumping/logging by
    relying on small and cheap BTF type ID as a data layout descriptor, for
    post-processing on user-space side.
  - ENUMVAL_EXISTS can be used for detecting the presence of enumerator value
    in kernel's enum type. Most direct application is to detect BPF helper
    support in kernel.
  - ENUMVAL_VALUE allows to relocate real integer value of kernel enumerator
    value, which is subject to change (e.g., always a potential issue for
    internal, non-UAPI, kernel enums).

I've indicated potential applications for these relocations, but relocations
themselves are generic and unassuming and are designed to work correctly even
in unintended applications. Furthermore, relocated values become constants,
known to the verifier and could and would be used for dead branch code
detection and elimination. This makes them ideal to do all sorts of feature
detection and guarding functionality that's not available on some older (but
still supported by BPF program) kernels, while having to compile and maintain
one unified source code.

Selftests are added for all the new features. Selftests utilizing new Clang
built-ins are designed such that they will compile with older Clangs and will
be skipped during test runs. So this shouldn't cause any build and test
failures on systems with slightly outdated Clang compiler.

LLVM patches adding these relocation in Clang:
  - __builtin_btf_type_id() ([0], [1], [2]);
  - __builtin_preserve_type_info(), __builtin_preserve_enum_value() ([3], [4]).

  [0] https://reviews.llvm.org/D74572
  [1] https://reviews.llvm.org/D74668
  [2] https://reviews.llvm.org/D85174
  [3] https://reviews.llvm.org/D83878
  [4] https://reviews.llvm.org/D83242

v2->v3:
  - fix feature detection for __builtin_btf_type_id() test (Yonghong);
  - fix extra empty lines at the end of files (Yonghong);

v1->v2:
  - selftests detect built-in support and are skipped if not found (Alexei).
====================
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents defcffeb 33574905
......@@ -19,6 +19,24 @@ enum bpf_field_info_kind {
BPF_FIELD_RSHIFT_U64 = 5,
};
/* second argument to __builtin_btf_type_id() built-in */
enum bpf_type_id_kind {
BPF_TYPE_ID_LOCAL = 0, /* BTF type ID in local program */
BPF_TYPE_ID_TARGET = 1, /* BTF type ID in target kernel */
};
/* second argument to __builtin_preserve_type_info() built-in */
enum bpf_type_info_kind {
BPF_TYPE_EXISTS = 0, /* type existence in target kernel */
BPF_TYPE_SIZE = 1, /* type size in target kernel */
};
/* second argument to __builtin_preserve_enum_value() built-in */
enum bpf_enum_value_kind {
BPF_ENUMVAL_EXISTS = 0, /* enum value existence in kernel */
BPF_ENUMVAL_VALUE = 1, /* enum value value relocation */
};
#define __CORE_RELO(src, field, info) \
__builtin_preserve_field_info((src)->field, BPF_FIELD_##info)
......@@ -94,12 +112,72 @@ enum bpf_field_info_kind {
__builtin_preserve_field_info(field, BPF_FIELD_EXISTS)
/*
* Convenience macro to get byte size of a field. Works for integers,
* Convenience macro to get the byte size of a field. Works for integers,
* struct/unions, pointers, arrays, and enums.
*/
#define bpf_core_field_size(field) \
__builtin_preserve_field_info(field, BPF_FIELD_BYTE_SIZE)
/*
* Convenience macro to get BTF type ID of a specified type, using a local BTF
* information. Return 32-bit unsigned integer with type ID from program's own
* BTF. Always succeeds.
*/
#define bpf_core_type_id_local(type) \
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_LOCAL)
/*
* Convenience macro to get BTF type ID of a target kernel's type that matches
* specified local type.
* Returns:
* - valid 32-bit unsigned type ID in kernel BTF;
* - 0, if no matching type was found in a target kernel BTF.
*/
#define bpf_core_type_id_kernel(type) \
__builtin_btf_type_id(*(typeof(type) *)0, BPF_TYPE_ID_TARGET)
/*
* Convenience macro to check that provided named type
* (struct/union/enum/typedef) exists in a target kernel.
* Returns:
* 1, if such type is present in target kernel's BTF;
* 0, if no matching type is found.
*/
#define bpf_core_type_exists(type) \
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_EXISTS)
/*
* Convenience macro to get the byte size of a provided named type
* (struct/union/enum/typedef) in a target kernel.
* Returns:
* >= 0 size (in bytes), if type is present in target kernel's BTF;
* 0, if no matching type is found.
*/
#define bpf_core_type_size(type) \
__builtin_preserve_type_info(*(typeof(type) *)0, BPF_TYPE_SIZE)
/*
* Convenience macro to check that provided enumerator value is defined in
* a target kernel.
* Returns:
* 1, if specified enum type and its enumerator value are present in target
* kernel's BTF;
* 0, if no matching enum and/or enum value within that enum is found.
*/
#define bpf_core_enum_value_exists(enum_type, enum_value) \
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_EXISTS)
/*
* Convenience macro to get the integer value of an enumerator value in
* a target kernel.
* Returns:
* 64-bit value, if specified enum type and its enumerator value are
* present in target kernel's BTF;
* 0, if no matching enum and/or enum value within that enum is found.
*/
#define bpf_core_enum_value(enum_type, enum_value) \
__builtin_preserve_enum_value(*(typeof(enum_type) *)enum_value, BPF_ENUMVAL_VALUE)
/*
* bpf_core_read() abstracts away bpf_probe_read_kernel() call and captures
* offset relocation for source address using __builtin_preserve_access_index()
......
This diff is collapsed.
......@@ -238,6 +238,12 @@ enum bpf_core_relo_kind {
BPF_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */
BPF_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */
BPF_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */
BPF_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */
BPF_TYPE_ID_TARGET = 7, /* type ID in target kernel */
BPF_TYPE_EXISTS = 8, /* type existence in target kernel */
BPF_TYPE_SIZE = 9, /* type size in bytes */
BPF_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */
BPF_ENUMVAL_VALUE = 11, /* enum value integer value */
};
/* The minimum bpf_core_relo checked by the loader
......
#include "core_reloc_types.h"
void f(struct core_reloc_enumval x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___diff x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___err_missing x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___val3_missing x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_based x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_based___all_missing x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_based___diff_sz x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_based___fn_wrong_args x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_based___incompat x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_id x) {}
#include "core_reloc_types.h"
void f(struct core_reloc_type_id___missing_targets x) {}
......@@ -652,7 +652,7 @@ struct core_reloc_misc_extensible {
};
/*
* EXISTENCE
* FIELD EXISTENCE
*/
struct core_reloc_existence_output {
int a_exists;
......@@ -834,3 +834,328 @@ struct core_reloc_size___err_ambiguous2 {
void *ptr_field;
enum { VALUE___2 = 123 } enum_field;
};
/*
* TYPE EXISTENCE & SIZE
*/
struct core_reloc_type_based_output {
bool struct_exists;
bool union_exists;
bool enum_exists;
bool typedef_named_struct_exists;
bool typedef_anon_struct_exists;
bool typedef_struct_ptr_exists;
bool typedef_int_exists;
bool typedef_enum_exists;
bool typedef_void_ptr_exists;
bool typedef_func_proto_exists;
bool typedef_arr_exists;
int struct_sz;
int union_sz;
int enum_sz;
int typedef_named_struct_sz;
int typedef_anon_struct_sz;
int typedef_struct_ptr_sz;
int typedef_int_sz;
int typedef_enum_sz;
int typedef_void_ptr_sz;
int typedef_func_proto_sz;
int typedef_arr_sz;
};
struct a_struct {
int x;
};
union a_union {
int y;
int z;
};
typedef struct a_struct named_struct_typedef;
typedef struct { int x, y, z; } anon_struct_typedef;
typedef struct {
int a, b, c;
} *struct_ptr_typedef;
enum an_enum {
AN_ENUM_VAL1 = 1,
AN_ENUM_VAL2 = 2,
AN_ENUM_VAL3 = 3,
};
typedef int int_typedef;
typedef enum { TYPEDEF_ENUM_VAL1, TYPEDEF_ENUM_VAL2 } enum_typedef;
typedef void *void_ptr_typedef;
typedef int (*func_proto_typedef)(long);
typedef char arr_typedef[20];
struct core_reloc_type_based {
struct a_struct f1;
union a_union f2;
enum an_enum f3;
named_struct_typedef f4;
anon_struct_typedef f5;
struct_ptr_typedef f6;
int_typedef f7;
enum_typedef f8;
void_ptr_typedef f9;
func_proto_typedef f10;
arr_typedef f11;
};
/* no types in target */
struct core_reloc_type_based___all_missing {
};
/* different type sizes, extra modifiers, anon vs named enums, etc */
struct a_struct___diff_sz {
long x;
int y;
char z;
};
union a_union___diff_sz {
char yy;
char zz;
};
typedef struct a_struct___diff_sz named_struct_typedef___diff_sz;
typedef struct { long xx, yy, zzz; } anon_struct_typedef___diff_sz;
typedef struct {
char aa[1], bb[2], cc[3];
} *struct_ptr_typedef___diff_sz;
enum an_enum___diff_sz {
AN_ENUM_VAL1___diff_sz = 0x123412341234,
AN_ENUM_VAL2___diff_sz = 2,
};
typedef unsigned long int_typedef___diff_sz;
typedef enum an_enum___diff_sz enum_typedef___diff_sz;
typedef const void * const void_ptr_typedef___diff_sz;
typedef int_typedef___diff_sz (*func_proto_typedef___diff_sz)(char);
typedef int arr_typedef___diff_sz[2];
struct core_reloc_type_based___diff_sz {
struct a_struct___diff_sz f1;
union a_union___diff_sz f2;
enum an_enum___diff_sz f3;
named_struct_typedef___diff_sz f4;
anon_struct_typedef___diff_sz f5;
struct_ptr_typedef___diff_sz f6;
int_typedef___diff_sz f7;
enum_typedef___diff_sz f8;
void_ptr_typedef___diff_sz f9;
func_proto_typedef___diff_sz f10;
arr_typedef___diff_sz f11;
};
/* incompatibilities between target and local types */
union a_struct___incompat { /* union instead of struct */
int x;
};
struct a_union___incompat { /* struct instead of union */
int y;
int z;
};
/* typedef to union, not to struct */
typedef union a_struct___incompat named_struct_typedef___incompat;
/* typedef to void pointer, instead of struct */
typedef void *anon_struct_typedef___incompat;
/* extra pointer indirection */
typedef struct {
int a, b, c;
} **struct_ptr_typedef___incompat;
/* typedef of a struct with int, instead of int */
typedef struct { int x; } int_typedef___incompat;
/* typedef to func_proto, instead of enum */
typedef int (*enum_typedef___incompat)(void);
/* pointer to char instead of void */
typedef char *void_ptr_typedef___incompat;
/* void return type instead of int */
typedef void (*func_proto_typedef___incompat)(long);
/* multi-dimensional array instead of a single-dimensional */
typedef int arr_typedef___incompat[20][2];
struct core_reloc_type_based___incompat {
union a_struct___incompat f1;
struct a_union___incompat f2;
/* the only valid one is enum, to check that something still succeeds */
enum an_enum f3;
named_struct_typedef___incompat f4;
anon_struct_typedef___incompat f5;
struct_ptr_typedef___incompat f6;
int_typedef___incompat f7;
enum_typedef___incompat f8;
void_ptr_typedef___incompat f9;
func_proto_typedef___incompat f10;
arr_typedef___incompat f11;
};
/* func_proto with incompatible signature */
typedef void (*func_proto_typedef___fn_wrong_ret1)(long);
typedef int * (*func_proto_typedef___fn_wrong_ret2)(long);
typedef struct { int x; } int_struct_typedef;
typedef int_struct_typedef (*func_proto_typedef___fn_wrong_ret3)(long);
typedef int (*func_proto_typedef___fn_wrong_arg)(void *);
typedef int (*func_proto_typedef___fn_wrong_arg_cnt1)(long, long);
typedef int (*func_proto_typedef___fn_wrong_arg_cnt2)(void);
struct core_reloc_type_based___fn_wrong_args {
/* one valid type to make sure relos still work */
struct a_struct f1;
func_proto_typedef___fn_wrong_ret1 f2;
func_proto_typedef___fn_wrong_ret2 f3;
func_proto_typedef___fn_wrong_ret3 f4;
func_proto_typedef___fn_wrong_arg f5;
func_proto_typedef___fn_wrong_arg_cnt1 f6;
func_proto_typedef___fn_wrong_arg_cnt2 f7;
};
/*
* TYPE ID MAPPING (LOCAL AND TARGET)
*/
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;
};
struct core_reloc_type_id {
struct a_struct f1;
union a_union f2;
enum an_enum f3;
named_struct_typedef f4;
func_proto_typedef f5;
arr_typedef f6;
};
struct core_reloc_type_id___missing_targets {
/* nothing */
};
/*
* ENUMERATOR VALUE EXISTENCE AND VALUE RELOCATION
*/
struct core_reloc_enumval_output {
bool named_val1_exists;
bool named_val2_exists;
bool named_val3_exists;
bool anon_val1_exists;
bool anon_val2_exists;
bool anon_val3_exists;
int named_val1;
int named_val2;
int anon_val1;
int anon_val2;
};
enum named_enum {
NAMED_ENUM_VAL1 = 1,
NAMED_ENUM_VAL2 = 2,
NAMED_ENUM_VAL3 = 3,
};
typedef enum {
ANON_ENUM_VAL1 = 0x10,
ANON_ENUM_VAL2 = 0x20,
ANON_ENUM_VAL3 = 0x30,
} anon_enum;
struct core_reloc_enumval {
enum named_enum f1;
anon_enum f2;
};
/* differing enumerator values */
enum named_enum___diff {
NAMED_ENUM_VAL1___diff = 101,
NAMED_ENUM_VAL2___diff = 202,
NAMED_ENUM_VAL3___diff = 303,
};
typedef enum {
ANON_ENUM_VAL1___diff = 0x11,
ANON_ENUM_VAL2___diff = 0x22,
ANON_ENUM_VAL3___diff = 0x33,
} anon_enum___diff;
struct core_reloc_enumval___diff {
enum named_enum___diff f1;
anon_enum___diff f2;
};
/* missing (optional) third enum value */
enum named_enum___val3_missing {
NAMED_ENUM_VAL1___val3_missing = 111,
NAMED_ENUM_VAL2___val3_missing = 222,
};
typedef enum {
ANON_ENUM_VAL1___val3_missing = 0x111,
ANON_ENUM_VAL2___val3_missing = 0x222,
} anon_enum___val3_missing;
struct core_reloc_enumval___val3_missing {
enum named_enum___val3_missing f1;
anon_enum___val3_missing f2;
};
/* missing (mandatory) second enum value, should fail */
enum named_enum___err_missing {
NAMED_ENUM_VAL1___err_missing = 1,
NAMED_ENUM_VAL3___err_missing = 3,
};
typedef enum {
ANON_ENUM_VAL1___err_missing = 0x111,
ANON_ENUM_VAL3___err_missing = 0x222,
} anon_enum___err_missing;
struct core_reloc_enumval___err_missing {
enum named_enum___err_missing f1;
anon_enum___err_missing f2;
};
// 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 = {};
enum named_enum {
NAMED_ENUM_VAL1 = 1,
NAMED_ENUM_VAL2 = 2,
NAMED_ENUM_VAL3 = 3,
};
typedef enum {
ANON_ENUM_VAL1 = 0x10,
ANON_ENUM_VAL2 = 0x20,
ANON_ENUM_VAL3 = 0x30,
} anon_enum;
struct core_reloc_enumval_output {
bool named_val1_exists;
bool named_val2_exists;
bool named_val3_exists;
bool anon_val1_exists;
bool anon_val2_exists;
bool anon_val3_exists;
int named_val1;
int named_val2;
int anon_val1;
int anon_val2;
};
SEC("raw_tracepoint/sys_enter")
int test_core_enumval(void *ctx)
{
#if __has_builtin(__builtin_preserve_enum_value)
struct core_reloc_enumval_output *out = (void *)&data.out;
enum named_enum named = 0;
anon_enum anon = 0;
out->named_val1_exists = bpf_core_enum_value_exists(named, NAMED_ENUM_VAL1);
out->named_val2_exists = bpf_core_enum_value_exists(enum named_enum, NAMED_ENUM_VAL2);
out->named_val3_exists = bpf_core_enum_value_exists(enum named_enum, NAMED_ENUM_VAL3);
out->anon_val1_exists = bpf_core_enum_value_exists(anon, ANON_ENUM_VAL1);
out->anon_val2_exists = bpf_core_enum_value_exists(anon_enum, ANON_ENUM_VAL2);
out->anon_val3_exists = bpf_core_enum_value_exists(anon_enum, ANON_ENUM_VAL3);
out->named_val1 = bpf_core_enum_value(named, NAMED_ENUM_VAL1);
out->named_val2 = bpf_core_enum_value(named, NAMED_ENUM_VAL2);
/* NAMED_ENUM_VAL3 value is optional */
out->anon_val1 = bpf_core_enum_value(anon, ANON_ENUM_VAL1);
out->anon_val2 = bpf_core_enum_value(anon, ANON_ENUM_VAL2);
/* ANON_ENUM_VAL3 value is optional */
#else
data.skip = true;
#endif
return 0;
}
......@@ -3,6 +3,7 @@
#include <linux/bpf.h>
#include <stdint.h>
#include <stdbool.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
......@@ -11,6 +12,7 @@ char _license[] SEC("license") = "GPL";
struct {
char in[256];
char out[256];
bool skip;
uint64_t my_pid_tgid;
} data = {};
......
// 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 = {};
struct a_struct {
int x;
};
union a_union {
int y;
int z;
};
typedef struct a_struct named_struct_typedef;
typedef struct { int x, y, z; } anon_struct_typedef;
typedef struct {
int a, b, c;
} *struct_ptr_typedef;
enum an_enum {
AN_ENUM_VAL1 = 1,
AN_ENUM_VAL2 = 2,
AN_ENUM_VAL3 = 3,
};
typedef int int_typedef;
typedef enum { TYPEDEF_ENUM_VAL1, TYPEDEF_ENUM_VAL2 } enum_typedef;
typedef void *void_ptr_typedef;
typedef int (*func_proto_typedef)(long);
typedef char arr_typedef[20];
struct core_reloc_type_based_output {
bool struct_exists;
bool union_exists;
bool enum_exists;
bool typedef_named_struct_exists;
bool typedef_anon_struct_exists;
bool typedef_struct_ptr_exists;
bool typedef_int_exists;
bool typedef_enum_exists;
bool typedef_void_ptr_exists;
bool typedef_func_proto_exists;
bool typedef_arr_exists;
int struct_sz;
int union_sz;
int enum_sz;
int typedef_named_struct_sz;
int typedef_anon_struct_sz;
int typedef_struct_ptr_sz;
int typedef_int_sz;
int typedef_enum_sz;
int typedef_void_ptr_sz;
int typedef_func_proto_sz;
int typedef_arr_sz;
};
SEC("raw_tracepoint/sys_enter")
int test_core_type_based(void *ctx)
{
#if __has_builtin(__builtin_preserve_type_info)
struct core_reloc_type_based_output *out = (void *)&data.out;
out->struct_exists = bpf_core_type_exists(struct a_struct);
out->union_exists = bpf_core_type_exists(union a_union);
out->enum_exists = bpf_core_type_exists(enum an_enum);
out->typedef_named_struct_exists = bpf_core_type_exists(named_struct_typedef);
out->typedef_anon_struct_exists = bpf_core_type_exists(anon_struct_typedef);
out->typedef_struct_ptr_exists = bpf_core_type_exists(struct_ptr_typedef);
out->typedef_int_exists = bpf_core_type_exists(int_typedef);
out->typedef_enum_exists = bpf_core_type_exists(enum_typedef);
out->typedef_void_ptr_exists = bpf_core_type_exists(void_ptr_typedef);
out->typedef_func_proto_exists = bpf_core_type_exists(func_proto_typedef);
out->typedef_arr_exists = bpf_core_type_exists(arr_typedef);
out->struct_sz = bpf_core_type_size(struct a_struct);
out->union_sz = bpf_core_type_size(union a_union);
out->enum_sz = bpf_core_type_size(enum an_enum);
out->typedef_named_struct_sz = bpf_core_type_size(named_struct_typedef);
out->typedef_anon_struct_sz = bpf_core_type_size(anon_struct_typedef);
out->typedef_struct_ptr_sz = bpf_core_type_size(struct_ptr_typedef);
out->typedef_int_sz = bpf_core_type_size(int_typedef);
out->typedef_enum_sz = bpf_core_type_size(enum_typedef);
out->typedef_void_ptr_sz = bpf_core_type_size(void_ptr_typedef);
out->typedef_func_proto_sz = bpf_core_type_size(func_proto_typedef);
out->typedef_arr_sz = bpf_core_type_size(arr_typedef);
#else
data.skip = true;
#endif
return 0;
}
// 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 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.
*/
#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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment