741 lines
24 KiB
C
741 lines
24 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <bpf/btf.h>
|
|
#include <test_btf.h>
|
|
#include <linux/btf.h>
|
|
#include <test_progs.h>
|
|
#include <network_helpers.h>
|
|
|
|
#include "linked_list.skel.h"
|
|
#include "linked_list_fail.skel.h"
|
|
|
|
static char log_buf[1024 * 1024];
|
|
|
|
static struct {
|
|
const char *prog_name;
|
|
const char *err_msg;
|
|
} linked_list_fail_tests[] = {
|
|
#define TEST(test, off) \
|
|
{ #test "_missing_lock_push_front", \
|
|
"bpf_spin_lock at off=" #off " must be held for bpf_list_head" }, \
|
|
{ #test "_missing_lock_push_back", \
|
|
"bpf_spin_lock at off=" #off " must be held for bpf_list_head" }, \
|
|
{ #test "_missing_lock_pop_front", \
|
|
"bpf_spin_lock at off=" #off " must be held for bpf_list_head" }, \
|
|
{ #test "_missing_lock_pop_back", \
|
|
"bpf_spin_lock at off=" #off " must be held for bpf_list_head" },
|
|
TEST(kptr, 32)
|
|
TEST(global, 16)
|
|
TEST(map, 0)
|
|
TEST(inner_map, 0)
|
|
#undef TEST
|
|
#define TEST(test, op) \
|
|
{ #test "_kptr_incorrect_lock_" #op, \
|
|
"held lock and object are not in the same allocation\n" \
|
|
"bpf_spin_lock at off=32 must be held for bpf_list_head" }, \
|
|
{ #test "_global_incorrect_lock_" #op, \
|
|
"held lock and object are not in the same allocation\n" \
|
|
"bpf_spin_lock at off=16 must be held for bpf_list_head" }, \
|
|
{ #test "_map_incorrect_lock_" #op, \
|
|
"held lock and object are not in the same allocation\n" \
|
|
"bpf_spin_lock at off=0 must be held for bpf_list_head" }, \
|
|
{ #test "_inner_map_incorrect_lock_" #op, \
|
|
"held lock and object are not in the same allocation\n" \
|
|
"bpf_spin_lock at off=0 must be held for bpf_list_head" },
|
|
TEST(kptr, push_front)
|
|
TEST(kptr, push_back)
|
|
TEST(kptr, pop_front)
|
|
TEST(kptr, pop_back)
|
|
TEST(global, push_front)
|
|
TEST(global, push_back)
|
|
TEST(global, pop_front)
|
|
TEST(global, pop_back)
|
|
TEST(map, push_front)
|
|
TEST(map, push_back)
|
|
TEST(map, pop_front)
|
|
TEST(map, pop_back)
|
|
TEST(inner_map, push_front)
|
|
TEST(inner_map, push_back)
|
|
TEST(inner_map, pop_front)
|
|
TEST(inner_map, pop_back)
|
|
#undef TEST
|
|
{ "map_compat_kprobe", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "map_compat_kretprobe", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "map_compat_tp", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "map_compat_perf", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "map_compat_raw_tp", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "map_compat_raw_tp_w", "tracing progs cannot use bpf_list_head yet" },
|
|
{ "obj_type_id_oor", "local type ID argument must be in range [0, U32_MAX]" },
|
|
{ "obj_new_no_composite", "bpf_obj_new type ID argument must be of a struct" },
|
|
{ "obj_new_no_struct", "bpf_obj_new type ID argument must be of a struct" },
|
|
{ "obj_drop_non_zero_off", "R1 must have zero offset when passed to release func" },
|
|
{ "new_null_ret", "R0 invalid mem access 'ptr_or_null_'" },
|
|
{ "obj_new_acq", "Unreleased reference id=" },
|
|
{ "use_after_drop", "invalid mem access 'scalar'" },
|
|
{ "ptr_walk_scalar", "type=scalar expected=percpu_ptr_" },
|
|
{ "direct_read_lock", "direct access to bpf_spin_lock is disallowed" },
|
|
{ "direct_write_lock", "direct access to bpf_spin_lock is disallowed" },
|
|
{ "direct_read_head", "direct access to bpf_list_head is disallowed" },
|
|
{ "direct_write_head", "direct access to bpf_list_head is disallowed" },
|
|
{ "direct_read_node", "direct access to bpf_list_node is disallowed" },
|
|
{ "direct_write_node", "direct access to bpf_list_node is disallowed" },
|
|
{ "write_after_push_front", "only read is supported" },
|
|
{ "write_after_push_back", "only read is supported" },
|
|
{ "use_after_unlock_push_front", "invalid mem access 'scalar'" },
|
|
{ "use_after_unlock_push_back", "invalid mem access 'scalar'" },
|
|
{ "double_push_front", "arg#1 expected pointer to allocated object" },
|
|
{ "double_push_back", "arg#1 expected pointer to allocated object" },
|
|
{ "no_node_value_type", "bpf_list_node not found at offset=0" },
|
|
{ "incorrect_value_type",
|
|
"operation on bpf_list_head expects arg#1 bpf_list_node at offset=0 in struct foo, "
|
|
"but arg is at offset=0 in struct bar" },
|
|
{ "incorrect_node_var_off", "variable ptr_ access var_off=(0x0; 0xffffffff) disallowed" },
|
|
{ "incorrect_node_off1", "bpf_list_node not found at offset=1" },
|
|
{ "incorrect_node_off2", "arg#1 offset=40, but expected bpf_list_node at offset=0 in struct foo" },
|
|
{ "no_head_type", "bpf_list_head not found at offset=0" },
|
|
{ "incorrect_head_var_off1", "R1 doesn't have constant offset" },
|
|
{ "incorrect_head_var_off2", "variable ptr_ access var_off=(0x0; 0xffffffff) disallowed" },
|
|
{ "incorrect_head_off1", "bpf_list_head not found at offset=17" },
|
|
{ "incorrect_head_off2", "bpf_list_head not found at offset=1" },
|
|
{ "pop_front_off",
|
|
"15: (bf) r1 = r6 ; R1_w=ptr_or_null_foo(id=4,ref_obj_id=4,off=40,imm=0) "
|
|
"R6_w=ptr_or_null_foo(id=4,ref_obj_id=4,off=40,imm=0) refs=2,4\n"
|
|
"16: (85) call bpf_this_cpu_ptr#154\nR1 type=ptr_or_null_ expected=percpu_ptr_" },
|
|
{ "pop_back_off",
|
|
"15: (bf) r1 = r6 ; R1_w=ptr_or_null_foo(id=4,ref_obj_id=4,off=40,imm=0) "
|
|
"R6_w=ptr_or_null_foo(id=4,ref_obj_id=4,off=40,imm=0) refs=2,4\n"
|
|
"16: (85) call bpf_this_cpu_ptr#154\nR1 type=ptr_or_null_ expected=percpu_ptr_" },
|
|
};
|
|
|
|
static void test_linked_list_fail_prog(const char *prog_name, const char *err_msg)
|
|
{
|
|
LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf,
|
|
.kernel_log_size = sizeof(log_buf),
|
|
.kernel_log_level = 1);
|
|
struct linked_list_fail *skel;
|
|
struct bpf_program *prog;
|
|
int ret;
|
|
|
|
skel = linked_list_fail__open_opts(&opts);
|
|
if (!ASSERT_OK_PTR(skel, "linked_list_fail__open_opts"))
|
|
return;
|
|
|
|
prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
|
if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
|
|
goto end;
|
|
|
|
bpf_program__set_autoload(prog, true);
|
|
|
|
ret = linked_list_fail__load(skel);
|
|
if (!ASSERT_ERR(ret, "linked_list_fail__load must fail"))
|
|
goto end;
|
|
|
|
if (!ASSERT_OK_PTR(strstr(log_buf, err_msg), "expected error message")) {
|
|
fprintf(stderr, "Expected: %s\n", err_msg);
|
|
fprintf(stderr, "Verifier: %s\n", log_buf);
|
|
}
|
|
|
|
end:
|
|
linked_list_fail__destroy(skel);
|
|
}
|
|
|
|
static void clear_fields(struct bpf_map *map)
|
|
{
|
|
char buf[24];
|
|
int key = 0;
|
|
|
|
memset(buf, 0xff, sizeof(buf));
|
|
ASSERT_OK(bpf_map__update_elem(map, &key, sizeof(key), buf, sizeof(buf), 0), "check_and_free_fields");
|
|
}
|
|
|
|
enum {
|
|
TEST_ALL,
|
|
PUSH_POP,
|
|
PUSH_POP_MULT,
|
|
LIST_IN_LIST,
|
|
};
|
|
|
|
static void test_linked_list_success(int mode, bool leave_in_map)
|
|
{
|
|
LIBBPF_OPTS(bpf_test_run_opts, opts,
|
|
.data_in = &pkt_v4,
|
|
.data_size_in = sizeof(pkt_v4),
|
|
.repeat = 1,
|
|
);
|
|
struct linked_list *skel;
|
|
int ret;
|
|
|
|
skel = linked_list__open_and_load();
|
|
if (!ASSERT_OK_PTR(skel, "linked_list__open_and_load"))
|
|
return;
|
|
|
|
if (mode == LIST_IN_LIST)
|
|
goto lil;
|
|
if (mode == PUSH_POP_MULT)
|
|
goto ppm;
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.map_list_push_pop), &opts);
|
|
ASSERT_OK(ret, "map_list_push_pop");
|
|
ASSERT_OK(opts.retval, "map_list_push_pop retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.array_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.inner_map_list_push_pop), &opts);
|
|
ASSERT_OK(ret, "inner_map_list_push_pop");
|
|
ASSERT_OK(opts.retval, "inner_map_list_push_pop retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.inner_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.global_list_push_pop), &opts);
|
|
ASSERT_OK(ret, "global_list_push_pop");
|
|
ASSERT_OK(opts.retval, "global_list_push_pop retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.bss_A);
|
|
|
|
if (mode == PUSH_POP)
|
|
goto end;
|
|
|
|
ppm:
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.map_list_push_pop_multiple), &opts);
|
|
ASSERT_OK(ret, "map_list_push_pop_multiple");
|
|
ASSERT_OK(opts.retval, "map_list_push_pop_multiple retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.array_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.inner_map_list_push_pop_multiple), &opts);
|
|
ASSERT_OK(ret, "inner_map_list_push_pop_multiple");
|
|
ASSERT_OK(opts.retval, "inner_map_list_push_pop_multiple retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.inner_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.global_list_push_pop_multiple), &opts);
|
|
ASSERT_OK(ret, "global_list_push_pop_multiple");
|
|
ASSERT_OK(opts.retval, "global_list_push_pop_multiple retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.bss_A);
|
|
|
|
if (mode == PUSH_POP_MULT)
|
|
goto end;
|
|
|
|
lil:
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.map_list_in_list), &opts);
|
|
ASSERT_OK(ret, "map_list_in_list");
|
|
ASSERT_OK(opts.retval, "map_list_in_list retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.array_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.inner_map_list_in_list), &opts);
|
|
ASSERT_OK(ret, "inner_map_list_in_list");
|
|
ASSERT_OK(opts.retval, "inner_map_list_in_list retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.inner_map);
|
|
|
|
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.global_list_in_list), &opts);
|
|
ASSERT_OK(ret, "global_list_in_list");
|
|
ASSERT_OK(opts.retval, "global_list_in_list retval");
|
|
if (!leave_in_map)
|
|
clear_fields(skel->maps.bss_A);
|
|
end:
|
|
linked_list__destroy(skel);
|
|
}
|
|
|
|
#define SPIN_LOCK 2
|
|
#define LIST_HEAD 3
|
|
#define LIST_NODE 4
|
|
|
|
static struct btf *init_btf(void)
|
|
{
|
|
int id, lid, hid, nid;
|
|
struct btf *btf;
|
|
|
|
btf = btf__new_empty();
|
|
if (!ASSERT_OK_PTR(btf, "btf__new_empty"))
|
|
return NULL;
|
|
id = btf__add_int(btf, "int", 4, BTF_INT_SIGNED);
|
|
if (!ASSERT_EQ(id, 1, "btf__add_int"))
|
|
goto end;
|
|
lid = btf__add_struct(btf, "bpf_spin_lock", 4);
|
|
if (!ASSERT_EQ(lid, SPIN_LOCK, "btf__add_struct bpf_spin_lock"))
|
|
goto end;
|
|
hid = btf__add_struct(btf, "bpf_list_head", 16);
|
|
if (!ASSERT_EQ(hid, LIST_HEAD, "btf__add_struct bpf_list_head"))
|
|
goto end;
|
|
nid = btf__add_struct(btf, "bpf_list_node", 16);
|
|
if (!ASSERT_EQ(nid, LIST_NODE, "btf__add_struct bpf_list_node"))
|
|
goto end;
|
|
return btf;
|
|
end:
|
|
btf__free(btf);
|
|
return NULL;
|
|
}
|
|
|
|
static void test_btf(void)
|
|
{
|
|
struct btf *btf = NULL;
|
|
int id, err;
|
|
|
|
while (test__start_subtest("btf: too many locks")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 24);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_struct foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", SPIN_LOCK, 32, 0);
|
|
if (!ASSERT_OK(err, "btf__add_struct foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "c", LIST_HEAD, 64, 0);
|
|
if (!ASSERT_OK(err, "btf__add_struct foo::a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -E2BIG, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: missing lock")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 16);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_struct foo::a"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:baz:a", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:baz:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "baz", 16);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct baz"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field baz::a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -EINVAL, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: bad offset")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 36);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:foo:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:foo:b"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -EEXIST, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: missing contains:")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 24);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_HEAD, 64, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -EINVAL, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: missing struct")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 24);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_HEAD, 64, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:bar", 5, 1);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:bar"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -ENOENT, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: missing node")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 24);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_HEAD, 64, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:foo:c", 5, 1);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:foo:c"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
btf__free(btf);
|
|
ASSERT_EQ(err, -ENOENT, "check btf");
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: node incorrect type")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 20);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", SPIN_LOCK, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:a", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 4);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", SPIN_LOCK, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -EINVAL, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: multiple bpf_list_node with name b")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 52);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::c"))
|
|
break;
|
|
err = btf__add_field(btf, "d", SPIN_LOCK, 384, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::d"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:foo:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:foo:b"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -EINVAL, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning | owned AA cycle")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 36);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:foo:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:foo:b"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -ELOOP, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning | owned ABA cycle")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 36);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:b"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 36);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:foo:b", 7, 0);
|
|
if (!ASSERT_EQ(id, 8, "btf__add_decl_tag contains:foo:b"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -ELOOP, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning -> owned")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 20);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", SPIN_LOCK, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:a", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 16);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, 0, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning -> owning | owned -> owned")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 20);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", SPIN_LOCK, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:b"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 36);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:baz:a", 7, 0);
|
|
if (!ASSERT_EQ(id, 8, "btf__add_decl_tag contains:baz:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "baz", 16);
|
|
if (!ASSERT_EQ(id, 9, "btf__add_struct baz"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field baz:a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, 0, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning | owned -> owning | owned -> owned")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 36);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:b"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 36);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar:a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar:b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar:c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:baz:a", 7, 0);
|
|
if (!ASSERT_EQ(id, 8, "btf__add_decl_tag contains:baz:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "baz", 16);
|
|
if (!ASSERT_EQ(id, 9, "btf__add_struct baz"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field baz:a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -ELOOP, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
|
|
while (test__start_subtest("btf: owning -> owning | owned -> owning | owned -> owned")) {
|
|
btf = init_btf();
|
|
if (!ASSERT_OK_PTR(btf, "init_btf"))
|
|
break;
|
|
id = btf__add_struct(btf, "foo", 20);
|
|
if (!ASSERT_EQ(id, 5, "btf__add_struct foo"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", SPIN_LOCK, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field foo::b"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bar:b", 5, 0);
|
|
if (!ASSERT_EQ(id, 6, "btf__add_decl_tag contains:bar:b"))
|
|
break;
|
|
id = btf__add_struct(btf, "bar", 36);
|
|
if (!ASSERT_EQ(id, 7, "btf__add_struct bar"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:baz:b", 7, 0);
|
|
if (!ASSERT_EQ(id, 8, "btf__add_decl_tag"))
|
|
break;
|
|
id = btf__add_struct(btf, "baz", 36);
|
|
if (!ASSERT_EQ(id, 9, "btf__add_struct baz"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_HEAD, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::a"))
|
|
break;
|
|
err = btf__add_field(btf, "b", LIST_NODE, 128, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::b"))
|
|
break;
|
|
err = btf__add_field(btf, "c", SPIN_LOCK, 256, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bar::c"))
|
|
break;
|
|
id = btf__add_decl_tag(btf, "contains:bam:a", 9, 0);
|
|
if (!ASSERT_EQ(id, 10, "btf__add_decl_tag contains:bam:a"))
|
|
break;
|
|
id = btf__add_struct(btf, "bam", 16);
|
|
if (!ASSERT_EQ(id, 11, "btf__add_struct bam"))
|
|
break;
|
|
err = btf__add_field(btf, "a", LIST_NODE, 0, 0);
|
|
if (!ASSERT_OK(err, "btf__add_field bam::a"))
|
|
break;
|
|
|
|
err = btf__load_into_kernel(btf);
|
|
ASSERT_EQ(err, -ELOOP, "check btf");
|
|
btf__free(btf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void test_linked_list(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(linked_list_fail_tests); i++) {
|
|
if (!test__start_subtest(linked_list_fail_tests[i].prog_name))
|
|
continue;
|
|
test_linked_list_fail_prog(linked_list_fail_tests[i].prog_name,
|
|
linked_list_fail_tests[i].err_msg);
|
|
}
|
|
test_btf();
|
|
test_linked_list_success(PUSH_POP, false);
|
|
test_linked_list_success(PUSH_POP, true);
|
|
test_linked_list_success(PUSH_POP_MULT, false);
|
|
test_linked_list_success(PUSH_POP_MULT, true);
|
|
test_linked_list_success(LIST_IN_LIST, false);
|
|
test_linked_list_success(LIST_IN_LIST, true);
|
|
test_linked_list_success(TEST_ALL, false);
|
|
}
|