vendor: cilium/ebbf 4032b1d8aae306b7bb94a2a11002932caf88c644
full diff: 60c3aa43f4...4032b1d8aa
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
297
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
297
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
@@ -4,12 +4,13 @@ import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/btf"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -18,6 +19,8 @@ type elfCode struct {
|
||||
*elf.File
|
||||
symbols []elf.Symbol
|
||||
symbolsPerSection map[elf.SectionIndex]map[uint64]string
|
||||
license string
|
||||
version uint32
|
||||
}
|
||||
|
||||
// LoadCollectionSpec parses an ELF file into a CollectionSpec.
|
||||
@@ -33,8 +36,8 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
|
||||
}
|
||||
|
||||
// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec.
|
||||
func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||
f, err := elf.NewFile(code)
|
||||
func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
||||
f, err := elf.NewFile(rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -45,12 +48,17 @@ func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||
return nil, errors.Wrap(err, "load symbols")
|
||||
}
|
||||
|
||||
ec := &elfCode{f, symbols, symbolsPerSection(symbols)}
|
||||
ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
|
||||
|
||||
var (
|
||||
licenseSection *elf.Section
|
||||
versionSection *elf.Section
|
||||
btfMaps = make(map[elf.SectionIndex]*elf.Section)
|
||||
progSections = make(map[elf.SectionIndex]*elf.Section)
|
||||
relSections = make(map[elf.SectionIndex]*elf.Section)
|
||||
mapSections = make(map[elf.SectionIndex]*elf.Section)
|
||||
)
|
||||
|
||||
var licenseSection, versionSection *elf.Section
|
||||
progSections := make(map[elf.SectionIndex]*elf.Section)
|
||||
relSections := make(map[elf.SectionIndex]*elf.Section)
|
||||
mapSections := make(map[elf.SectionIndex]*elf.Section)
|
||||
for i, sec := range ec.Sections {
|
||||
switch {
|
||||
case strings.HasPrefix(sec.Name, "license"):
|
||||
@@ -59,6 +67,8 @@ func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||
versionSection = sec
|
||||
case strings.HasPrefix(sec.Name, "maps"):
|
||||
mapSections[elf.SectionIndex(i)] = sec
|
||||
case sec.Name == ".maps":
|
||||
btfMaps[elf.SectionIndex(i)] = sec
|
||||
case sec.Type == elf.SHT_REL:
|
||||
if int(sec.Info) >= len(ec.Sections) {
|
||||
return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
|
||||
@@ -67,7 +77,7 @@ func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||
// Store relocations under the section index of the target
|
||||
idx := elf.SectionIndex(sec.Info)
|
||||
if relSections[idx] != nil {
|
||||
return nil, errors.Errorf("section %d has multiple relocation sections", idx)
|
||||
return nil, errors.Errorf("section %d has multiple relocation sections", sec.Info)
|
||||
}
|
||||
relSections[idx] = sec
|
||||
case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
|
||||
@@ -75,33 +85,36 @@ func LoadCollectionSpecFromReader(code io.ReaderAt) (*CollectionSpec, error) {
|
||||
}
|
||||
}
|
||||
|
||||
license, err := loadLicense(licenseSection)
|
||||
ec.license, err = loadLicense(licenseSection)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load license")
|
||||
}
|
||||
|
||||
version, err := loadVersion(versionSection, ec.ByteOrder)
|
||||
ec.version, err = loadVersion(versionSection, ec.ByteOrder)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load version")
|
||||
}
|
||||
|
||||
maps, err := ec.loadMaps(mapSections)
|
||||
btf, err := btf.LoadSpecFromReader(rd)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load BTF")
|
||||
}
|
||||
|
||||
maps := make(map[string]*MapSpec)
|
||||
|
||||
if err := ec.loadMaps(maps, mapSections); err != nil {
|
||||
return nil, errors.Wrap(err, "load maps")
|
||||
}
|
||||
|
||||
progs, libs, err := ec.loadPrograms(progSections, relSections, license, version)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load programs")
|
||||
if len(btfMaps) > 0 {
|
||||
if err := ec.loadBTFMaps(maps, btfMaps, btf); err != nil {
|
||||
return nil, errors.Wrap(err, "load BTF maps")
|
||||
}
|
||||
}
|
||||
|
||||
if len(libs) > 0 {
|
||||
for name, prog := range progs {
|
||||
prog.Instructions, err = link(prog.Instructions, libs...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "program %s", name)
|
||||
}
|
||||
}
|
||||
progs, err := ec.loadPrograms(progSections, relSections, btf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "load programs")
|
||||
}
|
||||
|
||||
return &CollectionSpec{maps, progs}, nil
|
||||
@@ -128,52 +141,74 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
|
||||
return version, errors.Wrapf(err, "section %s", sec.Name)
|
||||
}
|
||||
|
||||
func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, license string, version uint32) (map[string]*ProgramSpec, []asm.Instructions, error) {
|
||||
func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, btf *btf.Spec) (map[string]*ProgramSpec, error) {
|
||||
var (
|
||||
progs = make(map[string]*ProgramSpec)
|
||||
libs []asm.Instructions
|
||||
progs []*ProgramSpec
|
||||
libs []*ProgramSpec
|
||||
)
|
||||
|
||||
for idx, prog := range progSections {
|
||||
syms := ec.symbolsPerSection[idx]
|
||||
if len(syms) == 0 {
|
||||
return nil, nil, errors.Errorf("section %v: missing symbols", prog.Name)
|
||||
return nil, errors.Errorf("section %v: missing symbols", prog.Name)
|
||||
}
|
||||
|
||||
funcSym := syms[0]
|
||||
if funcSym == "" {
|
||||
return nil, nil, errors.Errorf("section %v: no label at start", prog.Name)
|
||||
return nil, errors.Errorf("section %v: no label at start", prog.Name)
|
||||
}
|
||||
|
||||
rels, err := ec.loadRelocations(relSections[idx])
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym)
|
||||
return nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym)
|
||||
}
|
||||
|
||||
insns, err := ec.loadInstructions(prog, syms, rels)
|
||||
insns, length, err := ec.loadInstructions(prog, syms, rels)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym)
|
||||
return nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym)
|
||||
}
|
||||
|
||||
if progType, attachType := getProgType(prog.Name); progType == UnspecifiedProgram {
|
||||
progType, attachType := getProgType(prog.Name)
|
||||
|
||||
spec := &ProgramSpec{
|
||||
Name: funcSym,
|
||||
Type: progType,
|
||||
AttachType: attachType,
|
||||
License: ec.license,
|
||||
KernelVersion: ec.version,
|
||||
Instructions: insns,
|
||||
}
|
||||
|
||||
if btf != nil {
|
||||
spec.BTF, err = btf.Program(prog.Name, length)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "BTF for section %s (program %s)", prog.Name, funcSym)
|
||||
}
|
||||
}
|
||||
|
||||
if spec.Type == UnspecifiedProgram {
|
||||
// There is no single name we can use for "library" sections,
|
||||
// since they may contain multiple functions. We'll decode the
|
||||
// labels they contain later on, and then link sections that way.
|
||||
libs = append(libs, insns)
|
||||
libs = append(libs, spec)
|
||||
} else {
|
||||
progs[funcSym] = &ProgramSpec{
|
||||
Name: funcSym,
|
||||
Type: progType,
|
||||
AttachType: attachType,
|
||||
License: license,
|
||||
KernelVersion: version,
|
||||
Instructions: insns,
|
||||
}
|
||||
progs = append(progs, spec)
|
||||
}
|
||||
}
|
||||
return progs, libs, nil
|
||||
|
||||
res := make(map[string]*ProgramSpec, len(progs))
|
||||
for _, prog := range progs {
|
||||
err := link(prog, libs)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "program %s", prog.Name)
|
||||
}
|
||||
res[prog.Name] = prog
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, error) {
|
||||
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, uint64, error) {
|
||||
var (
|
||||
r = section.Open()
|
||||
insns asm.Instructions
|
||||
@@ -183,10 +218,10 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
|
||||
for {
|
||||
n, err := ins.Unmarshal(r, ec.ByteOrder)
|
||||
if err == io.EOF {
|
||||
return insns, nil
|
||||
return insns, offset, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "offset %d", offset)
|
||||
return nil, 0, errors.Wrapf(err, "offset %d", offset)
|
||||
}
|
||||
|
||||
ins.Symbol = symbols[offset]
|
||||
@@ -197,19 +232,15 @@ func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations m
|
||||
}
|
||||
}
|
||||
|
||||
func (ec *elfCode) loadMaps(mapSections map[elf.SectionIndex]*elf.Section) (map[string]*MapSpec, error) {
|
||||
var (
|
||||
maps = make(map[string]*MapSpec)
|
||||
b = make([]byte, 1)
|
||||
)
|
||||
func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section) error {
|
||||
for idx, sec := range mapSections {
|
||||
syms := ec.symbolsPerSection[idx]
|
||||
if len(syms) == 0 {
|
||||
return nil, errors.Errorf("section %v: no symbols", sec.Name)
|
||||
return errors.Errorf("section %v: no symbols", sec.Name)
|
||||
}
|
||||
|
||||
if sec.Size%uint64(len(syms)) != 0 {
|
||||
return nil, errors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
|
||||
return errors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -219,12 +250,11 @@ func (ec *elfCode) loadMaps(mapSections map[elf.SectionIndex]*elf.Section) (map[
|
||||
for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
|
||||
mapSym := syms[offset]
|
||||
if mapSym == "" {
|
||||
fmt.Println(syms)
|
||||
return nil, errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
|
||||
return errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
|
||||
}
|
||||
|
||||
if maps[mapSym] != nil {
|
||||
return nil, errors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
|
||||
return errors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
|
||||
}
|
||||
|
||||
lr := io.LimitReader(r, int64(size))
|
||||
@@ -232,51 +262,152 @@ func (ec *elfCode) loadMaps(mapSections map[elf.SectionIndex]*elf.Section) (map[
|
||||
var spec MapSpec
|
||||
switch {
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
|
||||
return nil, errors.Errorf("map %v: missing type", mapSym)
|
||||
return errors.Errorf("map %v: missing type", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
|
||||
return nil, errors.Errorf("map %v: missing key size", mapSym)
|
||||
return errors.Errorf("map %v: missing key size", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
|
||||
return nil, errors.Errorf("map %v: missing value size", mapSym)
|
||||
return errors.Errorf("map %v: missing value size", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
|
||||
return nil, errors.Errorf("map %v: missing max entries", mapSym)
|
||||
return errors.Errorf("map %v: missing max entries", mapSym)
|
||||
case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
|
||||
return nil, errors.Errorf("map %v: missing flags", mapSym)
|
||||
return errors.Errorf("map %v: missing flags", mapSym)
|
||||
}
|
||||
|
||||
for {
|
||||
_, err := lr.Read(b)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b[0] != 0 {
|
||||
return nil, errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
|
||||
}
|
||||
if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
|
||||
return errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
|
||||
}
|
||||
|
||||
maps[mapSym] = &spec
|
||||
}
|
||||
}
|
||||
return maps, nil
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
|
||||
|
||||
if spec == nil {
|
||||
return errors.Errorf("missing BTF")
|
||||
}
|
||||
|
||||
for idx, sec := range mapSections {
|
||||
syms := ec.symbolsPerSection[idx]
|
||||
if len(syms) == 0 {
|
||||
return errors.Errorf("section %v: no symbols", sec.Name)
|
||||
}
|
||||
|
||||
for _, sym := range syms {
|
||||
if maps[sym] != nil {
|
||||
return errors.Errorf("section %v: map %v already exists", sec.Name, sym)
|
||||
}
|
||||
|
||||
btfMap, err := spec.Map(sym)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "map %v: can't get BTF", sym)
|
||||
}
|
||||
|
||||
spec, err := mapSpecFromBTF(btfMap)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "map %v", sym)
|
||||
}
|
||||
|
||||
maps[sym] = spec
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) {
|
||||
var (
|
||||
mapType, flags, maxEntries uint32
|
||||
err error
|
||||
)
|
||||
for _, member := range btf.MapType(btfMap).Members {
|
||||
switch member.Name {
|
||||
case "type":
|
||||
mapType, err = uintFromBTF(member.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get type")
|
||||
}
|
||||
|
||||
case "map_flags":
|
||||
flags, err = uintFromBTF(member.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get BTF map flags")
|
||||
}
|
||||
|
||||
case "max_entries":
|
||||
maxEntries, err = uintFromBTF(member.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get BTF map max entries")
|
||||
}
|
||||
|
||||
case "key":
|
||||
case "value":
|
||||
default:
|
||||
return nil, errors.Errorf("unrecognized field %s in BTF map definition", member.Name)
|
||||
}
|
||||
}
|
||||
|
||||
keySize, err := btf.Sizeof(btf.MapKey(btfMap))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get size of BTF key")
|
||||
}
|
||||
|
||||
valueSize, err := btf.Sizeof(btf.MapValue(btfMap))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get size of BTF value")
|
||||
}
|
||||
|
||||
return &MapSpec{
|
||||
Type: MapType(mapType),
|
||||
KeySize: uint32(keySize),
|
||||
ValueSize: uint32(valueSize),
|
||||
MaxEntries: maxEntries,
|
||||
Flags: flags,
|
||||
BTF: btfMap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// uintFromBTF resolves the __uint macro, which is a pointer to a sized
|
||||
// array, e.g. for int (*foo)[10], this function will return 10.
|
||||
func uintFromBTF(typ btf.Type) (uint32, error) {
|
||||
ptr, ok := typ.(*btf.Pointer)
|
||||
if !ok {
|
||||
return 0, errors.Errorf("not a pointer: %v", typ)
|
||||
}
|
||||
|
||||
arr, ok := ptr.Target.(*btf.Array)
|
||||
if !ok {
|
||||
return 0, errors.Errorf("not a pointer to array: %v", typ)
|
||||
}
|
||||
|
||||
return arr.Nelems, nil
|
||||
}
|
||||
|
||||
func getProgType(v string) (ProgramType, AttachType) {
|
||||
types := map[string]ProgramType{
|
||||
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c#n3568
|
||||
"socket": SocketFilter,
|
||||
"seccomp": SocketFilter,
|
||||
"kprobe/": Kprobe,
|
||||
"kretprobe/": Kprobe,
|
||||
"tracepoint/": TracePoint,
|
||||
"xdp": XDP,
|
||||
"perf_event": PerfEvent,
|
||||
"sockops": SockOps,
|
||||
"sk_skb": SkSKB,
|
||||
"sk_msg": SkMsg,
|
||||
"lirc_mode2": LircMode2,
|
||||
"flow_dissector": FlowDissector,
|
||||
"socket": SocketFilter,
|
||||
"seccomp": SocketFilter,
|
||||
"kprobe/": Kprobe,
|
||||
"uprobe/": Kprobe,
|
||||
"kretprobe/": Kprobe,
|
||||
"uretprobe/": Kprobe,
|
||||
"tracepoint/": TracePoint,
|
||||
"raw_tracepoint/": RawTracepoint,
|
||||
"xdp": XDP,
|
||||
"perf_event": PerfEvent,
|
||||
"lwt_in": LWTIn,
|
||||
"lwt_out": LWTOut,
|
||||
"lwt_xmit": LWTXmit,
|
||||
"lwt_seg6local": LWTSeg6Local,
|
||||
"sockops": SockOps,
|
||||
"sk_skb": SkSKB,
|
||||
"sk_msg": SkMsg,
|
||||
"lirc_mode2": LircMode2,
|
||||
"flow_dissector": FlowDissector,
|
||||
|
||||
"cgroup_skb/": CGroupSKB,
|
||||
"cgroup/dev": CGroupDevice,
|
||||
|
||||
Reference in New Issue
Block a user