Skip to content

Commit b0adcf6

Browse files
puwunti-mo
andcommitted
elf_reader: add tests for ELF objects without BTF
Adds infrastructure to test loading of ELF objects compiled without BTF information. Signed-off-by: Pavan More <pavansmore05@gmail.com> Co-authored-by: Timo Beckers <timo@isovalent.com>
1 parent 7cf6126 commit b0adcf6

14 files changed

+236
-190
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ TARGETS := \
4545
testdata/loader-clang-14 \
4646
testdata/loader-clang-17 \
4747
testdata/loader-$(CLANG) \
48+
testdata/loader_nobtf \
4849
testdata/manyprogs \
4950
testdata/btf_map_init \
5051
testdata/invalid_map \
@@ -126,6 +127,12 @@ testdata/loader-%-eb.elf: testdata/loader.c
126127
$(CLANG) $(CFLAGS) -target bpfeb -c $< -o $@
127128
$(STRIP) -g $@
128129

130+
testdata/loader_nobtf-el.elf: testdata/loader.c
131+
$(CLANG) $(CFLAGS) -D__NOBTF__ -target bpfel -c $< -o $@
132+
133+
testdata/loader_nobtf-eb.elf: testdata/loader.c
134+
$(CLANG) $(CFLAGS) -D__NOBTF__ -target bpfeb -c $< -o $@
135+
129136
testdata/linked-el.elf: testdata/linked1-el.elf testdata/linked2-el.elf
130137
bpftool gen object $@ $^
131138

btf/testdata/tags-eb.elf

3.09 KB
Binary file not shown.

elf_reader_test.go

Lines changed: 94 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"flag"
88
"fmt"
9+
"maps"
910
"os"
1011
"path/filepath"
1112
"strings"
@@ -59,76 +60,11 @@ func TestLoadCollectionSpec(t *testing.T) {
5960
ValueSize: 8,
6061
MaxEntries: 2,
6162
},
62-
"array_of_hash_map": {
63-
Name: "array_of_hash_map",
64-
Type: ArrayOfMaps,
65-
KeySize: 4,
66-
MaxEntries: 2,
67-
},
6863
"perf_event_array": {
6964
Name: "perf_event_array",
7065
Type: PerfEventArray,
7166
MaxEntries: 4096,
7267
},
73-
"btf_pin": {
74-
Name: "btf_pin",
75-
Type: Hash,
76-
KeySize: 4,
77-
ValueSize: 8,
78-
MaxEntries: 1,
79-
Pinning: PinByName,
80-
},
81-
"bpf_decl_map": {
82-
Name: "bpf_decl_map",
83-
Type: Array,
84-
KeySize: 4,
85-
ValueSize: 8,
86-
MaxEntries: 1,
87-
Tags: []string{"a", "b"},
88-
},
89-
"btf_decl_map": {
90-
Name: "btf_decl_map",
91-
Type: Array,
92-
KeySize: 4,
93-
ValueSize: 8,
94-
MaxEntries: 1,
95-
Tags: []string{"a", "b"},
96-
},
97-
"btf_outer_map": {
98-
Name: "btf_outer_map",
99-
Type: ArrayOfMaps,
100-
KeySize: 4,
101-
ValueSize: 4,
102-
MaxEntries: 1,
103-
InnerMap: &MapSpec{
104-
Name: "btf_outer_map_inner",
105-
Type: Hash,
106-
KeySize: 4,
107-
ValueSize: 4,
108-
MaxEntries: 1,
109-
},
110-
},
111-
"btf_outer_map_anon": {
112-
Name: "btf_outer_map_anon",
113-
Type: ArrayOfMaps,
114-
KeySize: 4,
115-
ValueSize: 4,
116-
MaxEntries: 1,
117-
InnerMap: &MapSpec{
118-
Name: "btf_outer_map_anon_inner",
119-
Type: Hash,
120-
KeySize: 4,
121-
ValueSize: 4,
122-
MaxEntries: 1,
123-
},
124-
},
125-
"btf_typedef_map": {
126-
Name: "btf_typedef_map",
127-
Type: Array,
128-
KeySize: 4,
129-
ValueSize: 8,
130-
MaxEntries: 1,
131-
},
13268
".bss": {
13369
Name: ".bss",
13470
Type: Array,
@@ -232,38 +168,107 @@ func TestLoadCollectionSpec(t *testing.T) {
232168
},
233169
}
234170

171+
// BTF-only maps.
172+
btfOnly := map[string]*MapSpec{
173+
"btf_pin": {
174+
Name: "btf_pin",
175+
Type: Hash,
176+
KeySize: 4,
177+
ValueSize: 8,
178+
MaxEntries: 1,
179+
Pinning: PinByName,
180+
},
181+
"bpf_decl_map": {
182+
Name: "bpf_decl_map",
183+
Type: Array,
184+
KeySize: 4,
185+
ValueSize: 8,
186+
MaxEntries: 1,
187+
Tags: []string{"a", "b"},
188+
},
189+
"btf_decl_map": {
190+
Name: "btf_decl_map",
191+
Type: Array,
192+
KeySize: 4,
193+
ValueSize: 8,
194+
MaxEntries: 1,
195+
Tags: []string{"a", "b"},
196+
},
197+
"btf_outer_map": {
198+
Name: "btf_outer_map",
199+
Type: ArrayOfMaps,
200+
KeySize: 4,
201+
ValueSize: 4,
202+
MaxEntries: 1,
203+
InnerMap: &MapSpec{
204+
Name: "btf_outer_map_inner",
205+
Type: Hash,
206+
KeySize: 4,
207+
ValueSize: 4,
208+
MaxEntries: 1,
209+
},
210+
},
211+
"btf_outer_map_anon": {
212+
Name: "btf_outer_map_anon",
213+
Type: ArrayOfMaps,
214+
KeySize: 4,
215+
ValueSize: 4,
216+
MaxEntries: 1,
217+
InnerMap: &MapSpec{
218+
Name: "btf_outer_map_anon_inner",
219+
Type: Hash,
220+
KeySize: 4,
221+
ValueSize: 4,
222+
MaxEntries: 1,
223+
},
224+
},
225+
"btf_typedef_map": {
226+
Name: "btf_typedef_map",
227+
Type: Array,
228+
KeySize: 4,
229+
ValueSize: 8,
230+
MaxEntries: 1,
231+
},
232+
}
233+
235234
testutils.Files(t, testutils.Glob(t, "testdata/loader-*.elf"), func(t *testing.T, file string) {
236-
have, err := LoadCollectionSpec(file)
237-
if err != nil {
238-
t.Fatal("Can't parse ELF:", err)
239-
}
235+
got, err := LoadCollectionSpec(file)
236+
qt.Assert(t, qt.IsNil(err))
240237

241-
qt.Assert(t, qt.Equals(have.Maps["perf_event_array"].ValueSize, 0))
242-
qt.Assert(t, qt.IsNotNil(have.Maps["perf_event_array"].Value))
238+
// BTF map definition contains a value type, but the size should remain 0.
239+
// The value type needs to be reflected in the MapSpec.
240+
qt.Assert(t, qt.Equals(got.Maps["perf_event_array"].ValueSize, 0))
241+
qt.Assert(t, qt.IsNotNil(got.Maps["perf_event_array"].Value))
243242

244-
qt.Assert(t, qt.CmpEquals(have, coll, csCmpOpts))
243+
// Copy and extend the CollectionSpec with BTF-only objects.
244+
want := coll.Copy()
245+
maps.Copy(want.Maps, btfOnly)
245246

246-
qt.Assert(t, qt.IsNil(have.Variables["arg"].Set(uint32(1))))
247-
qt.Assert(t, qt.IsNil(have.Variables["arg2"].Set(uint32(2))))
247+
testLoadCollectionSpec(t, got, want)
248+
})
248249

249-
have.Maps["array_of_hash_map"].InnerMap = have.Maps["hash_map"]
250-
coll, err := newCollection(t, have, &CollectionOptions{
251-
Maps: MapOptions{
252-
PinPath: testutils.TempBPFFS(t),
253-
},
254-
Programs: ProgramOptions{
255-
LogLevel: LogLevelBranch,
256-
},
257-
})
250+
testutils.Files(t, testutils.Glob(t, "testdata/loader_nobtf-*.elf"), func(t *testing.T, file string) {
251+
got, err := LoadCollectionSpec(file)
252+
qt.Assert(t, qt.IsNil(err))
258253

259-
testutils.SkipIfNotSupported(t, err)
260-
if err != nil {
261-
t.Fatal(err)
262-
}
254+
testLoadCollectionSpec(t, got, coll.Copy())
255+
})
256+
}
257+
258+
func testLoadCollectionSpec(t *testing.T, got, want *CollectionSpec) {
259+
t.Helper()
263260

264-
ret := mustRun(t, coll.Programs["xdp_prog"], nil)
265-
qt.Assert(t, qt.Equals(ret, 7))
261+
qt.Assert(t, qt.CmpEquals(got, want, csCmpOpts))
262+
263+
coll, err := newCollection(t, got, &CollectionOptions{
264+
Maps: MapOptions{PinPath: testutils.TempBPFFS(t)},
265+
Programs: ProgramOptions{LogLevel: LogLevelBranch},
266266
})
267+
testutils.SkipIfNotSupported(t, err)
268+
qt.Assert(t, qt.IsNil(err))
269+
270+
ret := mustRun(t, coll.Programs["xdp_prog"], nil)
271+
qt.Assert(t, qt.Equals(ret, 7))
267272
}
268273

269274
func BenchmarkELFLoader(b *testing.B) {

testdata/loader-clang-14-eb.elf

-112 Bytes
Binary file not shown.

testdata/loader-clang-14-el.elf

-112 Bytes
Binary file not shown.

testdata/loader-clang-17-eb.elf

-112 Bytes
Binary file not shown.

testdata/loader-clang-17-el.elf

-112 Bytes
Binary file not shown.

testdata/loader-clang-20-eb.elf

-104 Bytes
Binary file not shown.

testdata/loader-clang-20-el.elf

-104 Bytes
Binary file not shown.

testdata/loader.c

Lines changed: 9 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -5,103 +5,11 @@
55

66
char __license[] __section("license") = "MIT";
77

8-
struct {
9-
__uint(type, BPF_MAP_TYPE_HASH);
10-
__type(key, uint32_t);
11-
__type(value, uint64_t);
12-
__uint(max_entries, 1);
13-
__uint(map_flags, BPF_F_NO_PREALLOC);
14-
} hash_map __section(".maps");
15-
16-
struct {
17-
__uint(type, BPF_MAP_TYPE_HASH);
18-
__uint(key_size, sizeof(uint32_t));
19-
__uint(value_size, sizeof(uint64_t));
20-
__uint(max_entries, 2);
21-
} hash_map2 __section(".maps");
22-
23-
struct {
24-
__uint(type, BPF_MAP_TYPE_HASH);
25-
__type(key, uint32_t);
26-
__type(value, uint64_t);
27-
__uint(max_entries, 1);
28-
__uint(pinning, 1 /* LIBBPF_PIN_BY_NAME */);
29-
} btf_pin __section(".maps");
30-
31-
// Named map type definition, without structure variable declaration.
32-
struct inner_map_t {
33-
__uint(type, BPF_MAP_TYPE_HASH);
34-
__type(key, uint32_t);
35-
__type(value, int);
36-
__uint(max_entries, 1);
37-
};
38-
39-
// Anonymous map type definition with structure variable declaration.
40-
struct {
41-
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
42-
__uint(key_size, sizeof(uint32_t));
43-
__uint(max_entries, 1);
44-
__array(values, struct inner_map_t);
45-
} btf_outer_map __section(".maps");
46-
47-
// Array of maps with anonymous inner struct.
48-
struct {
49-
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
50-
__uint(key_size, sizeof(uint32_t));
51-
__uint(max_entries, 1);
52-
__array(
53-
values, struct {
54-
__uint(type, BPF_MAP_TYPE_HASH);
55-
__uint(max_entries, 1);
56-
__type(key, uint32_t);
57-
__type(value, uint32_t);
58-
});
59-
} btf_outer_map_anon __section(".maps");
60-
61-
struct perf_event {
62-
uint64_t foo;
63-
uint64_t bar;
64-
};
65-
66-
struct {
67-
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
68-
__uint(max_entries, 4096);
69-
__type(value, struct perf_event);
70-
} perf_event_array __section(".maps");
71-
72-
struct bpf_map_def array_of_hash_map __section("maps") = {
73-
.type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
74-
.key_size = sizeof(uint32_t),
75-
.max_entries = 2,
76-
};
77-
78-
typedef struct {
79-
__uint(type, BPF_MAP_TYPE_ARRAY);
80-
__uint(key_size, sizeof(uint32_t));
81-
__uint(value_size, sizeof(uint64_t));
82-
__uint(max_entries, 1);
83-
} array_map_t;
84-
85-
// Map definition behind a typedef.
86-
array_map_t btf_typedef_map __section(".maps");
87-
88-
#define __decl_tags __attribute__((btf_decl_tag("a"), btf_decl_tag("b")))
89-
90-
// Legacy map definition decorated with decl tags.
91-
struct bpf_map_def bpf_decl_map __decl_tags __section("maps") = {
92-
.type = BPF_MAP_TYPE_ARRAY,
93-
.key_size = sizeof(uint32_t),
94-
.value_size = sizeof(uint64_t),
95-
.max_entries = 1,
96-
};
97-
98-
// BTF map definition decorated with decl tags.
99-
struct {
100-
__uint(type, BPF_MAP_TYPE_ARRAY);
101-
__uint(key_size, sizeof(uint32_t));
102-
__uint(value_size, sizeof(uint64_t));
103-
__uint(max_entries, 1);
104-
} btf_decl_map __decl_tags __section(".maps");
8+
#ifdef __NOBTF__
9+
#include "loader_nobtf.h"
10+
#else
11+
#include "loader.h"
12+
#endif
10513

10614
static int __attribute__((noinline)) __section("static") static_fn(uint32_t arg) {
10715
return arg - 1;
@@ -123,10 +31,10 @@ volatile unsigned int key1 = 0; // .bss
12331
volatile unsigned int key2 = 1; // .data
12432
volatile const unsigned int key3 = 2; // .rodata
12533

126-
// .rodata, populated by loader
127-
volatile const uint32_t arg;
128-
// custom .rodata section, populated by loader
129-
volatile const uint32_t arg2 __section(".rodata.test");
34+
// .rodata
35+
volatile const uint32_t arg = 1;
36+
// custom .rodata section
37+
volatile const uint32_t arg2 __section(".rodata.test") = 2;
13038
// custom .data section
13139
volatile uint32_t arg3 __section(".data.test");
13240

0 commit comments

Comments
 (0)