selftests/bpf: Add tests for ENUMVAL_EXISTS/ENUMVAL_VALUE relocations
authorAndrii Nakryiko <andriin@fb.com>
Wed, 19 Aug 2020 19:45:19 +0000 (12:45 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 19 Aug 2020 21:19:39 +0000 (14:19 -0700)
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
tools/testing/selftests/bpf/prog_tests/core_reloc.c
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___diff.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___err_missing.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___val3_missing.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/core_reloc_types.h
tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c [new file with mode: 0644]

index ad55051..30e40ff 100644 (file)
@@ -289,6 +289,23 @@ static int duration = 0;
        .fails = true,                                                  \
 }
 
+#define ENUMVAL_CASE_COMMON(name)                                      \
+       .case_name = #name,                                             \
+       .bpf_obj_file = "test_core_reloc_enumval.o",                    \
+       .btf_src_file = "btf__core_reloc_" #name ".o"                   \
+
+#define ENUMVAL_CASE(name, ...) {                                      \
+       ENUMVAL_CASE_COMMON(name),                                      \
+       .output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output)         \
+                       __VA_ARGS__,                                    \
+       .output_len = sizeof(struct core_reloc_enumval_output),         \
+}
+
+#define ENUMVAL_ERR_CASE(name) {                                       \
+       ENUMVAL_CASE_COMMON(name),                                      \
+       .fails = true,                                                  \
+}
+
 struct core_reloc_test_case;
 
 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
@@ -686,6 +703,45 @@ static struct core_reloc_test_case test_cases[] = {
        /* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
        TYPE_ID_CASE(type_id, setup_type_id_case_success),
        TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
+
+       /* Enumerator value existence and value relocations */
+       ENUMVAL_CASE(enumval, {
+               .named_val1_exists = true,
+               .named_val2_exists = true,
+               .named_val3_exists = true,
+               .anon_val1_exists = true,
+               .anon_val2_exists = true,
+               .anon_val3_exists = true,
+               .named_val1 = 1,
+               .named_val2 = 2,
+               .anon_val1 = 0x10,
+               .anon_val2 = 0x20,
+       }),
+       ENUMVAL_CASE(enumval___diff, {
+               .named_val1_exists = true,
+               .named_val2_exists = true,
+               .named_val3_exists = true,
+               .anon_val1_exists = true,
+               .anon_val2_exists = true,
+               .anon_val3_exists = true,
+               .named_val1 = 101,
+               .named_val2 = 202,
+               .anon_val1 = 0x11,
+               .anon_val2 = 0x22,
+       }),
+       ENUMVAL_CASE(enumval___val3_missing, {
+               .named_val1_exists = true,
+               .named_val2_exists = true,
+               .named_val3_exists = false,
+               .anon_val1_exists = true,
+               .anon_val2_exists = true,
+               .anon_val3_exists = false,
+               .named_val1 = 111,
+               .named_val2 = 222,
+               .anon_val1 = 0x111,
+               .anon_val2 = 0x222,
+       }),
+       ENUMVAL_ERR_CASE(enumval___err_missing),
 };
 
 struct data {
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval.c
new file mode 100644 (file)
index 0000000..48e62f3
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enumval x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___diff.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___diff.c
new file mode 100644 (file)
index 0000000..53e5e5a
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enumval___diff x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___err_missing.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___err_missing.c
new file mode 100644 (file)
index 0000000..d024fb2
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enumval___err_missing x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___val3_missing.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_enumval___val3_missing.c
new file mode 100644 (file)
index 0000000..9de6595
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_enumval___val3_missing x) {}
index 10afcc5..e6e616c 100644 (file)
@@ -1075,3 +1075,87 @@ struct core_reloc_type_id {
 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;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c b/tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c
new file mode 100644 (file)
index 0000000..e7ef3da
--- /dev/null
@@ -0,0 +1,72 @@
+// 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;
+}