Revert "Merge pull request 101888 from kolyshkin/update-runc-rc94"

This reverts commit b1b06fe0a4, reversing
changes made to 382a33986b.
This commit is contained in:
Jordan Liggitt
2021-05-18 09:12:04 -04:00
parent 7ccd90e7d7
commit 4b45d0d921
336 changed files with 5393 additions and 17166 deletions

View File

@@ -18,14 +18,12 @@ import (
"github.com/cilium/ebpf/internal/unix"
)
// elfCode is a convenience to reduce the amount of arguments that have to
// be passed around explicitly. You should treat it's contents as immutable.
type elfCode struct {
*internal.SafeELFFile
sections map[elf.SectionIndex]*elfSection
license string
version uint32
btf *btf.Spec
*elf.File
symbols []elf.Symbol
symbolsPerSection map[elf.SectionIndex]map[uint64]elf.Symbol
license string
version uint32
}
// LoadCollectionSpec parses an ELF file into a CollectionSpec.
@@ -45,52 +43,63 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec.
func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
f, err := internal.NewSafeELFFile(rd)
f, err := elf.NewFile(rd)
if err != nil {
return nil, err
}
defer f.Close()
symbols, err := f.Symbols()
if err != nil {
return nil, fmt.Errorf("load symbols: %v", err)
}
ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
var (
licenseSection *elf.Section
versionSection *elf.Section
sections = make(map[elf.SectionIndex]*elfSection)
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)
dataSections = make(map[elf.SectionIndex]*elf.Section)
)
// This is the target of relocations generated by inline assembly.
sections[elf.SHN_UNDEF] = newElfSection(new(elf.Section), undefSection)
// Collect all the sections we're interested in. This includes relocations
// which we parse later.
for i, sec := range f.Sections {
idx := elf.SectionIndex(i)
for i, sec := range ec.Sections {
switch {
case strings.HasPrefix(sec.Name, "license"):
licenseSection = sec
case strings.HasPrefix(sec.Name, "version"):
versionSection = sec
case strings.HasPrefix(sec.Name, "maps"):
sections[idx] = newElfSection(sec, mapSection)
mapSections[elf.SectionIndex(i)] = sec
case sec.Name == ".maps":
sections[idx] = newElfSection(sec, btfMapSection)
case sec.Name == ".bss" || sec.Name == ".data" || strings.HasPrefix(sec.Name, ".rodata"):
sections[idx] = newElfSection(sec, dataSection)
btfMaps[elf.SectionIndex(i)] = sec
case sec.Name == ".bss" || sec.Name == ".rodata" || sec.Name == ".data":
dataSections[elf.SectionIndex(i)] = sec
case sec.Type == elf.SHT_REL:
if int(sec.Info) >= len(ec.Sections) {
return nil, fmt.Errorf("found relocation section %v for missing section %v", i, sec.Info)
}
// Store relocations under the section index of the target
relSections[elf.SectionIndex(sec.Info)] = sec
idx := elf.SectionIndex(sec.Info)
if relSections[idx] != nil {
return nil, fmt.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:
sections[idx] = newElfSection(sec, programSection)
progSections[elf.SectionIndex(i)] = sec
}
}
license, err := loadLicense(licenseSection)
ec.license, err = loadLicense(licenseSection)
if err != nil {
return nil, fmt.Errorf("load license: %w", err)
}
version, err := loadVersion(versionSection, f.ByteOrder)
ec.version, err = loadVersion(versionSection, ec.ByteOrder)
if err != nil {
return nil, fmt.Errorf("load version: %w", err)
}
@@ -100,90 +109,37 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
return nil, fmt.Errorf("load BTF: %w", err)
}
// Assign symbols to all the sections we're interested in.
symbols, err := f.Symbols()
relocations, referencedSections, err := ec.loadRelocations(relSections)
if err != nil {
return nil, fmt.Errorf("load symbols: %v", err)
return nil, fmt.Errorf("load relocations: %w", err)
}
for _, symbol := range symbols {
idx := symbol.Section
symType := elf.ST_TYPE(symbol.Info)
section := sections[idx]
if section == nil {
continue
}
// Older versions of LLVM don't tag symbols correctly, so keep
// all NOTYPE ones.
keep := symType == elf.STT_NOTYPE
switch section.kind {
case mapSection, btfMapSection, dataSection:
keep = keep || symType == elf.STT_OBJECT
case programSection:
keep = keep || symType == elf.STT_FUNC
}
if !keep || symbol.Name == "" {
continue
}
section.symbols[symbol.Value] = symbol
}
ec := &elfCode{
SafeELFFile: f,
sections: sections,
license: license,
version: version,
btf: btfSpec,
}
// Go through relocation sections, and parse the ones for sections we're
// interested in. Make sure that relocations point at valid sections.
for idx, relSection := range relSections {
section := sections[idx]
if section == nil {
continue
}
rels, err := ec.loadRelocations(relSection, symbols)
if err != nil {
return nil, fmt.Errorf("relocation for section %q: %w", section.Name, err)
}
for _, rel := range rels {
target := sections[rel.Section]
if target == nil {
return nil, fmt.Errorf("section %q: reference to %q in section %s: %w", section.Name, rel.Name, rel.Section, ErrNotSupported)
}
if target.Flags&elf.SHF_STRINGS > 0 {
return nil, fmt.Errorf("section %q: string %q is not stack allocated: %w", section.Name, rel.Name, ErrNotSupported)
}
target.references++
}
section.relocations = rels
}
// Collect all the various ways to define maps.
maps := make(map[string]*MapSpec)
if err := ec.loadMaps(maps); err != nil {
if err := ec.loadMaps(maps, mapSections); err != nil {
return nil, fmt.Errorf("load maps: %w", err)
}
if err := ec.loadBTFMaps(maps); err != nil {
return nil, fmt.Errorf("load BTF maps: %w", err)
if len(btfMaps) > 0 {
if err := ec.loadBTFMaps(maps, btfMaps, btfSpec); err != nil {
return nil, fmt.Errorf("load BTF maps: %w", err)
}
}
if err := ec.loadDataSections(maps); err != nil {
return nil, fmt.Errorf("load data sections: %w", err)
if len(dataSections) > 0 {
for idx := range dataSections {
if !referencedSections[idx] {
// Prune data sections which are not referenced by any
// instructions.
delete(dataSections, idx)
}
}
if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil {
return nil, fmt.Errorf("load data sections: %w", err)
}
}
// Finally, collect programs and link them.
progs, err := ec.loadPrograms()
progs, err := ec.loadPrograms(progSections, relocations, btfSpec)
if err != nil {
return nil, fmt.Errorf("load programs: %w", err)
}
@@ -215,69 +171,33 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
return version, nil
}
type elfSectionKind int
const (
undefSection elfSectionKind = iota
mapSection
btfMapSection
programSection
dataSection
)
type elfSection struct {
*elf.Section
kind elfSectionKind
// Offset from the start of the section to a symbol
symbols map[uint64]elf.Symbol
// Offset from the start of the section to a relocation, which points at
// a symbol in another section.
relocations map[uint64]elf.Symbol
// The number of relocations pointing at this section.
references int
}
func newElfSection(section *elf.Section, kind elfSectionKind) *elfSection {
return &elfSection{
section,
kind,
make(map[uint64]elf.Symbol),
make(map[uint64]elf.Symbol),
0,
}
}
func (ec *elfCode) loadPrograms() (map[string]*ProgramSpec, error) {
func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section, relocations map[elf.SectionIndex]map[uint64]elf.Symbol, btfSpec *btf.Spec) (map[string]*ProgramSpec, error) {
var (
progs []*ProgramSpec
libs []*ProgramSpec
)
for _, sec := range ec.sections {
if sec.kind != programSection {
continue
}
if len(sec.symbols) == 0 {
for idx, sec := range progSections {
syms := ec.symbolsPerSection[idx]
if len(syms) == 0 {
return nil, fmt.Errorf("section %v: missing symbols", sec.Name)
}
funcSym, ok := sec.symbols[0]
funcSym, ok := syms[0]
if !ok {
return nil, fmt.Errorf("section %v: no label at start", sec.Name)
}
insns, length, err := ec.loadInstructions(sec)
insns, length, err := ec.loadInstructions(sec, syms, relocations[idx])
if err != nil {
return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
return nil, fmt.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
}
progType, attachType, progFlags, attachTo := getProgType(sec.Name)
progType, attachType, attachTo := getProgType(sec.Name)
spec := &ProgramSpec{
Name: funcSym.Name,
Type: progType,
Flags: progFlags,
AttachType: attachType,
AttachTo: attachTo,
License: ec.license,
@@ -286,8 +206,8 @@ func (ec *elfCode) loadPrograms() (map[string]*ProgramSpec, error) {
ByteOrder: ec.ByteOrder,
}
if ec.btf != nil {
spec.BTF, err = ec.btf.Program(sec.Name, length)
if btfSpec != nil {
spec.BTF, err = btfSpec.Program(sec.Name, length)
if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) {
return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
}
@@ -315,7 +235,7 @@ func (ec *elfCode) loadPrograms() (map[string]*ProgramSpec, error) {
return res, nil
}
func (ec *elfCode) loadInstructions(section *elfSection) (asm.Instructions, uint64, error) {
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]elf.Symbol) (asm.Instructions, uint64, error) {
var (
r = bufio.NewReader(section.Open())
insns asm.Instructions
@@ -331,11 +251,11 @@ func (ec *elfCode) loadInstructions(section *elfSection) (asm.Instructions, uint
return nil, 0, fmt.Errorf("offset %d: %w", offset, err)
}
ins.Symbol = section.symbols[offset].Name
ins.Symbol = symbols[offset].Name
if rel, ok := section.relocations[offset]; ok {
if rel, ok := relocations[offset]; ok {
if err = ec.relocateInstruction(&ins, rel); err != nil {
return nil, 0, fmt.Errorf("offset %d: relocate instruction: %w", offset, err)
return nil, 0, fmt.Errorf("offset %d: can't relocate instruction: %w", offset, err)
}
}
@@ -351,66 +271,69 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
name = rel.Name
)
target := ec.sections[rel.Section]
switch target.kind {
case mapSection, btfMapSection:
if bind != elf.STB_GLOBAL {
return fmt.Errorf("possible erroneous static qualifier on map definition: found reference to %q", name)
if typ == elf.STT_SECTION {
// Symbols with section type do not have a name set. Get it
// from the section itself.
idx := int(rel.Section)
if idx > len(ec.Sections) {
return errors.New("out-of-bounds section index")
}
if typ != elf.STT_OBJECT && typ != elf.STT_NOTYPE {
// STT_NOTYPE is generated on clang < 8 which doesn't tag
// relocations appropriately.
return fmt.Errorf("map load: incorrect relocation type %v", typ)
}
name = ec.Sections[idx].Name
}
ins.Src = asm.PseudoMapFD
// Mark the instruction as needing an update when creating the
// collection.
if err := ins.RewriteMapPtr(-1); err != nil {
return err
}
case dataSection:
outer:
switch {
case ins.OpCode == asm.LoadImmOp(asm.DWord):
// There are two distinct types of a load from a map:
// a direct one, where the value is extracted without
// a call to map_lookup_elem in eBPF, and an indirect one
// that goes via the helper. They are distinguished by
// different relocations.
switch typ {
case elf.STT_SECTION:
// This is a direct load since the referenced symbol is a
// section. Weirdly, the offset of the real symbol in the
// section is encoded in the instruction stream.
if bind != elf.STB_LOCAL {
return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
}
case elf.STT_OBJECT:
if bind != elf.STB_GLOBAL {
return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
// For some reason, clang encodes the offset of the symbol its
// section in the first basic BPF instruction, while the kernel
// expects it in the second one.
ins.Constant <<= 32
ins.Src = asm.PseudoMapValue
case elf.STT_NOTYPE:
if bind == elf.STB_GLOBAL && rel.Section == elf.SHN_UNDEF {
// This is a relocation generated by inline assembly.
// We can't do more than assigning ins.Reference.
break outer
}
// This is an ELF generated on clang < 8, which doesn't tag
// relocations appropriately.
fallthrough
case elf.STT_OBJECT:
if bind != elf.STB_GLOBAL {
return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
}
ins.Src = asm.PseudoMapFD
default:
return fmt.Errorf("incorrect relocation type %v for direct map load", typ)
return fmt.Errorf("load: %s: unsupported relocation: %s", name, typ)
}
// We rely on using the name of the data section as the reference. It
// would be nicer to keep the real name in case of an STT_OBJECT, but
// it's not clear how to encode that into Instruction.
name = target.Name
// For some reason, clang encodes the offset of the symbol its
// section in the first basic BPF instruction, while the kernel
// expects it in the second one.
ins.Constant <<= 32
ins.Src = asm.PseudoMapValue
// Mark the instruction as needing an update when creating the
// collection.
if err := ins.RewriteMapPtr(-1); err != nil {
return err
}
case programSection:
if ins.OpCode.JumpOp() != asm.Call {
return fmt.Errorf("not a call instruction: %s", ins)
}
case ins.OpCode.JumpOp() == asm.Call:
if ins.Src != asm.PseudoCall {
return fmt.Errorf("call: %s: incorrect source register", name)
}
@@ -435,7 +358,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
return fmt.Errorf("call: %s: invalid offset %d", name, offset)
}
sym, ok := target.symbols[uint64(offset)]
sym, ok := ec.symbolsPerSection[rel.Section][uint64(offset)]
if !ok {
return fmt.Errorf("call: %s: no symbol at offset %d", name, offset)
}
@@ -447,46 +370,31 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
return fmt.Errorf("call: %s: invalid symbol type %s", name, typ)
}
case undefSection:
if bind != elf.STB_GLOBAL {
return fmt.Errorf("asm relocation: %s: unsupported binding: %s", name, bind)
}
if typ != elf.STT_NOTYPE {
return fmt.Errorf("asm relocation: %s: unsupported type %s", name, typ)
}
// There is nothing to do here but set ins.Reference.
default:
return fmt.Errorf("relocation to %q: %w", target.Name, ErrNotSupported)
return fmt.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
}
ins.Reference = name
return nil
}
func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
for _, sec := range ec.sections {
if sec.kind != mapSection {
continue
}
nSym := len(sec.symbols)
if nSym == 0 {
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 fmt.Errorf("section %v: no symbols", sec.Name)
}
if sec.Size%uint64(nSym) != 0 {
if sec.Size%uint64(len(syms)) != 0 {
return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name)
}
var (
r = bufio.NewReader(sec.Open())
size = sec.Size / uint64(nSym)
size = sec.Size / uint64(len(syms))
)
for i, offset := 0, uint64(0); i < nSym; i, offset = i+1, offset+size {
mapSym, ok := sec.symbols[offset]
for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
mapSym, ok := syms[offset]
if !ok {
return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
}
@@ -524,43 +432,24 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec) error {
return nil
}
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
for _, sec := range ec.sections {
if sec.kind != btfMapSection {
continue
func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec, mapSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
if spec == nil {
return fmt.Errorf("missing BTF")
}
for idx, sec := range mapSections {
syms := ec.symbolsPerSection[idx]
if len(syms) == 0 {
return fmt.Errorf("section %v: no symbols", sec.Name)
}
if ec.btf == nil {
return fmt.Errorf("missing BTF")
}
_, err := io.Copy(internal.DiscardZeroes{}, bufio.NewReader(sec.Open()))
if err != nil {
return fmt.Errorf("section %v: initializing BTF map definitions: %w", sec.Name, internal.ErrNotSupported)
}
var ds btf.Datasec
if err := ec.btf.FindType(sec.Name, &ds); err != nil {
return fmt.Errorf("cannot find section '%s' in BTF: %w", sec.Name, err)
}
for _, vs := range ds.Vars {
v, ok := vs.Type.(*btf.Var)
if !ok {
return fmt.Errorf("section %v: unexpected type %s", sec.Name, vs.Type)
}
name := string(v.Name)
for _, sym := range syms {
name := sym.Name
if maps[name] != nil {
return fmt.Errorf("section %v: map %s already exists", sec.Name, name)
return fmt.Errorf("section %v: map %v already exists", sec.Name, sym)
}
mapStruct, ok := v.Type.(*btf.Struct)
if !ok {
return fmt.Errorf("expected struct, got %s", v.Type)
}
mapSpec, err := mapSpecFromBTF(name, mapStruct, false, ec.btf)
mapSpec, err := mapSpecFromBTF(spec, name)
if err != nil {
return fmt.Errorf("map %v: %w", name, err)
}
@@ -572,21 +461,31 @@ func (ec *elfCode) loadBTFMaps(maps map[string]*MapSpec) error {
return nil
}
// mapSpecFromBTF produces a MapSpec based on a btf.Struct def representing
// a BTF map definition. The name and spec arguments will be copied to the
// resulting MapSpec, and inner must be true on any resursive invocations.
func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*MapSpec, error) {
func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
btfMap, btfMapMembers, err := spec.Map(name)
if err != nil {
return nil, fmt.Errorf("can't get BTF: %w", err)
}
keyType := btf.MapKey(btfMap)
size, err := btf.Sizeof(keyType)
if err != nil {
return nil, fmt.Errorf("can't get size of BTF key: %w", err)
}
keySize := uint32(size)
valueType := btf.MapValue(btfMap)
size, err = btf.Sizeof(valueType)
if err != nil {
return nil, fmt.Errorf("can't get size of BTF value: %w", err)
}
valueSize := uint32(size)
var (
key, value btf.Type
keySize, valueSize uint32
mapType, flags, maxEntries uint32
pinType PinType
innerMapSpec *MapSpec
err error
)
for i, member := range def.Members {
for _, member := range btfMapMembers {
switch member.Name {
case "type":
mapType, err = uintFromBTF(member.Type)
@@ -606,48 +505,8 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
return nil, fmt.Errorf("can't get BTF map max entries: %w", err)
}
case "key":
if keySize != 0 {
return nil, errors.New("both key and key_size given")
}
pk, ok := member.Type.(*btf.Pointer)
if !ok {
return nil, fmt.Errorf("key type is not a pointer: %T", member.Type)
}
key = pk.Target
size, err := btf.Sizeof(pk.Target)
if err != nil {
return nil, fmt.Errorf("can't get size of BTF key: %w", err)
}
keySize = uint32(size)
case "value":
if valueSize != 0 {
return nil, errors.New("both value and value_size given")
}
vk, ok := member.Type.(*btf.Pointer)
if !ok {
return nil, fmt.Errorf("value type is not a pointer: %T", member.Type)
}
value = vk.Target
size, err := btf.Sizeof(vk.Target)
if err != nil {
return nil, fmt.Errorf("can't get size of BTF value: %w", err)
}
valueSize = uint32(size)
case "key_size":
// Key needs to be nil and keySize needs to be 0 for key_size to be
// considered a valid member.
if key != nil || keySize != 0 {
if _, isVoid := keyType.(*btf.Void); !isVoid {
return nil, errors.New("both key and key_size given")
}
@@ -657,9 +516,7 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
}
case "value_size":
// Value needs to be nil and valueSize needs to be 0 for value_size to be
// considered a valid member.
if value != nil || valueSize != 0 {
if _, isVoid := valueType.(*btf.Void); !isVoid {
return nil, errors.New("both value and value_size given")
}
@@ -669,10 +526,6 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
}
case "pinning":
if inner {
return nil, errors.New("inner maps can't be pinned")
}
pinning, err := uintFromBTF(member.Type)
if err != nil {
return nil, fmt.Errorf("can't get pinning: %w", err)
@@ -680,58 +533,12 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
pinType = PinType(pinning)
case "values":
// The 'values' field in BTF map definitions is used for declaring map
// value types that are references to other BPF objects, like other maps
// or programs. It is always expected to be an array of pointers.
if i != len(def.Members)-1 {
return nil, errors.New("'values' must be the last member in a BTF map definition")
}
if valueSize != 0 && valueSize != 4 {
return nil, errors.New("value_size must be 0 or 4")
}
valueSize = 4
valueType, err := resolveBTFArrayMacro(member.Type)
if err != nil {
return nil, fmt.Errorf("can't resolve type of member 'values': %w", err)
}
switch t := valueType.(type) {
case *btf.Struct:
// The values member pointing to an array of structs means we're expecting
// a map-in-map declaration.
if MapType(mapType) != ArrayOfMaps && MapType(mapType) != HashOfMaps {
return nil, errors.New("outer map needs to be an array or a hash of maps")
}
if inner {
return nil, fmt.Errorf("nested inner maps are not supported")
}
// This inner map spec is used as a map template, but it needs to be
// created as a traditional map before it can be used to do so.
// libbpf names the inner map template '<outer_name>.inner', but we
// opted for _inner to simplify validation logic. (dots only supported
// on kernels 5.2 and up)
// Pass the BTF spec from the parent object, since both parent and
// child must be created from the same BTF blob (on kernels that support BTF).
innerMapSpec, err = mapSpecFromBTF(name+"_inner", t, true, spec)
if err != nil {
return nil, fmt.Errorf("can't parse BTF map definition of inner map: %w", err)
}
default:
return nil, fmt.Errorf("unsupported value type %q in 'values' field", t)
}
case "key", "value":
default:
return nil, fmt.Errorf("unrecognized field %s in BTF map definition", member.Name)
}
}
bm := btf.NewMap(spec, key, value)
return &MapSpec{
Name: SanitizeName(name, -1),
Type: MapType(mapType),
@@ -739,9 +546,8 @@ func mapSpecFromBTF(name string, def *btf.Struct, inner bool, spec *btf.Spec) (*
ValueSize: valueSize,
MaxEntries: maxEntries,
Flags: flags,
BTF: &bm,
BTF: btfMap,
Pinning: pinType,
InnerMap: innerMapSpec,
}, nil
}
@@ -761,40 +567,13 @@ func uintFromBTF(typ btf.Type) (uint32, error) {
return arr.Nelems, nil
}
// resolveBTFArrayMacro resolves the __array macro, which declares an array
// of pointers to a given type. This function returns the target Type of
// the pointers in the array.
func resolveBTFArrayMacro(typ btf.Type) (btf.Type, error) {
arr, ok := typ.(*btf.Array)
if !ok {
return nil, fmt.Errorf("not an array: %v", typ)
func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
if spec == nil {
return errors.New("data sections require BTF, make sure all consts are marked as static")
}
ptr, ok := arr.Type.(*btf.Pointer)
if !ok {
return nil, fmt.Errorf("not an array of pointers: %v", typ)
}
return ptr.Target, nil
}
func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
for _, sec := range ec.sections {
if sec.kind != dataSection {
continue
}
if sec.references == 0 {
// Prune data sections which are not referenced by any
// instructions.
continue
}
if ec.btf == nil {
return errors.New("data sections require BTF, make sure all consts are marked as static")
}
btfMap, err := ec.btf.Datasec(sec.Name)
for _, sec := range dataSections {
btfMap, err := spec.Datasec(sec.Name)
if err != nil {
return err
}
@@ -832,61 +611,56 @@ func (ec *elfCode) loadDataSections(maps map[string]*MapSpec) error {
return nil
}
func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
func getProgType(sectionName string) (ProgramType, AttachType, string) {
types := map[string]struct {
progType ProgramType
attachType AttachType
progFlags uint32
}{
// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
"socket": {SocketFilter, AttachNone, 0},
"seccomp": {SocketFilter, AttachNone, 0},
"kprobe/": {Kprobe, AttachNone, 0},
"uprobe/": {Kprobe, AttachNone, 0},
"kretprobe/": {Kprobe, AttachNone, 0},
"uretprobe/": {Kprobe, AttachNone, 0},
"tracepoint/": {TracePoint, AttachNone, 0},
"raw_tracepoint/": {RawTracepoint, AttachNone, 0},
"xdp": {XDP, AttachNone, 0},
"perf_event": {PerfEvent, AttachNone, 0},
"lwt_in": {LWTIn, AttachNone, 0},
"lwt_out": {LWTOut, AttachNone, 0},
"lwt_xmit": {LWTXmit, AttachNone, 0},
"lwt_seg6local": {LWTSeg6Local, AttachNone, 0},
"sockops": {SockOps, AttachCGroupSockOps, 0},
"sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser, 0},
"sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser, 0},
"sk_msg": {SkMsg, AttachSkSKBStreamVerdict, 0},
"lirc_mode2": {LircMode2, AttachLircMode2, 0},
"flow_dissector": {FlowDissector, AttachFlowDissector, 0},
"iter/": {Tracing, AttachTraceIter, 0},
"fentry.s/": {Tracing, AttachTraceFEntry, unix.BPF_F_SLEEPABLE},
"fmod_ret.s/": {Tracing, AttachModifyReturn, unix.BPF_F_SLEEPABLE},
"fexit.s/": {Tracing, AttachTraceFExit, unix.BPF_F_SLEEPABLE},
"sk_lookup/": {SkLookup, AttachSkLookup, 0},
"lsm/": {LSM, AttachLSMMac, 0},
"lsm.s/": {LSM, AttachLSMMac, unix.BPF_F_SLEEPABLE},
"socket": {SocketFilter, AttachNone},
"seccomp": {SocketFilter, AttachNone},
"kprobe/": {Kprobe, AttachNone},
"uprobe/": {Kprobe, AttachNone},
"kretprobe/": {Kprobe, AttachNone},
"uretprobe/": {Kprobe, AttachNone},
"tracepoint/": {TracePoint, AttachNone},
"raw_tracepoint/": {RawTracepoint, AttachNone},
"xdp": {XDP, AttachNone},
"perf_event": {PerfEvent, AttachNone},
"lwt_in": {LWTIn, AttachNone},
"lwt_out": {LWTOut, AttachNone},
"lwt_xmit": {LWTXmit, AttachNone},
"lwt_seg6local": {LWTSeg6Local, AttachNone},
"sockops": {SockOps, AttachCGroupSockOps},
"sk_skb/stream_parser": {SkSKB, AttachSkSKBStreamParser},
"sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser},
"sk_msg": {SkMsg, AttachSkSKBStreamVerdict},
"lirc_mode2": {LircMode2, AttachLircMode2},
"flow_dissector": {FlowDissector, AttachFlowDissector},
"iter/": {Tracing, AttachTraceIter},
"sk_lookup/": {SkLookup, AttachSkLookup},
"lsm/": {LSM, AttachLSMMac},
"cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress, 0},
"cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress, 0},
"cgroup/dev": {CGroupDevice, AttachCGroupDevice, 0},
"cgroup/skb": {CGroupSKB, AttachNone, 0},
"cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate, 0},
"cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind, 0},
"cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind, 0},
"cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind, 0},
"cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind, 0},
"cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect, 0},
"cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect, 0},
"cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg, 0},
"cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg, 0},
"cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg, 0},
"cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg, 0},
"cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl, 0},
"cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt, 0},
"cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt, 0},
"classifier": {SchedCLS, AttachNone, 0},
"action": {SchedACT, AttachNone, 0},
"cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress},
"cgroup_skb/egress": {CGroupSKB, AttachCGroupInetEgress},
"cgroup/dev": {CGroupDevice, AttachCGroupDevice},
"cgroup/skb": {CGroupSKB, AttachNone},
"cgroup/sock": {CGroupSock, AttachCGroupInetSockCreate},
"cgroup/post_bind4": {CGroupSock, AttachCGroupInet4PostBind},
"cgroup/post_bind6": {CGroupSock, AttachCGroupInet6PostBind},
"cgroup/bind4": {CGroupSockAddr, AttachCGroupInet4Bind},
"cgroup/bind6": {CGroupSockAddr, AttachCGroupInet6Bind},
"cgroup/connect4": {CGroupSockAddr, AttachCGroupInet4Connect},
"cgroup/connect6": {CGroupSockAddr, AttachCGroupInet6Connect},
"cgroup/sendmsg4": {CGroupSockAddr, AttachCGroupUDP4Sendmsg},
"cgroup/sendmsg6": {CGroupSockAddr, AttachCGroupUDP6Sendmsg},
"cgroup/recvmsg4": {CGroupSockAddr, AttachCGroupUDP4Recvmsg},
"cgroup/recvmsg6": {CGroupSockAddr, AttachCGroupUDP6Recvmsg},
"cgroup/sysctl": {CGroupSysctl, AttachCGroupSysctl},
"cgroup/getsockopt": {CGroupSockopt, AttachCGroupGetsockopt},
"cgroup/setsockopt": {CGroupSockopt, AttachCGroupSetsockopt},
"classifier": {SchedCLS, AttachNone},
"action": {SchedACT, AttachNone},
}
for prefix, t := range types {
@@ -895,39 +669,78 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
}
if !strings.HasSuffix(prefix, "/") {
return t.progType, t.attachType, t.progFlags, ""
return t.progType, t.attachType, ""
}
return t.progType, t.attachType, t.progFlags, sectionName[len(prefix):]
return t.progType, t.attachType, sectionName[len(prefix):]
}
return UnspecifiedProgram, AttachNone, 0, ""
return UnspecifiedProgram, AttachNone, ""
}
func (ec *elfCode) loadRelocations(sec *elf.Section, symbols []elf.Symbol) (map[uint64]elf.Symbol, error) {
rels := make(map[uint64]elf.Symbol)
func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (map[elf.SectionIndex]map[uint64]elf.Symbol, map[elf.SectionIndex]bool, error) {
result := make(map[elf.SectionIndex]map[uint64]elf.Symbol)
targets := make(map[elf.SectionIndex]bool)
for idx, sec := range sections {
rels := make(map[uint64]elf.Symbol)
if sec.Entsize < 16 {
return nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
}
r := bufio.NewReader(sec.Open())
for off := uint64(0); off < sec.Size; off += sec.Entsize {
ent := io.LimitReader(r, int64(sec.Entsize))
var rel elf.Rel64
if binary.Read(ent, ec.ByteOrder, &rel) != nil {
return nil, fmt.Errorf("can't parse relocation at offset %v", off)
if sec.Entsize < 16 {
return nil, nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
}
symNo := int(elf.R_SYM64(rel.Info) - 1)
if symNo >= len(symbols) {
return nil, fmt.Errorf("offset %d: symbol %d doesn't exist", off, symNo)
r := bufio.NewReader(sec.Open())
for off := uint64(0); off < sec.Size; off += sec.Entsize {
ent := io.LimitReader(r, int64(sec.Entsize))
var rel elf.Rel64
if binary.Read(ent, ec.ByteOrder, &rel) != nil {
return nil, nil, fmt.Errorf("can't parse relocation at offset %v", off)
}
symNo := int(elf.R_SYM64(rel.Info) - 1)
if symNo >= len(ec.symbols) {
return nil, nil, fmt.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
}
symbol := ec.symbols[symNo]
targets[symbol.Section] = true
rels[rel.Off] = ec.symbols[symNo]
}
symbol := symbols[symNo]
rels[rel.Off] = symbol
result[idx] = rels
}
return rels, nil
return result, targets, nil
}
func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]elf.Symbol {
result := make(map[elf.SectionIndex]map[uint64]elf.Symbol)
for _, sym := range symbols {
switch elf.ST_TYPE(sym.Info) {
case elf.STT_NOTYPE:
// Older versions of LLVM doesn't tag
// symbols correctly.
break
case elf.STT_OBJECT:
break
case elf.STT_FUNC:
break
default:
continue
}
if sym.Section == elf.SHN_UNDEF || sym.Section >= elf.SHN_LORESERVE {
continue
}
if sym.Name == "" {
continue
}
idx := sym.Section
if _, ok := result[idx]; !ok {
result[idx] = make(map[uint64]elf.Symbol)
}
result[idx][sym.Value] = sym
}
return result
}