Skip to content

Commit 0acd95c

Browse files
lmbti-mo
authored andcommitted
elf: generate ELF section patterns from libbpf
We've historically relied on manually pulling in updated ELF section names from libbpf. This has led to errors creeping in as well as being constantly out of sync. Fix this by using a small awk script to pull the section definitions out of libbpf.c. We already rely on awk to update function names in the awk package so this isn't a new requirement. It turns out that we've strayed from libbpf in a couple of places. This commit adds compatibility behaviour to avoid outward visible changes for the section names we have tests for. The old generate-btf target is repurposed to do the generation and therefore renamed to update-kernel-deps. Fixes #1162 Signed-off-by: Lorenz Bauer <[email protected]>
1 parent 7e286e7 commit 0acd95c

12 files changed

+514
-292
lines changed

Makefile

+5-3
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,12 @@ testdata/loader-%-eb.elf: testdata/loader.c
102102
$(CLANG) $(CFLAGS) -target bpfeb -c $< -o $@
103103
$(STRIP) -g $@
104104

105-
.PHONY: generate-btf
106-
generate-btf: KERNEL_VERSION?=6.6
107-
generate-btf:
105+
.PHONY: update-kernel-deps
106+
update-kernel-deps: KERNEL_VERSION?=6.6
107+
update-kernel-deps:
108108
$(eval TMP := $(shell mktemp -d))
109+
curl -fL https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/tools/lib/bpf/libbpf.c?h=v$(KERNEL_VERSION) -o "$(TMP)/libbpf.c"
110+
"$(CURDIR)/internal/cmd/gensections.awk" "$(TMP)/libbpf.c" | gofmt > "$(CURDIR)/elf_sections.go"
109111
curl -fL "$(CI_KERNEL_URL)/linux-$(KERNEL_VERSION)-amd64.tgz" -o "$(TMP)/linux.tgz"
110112
tar xvf "$(TMP)/linux.tgz" -C "$(TMP)" --strip-components=2 ./boot/vmlinuz ./lib/modules
111113
/lib/modules/$(shell uname -r)/build/scripts/extract-vmlinux "$(TMP)/vmlinuz" > "$(TMP)/vmlinux"

attachtype_string.go

+8-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

btf/core_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ func TestCORERelocation(t *testing.T) {
583583
}
584584

585585
for section := range extInfos.funcInfos {
586-
name := strings.TrimPrefix(section, "socket_filter/")
586+
name := strings.TrimPrefix(section, "socket/")
587587
t.Run(name, func(t *testing.T) {
588588
var relos []*CORERelocation
589589
for _, reloInfo := range extInfos.relocationInfos[section].infos {

btf/testdata/relocs-eb.elf

-120 Bytes
Binary file not shown.

btf/testdata/relocs-el.elf

-120 Bytes
Binary file not shown.

btf/testdata/relocs.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ typedef union u u_t;
4343
} \
4444
})
4545

46-
__section("socket_filter/type_ids") int type_ids() {
46+
__section("socket/type_ids") int type_ids() {
4747
local_id_not_zero(int);
4848
local_id_not_zero(struct { int frob; });
4949
local_id_not_zero(enum {FRAP});
@@ -97,7 +97,7 @@ __section("socket_filter/type_ids") int type_ids() {
9797
} \
9898
})
9999

100-
__section("socket_filter/types") int types() {
100+
__section("socket/types") int types() {
101101
type_exists(struct s);
102102
type_exists(s_t);
103103
type_exists(const s_t);
@@ -142,7 +142,7 @@ __section("socket_filter/types") int types() {
142142
} \
143143
})
144144

145-
__section("socket_filter/enums") int enums() {
145+
__section("socket/enums") int enums() {
146146
enum_value_exists(enum e, ONE);
147147
enum_value_exists(volatile enum e, ONE);
148148
enum_value_exists(const enum e, ONE);
@@ -195,7 +195,7 @@ __section("socket_filter/enums") int enums() {
195195
} \
196196
})
197197

198-
__section("socket_filter/fields") int fields() {
198+
__section("socket/fields") int fields() {
199199
field_exists((struct s){}._1);
200200
field_exists((s_t){}._2);
201201
field_exists((union u){}._1);
@@ -262,10 +262,10 @@ struct ambiguous___flavour {
262262
int _2;
263263
};
264264

265-
__section("socket_filter/err_ambiguous") int err_ambiguous() {
265+
__section("socket/err_ambiguous") int err_ambiguous() {
266266
return bpf_core_type_id_kernel(struct ambiguous);
267267
}
268268

269-
__section("socket_filter/err_ambiguous_flavour") int err_ambiguous_flavour() {
269+
__section("socket/err_ambiguous_flavour") int err_ambiguous_flavour() {
270270
return bpf_core_type_id_kernel(struct ambiguous___flavour);
271271
}

elf_reader.go

+89-91
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/cilium/ebpf/asm"
1616
"github.com/cilium/ebpf/btf"
1717
"github.com/cilium/ebpf/internal"
18+
"github.com/cilium/ebpf/internal/sys"
1819
"github.com/cilium/ebpf/internal/unix"
1920
)
2021

@@ -1181,109 +1182,106 @@ func (ec *elfCode) loadKsymsSection() error {
11811182
return nil
11821183
}
11831184

1185+
type libbpfElfSectionDef struct {
1186+
pattern string
1187+
programType sys.ProgType
1188+
attachType sys.AttachType
1189+
flags libbpfElfSectionFlag
1190+
}
1191+
1192+
type libbpfElfSectionFlag uint32
1193+
1194+
// The values correspond to enum sec_def_flags in libbpf.
1195+
const (
1196+
_SEC_NONE libbpfElfSectionFlag = 0
1197+
1198+
_SEC_EXP_ATTACH_OPT libbpfElfSectionFlag = 1 << (iota - 1)
1199+
_SEC_ATTACHABLE
1200+
_SEC_ATTACH_BTF
1201+
_SEC_SLEEPABLE
1202+
_SEC_XDP_FRAGS
1203+
_SEC_USDT
1204+
1205+
// Ignore any present extra in order to preserve backwards compatibility
1206+
// with earlier versions of the library.
1207+
ignoreExtra
1208+
1209+
_SEC_ATTACHABLE_OPT = _SEC_ATTACHABLE | _SEC_EXP_ATTACH_OPT
1210+
)
1211+
1212+
func init() {
1213+
// Compatibility with older versions of the library.
1214+
// We prepend libbpf definitions since they contain a prefix match
1215+
// for "xdp".
1216+
elfSectionDefs = append([]libbpfElfSectionDef{
1217+
{"xdp.frags/", sys.BPF_PROG_TYPE_XDP, sys.BPF_XDP, _SEC_XDP_FRAGS | ignoreExtra},
1218+
{"xdp.frags_devmap/", sys.BPF_PROG_TYPE_XDP, sys.BPF_XDP_DEVMAP, _SEC_XDP_FRAGS},
1219+
{"xdp_devmap/", sys.BPF_PROG_TYPE_XDP, sys.BPF_XDP_DEVMAP, 0},
1220+
{"xdp.frags_cpumap/", sys.BPF_PROG_TYPE_XDP, sys.BPF_XDP_CPUMAP, _SEC_XDP_FRAGS},
1221+
{"xdp_cpumap/", sys.BPF_PROG_TYPE_XDP, sys.BPF_XDP_CPUMAP, 0},
1222+
// This has been in the library since the beginning of time. Not sure
1223+
// where it came from.
1224+
{"seccomp", sys.BPF_PROG_TYPE_SOCKET_FILTER, 0, _SEC_NONE},
1225+
}, elfSectionDefs...)
1226+
}
1227+
11841228
func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
1185-
types := []struct {
1186-
prefix string
1187-
progType ProgramType
1188-
attachType AttachType
1189-
progFlags uint32
1190-
}{
1191-
// Please update the types from libbpf.c and follow the order of it.
1192-
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
1193-
{"socket", SocketFilter, AttachNone, 0},
1194-
{"sk_reuseport/migrate", SkReuseport, AttachSkReuseportSelectOrMigrate, 0},
1195-
{"sk_reuseport", SkReuseport, AttachSkReuseportSelect, 0},
1196-
{"kprobe/", Kprobe, AttachNone, 0},
1197-
{"uprobe/", Kprobe, AttachNone, 0},
1198-
{"kretprobe/", Kprobe, AttachNone, 0},
1199-
{"uretprobe/", Kprobe, AttachNone, 0},
1200-
{"tc", SchedCLS, AttachNone, 0},
1201-
{"classifier", SchedCLS, AttachNone, 0},
1202-
{"action", SchedACT, AttachNone, 0},
1203-
{"tracepoint/", TracePoint, AttachNone, 0},
1204-
{"tp/", TracePoint, AttachNone, 0},
1205-
{"raw_tracepoint/", RawTracepoint, AttachNone, 0},
1206-
{"raw_tp/", RawTracepoint, AttachNone, 0},
1207-
{"raw_tracepoint.w/", RawTracepointWritable, AttachNone, 0},
1208-
{"raw_tp.w/", RawTracepointWritable, AttachNone, 0},
1209-
{"tp_btf/", Tracing, AttachTraceRawTp, 0},
1210-
{"fentry/", Tracing, AttachTraceFEntry, 0},
1211-
{"fmod_ret/", Tracing, AttachModifyReturn, 0},
1212-
{"fexit/", Tracing, AttachTraceFExit, 0},
1213-
{"fentry.s/", Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
1214-
{"fmod_ret.s/", Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
1215-
{"fexit.s/", Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
1216-
{"freplace/", Extension, AttachNone, 0},
1217-
{"lsm/", LSM, AttachLSMMac, 0},
1218-
{"lsm.s/", LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
1219-
{"iter/", Tracing, AttachTraceIter, 0},
1220-
{"iter.s/", Tracing, AttachTraceIter, unix.BPF_F_SLEEPABLE},
1221-
{"syscall", Syscall, AttachNone, 0},
1222-
{"xdp.frags_devmap/", XDP, AttachXDPDevMap, unix.BPF_F_XDP_HAS_FRAGS},
1223-
{"xdp_devmap/", XDP, AttachXDPDevMap, 0},
1224-
{"xdp.frags_cpumap/", XDP, AttachXDPCPUMap, unix.BPF_F_XDP_HAS_FRAGS},
1225-
{"xdp_cpumap/", XDP, AttachXDPCPUMap, 0},
1226-
{"xdp.frags", XDP, AttachNone, unix.BPF_F_XDP_HAS_FRAGS},
1227-
{"xdp", XDP, AttachNone, 0},
1228-
{"perf_event", PerfEvent, AttachNone, 0},
1229-
{"lwt_in", LWTIn, AttachNone, 0},
1230-
{"lwt_out", LWTOut, AttachNone, 0},
1231-
{"lwt_xmit", LWTXmit, AttachNone, 0},
1232-
{"lwt_seg6local", LWTSeg6Local, AttachNone, 0},
1233-
{"cgroup_skb/ingress", CGroupSKB, AttachCGroupInetIngress, 0},
1234-
{"cgroup_skb/egress", CGroupSKB, AttachCGroupInetEgress, 0},
1235-
{"cgroup/skb", CGroupSKB, AttachNone, 0},
1236-
{"cgroup/sock_create", CGroupSock, AttachCGroupInetSockCreate, 0},
1237-
{"cgroup/sock_release", CGroupSock, AttachCgroupInetSockRelease, 0},
1238-
{"cgroup/sock", CGroupSock, AttachCGroupInetSockCreate, 0},
1239-
{"cgroup/post_bind4", CGroupSock, AttachCGroupInet4PostBind, 0},
1240-
{"cgroup/post_bind6", CGroupSock, AttachCGroupInet6PostBind, 0},
1241-
{"cgroup/dev", CGroupDevice, AttachCGroupDevice, 0},
1242-
{"sockops", SockOps, AttachCGroupSockOps, 0},
1243-
{"sk_skb/stream_parser", SkSKB, AttachSkSKBStreamParser, 0},
1244-
{"sk_skb/stream_verdict", SkSKB, AttachSkSKBStreamVerdict, 0},
1245-
{"sk_skb", SkSKB, AttachNone, 0},
1246-
{"sk_msg", SkMsg, AttachSkMsgVerdict, 0},
1247-
{"lirc_mode2", LircMode2, AttachLircMode2, 0},
1248-
{"flow_dissector", FlowDissector, AttachFlowDissector, 0},
1249-
{"cgroup/bind4", CGroupSockAddr, AttachCGroupInet4Bind, 0},
1250-
{"cgroup/bind6", CGroupSockAddr, AttachCGroupInet6Bind, 0},
1251-
{"cgroup/connect4", CGroupSockAddr, AttachCGroupInet4Connect, 0},
1252-
{"cgroup/connect6", CGroupSockAddr, AttachCGroupInet6Connect, 0},
1253-
{"cgroup/sendmsg4", CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
1254-
{"cgroup/sendmsg6", CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
1255-
{"cgroup/recvmsg4", CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
1256-
{"cgroup/recvmsg6", CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
1257-
{"cgroup/getpeername4", CGroupSockAddr, AttachCgroupInet4GetPeername, 0},
1258-
{"cgroup/getpeername6", CGroupSockAddr, AttachCgroupInet6GetPeername, 0},
1259-
{"cgroup/getsockname4", CGroupSockAddr, AttachCgroupInet4GetSockname, 0},
1260-
{"cgroup/getsockname6", CGroupSockAddr, AttachCgroupInet6GetSockname, 0},
1261-
{"cgroup/sysctl", CGroupSysctl, AttachCGroupSysctl, 0},
1262-
{"cgroup/getsockopt", CGroupSockopt, AttachCGroupGetsockopt, 0},
1263-
{"cgroup/setsockopt", CGroupSockopt, AttachCGroupSetsockopt, 0},
1264-
{"struct_ops+", StructOps, AttachNone, 0},
1265-
{"sk_lookup/", SkLookup, AttachSkLookup, 0},
1266-
{"seccomp", SocketFilter, AttachNone, 0},
1267-
{"kprobe.multi", Kprobe, AttachTraceKprobeMulti, 0},
1268-
{"kretprobe.multi", Kprobe, AttachTraceKprobeMulti, 0},
1269-
// Document all prefixes in docs/ebpf/concepts/elf-sections.md.
1270-
}
1229+
// Skip optional program marking for now.
1230+
sectionName = strings.TrimPrefix(sectionName, "?")
12711231

1272-
for _, t := range types {
1273-
if !strings.HasPrefix(sectionName, t.prefix) {
1232+
for _, t := range elfSectionDefs {
1233+
extra, ok := matchSectionName(sectionName, t.pattern)
1234+
if !ok {
12741235
continue
12751236
}
12761237

1277-
if !strings.HasSuffix(t.prefix, "/") {
1278-
return t.progType, t.attachType, t.progFlags, ""
1238+
programType := ProgramType(t.programType)
1239+
attachType := AttachType(t.attachType)
1240+
1241+
var flags uint32
1242+
if t.flags&_SEC_SLEEPABLE > 0 {
1243+
flags |= unix.BPF_F_SLEEPABLE
1244+
}
1245+
if t.flags&_SEC_XDP_FRAGS > 0 {
1246+
flags |= unix.BPF_F_XDP_HAS_FRAGS
1247+
}
1248+
if t.flags&_SEC_EXP_ATTACH_OPT > 0 {
1249+
if programType == XDP {
1250+
// The library doesn't yet have code to fallback to not specifying
1251+
// attach type. Only do this for XDP since we've enforced correct
1252+
// attach type for all other program types.
1253+
attachType = AttachNone
1254+
}
1255+
}
1256+
if t.flags&ignoreExtra > 0 {
1257+
extra = ""
12791258
}
12801259

1281-
return t.progType, t.attachType, t.progFlags, sectionName[len(t.prefix):]
1260+
return programType, attachType, flags, extra
12821261
}
12831262

12841263
return UnspecifiedProgram, AttachNone, 0, ""
12851264
}
12861265

1266+
// matchSectionName checks a section name against a pattern.
1267+
//
1268+
// It's behaviour mirrors that of libbpf's sec_def_matches.
1269+
func matchSectionName(sectionName, pattern string) (extra string, found bool) {
1270+
have, extra, found := strings.Cut(sectionName, "/")
1271+
want := strings.TrimRight(pattern, "+/")
1272+
1273+
if strings.HasSuffix(pattern, "/") {
1274+
// Section name must have a slash and extra may be empty.
1275+
return extra, have == want && found
1276+
} else if strings.HasSuffix(pattern, "+") {
1277+
// Section name may have a slash and extra may be empty.
1278+
return extra, have == want
1279+
}
1280+
1281+
// Section name must have a prefix. extra is ignored.
1282+
return "", strings.HasPrefix(sectionName, pattern)
1283+
}
1284+
12871285
func (ec *elfCode) loadSectionRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) {
12881286
rels := make(map[uint64]elf.Symbol)
12891287

0 commit comments

Comments
 (0)