Commit 23b2a3a8 authored by Yonghong Song's avatar Yonghong Song Committed by Alexei Starovoitov

libbpf: Add enum64 relocation support

The enum64 relocation support is added. The bpf local type
could be either enum or enum64 and the remote type could be
either enum or enum64 too. The all combinations of local enum/enum64
and remote enum/enum64 are supported.
Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarYonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/r/20220607062647.3721719-1-yhs@fb.comSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 6ec7d79b
...@@ -537,6 +537,13 @@ static inline bool btf_is_any_enum(const struct btf_type *t) ...@@ -537,6 +537,13 @@ static inline bool btf_is_any_enum(const struct btf_type *t)
return btf_is_enum(t) || btf_is_enum64(t); return btf_is_enum(t) || btf_is_enum64(t);
} }
static inline bool btf_kind_core_compat(const struct btf_type *t1,
const struct btf_type *t2)
{
return btf_kind(t1) == btf_kind(t2) ||
(btf_is_any_enum(t1) && btf_is_any_enum(t2));
}
static inline __u8 btf_int_encoding(const struct btf_type *t) static inline __u8 btf_int_encoding(const struct btf_type *t)
{ {
return BTF_INT_ENCODING(*(__u32 *)(t + 1)); return BTF_INT_ENCODING(*(__u32 *)(t + 1));
......
...@@ -5524,7 +5524,7 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand, ...@@ -5524,7 +5524,7 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
n = btf__type_cnt(targ_btf); n = btf__type_cnt(targ_btf);
for (i = targ_start_id; i < n; i++) { for (i = targ_start_id; i < n; i++) {
t = btf__type_by_id(targ_btf, i); t = btf__type_by_id(targ_btf, i);
if (btf_kind(t) != btf_kind(local_t)) if (!btf_kind_core_compat(t, local_t))
continue; continue;
targ_name = btf__name_by_offset(targ_btf, t->name_off); targ_name = btf__name_by_offset(targ_btf, t->name_off);
...@@ -5738,7 +5738,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id, ...@@ -5738,7 +5738,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
/* caller made sure that names match (ignoring flavor suffix) */ /* caller made sure that names match (ignoring flavor suffix) */
local_type = btf__type_by_id(local_btf, local_id); local_type = btf__type_by_id(local_btf, local_id);
targ_type = btf__type_by_id(targ_btf, targ_id); targ_type = btf__type_by_id(targ_btf, targ_id);
if (btf_kind(local_type) != btf_kind(targ_type)) if (!btf_kind_core_compat(local_type, targ_type))
return 0; return 0;
recur: recur:
...@@ -5751,7 +5751,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id, ...@@ -5751,7 +5751,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
if (!local_type || !targ_type) if (!local_type || !targ_type)
return -EINVAL; return -EINVAL;
if (btf_kind(local_type) != btf_kind(targ_type)) if (!btf_kind_core_compat(local_type, targ_type))
return 0; return 0;
switch (btf_kind(local_type)) { switch (btf_kind(local_type)) {
...@@ -5759,6 +5759,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id, ...@@ -5759,6 +5759,7 @@ int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
case BTF_KIND_STRUCT: case BTF_KIND_STRUCT:
case BTF_KIND_UNION: case BTF_KIND_UNION:
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
case BTF_KIND_ENUM64:
case BTF_KIND_FWD: case BTF_KIND_FWD:
return 1; return 1;
case BTF_KIND_INT: case BTF_KIND_INT:
......
...@@ -186,7 +186,7 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, ...@@ -186,7 +186,7 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
struct bpf_core_accessor *acc; struct bpf_core_accessor *acc;
const struct btf_type *t; const struct btf_type *t;
const char *name, *spec_str; const char *name, *spec_str;
__u32 id; __u32 id, name_off;
__s64 sz; __s64 sz;
spec_str = btf__name_by_offset(btf, relo->access_str_off); spec_str = btf__name_by_offset(btf, relo->access_str_off);
...@@ -231,11 +231,13 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf, ...@@ -231,11 +231,13 @@ int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
spec->len++; spec->len++;
if (core_relo_is_enumval_based(relo->kind)) { if (core_relo_is_enumval_based(relo->kind)) {
if (!btf_is_enum(t) || spec->raw_len > 1 || access_idx >= btf_vlen(t)) if (!btf_is_any_enum(t) || spec->raw_len > 1 || access_idx >= btf_vlen(t))
return -EINVAL; return -EINVAL;
/* record enumerator name in a first accessor */ /* record enumerator name in a first accessor */
acc->name = btf__name_by_offset(btf, btf_enum(t)[access_idx].name_off); name_off = btf_is_enum(t) ? btf_enum(t)[access_idx].name_off
: btf_enum64(t)[access_idx].name_off;
acc->name = btf__name_by_offset(btf, name_off);
return 0; return 0;
} }
...@@ -340,7 +342,7 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf, ...@@ -340,7 +342,7 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf,
if (btf_is_composite(local_type) && btf_is_composite(targ_type)) if (btf_is_composite(local_type) && btf_is_composite(targ_type))
return 1; return 1;
if (btf_kind(local_type) != btf_kind(targ_type)) if (!btf_kind_core_compat(local_type, targ_type))
return 0; return 0;
switch (btf_kind(local_type)) { switch (btf_kind(local_type)) {
...@@ -348,6 +350,7 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf, ...@@ -348,6 +350,7 @@ static int bpf_core_fields_are_compat(const struct btf *local_btf,
case BTF_KIND_FLOAT: case BTF_KIND_FLOAT:
return 1; return 1;
case BTF_KIND_FWD: case BTF_KIND_FWD:
case BTF_KIND_ENUM64:
case BTF_KIND_ENUM: { case BTF_KIND_ENUM: {
const char *local_name, *targ_name; const char *local_name, *targ_name;
size_t local_len, targ_len; size_t local_len, targ_len;
...@@ -477,6 +480,7 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec, ...@@ -477,6 +480,7 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
const struct bpf_core_accessor *local_acc; const struct bpf_core_accessor *local_acc;
struct bpf_core_accessor *targ_acc; struct bpf_core_accessor *targ_acc;
int i, sz, matched; int i, sz, matched;
__u32 name_off;
memset(targ_spec, 0, sizeof(*targ_spec)); memset(targ_spec, 0, sizeof(*targ_spec));
targ_spec->btf = targ_btf; targ_spec->btf = targ_btf;
...@@ -494,18 +498,22 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec, ...@@ -494,18 +498,22 @@ static int bpf_core_spec_match(struct bpf_core_spec *local_spec,
if (core_relo_is_enumval_based(local_spec->relo_kind)) { if (core_relo_is_enumval_based(local_spec->relo_kind)) {
size_t local_essent_len, targ_essent_len; size_t local_essent_len, targ_essent_len;
const struct btf_enum *e;
const char *targ_name; const char *targ_name;
/* has to resolve to an enum */ /* has to resolve to an enum */
targ_type = skip_mods_and_typedefs(targ_spec->btf, targ_id, &targ_id); targ_type = skip_mods_and_typedefs(targ_spec->btf, targ_id, &targ_id);
if (!btf_is_enum(targ_type)) if (!btf_is_any_enum(targ_type))
return 0; return 0;
local_essent_len = bpf_core_essential_name_len(local_acc->name); local_essent_len = bpf_core_essential_name_len(local_acc->name);
for (i = 0, e = btf_enum(targ_type); i < btf_vlen(targ_type); i++, e++) { for (i = 0; i < btf_vlen(targ_type); i++) {
targ_name = btf__name_by_offset(targ_spec->btf, e->name_off); if (btf_is_enum(targ_type))
name_off = btf_enum(targ_type)[i].name_off;
else
name_off = btf_enum64(targ_type)[i].name_off;
targ_name = btf__name_by_offset(targ_spec->btf, name_off);
targ_essent_len = bpf_core_essential_name_len(targ_name); targ_essent_len = bpf_core_essential_name_len(targ_name);
if (targ_essent_len != local_essent_len) if (targ_essent_len != local_essent_len)
continue; continue;
...@@ -680,8 +688,7 @@ static int bpf_core_calc_field_relo(const char *prog_name, ...@@ -680,8 +688,7 @@ static int bpf_core_calc_field_relo(const char *prog_name,
*val = byte_sz; *val = byte_sz;
break; break;
case BPF_CORE_FIELD_SIGNED: case BPF_CORE_FIELD_SIGNED:
/* enums will be assumed unsigned */ *val = (btf_is_any_enum(mt) && BTF_INFO_KFLAG(mt->info)) ||
*val = btf_is_enum(mt) ||
(btf_int_encoding(mt) & BTF_INT_SIGNED); (btf_int_encoding(mt) & BTF_INT_SIGNED);
if (validate) if (validate)
*validate = true; /* signedness is never ambiguous */ *validate = true; /* signedness is never ambiguous */
...@@ -754,7 +761,6 @@ static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo, ...@@ -754,7 +761,6 @@ static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo,
__u64 *val) __u64 *val)
{ {
const struct btf_type *t; const struct btf_type *t;
const struct btf_enum *e;
switch (relo->kind) { switch (relo->kind) {
case BPF_CORE_ENUMVAL_EXISTS: case BPF_CORE_ENUMVAL_EXISTS:
...@@ -764,8 +770,10 @@ static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo, ...@@ -764,8 +770,10 @@ static int bpf_core_calc_enumval_relo(const struct bpf_core_relo *relo,
if (!spec) if (!spec)
return -EUCLEAN; /* request instruction poisoning */ return -EUCLEAN; /* request instruction poisoning */
t = btf_type_by_id(spec->btf, spec->spec[0].type_id); t = btf_type_by_id(spec->btf, spec->spec[0].type_id);
e = btf_enum(t) + spec->spec[0].idx; if (btf_is_enum(t))
*val = e->val; *val = btf_enum(t)[spec->spec[0].idx].val;
else
*val = btf_enum64_value(btf_enum64(t) + spec->spec[0].idx);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1060,7 +1068,6 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1060,7 +1068,6 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *spec) int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *spec)
{ {
const struct btf_type *t; const struct btf_type *t;
const struct btf_enum *e;
const char *s; const char *s;
__u32 type_id; __u32 type_id;
int i, len = 0; int i, len = 0;
...@@ -1089,10 +1096,23 @@ int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *s ...@@ -1089,10 +1096,23 @@ int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *s
if (core_relo_is_enumval_based(spec->relo_kind)) { if (core_relo_is_enumval_based(spec->relo_kind)) {
t = skip_mods_and_typedefs(spec->btf, type_id, NULL); t = skip_mods_and_typedefs(spec->btf, type_id, NULL);
if (btf_is_enum(t)) {
const struct btf_enum *e;
const char *fmt_str;
e = btf_enum(t) + spec->raw_spec[0]; e = btf_enum(t) + spec->raw_spec[0];
s = btf__name_by_offset(spec->btf, e->name_off); s = btf__name_by_offset(spec->btf, e->name_off);
fmt_str = BTF_INFO_KFLAG(t->info) ? "::%s = %d" : "::%s = %u";
append_buf(fmt_str, s, e->val);
} else {
const struct btf_enum64 *e;
const char *fmt_str;
append_buf("::%s = %u", s, e->val); e = btf_enum64(t) + spec->raw_spec[0];
s = btf__name_by_offset(spec->btf, e->name_off);
fmt_str = BTF_INFO_KFLAG(t->info) ? "::%s = %lld" : "::%s = %llu";
append_buf(fmt_str, s, (unsigned long long)btf_enum64_value(e));
}
return len; return len;
} }
......
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