bpftool: Skip pieces of variables in DATASEC

The kernel accepts a variable in DATASEC that is smaller than its type.
It's a piece of a variable that the compiler split, with the type of
the whole variable. bpftool prints a variable by its type, so it reads
past the piece and, when the piece is the last in the section, past
the buffer with the value of the map:

  $ bpftool map dump pinned /sys/fs/bpf/piece
  ".bss": [{
          "whole": 67305985
      },{
          "piece.0": {
              "a": [134678021,1994496712,32592,32,0,833,0,414764080

Only the first number is in the map. Skip the pieces in
btf_dumper_datasec(), like btf_datasec_show() in the kernel does, and
in show_prog_metadata().

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20261002124714.180012-11-alexei.starovoitov@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
Alexei Starovoitov 2026-10-02 12:47:09 +00:00 committed by Kumar Kartikeya Dwivedi
parent 9094a158e8
commit 124a5a2bc0
No known key found for this signature in database
GPG Key ID: 472D377B63542F83
3 changed files with 15 additions and 2 deletions

View File

@ -524,6 +524,15 @@ static int btf_dumper_var(const struct btf_dumper *d, __u32 type_id,
return ret;
}
/*
* The compiler splits a variable into pieces. Every piece is a VAR with the
* type of the whole variable, so there is less data than the type takes.
*/
bool btf_var_is_piece(const struct btf *btf, const struct btf_var_secinfo *vsi)
{
return btf__resolve_size(btf, vsi->type) > vsi->size;
}
static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id,
const void *data)
{
@ -542,6 +551,8 @@ static int btf_dumper_datasec(const struct btf_dumper *d, __u32 type_id,
jsonw_name(d->jw, btf__name_by_offset(d->btf, t->name_off));
jsonw_start_array(d->jw);
for (i = 0; i < vlen; i++) {
if (btf_var_is_piece(d->btf, &vsi[i]))
continue;
ret = btf_dumper_do_type(d, vsi[i].type, 0, data + vsi[i].offset);
if (ret)
break;

View File

@ -121,6 +121,7 @@ struct obj_refs {
};
struct btf;
struct btf_var_secinfo;
struct bpf_line_info;
int build_pinned_obj_table(struct hashmap *table,
@ -239,6 +240,7 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
const void *data);
void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id,
char *func_only, int size);
bool btf_var_is_piece(const struct btf *btf, const struct btf_var_secinfo *vsi);
void btf_dump_linfo_plain(const struct btf *btf,
const struct bpf_line_info *linfo,

View File

@ -348,7 +348,7 @@ static void show_prog_metadata(int fd, __u32 num_maps)
t_var = btf__type_by_id(btf, vsi->type);
name = btf__name_by_offset(btf, t_var->name_off);
if (!has_metadata_prefix(name))
if (!has_metadata_prefix(name) || btf_var_is_piece(btf, vsi))
continue;
if (!printed_header) {
@ -377,7 +377,7 @@ static void show_prog_metadata(int fd, __u32 num_maps)
t_var = btf__type_by_id(btf, vsi->type);
name = btf__name_by_offset(btf, t_var->name_off);
if (!has_metadata_prefix(name))
if (!has_metadata_prefix(name) || btf_var_is_piece(btf, vsi))
continue;
if (!printed_header) {