forked from Minki/linux
selftests/bpf: Add field existence CO-RE relocs tests
Add a bunch of tests validating CO-RE is handling field existence relocation. Relaxed CO-RE relocation mode is activated for these new tests to prevent libbpf from rejecting BPF object for no-match relocation, even though test BPF program is not going to use that relocation, if field is missing. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20191015182849.3922287-6-andriin@fb.com
This commit is contained in:
parent
01340e3191
commit
c7566a6969
@ -174,6 +174,21 @@
|
|||||||
.fails = true, \
|
.fails = true, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EXISTENCE_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
|
||||||
|
.a = 42, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXISTENCE_CASE_COMMON(name) \
|
||||||
|
.case_name = #name, \
|
||||||
|
.bpf_obj_file = "test_core_reloc_existence.o", \
|
||||||
|
.btf_src_file = "btf__core_reloc_" #name ".o", \
|
||||||
|
.relaxed_core_relocs = true \
|
||||||
|
|
||||||
|
#define EXISTENCE_ERR_CASE(name) { \
|
||||||
|
EXISTENCE_CASE_COMMON(name), \
|
||||||
|
.fails = true, \
|
||||||
|
}
|
||||||
|
|
||||||
struct core_reloc_test_case {
|
struct core_reloc_test_case {
|
||||||
const char *case_name;
|
const char *case_name;
|
||||||
const char *bpf_obj_file;
|
const char *bpf_obj_file;
|
||||||
@ -183,6 +198,7 @@ struct core_reloc_test_case {
|
|||||||
const char *output;
|
const char *output;
|
||||||
int output_len;
|
int output_len;
|
||||||
bool fails;
|
bool fails;
|
||||||
|
bool relaxed_core_relocs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct core_reloc_test_case test_cases[] = {
|
static struct core_reloc_test_case test_cases[] = {
|
||||||
@ -283,6 +299,59 @@ static struct core_reloc_test_case test_cases[] = {
|
|||||||
},
|
},
|
||||||
.output_len = sizeof(struct core_reloc_misc_output),
|
.output_len = sizeof(struct core_reloc_misc_output),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/* validate field existence checks */
|
||||||
|
{
|
||||||
|
EXISTENCE_CASE_COMMON(existence),
|
||||||
|
.input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
|
||||||
|
.a = 1,
|
||||||
|
.b = 2,
|
||||||
|
.c = 3,
|
||||||
|
.arr = { 4 },
|
||||||
|
.s = { .x = 5 },
|
||||||
|
},
|
||||||
|
.input_len = sizeof(struct core_reloc_existence),
|
||||||
|
.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
|
||||||
|
.a_exists = 1,
|
||||||
|
.b_exists = 1,
|
||||||
|
.c_exists = 1,
|
||||||
|
.arr_exists = 1,
|
||||||
|
.s_exists = 1,
|
||||||
|
.a_value = 1,
|
||||||
|
.b_value = 2,
|
||||||
|
.c_value = 3,
|
||||||
|
.arr_value = 4,
|
||||||
|
.s_value = 5,
|
||||||
|
},
|
||||||
|
.output_len = sizeof(struct core_reloc_existence_output),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
EXISTENCE_CASE_COMMON(existence___minimal),
|
||||||
|
.input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
|
||||||
|
.a = 42,
|
||||||
|
},
|
||||||
|
.input_len = sizeof(struct core_reloc_existence),
|
||||||
|
.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
|
||||||
|
.a_exists = 1,
|
||||||
|
.b_exists = 0,
|
||||||
|
.c_exists = 0,
|
||||||
|
.arr_exists = 0,
|
||||||
|
.s_exists = 0,
|
||||||
|
.a_value = 42,
|
||||||
|
.b_value = 0xff000002u,
|
||||||
|
.c_value = 0xff000003u,
|
||||||
|
.arr_value = 0xff000004u,
|
||||||
|
.s_value = 0xff000005u,
|
||||||
|
},
|
||||||
|
.output_len = sizeof(struct core_reloc_existence_output),
|
||||||
|
},
|
||||||
|
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_int_sz),
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_int_type),
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_int_kind),
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_arr_kind),
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_arr_value_type),
|
||||||
|
EXISTENCE_ERR_CASE(existence__err_struct_type),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct data {
|
struct data {
|
||||||
@ -305,11 +374,14 @@ void test_core_reloc(void)
|
|||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
|
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
|
||||||
test_case = &test_cases[i];
|
test_case = &test_cases[i];
|
||||||
|
|
||||||
if (!test__start_subtest(test_case->case_name))
|
if (!test__start_subtest(test_case->case_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
obj = bpf_object__open(test_case->bpf_obj_file);
|
LIBBPF_OPTS(bpf_object_open_opts, opts,
|
||||||
|
.relaxed_core_relocs = test_case->relaxed_core_relocs,
|
||||||
|
);
|
||||||
|
|
||||||
|
obj = bpf_object__open_file(test_case->bpf_obj_file, &opts);
|
||||||
if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
|
if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
|
||||||
"failed to open '%s': %ld\n",
|
"failed to open '%s': %ld\n",
|
||||||
test_case->bpf_obj_file, PTR_ERR(obj)))
|
test_case->bpf_obj_file, PTR_ERR(obj)))
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_arr_kind x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_arr_value_type x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_int_kind x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_int_sz x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_int_type x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___err_wrong_struct_type x) {}
|
@ -0,0 +1,3 @@
|
|||||||
|
#include "core_reloc_types.h"
|
||||||
|
|
||||||
|
void f(struct core_reloc_existence___minimal x) {}
|
@ -674,3 +674,59 @@ struct core_reloc_misc_extensible {
|
|||||||
int c;
|
int c;
|
||||||
int d;
|
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;
|
||||||
|
};
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (c) 2019 Facebook
|
||||||
|
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "bpf_helpers.h"
|
||||||
|
#include "bpf_core_read.h"
|
||||||
|
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
static volatile struct data {
|
||||||
|
char in[256];
|
||||||
|
char out[256];
|
||||||
|
} data;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
struct {
|
||||||
|
int x;
|
||||||
|
} s;
|
||||||
|
int arr[1];
|
||||||
|
int a;
|
||||||
|
struct {
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
int c;
|
||||||
|
};
|
||||||
|
|
||||||
|
SEC("raw_tracepoint/sys_enter")
|
||||||
|
int test_core_existence(void *ctx)
|
||||||
|
{
|
||||||
|
struct core_reloc_existence *in = (void *)&data.in;
|
||||||
|
struct core_reloc_existence_output *out = (void *)&data.out;
|
||||||
|
|
||||||
|
out->a_exists = bpf_core_field_exists(in->a);
|
||||||
|
if (bpf_core_field_exists(in->a))
|
||||||
|
out->a_value = BPF_CORE_READ(in, a);
|
||||||
|
else
|
||||||
|
out->a_value = 0xff000001u;
|
||||||
|
|
||||||
|
out->b_exists = bpf_core_field_exists(in->b);
|
||||||
|
if (bpf_core_field_exists(in->b))
|
||||||
|
out->b_value = BPF_CORE_READ(in, b);
|
||||||
|
else
|
||||||
|
out->b_value = 0xff000002u;
|
||||||
|
|
||||||
|
out->c_exists = bpf_core_field_exists(in->c);
|
||||||
|
if (bpf_core_field_exists(in->c))
|
||||||
|
out->c_value = BPF_CORE_READ(in, c);
|
||||||
|
else
|
||||||
|
out->c_value = 0xff000003u;
|
||||||
|
|
||||||
|
out->arr_exists = bpf_core_field_exists(in->arr);
|
||||||
|
if (bpf_core_field_exists(in->arr))
|
||||||
|
out->arr_value = BPF_CORE_READ(in, arr[0]);
|
||||||
|
else
|
||||||
|
out->arr_value = 0xff000004u;
|
||||||
|
|
||||||
|
out->s_exists = bpf_core_field_exists(in->s);
|
||||||
|
if (bpf_core_field_exists(in->s))
|
||||||
|
out->s_value = BPF_CORE_READ(in, s.x);
|
||||||
|
else
|
||||||
|
out->s_value = 0xff000005u;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user