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
This commit is contained in:
Andrii Nakryiko 2020-08-19 12:45:19 -07:00 committed by Alexei Starovoitov
parent eacaaed784
commit 3357490555
7 changed files with 224 additions and 0 deletions

View 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 {

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_enumval x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___diff x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___err_missing x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_enumval___val3_missing x) {}

View 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;
};

View File

@ -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;
}