Commit b58af63a authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Alexei Starovoitov

libbpf: Refactor CO-RE relo human description formatting routine

Refactor how CO-RE relocation is formatted. Now it dumps human-readable
representation, currently used by libbpf in either debug or error
message output during CO-RE relocation resolution process, into provided
buffer. This approach allows for better reuse of this functionality
outside of CO-RE relocation resolution, which we'll use in next patch
for providing better error message for BPF verifier rejecting BPF
program due to unguarded failed CO-RE relocation.

It also gets rid of annoying "stitching" of libbpf_print() calls, which
was the only place where we did this.
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20220426004511.2691730-8-andrii@kernel.org
parent 185cfe83
...@@ -1055,51 +1055,66 @@ int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn, ...@@ -1055,51 +1055,66 @@ 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(const char *prog_name, int level, const struct bpf_core_spec *spec) static 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 struct btf_enum *e;
const char *s; const char *s;
__u32 type_id; __u32 type_id;
int i; int i, len = 0;
#define append_buf(fmt, args...) \
({ \
int r; \
r = snprintf(buf, buf_sz, fmt, ##args); \
len += r; \
if (r >= buf_sz) \
r = buf_sz; \
buf += r; \
buf_sz -= r; \
})
type_id = spec->root_type_id; type_id = spec->root_type_id;
t = btf_type_by_id(spec->btf, type_id); t = btf_type_by_id(spec->btf, type_id);
s = btf__name_by_offset(spec->btf, t->name_off); s = btf__name_by_offset(spec->btf, t->name_off);
libbpf_print(level, "[%u] %s %s", type_id, btf_kind_str(t), str_is_empty(s) ? "<anon>" : s); append_buf("<%s> [%u] %s %s",
core_relo_kind_str(spec->relo_kind),
type_id, btf_kind_str(t), str_is_empty(s) ? "<anon>" : s);
if (core_relo_is_type_based(spec->relo_kind)) if (core_relo_is_type_based(spec->relo_kind))
return; return len;
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);
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);
libbpf_print(level, "::%s = %u", s, e->val); append_buf("::%s = %u", s, e->val);
return; return len;
} }
if (core_relo_is_field_based(spec->relo_kind)) { if (core_relo_is_field_based(spec->relo_kind)) {
for (i = 0; i < spec->len; i++) { for (i = 0; i < spec->len; i++) {
if (spec->spec[i].name) if (spec->spec[i].name)
libbpf_print(level, ".%s", spec->spec[i].name); append_buf(".%s", spec->spec[i].name);
else if (i > 0 || spec->spec[i].idx > 0) else if (i > 0 || spec->spec[i].idx > 0)
libbpf_print(level, "[%u]", spec->spec[i].idx); append_buf("[%u]", spec->spec[i].idx);
} }
libbpf_print(level, " ("); append_buf(" (");
for (i = 0; i < spec->raw_len; i++) for (i = 0; i < spec->raw_len; i++)
libbpf_print(level, "%s%d", i == 0 ? "" : ":", spec->raw_spec[i]); append_buf("%s%d", i == 0 ? "" : ":", spec->raw_spec[i]);
if (spec->bit_offset % 8) if (spec->bit_offset % 8)
libbpf_print(level, " @ offset %u.%u)", append_buf(" @ offset %u.%u)", spec->bit_offset / 8, spec->bit_offset % 8);
spec->bit_offset / 8, spec->bit_offset % 8);
else else
libbpf_print(level, " @ offset %u)", spec->bit_offset / 8); append_buf(" @ offset %u)", spec->bit_offset / 8);
return; return len;
} }
return len;
#undef append_buf
} }
/* /*
...@@ -1168,6 +1183,7 @@ int bpf_core_calc_relo_insn(const char *prog_name, ...@@ -1168,6 +1183,7 @@ int bpf_core_calc_relo_insn(const char *prog_name,
const char *local_name; const char *local_name;
__u32 local_id; __u32 local_id;
const char *spec_str; const char *spec_str;
char spec_buf[256];
int i, j, err; int i, j, err;
local_id = relo->type_id; local_id = relo->type_id;
...@@ -1190,10 +1206,8 @@ int bpf_core_calc_relo_insn(const char *prog_name, ...@@ -1190,10 +1206,8 @@ int bpf_core_calc_relo_insn(const char *prog_name,
return -EINVAL; return -EINVAL;
} }
pr_debug("prog '%s': relo #%d: kind <%s> (%d), spec is ", prog_name, bpf_core_format_spec(spec_buf, sizeof(spec_buf), local_spec);
relo_idx, core_relo_kind_str(relo->kind), relo->kind); pr_debug("prog '%s': relo #%d: %s\n", prog_name, relo_idx, spec_buf);
bpf_core_dump_spec(prog_name, LIBBPF_DEBUG, local_spec);
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 */
if (relo->kind == BPF_CORE_TYPE_ID_LOCAL) { if (relo->kind == BPF_CORE_TYPE_ID_LOCAL) {
...@@ -1217,17 +1231,15 @@ int bpf_core_calc_relo_insn(const char *prog_name, ...@@ -1217,17 +1231,15 @@ int bpf_core_calc_relo_insn(const char *prog_name,
err = bpf_core_spec_match(local_spec, cands->cands[i].btf, err = bpf_core_spec_match(local_spec, cands->cands[i].btf,
cands->cands[i].id, cand_spec); cands->cands[i].id, cand_spec);
if (err < 0) { if (err < 0) {
pr_warn("prog '%s': relo #%d: error matching candidate #%d ", bpf_core_format_spec(spec_buf, sizeof(spec_buf), cand_spec);
prog_name, relo_idx, i); pr_warn("prog '%s': relo #%d: error matching candidate #%d %s: %d\n ",
bpf_core_dump_spec(prog_name, LIBBPF_WARN, cand_spec); prog_name, relo_idx, i, spec_buf, err);
libbpf_print(LIBBPF_WARN, ": %d\n", err);
return err; return err;
} }
pr_debug("prog '%s': relo #%d: %s candidate #%d ", prog_name, bpf_core_format_spec(spec_buf, sizeof(spec_buf), cand_spec);
relo_idx, err == 0 ? "non-matching" : "matching", i); pr_debug("prog '%s': relo #%d: %s candidate #%d %s\n", prog_name,
bpf_core_dump_spec(prog_name, LIBBPF_DEBUG, cand_spec); relo_idx, err == 0 ? "non-matching" : "matching", i, spec_buf);
libbpf_print(LIBBPF_DEBUG, "\n");
if (err == 0) if (err == 0)
continue; continue;
......
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