Skip to content

Commit

Permalink
elf_reader: support value BTF on ringbuf and perf array maps
Browse files Browse the repository at this point in the history
While reviewing #1610, I noticed we were generating VariableSpecs for variables
named 'unused' in our examples. There had to be a better way to get their BTF
info into the ELF.

I thoroughly checked all map types present in Linux 6.12 for any validation code
on attr->value_size, and only RingBuf and Arena maps require value_size to be
zero at all times. Special-case PerfEventArray so type annotations aren't limited
to 4 bytes.

Signed-off-by: Timo Beckers <timo@isovalent.com>
  • Loading branch information
ti-mo committed Dec 16, 2024
1 parent 0a77f25 commit e9bcebb
Show file tree
Hide file tree
Showing 10 changed files with 31 additions and 0 deletions.
7 changes: 7 additions & 0 deletions elf_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,13 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
}
}

// Some maps don't support value sizes, but annotating their map definitions
// with __type macros can still be useful, especially to let bpf2go generate
// type definitions for them.
if value != nil && !mapType.canHaveValueSize() {
valueSize = 0
}

return &MapSpec{
Name: SanitizeName(name, -1),
Type: MapType(mapType),
Expand Down
3 changes: 3 additions & 0 deletions elf_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ func TestLoadCollectionSpec(t *testing.T) {
}
qt.Assert(t, qt.ContentEquals(mErr.Constants, []string{"totallyBogus", "totallyBogus2"}))

qt.Assert(t, qt.Equals(have.Maps["perf_event_array"].ValueSize, 0))
qt.Assert(t, qt.IsNotNil(have.Maps["perf_event_array"].Value))

if diff := cmp.Diff(coll, have, cmpOpts...); diff != "" {
t.Errorf("MapSpec mismatch (-want +got):\n%s", diff)
}
Expand Down
Binary file modified testdata/loader-clang-11-eb.elf
Binary file not shown.
Binary file modified testdata/loader-clang-11-el.elf
Binary file not shown.
Binary file modified testdata/loader-clang-14-eb.elf
Binary file not shown.
Binary file modified testdata/loader-clang-14-el.elf
Binary file not shown.
Binary file modified testdata/loader-clang-17-eb.elf
Binary file not shown.
Binary file modified testdata/loader-clang-17-el.elf
Binary file not shown.
6 changes: 6 additions & 0 deletions testdata/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ struct {
});
} btf_outer_map_anon __section(".maps");

struct perf_event {
uint64_t foo;
uint64_t bar;
};

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(max_entries, 4096);
__type(value, struct perf_event);
} perf_event_array __section(".maps");

struct bpf_map_def array_of_hash_map __section("maps") = {
Expand Down
15 changes: 15 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ func (mt MapType) canStoreProgram() bool {
return mt == ProgramArray
}

// canHaveValueSize returns true if the map type supports setting a value size.
func (mt MapType) canHaveValueSize() bool {
switch mt {
case RingBuf, Arena:
return false

// Special-case perf events since they require a value size of either 0 or 4
// for historical reasons. Let the library fix this up later.
case PerfEventArray:
return false
}

return true
}

// ProgramType of the eBPF program
type ProgramType uint32

Expand Down

0 comments on commit e9bcebb

Please sign in to comment.