Commit 29db4bea authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by Andrii Nakryiko

bpf: Prepare relo_core.c for kernel duty.

Make relo_core.c to be compiled for the kernel and for user space libbpf.

Note the patch is reducing BPF_CORE_SPEC_MAX_LEN from 64 to 32.
This is the maximum number of nested structs and arrays.
For example:
 struct sample {
     int a;
     struct {
         int b[10];
     };
 };

 struct sample *s = ...;
 int *y = &s->b[5];
This field access is encoded as "0:1:0:5" and spec len is 4.

The follow up patch might bump it back to 64.
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20211201181040.23337-4-alexei.starovoitov@gmail.com
parent 8293eb99
...@@ -144,6 +144,53 @@ static inline bool btf_type_is_enum(const struct btf_type *t) ...@@ -144,6 +144,53 @@ static inline bool btf_type_is_enum(const struct btf_type *t)
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM; return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM;
} }
static inline bool str_is_empty(const char *s)
{
return !s || !s[0];
}
static inline u16 btf_kind(const struct btf_type *t)
{
return BTF_INFO_KIND(t->info);
}
static inline bool btf_is_enum(const struct btf_type *t)
{
return btf_kind(t) == BTF_KIND_ENUM;
}
static inline bool btf_is_composite(const struct btf_type *t)
{
u16 kind = btf_kind(t);
return kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION;
}
static inline bool btf_is_array(const struct btf_type *t)
{
return btf_kind(t) == BTF_KIND_ARRAY;
}
static inline bool btf_is_int(const struct btf_type *t)
{
return btf_kind(t) == BTF_KIND_INT;
}
static inline bool btf_is_ptr(const struct btf_type *t)
{
return btf_kind(t) == BTF_KIND_PTR;
}
static inline u8 btf_int_offset(const struct btf_type *t)
{
return BTF_INT_OFFSET(*(u32 *)(t + 1));
}
static inline u8 btf_int_encoding(const struct btf_type *t)
{
return BTF_INT_ENCODING(*(u32 *)(t + 1));
}
static inline bool btf_type_is_scalar(const struct btf_type *t) static inline bool btf_type_is_scalar(const struct btf_type *t)
{ {
return btf_type_is_int(t) || btf_type_is_enum(t); return btf_type_is_int(t) || btf_type_is_enum(t);
...@@ -184,6 +231,11 @@ static inline u16 btf_type_vlen(const struct btf_type *t) ...@@ -184,6 +231,11 @@ static inline u16 btf_type_vlen(const struct btf_type *t)
return BTF_INFO_VLEN(t->info); return BTF_INFO_VLEN(t->info);
} }
static inline u16 btf_vlen(const struct btf_type *t)
{
return btf_type_vlen(t);
}
static inline u16 btf_func_linkage(const struct btf_type *t) static inline u16 btf_func_linkage(const struct btf_type *t)
{ {
return BTF_INFO_VLEN(t->info); return BTF_INFO_VLEN(t->info);
...@@ -208,11 +260,40 @@ static inline u32 __btf_member_bitfield_size(const struct btf_type *struct_type, ...@@ -208,11 +260,40 @@ static inline u32 __btf_member_bitfield_size(const struct btf_type *struct_type,
: 0; : 0;
} }
static inline struct btf_member *btf_members(const struct btf_type *t)
{
return (struct btf_member *)(t + 1);
}
static inline u32 btf_member_bit_offset(const struct btf_type *t, u32 member_idx)
{
const struct btf_member *m = btf_members(t) + member_idx;
return __btf_member_bit_offset(t, m);
}
static inline u32 btf_member_bitfield_size(const struct btf_type *t, u32 member_idx)
{
const struct btf_member *m = btf_members(t) + member_idx;
return __btf_member_bitfield_size(t, m);
}
static inline const struct btf_member *btf_type_member(const struct btf_type *t) static inline const struct btf_member *btf_type_member(const struct btf_type *t)
{ {
return (const struct btf_member *)(t + 1); return (const struct btf_member *)(t + 1);
} }
static inline struct btf_array *btf_array(const struct btf_type *t)
{
return (struct btf_array *)(t + 1);
}
static inline struct btf_enum *btf_enum(const struct btf_type *t)
{
return (struct btf_enum *)(t + 1);
}
static inline const struct btf_var_secinfo *btf_type_var_secinfo( static inline const struct btf_var_secinfo *btf_type_var_secinfo(
const struct btf_type *t) const struct btf_type *t)
{ {
......
...@@ -36,3 +36,7 @@ obj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o ...@@ -36,3 +36,7 @@ obj-$(CONFIG_BPF_SYSCALL) += bpf_struct_ops.o
obj-${CONFIG_BPF_LSM} += bpf_lsm.o obj-${CONFIG_BPF_LSM} += bpf_lsm.o
endif endif
obj-$(CONFIG_BPF_PRELOAD) += preload/ obj-$(CONFIG_BPF_PRELOAD) += preload/
obj-$(CONFIG_BPF_SYSCALL) += relo_core.o
$(obj)/relo_core.o: $(srctree)/tools/lib/bpf/relo_core.c FORCE
$(call if_changed_rule,cc_o_c)
...@@ -6413,3 +6413,29 @@ bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id, ...@@ -6413,3 +6413,29 @@ bool bpf_check_mod_kfunc_call(struct kfunc_btf_id_list *klist, u32 kfunc_id,
DEFINE_KFUNC_BTF_ID_LIST(bpf_tcp_ca_kfunc_list); DEFINE_KFUNC_BTF_ID_LIST(bpf_tcp_ca_kfunc_list);
DEFINE_KFUNC_BTF_ID_LIST(prog_test_kfunc_list); DEFINE_KFUNC_BTF_ID_LIST(prog_test_kfunc_list);
int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
const struct btf *targ_btf, __u32 targ_id)
{
return -EOPNOTSUPP;
}
static bool bpf_core_is_flavor_sep(const char *s)
{
/* check X___Y name pattern, where X and Y are not underscores */
return s[0] != '_' && /* X */
s[1] == '_' && s[2] == '_' && s[3] == '_' && /* ___ */
s[4] != '_'; /* Y */
}
size_t bpf_core_essential_name_len(const char *name)
{
size_t n = strlen(name);
int i;
for (i = n - 5; i >= 0; i--) {
if (bpf_core_is_flavor_sep(name + i))
return i + 1;
}
return n;
}
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2019 Facebook */ /* Copyright (c) 2019 Facebook */
#ifdef __KERNEL__
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/string.h>
#include <linux/bpf_verifier.h>
#include "relo_core.h"
static const char *btf_kind_str(const struct btf_type *t)
{
return btf_type_str(t);
}
static bool is_ldimm64_insn(struct bpf_insn *insn)
{
return insn->code == (BPF_LD | BPF_IMM | BPF_DW);
}
static const struct btf_type *
skip_mods_and_typedefs(const struct btf *btf, u32 id, u32 *res_id)
{
return btf_type_skip_modifiers(btf, id, res_id);
}
static const char *btf__name_by_offset(const struct btf *btf, u32 offset)
{
return btf_name_by_offset(btf, offset);
}
static s64 btf__resolve_size(const struct btf *btf, u32 type_id)
{
const struct btf_type *t;
int size;
t = btf_type_by_id(btf, type_id);
t = btf_resolve_size(btf, t, &size);
if (IS_ERR(t))
return PTR_ERR(t);
return size;
}
enum libbpf_print_level {
LIBBPF_WARN,
LIBBPF_INFO,
LIBBPF_DEBUG,
};
#undef pr_warn
#undef pr_info
#undef pr_debug
#define pr_warn(fmt, log, ...) bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
#define pr_info(fmt, log, ...) bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
#define pr_debug(fmt, log, ...) bpf_log((void *)log, fmt, "", ##__VA_ARGS__)
#define libbpf_print(level, fmt, ...) bpf_log((void *)prog_name, fmt, ##__VA_ARGS__)
#else
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
...@@ -12,8 +66,9 @@ ...@@ -12,8 +66,9 @@
#include "btf.h" #include "btf.h"
#include "str_error.h" #include "str_error.h"
#include "libbpf_internal.h" #include "libbpf_internal.h"
#endif
#define BPF_CORE_SPEC_MAX_LEN 64 #define BPF_CORE_SPEC_MAX_LEN 32
/* represents BPF CO-RE field or array element accessor */ /* represents BPF CO-RE field or array element accessor */
struct bpf_core_accessor { struct bpf_core_accessor {
...@@ -150,7 +205,7 @@ static bool core_relo_is_enumval_based(enum bpf_core_relo_kind kind) ...@@ -150,7 +205,7 @@ static bool core_relo_is_enumval_based(enum bpf_core_relo_kind kind)
* Enum value-based relocations (ENUMVAL_EXISTS/ENUMVAL_VALUE) use access * Enum value-based relocations (ENUMVAL_EXISTS/ENUMVAL_VALUE) use access
* string to specify enumerator's value index that need to be relocated. * string to specify enumerator's value index that need to be relocated.
*/ */
static int bpf_core_parse_spec(const struct btf *btf, static int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
__u32 type_id, __u32 type_id,
const char *spec_str, const char *spec_str,
enum bpf_core_relo_kind relo_kind, enum bpf_core_relo_kind relo_kind,
...@@ -272,8 +327,8 @@ static int bpf_core_parse_spec(const struct btf *btf, ...@@ -272,8 +327,8 @@ static int bpf_core_parse_spec(const struct btf *btf,
return sz; return sz;
spec->bit_offset += access_idx * sz * 8; spec->bit_offset += access_idx * sz * 8;
} else { } else {
pr_warn("relo for [%u] %s (at idx %d) captures type [%d] of unexpected kind %s\n", pr_warn("prog '%s': relo for [%u] %s (at idx %d) captures type [%d] of unexpected kind %s\n",
type_id, spec_str, i, id, btf_kind_str(t)); prog_name, type_id, spec_str, i, id, btf_kind_str(t));
return -EINVAL; return -EINVAL;
} }
} }
...@@ -346,8 +401,6 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf, ...@@ -346,8 +401,6 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf,
targ_id = btf_array(targ_type)->type; targ_id = btf_array(targ_type)->type;
goto recur; goto recur;
default: default:
pr_warn("unexpected kind %d relocated, local [%d], target [%d]\n",
btf_kind(local_type), local_id, targ_id);
return 0; return 0;
} }
} }
...@@ -1045,7 +1098,7 @@ static int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1045,7 +1098,7 @@ static int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
* [<type-id>] (<type-name>) + <raw-spec> => <offset>@<spec>, * [<type-id>] (<type-name>) + <raw-spec> => <offset>@<spec>,
* where <spec> is a C-syntax view of recorded field access, e.g.: x.a[3].b * where <spec> is a C-syntax view of recorded field access, e.g.: x.a[3].b
*/ */
static void bpf_core_dump_spec(int level, const struct bpf_core_spec *spec) static void bpf_core_dump_spec(const char *prog_name, int level, const struct bpf_core_spec *spec)
{ {
const struct btf_type *t; const struct btf_type *t;
const struct btf_enum *e; const struct btf_enum *e;
...@@ -1167,7 +1220,8 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1167,7 +1220,8 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn,
if (str_is_empty(spec_str)) if (str_is_empty(spec_str))
return -EINVAL; return -EINVAL;
err = bpf_core_parse_spec(local_btf, local_id, spec_str, relo->kind, &local_spec); err = bpf_core_parse_spec(prog_name, local_btf, local_id, spec_str,
relo->kind, &local_spec);
if (err) { if (err) {
pr_warn("prog '%s': relo #%d: parsing [%d] %s %s + %s failed: %d\n", pr_warn("prog '%s': relo #%d: parsing [%d] %s %s + %s failed: %d\n",
prog_name, relo_idx, local_id, btf_kind_str(local_type), prog_name, relo_idx, local_id, btf_kind_str(local_type),
...@@ -1178,7 +1232,7 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1178,7 +1232,7 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn,
pr_debug("prog '%s': relo #%d: kind <%s> (%d), spec is ", prog_name, pr_debug("prog '%s': relo #%d: kind <%s> (%d), spec is ", prog_name,
relo_idx, core_relo_kind_str(relo->kind), relo->kind); relo_idx, core_relo_kind_str(relo->kind), relo->kind);
bpf_core_dump_spec(LIBBPF_DEBUG, &local_spec); bpf_core_dump_spec(prog_name, LIBBPF_DEBUG, &local_spec);
libbpf_print(LIBBPF_DEBUG, "\n"); libbpf_print(LIBBPF_DEBUG, "\n");
/* TYPE_ID_LOCAL relo is special and doesn't need candidate search */ /* TYPE_ID_LOCAL relo is special and doesn't need candidate search */
...@@ -1204,14 +1258,14 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1204,14 +1258,14 @@ int bpf_core_apply_relo_insn(const char *prog_name, struct bpf_insn *insn,
if (err < 0) { if (err < 0) {
pr_warn("prog '%s': relo #%d: error matching candidate #%d ", pr_warn("prog '%s': relo #%d: error matching candidate #%d ",
prog_name, relo_idx, i); prog_name, relo_idx, i);
bpf_core_dump_spec(LIBBPF_WARN, &cand_spec); bpf_core_dump_spec(prog_name, LIBBPF_WARN, &cand_spec);
libbpf_print(LIBBPF_WARN, ": %d\n", err); libbpf_print(LIBBPF_WARN, ": %d\n", err);
return err; return err;
} }
pr_debug("prog '%s': relo #%d: %s candidate #%d ", prog_name, pr_debug("prog '%s': relo #%d: %s candidate #%d ", prog_name,
relo_idx, err == 0 ? "non-matching" : "matching", i); relo_idx, err == 0 ? "non-matching" : "matching", i);
bpf_core_dump_spec(LIBBPF_DEBUG, &cand_spec); bpf_core_dump_spec(prog_name, LIBBPF_DEBUG, &cand_spec);
libbpf_print(LIBBPF_DEBUG, "\n"); libbpf_print(LIBBPF_DEBUG, "\n");
if (err == 0) if (err == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment