Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add tests for ENUMVAL_EXISTS/ENUMVAL_VALUE relocations

Add tests validating existence and value relocations for enum value-based
relocations. If __builtin_preserve_enum_value() built-in is not supported,
skip tests.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20200819194519.3375898-6-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
33574905 eacaaed7

+224
+56
tools/testing/selftests/bpf/prog_tests/core_reloc.c
··· 289 289 .fails = true, \ 290 290 } 291 291 292 + #define ENUMVAL_CASE_COMMON(name) \ 293 + .case_name = #name, \ 294 + .bpf_obj_file = "test_core_reloc_enumval.o", \ 295 + .btf_src_file = "btf__core_reloc_" #name ".o" \ 296 + 297 + #define ENUMVAL_CASE(name, ...) { \ 298 + ENUMVAL_CASE_COMMON(name), \ 299 + .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output) \ 300 + __VA_ARGS__, \ 301 + .output_len = sizeof(struct core_reloc_enumval_output), \ 302 + } 303 + 304 + #define ENUMVAL_ERR_CASE(name) { \ 305 + ENUMVAL_CASE_COMMON(name), \ 306 + .fails = true, \ 307 + } 308 + 292 309 struct core_reloc_test_case; 293 310 294 311 typedef int (*setup_test_fn)(struct core_reloc_test_case *test); ··· 703 686 /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */ 704 687 TYPE_ID_CASE(type_id, setup_type_id_case_success), 705 688 TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure), 689 + 690 + /* Enumerator value existence and value relocations */ 691 + ENUMVAL_CASE(enumval, { 692 + .named_val1_exists = true, 693 + .named_val2_exists = true, 694 + .named_val3_exists = true, 695 + .anon_val1_exists = true, 696 + .anon_val2_exists = true, 697 + .anon_val3_exists = true, 698 + .named_val1 = 1, 699 + .named_val2 = 2, 700 + .anon_val1 = 0x10, 701 + .anon_val2 = 0x20, 702 + }), 703 + ENUMVAL_CASE(enumval___diff, { 704 + .named_val1_exists = true, 705 + .named_val2_exists = true, 706 + .named_val3_exists = true, 707 + .anon_val1_exists = true, 708 + .anon_val2_exists = true, 709 + .anon_val3_exists = true, 710 + .named_val1 = 101, 711 + .named_val2 = 202, 712 + .anon_val1 = 0x11, 713 + .anon_val2 = 0x22, 714 + }), 715 + ENUMVAL_CASE(enumval___val3_missing, { 716 + .named_val1_exists = true, 717 + .named_val2_exists = true, 718 + .named_val3_exists = false, 719 + .anon_val1_exists = true, 720 + .anon_val2_exists = true, 721 + .anon_val3_exists = false, 722 + .named_val1 = 111, 723 + .named_val2 = 222, 724 + .anon_val1 = 0x111, 725 + .anon_val2 = 0x222, 726 + }), 727 + ENUMVAL_ERR_CASE(enumval___err_missing), 706 728 }; 707 729 708 730 struct data {
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_enumval x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___diff.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_enumval___diff x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___err_missing.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_enumval___err_missing x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___val3_missing.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_enumval___val3_missing x) {}
+84
tools/testing/selftests/bpf/progs/core_reloc_types.h
··· 1075 1075 struct core_reloc_type_id___missing_targets { 1076 1076 /* nothing */ 1077 1077 }; 1078 + 1079 + /* 1080 + * ENUMERATOR VALUE EXISTENCE AND VALUE RELOCATION 1081 + */ 1082 + struct core_reloc_enumval_output { 1083 + bool named_val1_exists; 1084 + bool named_val2_exists; 1085 + bool named_val3_exists; 1086 + bool anon_val1_exists; 1087 + bool anon_val2_exists; 1088 + bool anon_val3_exists; 1089 + 1090 + int named_val1; 1091 + int named_val2; 1092 + int anon_val1; 1093 + int anon_val2; 1094 + }; 1095 + 1096 + enum named_enum { 1097 + NAMED_ENUM_VAL1 = 1, 1098 + NAMED_ENUM_VAL2 = 2, 1099 + NAMED_ENUM_VAL3 = 3, 1100 + }; 1101 + 1102 + typedef enum { 1103 + ANON_ENUM_VAL1 = 0x10, 1104 + ANON_ENUM_VAL2 = 0x20, 1105 + ANON_ENUM_VAL3 = 0x30, 1106 + } anon_enum; 1107 + 1108 + struct core_reloc_enumval { 1109 + enum named_enum f1; 1110 + anon_enum f2; 1111 + }; 1112 + 1113 + /* differing enumerator values */ 1114 + enum named_enum___diff { 1115 + NAMED_ENUM_VAL1___diff = 101, 1116 + NAMED_ENUM_VAL2___diff = 202, 1117 + NAMED_ENUM_VAL3___diff = 303, 1118 + }; 1119 + 1120 + typedef enum { 1121 + ANON_ENUM_VAL1___diff = 0x11, 1122 + ANON_ENUM_VAL2___diff = 0x22, 1123 + ANON_ENUM_VAL3___diff = 0x33, 1124 + } anon_enum___diff; 1125 + 1126 + struct core_reloc_enumval___diff { 1127 + enum named_enum___diff f1; 1128 + anon_enum___diff f2; 1129 + }; 1130 + 1131 + /* missing (optional) third enum value */ 1132 + enum named_enum___val3_missing { 1133 + NAMED_ENUM_VAL1___val3_missing = 111, 1134 + NAMED_ENUM_VAL2___val3_missing = 222, 1135 + }; 1136 + 1137 + typedef enum { 1138 + ANON_ENUM_VAL1___val3_missing = 0x111, 1139 + ANON_ENUM_VAL2___val3_missing = 0x222, 1140 + } anon_enum___val3_missing; 1141 + 1142 + struct core_reloc_enumval___val3_missing { 1143 + enum named_enum___val3_missing f1; 1144 + anon_enum___val3_missing f2; 1145 + }; 1146 + 1147 + /* missing (mandatory) second enum value, should fail */ 1148 + enum named_enum___err_missing { 1149 + NAMED_ENUM_VAL1___err_missing = 1, 1150 + NAMED_ENUM_VAL3___err_missing = 3, 1151 + }; 1152 + 1153 + typedef enum { 1154 + ANON_ENUM_VAL1___err_missing = 0x111, 1155 + ANON_ENUM_VAL3___err_missing = 0x222, 1156 + } anon_enum___err_missing; 1157 + 1158 + struct core_reloc_enumval___err_missing { 1159 + enum named_enum___err_missing f1; 1160 + anon_enum___err_missing f2; 1161 + };
+72
tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2020 Facebook 3 + 4 + #include <linux/bpf.h> 5 + #include <stdint.h> 6 + #include <stdbool.h> 7 + #include <bpf/bpf_helpers.h> 8 + #include <bpf/bpf_core_read.h> 9 + 10 + char _license[] SEC("license") = "GPL"; 11 + 12 + struct { 13 + char in[256]; 14 + char out[256]; 15 + bool skip; 16 + } data = {}; 17 + 18 + enum named_enum { 19 + NAMED_ENUM_VAL1 = 1, 20 + NAMED_ENUM_VAL2 = 2, 21 + NAMED_ENUM_VAL3 = 3, 22 + }; 23 + 24 + typedef enum { 25 + ANON_ENUM_VAL1 = 0x10, 26 + ANON_ENUM_VAL2 = 0x20, 27 + ANON_ENUM_VAL3 = 0x30, 28 + } anon_enum; 29 + 30 + struct core_reloc_enumval_output { 31 + bool named_val1_exists; 32 + bool named_val2_exists; 33 + bool named_val3_exists; 34 + bool anon_val1_exists; 35 + bool anon_val2_exists; 36 + bool anon_val3_exists; 37 + 38 + int named_val1; 39 + int named_val2; 40 + int anon_val1; 41 + int anon_val2; 42 + }; 43 + 44 + SEC("raw_tracepoint/sys_enter") 45 + int test_core_enumval(void *ctx) 46 + { 47 + #if __has_builtin(__builtin_preserve_enum_value) 48 + struct core_reloc_enumval_output *out = (void *)&data.out; 49 + enum named_enum named = 0; 50 + anon_enum anon = 0; 51 + 52 + out->named_val1_exists = bpf_core_enum_value_exists(named, NAMED_ENUM_VAL1); 53 + out->named_val2_exists = bpf_core_enum_value_exists(enum named_enum, NAMED_ENUM_VAL2); 54 + out->named_val3_exists = bpf_core_enum_value_exists(enum named_enum, NAMED_ENUM_VAL3); 55 + 56 + out->anon_val1_exists = bpf_core_enum_value_exists(anon, ANON_ENUM_VAL1); 57 + out->anon_val2_exists = bpf_core_enum_value_exists(anon_enum, ANON_ENUM_VAL2); 58 + out->anon_val3_exists = bpf_core_enum_value_exists(anon_enum, ANON_ENUM_VAL3); 59 + 60 + out->named_val1 = bpf_core_enum_value(named, NAMED_ENUM_VAL1); 61 + out->named_val2 = bpf_core_enum_value(named, NAMED_ENUM_VAL2); 62 + /* NAMED_ENUM_VAL3 value is optional */ 63 + 64 + out->anon_val1 = bpf_core_enum_value(anon, ANON_ENUM_VAL1); 65 + out->anon_val2 = bpf_core_enum_value(anon, ANON_ENUM_VAL2); 66 + /* ANON_ENUM_VAL3 value is optional */ 67 + #else 68 + data.skip = true; 69 + #endif 70 + 71 + return 0; 72 + }