| #include <stdint.h> |
| #include <stdbool.h> |
| /* |
| * KERNEL |
| */ |
| |
| struct core_reloc_kernel_output { |
| int valid[10]; |
| char comm[sizeof("test_progs")]; |
| int comm_len; |
| }; |
| |
| /* |
| * FLAVORS |
| */ |
| struct core_reloc_flavors { |
| int a; |
| int b; |
| int c; |
| }; |
| |
| /* this is not a flavor, as it doesn't have triple underscore */ |
| struct core_reloc_flavors__err_wrong_name { |
| int a; |
| int b; |
| int c; |
| }; |
| |
| /* |
| * NESTING |
| */ |
| /* original set up, used to record relocations in BPF program */ |
| struct core_reloc_nesting_substruct { |
| int a; |
| }; |
| |
| union core_reloc_nesting_subunion { |
| int b; |
| }; |
| |
| struct core_reloc_nesting { |
| union { |
| struct core_reloc_nesting_substruct a; |
| } a; |
| struct { |
| union core_reloc_nesting_subunion b; |
| } b; |
| }; |
| |
| /* inlined anonymous struct/union instead of named structs in original */ |
| struct core_reloc_nesting___anon_embed { |
| int __just_for_padding; |
| union { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| union { |
| int b; |
| } b; |
| } b; |
| }; |
| |
| /* different mix of nested structs/unions than in original */ |
| struct core_reloc_nesting___struct_union_mixup { |
| int __a; |
| struct { |
| int __a; |
| union { |
| char __a; |
| int a; |
| } a; |
| } a; |
| int __b; |
| union { |
| int __b; |
| union { |
| char __b; |
| int b; |
| } b; |
| } b; |
| }; |
| |
| /* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */ |
| struct core_reloc_nesting___extra_nesting { |
| int __padding; |
| struct { |
| struct { |
| struct { |
| struct { |
| union { |
| int a; |
| } a; |
| }; |
| }; |
| } a; |
| int __some_more; |
| struct { |
| union { |
| union { |
| union { |
| struct { |
| int b; |
| }; |
| } b; |
| }; |
| } b; |
| }; |
| }; |
| }; |
| |
| /* three flavors of same struct with different structure but same layout for |
| * a.a.a and b.b.b, thus successfully resolved and relocatable */ |
| struct core_reloc_nesting___dup_compat_types { |
| char __just_for_padding; |
| /* 3 more bytes of padding */ |
| struct { |
| struct { |
| int a; /* offset 4 */ |
| } a; |
| } a; |
| long long __more_padding; |
| struct { |
| struct { |
| int b; /* offset 16 */ |
| } b; |
| } b; |
| }; |
| |
| struct core_reloc_nesting___dup_compat_types__2 { |
| int __aligned_padding; |
| struct { |
| int __trickier_noop[0]; |
| struct { |
| char __some_more_noops[0]; |
| int a; /* offset 4 */ |
| } a; |
| } a; |
| int __more_padding; |
| struct { |
| struct { |
| struct { |
| int __critical_padding; |
| int b; /* offset 16 */ |
| } b; |
| int __does_not_matter; |
| }; |
| } b; |
| int __more_irrelevant_stuff; |
| }; |
| |
| struct core_reloc_nesting___dup_compat_types__3 { |
| char __correct_padding[4]; |
| struct { |
| struct { |
| int a; /* offset 4 */ |
| } a; |
| } a; |
| /* 8 byte padding due to next struct's alignment */ |
| struct { |
| struct { |
| int b; |
| } b; |
| } b __attribute__((aligned(16))); |
| }; |
| |
| /* b.b.b field is missing */ |
| struct core_reloc_nesting___err_missing_field { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| struct { |
| int x; |
| } b; |
| } b; |
| }; |
| |
| /* b.b.b field is an array of integers instead of plain int */ |
| struct core_reloc_nesting___err_array_field { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| struct { |
| int b[1]; |
| } b; |
| } b; |
| }; |
| |
| /* middle b container is missing */ |
| struct core_reloc_nesting___err_missing_container { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| int x; |
| } b; |
| }; |
| |
| /* middle b container is referenced through pointer instead of being embedded */ |
| struct core_reloc_nesting___err_nonstruct_container { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| struct { |
| int b; |
| } *b; |
| } b; |
| }; |
| |
| /* middle b container is an array of structs instead of plain struct */ |
| struct core_reloc_nesting___err_array_container { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| struct { |
| struct { |
| int b; |
| } b[1]; |
| } b; |
| }; |
| |
| /* two flavors of same struct with incompatible layout for b.b.b */ |
| struct core_reloc_nesting___err_dup_incompat_types__1 { |
| struct { |
| struct { |
| int a; /* offset 0 */ |
| } a; |
| } a; |
| struct { |
| struct { |
| int b; /* offset 4 */ |
| } b; |
| } b; |
| }; |
| |
| struct core_reloc_nesting___err_dup_incompat_types__2 { |
| struct { |
| struct { |
| int a; /* offset 0 */ |
| } a; |
| } a; |
| int __extra_padding; |
| struct { |
| struct { |
| int b; /* offset 8 (!) */ |
| } b; |
| } b; |
| }; |
| |
| /* two flavors of same struct having one of a.a.a and b.b.b, but not both */ |
| struct core_reloc_nesting___err_partial_match_dups__a { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| }; |
| |
| struct core_reloc_nesting___err_partial_match_dups__b { |
| struct { |
| struct { |
| int b; |
| } b; |
| } b; |
| }; |
| |
| struct core_reloc_nesting___err_too_deep { |
| struct { |
| struct { |
| int a; |
| } a; |
| } a; |
| /* 65 levels of nestedness for b.b.b */ |
| struct { |
| struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| struct { struct { struct { struct { struct { |
| /* this one is one too much */ |
| struct { |
| int b; |
| }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| }; }; }; }; }; |
| } b; |
| } b; |
| }; |
| |
| /* |
| * ARRAYS |
| */ |
| struct core_reloc_arrays_output { |
| int a2; |
| char b123; |
| int c1c; |
| int d00d; |
| int f10c; |
| }; |
| |
| struct core_reloc_arrays_substruct { |
| int c; |
| int d; |
| }; |
| |
| struct core_reloc_arrays { |
| int a[5]; |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| struct core_reloc_arrays_substruct f[][2]; |
| }; |
| |
| /* bigger array dimensions */ |
| struct core_reloc_arrays___diff_arr_dim { |
| int a[7]; |
| char b[3][4][5]; |
| struct core_reloc_arrays_substruct c[4]; |
| struct core_reloc_arrays_substruct d[2][3]; |
| struct core_reloc_arrays_substruct f[1][3]; |
| }; |
| |
| /* different size of array's value (struct) */ |
| struct core_reloc_arrays___diff_arr_val_sz { |
| int a[5]; |
| char b[2][3][4]; |
| struct { |
| int __padding1; |
| int c; |
| int __padding2; |
| } c[3]; |
| struct { |
| int __padding1; |
| int d; |
| int __padding2; |
| } d[1][2]; |
| struct { |
| int __padding1; |
| int c; |
| int __padding2; |
| } f[][2]; |
| }; |
| |
| struct core_reloc_arrays___equiv_zero_sz_arr { |
| int a[5]; |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| /* equivalent to flexible array */ |
| struct core_reloc_arrays_substruct f[0][2]; |
| }; |
| |
| struct core_reloc_arrays___fixed_arr { |
| int a[5]; |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| /* not a flexible array anymore, but within access bounds */ |
| struct core_reloc_arrays_substruct f[1][2]; |
| }; |
| |
| struct core_reloc_arrays___err_too_small { |
| int a[2]; /* this one is too small */ |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| struct core_reloc_arrays_substruct f[][2]; |
| }; |
| |
| struct core_reloc_arrays___err_too_shallow { |
| int a[5]; |
| char b[2][3]; /* this one lacks one dimension */ |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| struct core_reloc_arrays_substruct f[][2]; |
| }; |
| |
| struct core_reloc_arrays___err_non_array { |
| int a; /* not an array */ |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| struct core_reloc_arrays_substruct f[][2]; |
| }; |
| |
| struct core_reloc_arrays___err_wrong_val_type { |
| int a[5]; |
| char b[2][3][4]; |
| int c[3]; /* value is not a struct */ |
| struct core_reloc_arrays_substruct d[1][2]; |
| struct core_reloc_arrays_substruct f[][2]; |
| }; |
| |
| struct core_reloc_arrays___err_bad_zero_sz_arr { |
| /* zero-sized array, but not at the end */ |
| struct core_reloc_arrays_substruct f[0][2]; |
| int a[5]; |
| char b[2][3][4]; |
| struct core_reloc_arrays_substruct c[3]; |
| struct core_reloc_arrays_substruct d[1][2]; |
| }; |
| |
| /* |
| * PRIMITIVES |
| */ |
| enum core_reloc_primitives_enum { |
| A = 0, |
| B = 1, |
| }; |
| |
| struct core_reloc_primitives { |
| char a; |
| int b; |
| enum core_reloc_primitives_enum c; |
| void *d; |
| int (*f)(const char *); |
| }; |
| |
| struct core_reloc_primitives___diff_enum_def { |
| char a; |
| int b; |
| void *d; |
| int (*f)(const char *); |
| enum { |
| X = 100, |
| Y = 200, |
| } c; /* inline enum def with differing set of values */ |
| }; |
| |
| struct core_reloc_primitives___diff_func_proto { |
| void (*f)(int); /* incompatible function prototype */ |
| void *d; |
| enum core_reloc_primitives_enum c; |
| int b; |
| char a; |
| }; |
| |
| struct core_reloc_primitives___diff_ptr_type { |
| const char * const d; /* different pointee type + modifiers */ |
| char a; |
| int b; |
| enum core_reloc_primitives_enum c; |
| int (*f)(const char *); |
| }; |
| |
| struct core_reloc_primitives___err_non_enum { |
| char a[1]; |
| int b; |
| int c; /* int instead of enum */ |
| void *d; |
| int (*f)(const char *); |
| }; |
| |
| struct core_reloc_primitives___err_non_int { |
| char a[1]; |
| int *b; /* ptr instead of int */ |
| enum core_reloc_primitives_enum c; |
| void *d; |
| int (*f)(const char *); |
| }; |
| |
| struct core_reloc_primitives___err_non_ptr { |
| char a[1]; |
| int b; |
| enum core_reloc_primitives_enum c; |
| int d; /* int instead of ptr */ |
| int (*f)(const char *); |
| }; |
| |
| /* |
| * MODS |
| */ |
| struct core_reloc_mods_output { |
| int a, b, c, d, e, f, g, h; |
| }; |
| |
| typedef const int int_t; |
| typedef const char *char_ptr_t; |
| typedef const int arr_t[7]; |
| |
| struct core_reloc_mods_substruct { |
| int x; |
| int y; |
| }; |
| |
| typedef struct { |
| int x; |
| int y; |
| } core_reloc_mods_substruct_t; |
| |
| struct core_reloc_mods { |
| int a; |
| int_t b; |
| char *c; |
| char_ptr_t d; |
| int e[3]; |
| arr_t f; |
| struct core_reloc_mods_substruct g; |
| core_reloc_mods_substruct_t h; |
| }; |
| |
| /* a/b, c/d, e/f, and g/h pairs are swapped */ |
| struct core_reloc_mods___mod_swap { |
| int b; |
| int_t a; |
| char *d; |
| char_ptr_t c; |
| int f[3]; |
| arr_t e; |
| struct { |
| int y; |
| int x; |
| } h; |
| core_reloc_mods_substruct_t g; |
| }; |
| |
| typedef int int1_t; |
| typedef int1_t int2_t; |
| typedef int2_t int3_t; |
| |
| typedef int arr1_t[5]; |
| typedef arr1_t arr2_t; |
| typedef arr2_t arr3_t; |
| typedef arr3_t arr4_t; |
| |
| typedef const char * const volatile fancy_char_ptr_t; |
| |
| typedef core_reloc_mods_substruct_t core_reloc_mods_substruct_tt; |
| |
| /* we need more typedefs */ |
| struct core_reloc_mods___typedefs { |
| core_reloc_mods_substruct_tt g; |
| core_reloc_mods_substruct_tt h; |
| arr4_t f; |
| arr4_t e; |
| fancy_char_ptr_t d; |
| fancy_char_ptr_t c; |
| int3_t b; |
| int3_t a; |
| }; |
| |
| /* |
| * PTR_AS_ARR |
| */ |
| struct core_reloc_ptr_as_arr { |
| int a; |
| }; |
| |
| struct core_reloc_ptr_as_arr___diff_sz { |
| int :32; /* padding */ |
| char __some_more_padding; |
| int a; |
| }; |
| |
| /* |
| * INTS |
| */ |
| struct core_reloc_ints { |
| uint8_t u8_field; |
| int8_t s8_field; |
| uint16_t u16_field; |
| int16_t s16_field; |
| uint32_t u32_field; |
| int32_t s32_field; |
| uint64_t u64_field; |
| int64_t s64_field; |
| }; |
| |
| /* signed/unsigned types swap */ |
| struct core_reloc_ints___reverse_sign { |
| int8_t u8_field; |
| uint8_t s8_field; |
| int16_t u16_field; |
| uint16_t s16_field; |
| int32_t u32_field; |
| uint32_t s32_field; |
| int64_t u64_field; |
| uint64_t s64_field; |
| }; |
| |
| struct core_reloc_ints___bool { |
| bool u8_field; /* bool instead of uint8 */ |
| int8_t s8_field; |
| uint16_t u16_field; |
| int16_t s16_field; |
| uint32_t u32_field; |
| int32_t s32_field; |
| uint64_t u64_field; |
| int64_t s64_field; |
| }; |
| |
| /* |
| * MISC |
| */ |
| struct core_reloc_misc_output { |
| int a, b, c; |
| }; |
| |
| struct core_reloc_misc___a { |
| int a1; |
| int a2; |
| }; |
| |
| struct core_reloc_misc___b { |
| int b1; |
| int b2; |
| }; |
| |
| /* this one extends core_reloc_misc_extensible struct from BPF prog */ |
| struct core_reloc_misc_extensible { |
| int a; |
| int b; |
| int c; |
| int d; |
| }; |
| |
| /* |
| * EXISTENCE |
| */ |
| struct core_reloc_existence_output { |
| int a_exists; |
| int a_value; |
| int b_exists; |
| int b_value; |
| int c_exists; |
| int c_value; |
| int arr_exists; |
| int arr_value; |
| int s_exists; |
| int s_value; |
| }; |
| |
| struct core_reloc_existence { |
| int a; |
| struct { |
| int b; |
| }; |
| int c; |
| int arr[1]; |
| struct { |
| int x; |
| } s; |
| }; |
| |
| struct core_reloc_existence___minimal { |
| int a; |
| }; |
| |
| struct core_reloc_existence___err_wrong_int_sz { |
| short a; |
| }; |
| |
| struct core_reloc_existence___err_wrong_int_type { |
| int b[1]; |
| }; |
| |
| struct core_reloc_existence___err_wrong_int_kind { |
| struct{ int x; } c; |
| }; |
| |
| struct core_reloc_existence___err_wrong_arr_kind { |
| int arr; |
| }; |
| |
| struct core_reloc_existence___err_wrong_arr_value_type { |
| short arr[1]; |
| }; |
| |
| struct core_reloc_existence___err_wrong_struct_type { |
| int s; |
| }; |
| |
| /* |
| * BITFIELDS |
| */ |
| /* bitfield read results, all as plain integers */ |
| struct core_reloc_bitfields_output { |
| int64_t ub1; |
| int64_t ub2; |
| int64_t ub7; |
| int64_t sb4; |
| int64_t sb20; |
| int64_t u32; |
| int64_t s32; |
| }; |
| |
| struct core_reloc_bitfields { |
| /* unsigned bitfields */ |
| uint8_t ub1: 1; |
| uint8_t ub2: 2; |
| uint32_t ub7: 7; |
| /* signed bitfields */ |
| int8_t sb4: 4; |
| int32_t sb20: 20; |
| /* non-bitfields */ |
| uint32_t u32; |
| int32_t s32; |
| }; |
| |
| /* different bit sizes (both up and down) */ |
| struct core_reloc_bitfields___bit_sz_change { |
| /* unsigned bitfields */ |
| uint16_t ub1: 3; /* 1 -> 3 */ |
| uint32_t ub2: 20; /* 2 -> 20 */ |
| uint8_t ub7: 1; /* 7 -> 1 */ |
| /* signed bitfields */ |
| int8_t sb4: 1; /* 4 -> 1 */ |
| int32_t sb20: 30; /* 20 -> 30 */ |
| /* non-bitfields */ |
| uint16_t u32; /* 32 -> 16 */ |
| int64_t s32; /* 32 -> 64 */ |
| }; |
| |
| /* turn bitfield into non-bitfield and vice versa */ |
| struct core_reloc_bitfields___bitfield_vs_int { |
| uint64_t ub1; /* 3 -> 64 non-bitfield */ |
| uint8_t ub2; /* 20 -> 8 non-bitfield */ |
| int64_t ub7; /* 7 -> 64 non-bitfield signed */ |
| int64_t sb4; /* 4 -> 64 non-bitfield signed */ |
| uint64_t sb20; /* 20 -> 16 non-bitfield unsigned */ |
| int32_t u32: 20; /* 32 non-bitfield -> 20 bitfield */ |
| uint64_t s32: 60; /* 32 non-bitfield -> 60 bitfield */ |
| }; |
| |
| struct core_reloc_bitfields___just_big_enough { |
| uint64_t ub1: 4; |
| uint64_t ub2: 60; /* packed tightly */ |
| uint32_t ub7; |
| uint32_t sb4; |
| uint32_t sb20; |
| uint32_t u32; |
| uint32_t s32; |
| } __attribute__((packed)) ; |
| |
| struct core_reloc_bitfields___err_too_big_bitfield { |
| uint64_t ub1: 4; |
| uint64_t ub2: 61; /* packed tightly */ |
| uint32_t ub7; |
| uint32_t sb4; |
| uint32_t sb20; |
| uint32_t u32; |
| uint32_t s32; |
| } __attribute__((packed)) ; |
| |
| /* |
| * SIZE |
| */ |
| struct core_reloc_size_output { |
| int int_sz; |
| int struct_sz; |
| int union_sz; |
| int arr_sz; |
| int arr_elem_sz; |
| int ptr_sz; |
| int enum_sz; |
| }; |
| |
| struct core_reloc_size { |
| int int_field; |
| struct { int x; } struct_field; |
| union { int x; } union_field; |
| int arr_field[4]; |
| void *ptr_field; |
| enum { VALUE = 123 } enum_field; |
| }; |
| |
| struct core_reloc_size___diff_sz { |
| uint64_t int_field; |
| struct { int x; int y; int z; } struct_field; |
| union { int x; char bla[123]; } union_field; |
| char arr_field[10]; |
| void *ptr_field; |
| enum { OTHER_VALUE = 0xFFFFFFFFFFFFFFFF } enum_field; |
| }; |