blob: daf777cadfda399792cf511ff3a8a5e89cbc4a4e [file] [edit]
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include <bpf/btf.h>
#include "bpftool_helpers.h"
#define FUNC_NAME "write_fmt<scx_simple::BpfStream>"
#define KSYM_NAME "write_fmt_scx_simple__BpfStream_"
/* The name of a function of Rust is a part of the name of the program in kallsyms */
static void test_func_name(void)
{
struct bpf_insn insns[] = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};
LIBBPF_OPTS(bpf_prog_load_opts, opts);
int int_id, proto_id, prog_fd = -1, i;
struct bpf_func_info func_info = {};
struct bpf_prog_info info = {};
unsigned long long addr;
__u32 len = sizeof(info);
char sym[128], *p = sym;
struct btf *btf;
btf = btf__new_empty();
if (!ASSERT_OK_PTR(btf, "btf"))
return;
int_id = btf__add_int(btf, "i32", 4, BTF_INT_SIGNED);
ASSERT_GT(int_id, 0, "int");
proto_id = btf__add_func_proto(btf, int_id);
ASSERT_GT(proto_id, 0, "proto");
ASSERT_OK(btf__add_func_param(btf, "ctx", int_id), "param");
func_info.type_id = btf__add_func(btf, FUNC_NAME, BTF_FUNC_STATIC, proto_id);
ASSERT_GT(func_info.type_id, 0, "func");
if (!ASSERT_OK(btf__load_into_kernel(btf), "btf load"))
goto out;
opts.prog_btf_fd = btf__fd(btf);
opts.func_info = &func_info;
opts.func_info_cnt = 1;
opts.func_info_rec_size = sizeof(func_info);
prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL", insns,
ARRAY_SIZE(insns), &opts);
if (!ASSERT_GE(prog_fd, 0, "prog load"))
goto out;
if (!ASSERT_OK(bpf_prog_get_info_by_fd(prog_fd, &info, &len), "prog info"))
goto out;
if (!info.jited_prog_len) {
test__skip();
goto out;
}
p += sprintf(p, "bpf_prog_");
for (i = 0; i < BPF_TAG_SIZE; i++)
p += sprintf(p, "%02x", info.tag[i]);
sprintf(p, "_%s", KSYM_NAME);
ASSERT_OK(kallsyms_find(sym, &addr), sym);
out:
if (prog_fd >= 0)
close(prog_fd);
btf__free(btf);
}
#define PIN_PATH "/sys/fs/bpf/btf_rust_piece"
/*
* A piece of a static that LLVM split has the type of the whole static.
* It's the last variable in the section, so its type ends past the map value.
*/
static void test_piece(void)
{
LIBBPF_OPTS(bpf_map_create_opts, opts);
int int_id, struct_id, var_id, piece_id, sec_id, map_fd = -1, key = 0;
__u32 value[2] = { 0x11111111, 0x22222222 };
char line[256] = {}, out[1024] = {};
struct btf *btf;
FILE *f = NULL;
btf = btf__new_empty();
if (!ASSERT_OK_PTR(btf, "btf"))
return;
int_id = btf__add_int(btf, "u32", 4, 0);
ASSERT_GT(int_id, 0, "int");
struct_id = btf__add_struct(btf, "Whole", 8);
ASSERT_GT(struct_id, 0, "struct");
ASSERT_OK(btf__add_field(btf, "a", int_id, 0, 0), "field");
ASSERT_OK(btf__add_field(btf, "b", int_id, 32, 0), "field");
var_id = btf__add_var(btf, "CNT", BTF_VAR_STATIC, int_id);
ASSERT_GT(var_id, 0, "var");
piece_id = btf__add_var(btf, "WHOLE.1", BTF_VAR_STATIC, struct_id);
ASSERT_GT(piece_id, 0, "piece");
sec_id = btf__add_datasec(btf, ".bss", sizeof(value));
ASSERT_GT(sec_id, 0, "datasec");
ASSERT_OK(btf__add_datasec_var_info(btf, var_id, 0, 4), "var info");
ASSERT_OK(btf__add_datasec_var_info(btf, piece_id, 4, 4), "piece info");
if (!ASSERT_OK(btf__load_into_kernel(btf), "btf load"))
goto out;
opts.btf_fd = btf__fd(btf);
opts.btf_value_type_id = sec_id;
map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, ".bss", sizeof(key), sizeof(value), 1, &opts);
if (!ASSERT_GE(map_fd, 0, "map create"))
goto out;
if (!ASSERT_OK(bpf_map_update_elem(map_fd, &key, value, 0), "map update"))
goto out;
/* the variable is printed, the piece is not */
unlink(PIN_PATH);
if (!ASSERT_OK(bpf_obj_pin(map_fd, PIN_PATH), "pin"))
goto out;
f = fopen(PIN_PATH, "r");
if (!ASSERT_OK_PTR(f, "open"))
goto out;
while (fgets(line, sizeof(line), f) && line[0] == '#')
;
ASSERT_HAS_SUBSTR(line, "286331153", "var");
ASSERT_NULL(strstr(line, "572662306"), "piece");
/* the same for bpftool */
if (!ASSERT_OK(get_bpftool_command_output("map dump pinned " PIN_PATH, out, sizeof(out)),
"bpftool"))
goto out;
ASSERT_HAS_SUBSTR(out, "CNT", "var");
ASSERT_NULL(strstr(out, "WHOLE.1"), "piece");
out:
if (f)
fclose(f);
unlink(PIN_PATH);
if (map_fd >= 0)
close(map_fd);
btf__free(btf);
}
/* Serial: programs are not in kallsyms while another test sets bpf_jit_harden */
void serial_test_btf_rust(void)
{
if (test__start_subtest("func_name"))
test_func_name();
if (test__start_subtest("piece"))
test_piece();
}