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:
parent
eacaaed784
commit
3357490555
@ -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 {
|
||||
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_enumval x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_enumval___diff x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_enumval___err_missing x) {}
|
@ -0,0 +1,3 @@
|
||||
#include "core_reloc_types.h"
|
||||
|
||||
void f(struct core_reloc_enumval___val3_missing x) {}
|
@ -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;
|
||||
};
|
||||
|
72
tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c
Normal file
72
tools/testing/selftests/bpf/progs/test_core_reloc_enumval.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user