vendor: cilium/ebbf 4032b1d8aae306b7bb94a2a11002932caf88c644
full diff: 60c3aa43f4...4032b1d8aa
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
			
			
This commit is contained in:
		| @@ -53,7 +53,7 @@ google.golang.org/grpc                              f495f5b15ae7ccda3b38c53a1bfc | ||||
| gotest.tools/v3                                     bb0d8a963040ea5048dcef1a14d8f8b58a33d4b3 # v3.0.2 | ||||
|  | ||||
| # cgroups dependencies | ||||
| github.com/cilium/ebpf                              60c3aa43f488292fe2ee50fb8b833b383ca8ebbb | ||||
| github.com/cilium/ebpf                              4032b1d8aae306b7bb94a2a11002932caf88c644 | ||||
|  | ||||
| # cri dependencies | ||||
| github.com/containerd/cri                           92cb4ed9786a6cd271152ba1f862183d84701003 # master | ||||
|   | ||||
							
								
								
									
										17
									
								
								vendor/github.com/cilium/ebpf/abi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/cilium/ebpf/abi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,6 +9,7 @@ import ( | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| @@ -31,7 +32,7 @@ func newMapABIFromSpec(spec *MapSpec) *MapABI { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newMapABIFromFd(fd *bpfFD) (string, *MapABI, error) { | ||||
| func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) { | ||||
| 	info, err := bpfGetMapInfoByFD(fd) | ||||
| 	if err != nil { | ||||
| 		if errors.Cause(err) == syscall.EINVAL { | ||||
| @@ -50,7 +51,7 @@ func newMapABIFromFd(fd *bpfFD) (string, *MapABI, error) { | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func newMapABIFromProc(fd *bpfFD) (*MapABI, error) { | ||||
| func newMapABIFromProc(fd *internal.FD) (*MapABI, error) { | ||||
| 	var abi MapABI | ||||
| 	err := scanFdInfo(fd, map[string]interface{}{ | ||||
| 		"map_type":    &abi.Type, | ||||
| @@ -94,7 +95,7 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func newProgramABIFromFd(fd *bpfFD) (string, *ProgramABI, error) { | ||||
| func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) { | ||||
| 	info, err := bpfGetProgInfoByFD(fd) | ||||
| 	if err != nil { | ||||
| 		if errors.Cause(err) == syscall.EINVAL { | ||||
| @@ -105,10 +106,10 @@ func newProgramABIFromFd(fd *bpfFD) (string, *ProgramABI, error) { | ||||
| 	} | ||||
|  | ||||
| 	var name string | ||||
| 	if bpfName := convertCString(info.name[:]); bpfName != "" { | ||||
| 	if bpfName := internal.CString(info.name[:]); bpfName != "" { | ||||
| 		name = bpfName | ||||
| 	} else { | ||||
| 		name = convertCString(info.tag[:]) | ||||
| 		name = internal.CString(info.tag[:]) | ||||
| 	} | ||||
|  | ||||
| 	return name, &ProgramABI{ | ||||
| @@ -116,7 +117,7 @@ func newProgramABIFromFd(fd *bpfFD) (string, *ProgramABI, error) { | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func newProgramABIFromProc(fd *bpfFD) (string, *ProgramABI, error) { | ||||
| func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) { | ||||
| 	var ( | ||||
| 		abi  ProgramABI | ||||
| 		name string | ||||
| @@ -139,8 +140,8 @@ func newProgramABIFromProc(fd *bpfFD) (string, *ProgramABI, error) { | ||||
| 	return name, &abi, nil | ||||
| } | ||||
|  | ||||
| func scanFdInfo(fd *bpfFD, fields map[string]interface{}) error { | ||||
| 	raw, err := fd.value() | ||||
| func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error { | ||||
| 	raw, err := fd.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										63
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,6 +2,7 @@ package ebpf | ||||
|  | ||||
| import ( | ||||
| 	"github.com/cilium/ebpf/asm" | ||||
| 	"github.com/cilium/ebpf/internal/btf" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| @@ -55,17 +56,61 @@ func NewCollection(spec *CollectionSpec) (*Collection, error) { | ||||
| // NewCollectionWithOptions creates a Collection from a specification. | ||||
| // | ||||
| // Only maps referenced by at least one of the programs are initialized. | ||||
| func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Collection, error) { | ||||
| 	maps := make(map[string]*Map) | ||||
| func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (coll *Collection, err error) { | ||||
| 	var ( | ||||
| 		maps  = make(map[string]*Map) | ||||
| 		progs = make(map[string]*Program) | ||||
| 		btfs  = make(map[*btf.Spec]*btf.Handle) | ||||
| 	) | ||||
|  | ||||
| 	defer func() { | ||||
| 		for _, btf := range btfs { | ||||
| 			btf.Close() | ||||
| 		} | ||||
|  | ||||
| 		if err == nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		for _, m := range maps { | ||||
| 			m.Close() | ||||
| 		} | ||||
|  | ||||
| 		for _, p := range progs { | ||||
| 			p.Close() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	loadBTF := func(spec *btf.Spec) (*btf.Handle, error) { | ||||
| 		if btfs[spec] != nil { | ||||
| 			return btfs[spec], nil | ||||
| 		} | ||||
|  | ||||
| 		handle, err := btf.NewHandle(spec) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		btfs[spec] = handle | ||||
| 		return handle, nil | ||||
| 	} | ||||
|  | ||||
| 	for mapName, mapSpec := range spec.Maps { | ||||
| 		m, err := NewMap(mapSpec) | ||||
| 		var handle *btf.Handle | ||||
| 		if mapSpec.BTF != nil { | ||||
| 			handle, err = loadBTF(btf.MapSpec(mapSpec.BTF)) | ||||
| 			if err != nil && !btf.IsNotSupported(err) { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		m, err := newMapWithBTF(mapSpec, handle) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "map %s", mapName) | ||||
| 		} | ||||
| 		maps[mapName] = m | ||||
| 	} | ||||
|  | ||||
| 	progs := make(map[string]*Program) | ||||
| 	for progName, origProgSpec := range spec.Programs { | ||||
| 		progSpec := origProgSpec.Copy() | ||||
|  | ||||
| @@ -91,7 +136,15 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		prog, err := NewProgramWithOptions(progSpec, opts.Programs) | ||||
| 		var handle *btf.Handle | ||||
| 		if progSpec.BTF != nil { | ||||
| 			handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF)) | ||||
| 			if err != nil && !btf.IsNotSupported(err) { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		prog, err := newProgramWithBTF(progSpec, handle, opts.Programs) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "program %s", progName) | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										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, | ||||
|   | ||||
							
								
								
									
										530
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,530 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"debug/elf" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const btfMagic = 0xeB9F | ||||
|  | ||||
| // Spec represents decoded BTF. | ||||
| type Spec struct { | ||||
| 	rawTypes  []rawType | ||||
| 	strings   stringTable | ||||
| 	types     map[string][]Type | ||||
| 	funcInfos map[string]extInfo | ||||
| 	lineInfos map[string]extInfo | ||||
| } | ||||
|  | ||||
| type btfHeader struct { | ||||
| 	Magic   uint16 | ||||
| 	Version uint8 | ||||
| 	Flags   uint8 | ||||
| 	HdrLen  uint32 | ||||
|  | ||||
| 	TypeOff   uint32 | ||||
| 	TypeLen   uint32 | ||||
| 	StringOff uint32 | ||||
| 	StringLen uint32 | ||||
| } | ||||
|  | ||||
| // LoadSpecFromReader reads BTF sections from an ELF. | ||||
| // | ||||
| // Returns a nil Spec and no error if no BTF was present. | ||||
| func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { | ||||
| 	file, err := elf.NewFile(rd) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer file.Close() | ||||
|  | ||||
| 	var ( | ||||
| 		btfSection    *elf.Section | ||||
| 		btfExtSection *elf.Section | ||||
| 	) | ||||
|  | ||||
| 	for _, sec := range file.Sections { | ||||
| 		switch sec.Name { | ||||
| 		case ".BTF": | ||||
| 			btfSection = sec | ||||
| 		case ".BTF.ext": | ||||
| 			btfExtSection = sec | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if btfSection == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	spec, err := parseBTF(btfSection.Open(), file.ByteOrder) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if btfExtSection != nil { | ||||
| 		spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't read ext info") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return spec, nil | ||||
| } | ||||
|  | ||||
| func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) { | ||||
| 	rawBTF, err := ioutil.ReadAll(btf) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read BTF") | ||||
| 	} | ||||
|  | ||||
| 	rd := bytes.NewReader(rawBTF) | ||||
|  | ||||
| 	var header btfHeader | ||||
| 	if err := binary.Read(rd, bo, &header); err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read header") | ||||
| 	} | ||||
|  | ||||
| 	if header.Magic != btfMagic { | ||||
| 		return nil, errors.Errorf("incorrect magic value %v", header.Magic) | ||||
| 	} | ||||
|  | ||||
| 	if header.Version != 1 { | ||||
| 		return nil, errors.Errorf("unexpected version %v", header.Version) | ||||
| 	} | ||||
|  | ||||
| 	if header.Flags != 0 { | ||||
| 		return nil, errors.Errorf("unsupported flags %v", header.Flags) | ||||
| 	} | ||||
|  | ||||
| 	remainder := int64(header.HdrLen) - int64(binary.Size(&header)) | ||||
| 	if remainder < 0 { | ||||
| 		return nil, errors.New("header is too short") | ||||
| 	} | ||||
|  | ||||
| 	if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil { | ||||
| 		return nil, errors.Wrap(err, "header padding") | ||||
| 	} | ||||
|  | ||||
| 	if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't seek to start of string section") | ||||
| 	} | ||||
|  | ||||
| 	strings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen))) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read type names") | ||||
| 	} | ||||
|  | ||||
| 	if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't seek to start of type section") | ||||
| 	} | ||||
|  | ||||
| 	rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read types") | ||||
| 	} | ||||
|  | ||||
| 	types, err := inflateRawTypes(rawTypes, strings) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &Spec{ | ||||
| 		rawTypes:  rawTypes, | ||||
| 		types:     types, | ||||
| 		strings:   strings, | ||||
| 		funcInfos: make(map[string]extInfo), | ||||
| 		lineInfos: make(map[string]extInfo), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) { | ||||
| 	var ( | ||||
| 		buf       bytes.Buffer | ||||
| 		header    = new(btfHeader) | ||||
| 		headerLen = binary.Size(header) | ||||
| 	) | ||||
|  | ||||
| 	// Reserve space for the header. We have to write it last since | ||||
| 	// we don't know the size of the type section yet. | ||||
| 	_, _ = buf.Write(make([]byte, headerLen)) | ||||
|  | ||||
| 	// Write type section, just after the header. | ||||
| 	for _, typ := range s.rawTypes { | ||||
| 		if typ.Kind() == kindDatasec { | ||||
| 			// Datasec requires patching with information from the ELF | ||||
| 			// file. We don't support this at the moment, so patch | ||||
| 			// out any Datasec by turning it into a void*. | ||||
| 			typ = rawType{} | ||||
| 			typ.SetKind(kindPointer) | ||||
| 		} | ||||
|  | ||||
| 		if err := typ.Marshal(&buf, bo); err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't marshal BTF") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	typeLen := uint32(buf.Len() - headerLen) | ||||
|  | ||||
| 	// Write string section after type section. | ||||
| 	_, _ = buf.Write(s.strings) | ||||
|  | ||||
| 	// Fill out the header, and write it out. | ||||
| 	header = &btfHeader{ | ||||
| 		Magic:     btfMagic, | ||||
| 		Version:   1, | ||||
| 		Flags:     0, | ||||
| 		HdrLen:    uint32(headerLen), | ||||
| 		TypeOff:   0, | ||||
| 		TypeLen:   typeLen, | ||||
| 		StringOff: typeLen, | ||||
| 		StringLen: uint32(len(s.strings)), | ||||
| 	} | ||||
|  | ||||
| 	raw := buf.Bytes() | ||||
| 	err := binary.Write(sliceWriter(raw[:headerLen]), bo, header) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't write header") | ||||
| 	} | ||||
|  | ||||
| 	return raw, nil | ||||
| } | ||||
|  | ||||
| type sliceWriter []byte | ||||
|  | ||||
| func (sw sliceWriter) Write(p []byte) (int, error) { | ||||
| 	if len(p) != len(sw) { | ||||
| 		return 0, errors.New("size doesn't match") | ||||
| 	} | ||||
|  | ||||
| 	return copy(sw, p), nil | ||||
| } | ||||
|  | ||||
| // Program finds the BTF for a specific section. | ||||
| // | ||||
| // Length is the number of bytes in the raw BPF instruction stream. | ||||
| // | ||||
| // Returns an error if there is no BTF. | ||||
| func (s *Spec) Program(name string, length uint64) (*Program, error) { | ||||
| 	if length == 0 { | ||||
| 		return nil, errors.New("length musn't be zero") | ||||
| 	} | ||||
|  | ||||
| 	funcInfos, funcOK := s.funcInfos[name] | ||||
| 	lineInfos, lineOK := s.lineInfos[name] | ||||
|  | ||||
| 	if !funcOK && !lineOK { | ||||
| 		return nil, errors.Errorf("no BTF for program %s", name) | ||||
| 	} | ||||
|  | ||||
| 	return &Program{s, length, funcInfos, lineInfos}, nil | ||||
| } | ||||
|  | ||||
| // Map finds the BTF for a map. | ||||
| // | ||||
| // Returns an error if there is no BTF for the given name. | ||||
| func (s *Spec) Map(name string) (*Map, error) { | ||||
| 	var mapVar Var | ||||
| 	if err := s.FindType(name, &mapVar); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	mapStruct, ok := mapVar.Type.(*Struct) | ||||
| 	if !ok { | ||||
| 		return nil, errors.Errorf("expected struct, have %s", mapVar.Type) | ||||
| 	} | ||||
|  | ||||
| 	var key, value Type | ||||
| 	for _, member := range mapStruct.Members { | ||||
| 		switch member.Name { | ||||
| 		case "key": | ||||
| 			key = member.Type | ||||
|  | ||||
| 		case "value": | ||||
| 			value = member.Type | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if key == nil { | ||||
| 		return nil, errors.Errorf("map %s: missing 'key' in type", name) | ||||
| 	} | ||||
|  | ||||
| 	if value == nil { | ||||
| 		return nil, errors.Errorf("map %s: missing 'value' in type", name) | ||||
| 	} | ||||
|  | ||||
| 	return &Map{mapStruct, s, key, value}, nil | ||||
| } | ||||
|  | ||||
| var errNotFound = errors.New("not found") | ||||
|  | ||||
| // FindType searches for a type with a specific name. | ||||
| // | ||||
| // hint determines the type of the returned Type. | ||||
| // | ||||
| // Returns an error if there is no or multiple matches. | ||||
| func (s *Spec) FindType(name string, typ Type) error { | ||||
| 	var ( | ||||
| 		wanted    = reflect.TypeOf(typ) | ||||
| 		candidate Type | ||||
| 	) | ||||
|  | ||||
| 	for _, typ := range s.types[name] { | ||||
| 		if reflect.TypeOf(typ) != wanted { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if candidate != nil { | ||||
| 			return errors.Errorf("type %s: multiple candidates for %T", name, typ) | ||||
| 		} | ||||
|  | ||||
| 		candidate = typ | ||||
| 	} | ||||
|  | ||||
| 	if candidate == nil { | ||||
| 		return errors.WithMessagef(errNotFound, "type %s", name) | ||||
| 	} | ||||
|  | ||||
| 	value := reflect.Indirect(reflect.ValueOf(copyType(candidate))) | ||||
| 	reflect.Indirect(reflect.ValueOf(typ)).Set(value) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Handle is a reference to BTF loaded into the kernel. | ||||
| type Handle struct { | ||||
| 	fd *internal.FD | ||||
| } | ||||
|  | ||||
| // NewHandle loads BTF into the kernel. | ||||
| // | ||||
| // Returns an error if BTF is not supported, which can | ||||
| // be checked by IsNotSupported. | ||||
| func NewHandle(spec *Spec) (*Handle, error) { | ||||
| 	if err := haveBTF(); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	btf, err := spec.marshal(internal.NativeEndian) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't marshal BTF") | ||||
| 	} | ||||
|  | ||||
| 	if uint64(len(btf)) > math.MaxUint32 { | ||||
| 		return nil, errors.New("BTF exceeds the maximum size") | ||||
| 	} | ||||
|  | ||||
| 	attr := &bpfLoadBTFAttr{ | ||||
| 		btf:     internal.NewSlicePointer(btf), | ||||
| 		btfSize: uint32(len(btf)), | ||||
| 	} | ||||
|  | ||||
| 	fd, err := bpfLoadBTF(attr) | ||||
| 	if err != nil { | ||||
| 		logBuf := make([]byte, 64*1024) | ||||
| 		attr.logBuf = internal.NewSlicePointer(logBuf) | ||||
| 		attr.btfLogSize = uint32(len(logBuf)) | ||||
| 		attr.btfLogLevel = 1 | ||||
| 		_, logErr := bpfLoadBTF(attr) | ||||
| 		return nil, internal.ErrorWithLog(err, logBuf, logErr) | ||||
| 	} | ||||
|  | ||||
| 	return &Handle{fd}, nil | ||||
| } | ||||
|  | ||||
| // Close destroys the handle. | ||||
| // | ||||
| // Subsequent calls to FD will return an invalid value. | ||||
| func (h *Handle) Close() error { | ||||
| 	return h.fd.Close() | ||||
| } | ||||
|  | ||||
| // FD returns the file descriptor for the handle. | ||||
| func (h *Handle) FD() int { | ||||
| 	value, err := h.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return -1 | ||||
| 	} | ||||
|  | ||||
| 	return int(value) | ||||
| } | ||||
|  | ||||
| // Map is the BTF for a map. | ||||
| type Map struct { | ||||
| 	definition *Struct | ||||
| 	spec       *Spec | ||||
| 	key, value Type | ||||
| } | ||||
|  | ||||
| // MapSpec should be a method on Map, but is a free function | ||||
| // to hide it from users of the ebpf package. | ||||
| func MapSpec(m *Map) *Spec { | ||||
| 	return m.spec | ||||
| } | ||||
|  | ||||
| // MapType should be a method on Map, but is a free function | ||||
| // to hide it from users of the ebpf package. | ||||
| func MapType(m *Map) *Struct { | ||||
| 	return m.definition | ||||
| } | ||||
|  | ||||
| // MapKey should be a method on Map, but is a free function | ||||
| // to hide it from users of the ebpf package. | ||||
| func MapKey(m *Map) Type { | ||||
| 	return m.key | ||||
| } | ||||
|  | ||||
| // MapValue should be a method on Map, but is a free function | ||||
| // to hide it from users of the ebpf package. | ||||
| func MapValue(m *Map) Type { | ||||
| 	return m.value | ||||
| } | ||||
|  | ||||
| // Program is the BTF information for a stream of instructions. | ||||
| type Program struct { | ||||
| 	spec                 *Spec | ||||
| 	length               uint64 | ||||
| 	funcInfos, lineInfos extInfo | ||||
| } | ||||
|  | ||||
| // ProgramSpec returns the Spec needed for loading function and line infos into the kernel. | ||||
| // | ||||
| // This is a free function instead of a method to hide it from users | ||||
| // of package ebpf. | ||||
| func ProgramSpec(s *Program) *Spec { | ||||
| 	return s.spec | ||||
| } | ||||
|  | ||||
| // ProgramAppend the information from other to the Program. | ||||
| // | ||||
| // This is a free function instead of a method to hide it from users | ||||
| // of package ebpf. | ||||
| func ProgramAppend(s, other *Program) error { | ||||
| 	funcInfos, err := s.funcInfos.append(other.funcInfos, s.length) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "func infos") | ||||
| 	} | ||||
|  | ||||
| 	lineInfos, err := s.lineInfos.append(other.lineInfos, s.length) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "line infos") | ||||
| 	} | ||||
|  | ||||
| 	s.length += other.length | ||||
| 	s.funcInfos = funcInfos | ||||
| 	s.lineInfos = lineInfos | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ProgramFuncInfos returns the binary form of BTF function infos. | ||||
| // | ||||
| // This is a free function instead of a method to hide it from users | ||||
| // of package ebpf. | ||||
| func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) { | ||||
| 	bytes, err = s.funcInfos.MarshalBinary() | ||||
| 	if err != nil { | ||||
| 		return 0, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return s.funcInfos.recordSize, bytes, nil | ||||
| } | ||||
|  | ||||
| // ProgramLineInfos returns the binary form of BTF line infos. | ||||
| // | ||||
| // This is a free function instead of a method to hide it from users | ||||
| // of package ebpf. | ||||
| func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) { | ||||
| 	bytes, err = s.lineInfos.MarshalBinary() | ||||
| 	if err != nil { | ||||
| 		return 0, nil, err | ||||
| 	} | ||||
|  | ||||
| 	return s.lineInfos.recordSize, bytes, nil | ||||
| } | ||||
|  | ||||
| // IsNotSupported returns true if the error indicates that the kernel | ||||
| // doesn't support BTF. | ||||
| func IsNotSupported(err error) bool { | ||||
| 	ufe, ok := errors.Cause(err).(*internal.UnsupportedFeatureError) | ||||
| 	return ok && ufe.Name == "BTF" | ||||
| } | ||||
|  | ||||
| type bpfLoadBTFAttr struct { | ||||
| 	btf         internal.Pointer | ||||
| 	logBuf      internal.Pointer | ||||
| 	btfSize     uint32 | ||||
| 	btfLogSize  uint32 | ||||
| 	btfLogLevel uint32 | ||||
| } | ||||
|  | ||||
| func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) { | ||||
| 	const _BTFLoad = 18 | ||||
|  | ||||
| 	fd, err := internal.BPF(_BTFLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return internal.NewFD(uint32(fd)), nil | ||||
| } | ||||
|  | ||||
| func minimalBTF(bo binary.ByteOrder) []byte { | ||||
| 	const minHeaderLength = 24 | ||||
|  | ||||
| 	var ( | ||||
| 		types struct { | ||||
| 			Integer btfType | ||||
| 			Var     btfType | ||||
| 			btfVar  struct{ Linkage uint32 } | ||||
| 		} | ||||
| 		typLen  = uint32(binary.Size(&types)) | ||||
| 		strings = []byte{0, 'a', 0} | ||||
| 		header  = btfHeader{ | ||||
| 			Magic:     btfMagic, | ||||
| 			Version:   1, | ||||
| 			HdrLen:    minHeaderLength, | ||||
| 			TypeOff:   0, | ||||
| 			TypeLen:   typLen, | ||||
| 			StringOff: typLen, | ||||
| 			StringLen: uint32(len(strings)), | ||||
| 		} | ||||
| 	) | ||||
|  | ||||
| 	// We use a BTF_KIND_VAR here, to make sure that | ||||
| 	// the kernel understands BTF at least as well as we | ||||
| 	// do. BTF_KIND_VAR was introduced ~5.1. | ||||
| 	types.Integer.SetKind(kindPointer) | ||||
| 	types.Var.NameOff = 1 | ||||
| 	types.Var.SetKind(kindVar) | ||||
| 	types.Var.SizeType = 1 | ||||
|  | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	_ = binary.Write(buf, bo, &header) | ||||
| 	_ = binary.Write(buf, bo, &types) | ||||
| 	buf.Write(strings) | ||||
|  | ||||
| 	return buf.Bytes() | ||||
| } | ||||
|  | ||||
| var haveBTF = internal.FeatureTest("BTF", "5.1", func() bool { | ||||
| 	btf := minimalBTF(internal.NativeEndian) | ||||
| 	fd, err := bpfLoadBTF(&bpfLoadBTFAttr{ | ||||
| 		btf:     internal.NewSlicePointer(btf), | ||||
| 		btfSize: uint32(len(btf)), | ||||
| 	}) | ||||
| 	if err == nil { | ||||
| 		fd.Close() | ||||
| 	} | ||||
| 	// Check for EINVAL specifically, rather than err != nil since we | ||||
| 	// otherwise misdetect due to insufficient permissions. | ||||
| 	return errors.Cause(err) != unix.EINVAL | ||||
| }) | ||||
							
								
								
									
										190
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // btfKind describes a Type. | ||||
| type btfKind uint8 | ||||
|  | ||||
| // Equivalents of the BTF_KIND_* constants. | ||||
| const ( | ||||
| 	kindUnknown btfKind = iota | ||||
| 	kindInt | ||||
| 	kindPointer | ||||
| 	kindArray | ||||
| 	kindStruct | ||||
| 	kindUnion | ||||
| 	kindEnum | ||||
| 	kindForward | ||||
| 	kindTypedef | ||||
| 	kindVolatile | ||||
| 	kindConst | ||||
| 	kindRestrict | ||||
| 	// Added ~4.20 | ||||
| 	kindFunc | ||||
| 	kindFuncProto | ||||
| 	// Added ~5.1 | ||||
| 	kindVar | ||||
| 	kindDatasec | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	btfTypeKindShift = 24 | ||||
| 	btfTypeKindLen   = 4 | ||||
| 	btfTypeVlenShift = 0 | ||||
| 	btfTypeVlenMask  = 16 | ||||
| ) | ||||
|  | ||||
| // btfType is equivalent to struct btf_type in Documentation/bpf/btf.rst. | ||||
| type btfType struct { | ||||
| 	NameOff uint32 | ||||
| 	/* "info" bits arrangement | ||||
| 	 * bits  0-15: vlen (e.g. # of struct's members) | ||||
| 	 * bits 16-23: unused | ||||
| 	 * bits 24-27: kind (e.g. int, ptr, array...etc) | ||||
| 	 * bits 28-30: unused | ||||
| 	 * bit     31: kind_flag, currently used by | ||||
| 	 *             struct, union and fwd | ||||
| 	 */ | ||||
| 	Info uint32 | ||||
| 	/* "size" is used by INT, ENUM, STRUCT and UNION. | ||||
| 	 * "size" tells the size of the type it is describing. | ||||
| 	 * | ||||
| 	 * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, | ||||
| 	 * FUNC and FUNC_PROTO. | ||||
| 	 * "type" is a type_id referring to another type. | ||||
| 	 */ | ||||
| 	SizeType uint32 | ||||
| } | ||||
|  | ||||
| func mask(len uint32) uint32 { | ||||
| 	return (1 << len) - 1 | ||||
| } | ||||
|  | ||||
| func (bt *btfType) info(len, shift uint32) uint32 { | ||||
| 	return (bt.Info >> shift) & mask(len) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) setInfo(value, len, shift uint32) { | ||||
| 	bt.Info &^= mask(len) << shift | ||||
| 	bt.Info |= (value & mask(len)) << shift | ||||
| } | ||||
|  | ||||
| func (bt *btfType) Kind() btfKind { | ||||
| 	return btfKind(bt.info(btfTypeKindLen, btfTypeKindShift)) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) SetKind(kind btfKind) { | ||||
| 	bt.setInfo(uint32(kind), btfTypeKindLen, btfTypeKindShift) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) Vlen() int { | ||||
| 	return int(bt.info(btfTypeVlenMask, btfTypeVlenShift)) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) SetVlen(vlen int) { | ||||
| 	bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) Type() TypeID { | ||||
| 	// TODO: Panic here if wrong kind? | ||||
| 	return TypeID(bt.SizeType) | ||||
| } | ||||
|  | ||||
| func (bt *btfType) Size() uint32 { | ||||
| 	// TODO: Panic here if wrong kind? | ||||
| 	return bt.SizeType | ||||
| } | ||||
|  | ||||
| type rawType struct { | ||||
| 	btfType | ||||
| 	data interface{} | ||||
| } | ||||
|  | ||||
| func (rt *rawType) Marshal(w io.Writer, bo binary.ByteOrder) error { | ||||
| 	if err := binary.Write(w, bo, &rt.btfType); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if rt.data == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return binary.Write(w, bo, rt.data) | ||||
| } | ||||
|  | ||||
| type btfArray struct { | ||||
| 	Type      TypeID | ||||
| 	IndexType TypeID | ||||
| 	Nelems    uint32 | ||||
| } | ||||
|  | ||||
| type btfMember struct { | ||||
| 	NameOff uint32 | ||||
| 	Type    TypeID | ||||
| 	Offset  uint32 | ||||
| } | ||||
|  | ||||
| func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) { | ||||
| 	var ( | ||||
| 		header btfType | ||||
| 		types  []rawType | ||||
| 	) | ||||
|  | ||||
| 	for id := TypeID(1); ; id++ { | ||||
| 		if err := binary.Read(r, bo, &header); err == io.EOF { | ||||
| 			return types, nil | ||||
| 		} else if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "can't read type info for id %v", id) | ||||
| 		} | ||||
|  | ||||
| 		var data interface{} | ||||
| 		switch header.Kind() { | ||||
| 		case kindInt: | ||||
| 			// sizeof(uint32) | ||||
| 			data = make([]byte, 4) | ||||
| 		case kindPointer: | ||||
| 		case kindArray: | ||||
| 			data = new(btfArray) | ||||
| 		case kindStruct: | ||||
| 			fallthrough | ||||
| 		case kindUnion: | ||||
| 			data = make([]btfMember, header.Vlen()) | ||||
| 		case kindEnum: | ||||
| 			// sizeof(struct btf_enum) | ||||
| 			data = make([]byte, header.Vlen()*4*2) | ||||
| 		case kindForward: | ||||
| 		case kindTypedef: | ||||
| 		case kindVolatile: | ||||
| 		case kindConst: | ||||
| 		case kindRestrict: | ||||
| 		case kindFunc: | ||||
| 		case kindFuncProto: | ||||
| 			// sizeof(struct btf_param) | ||||
| 			data = make([]byte, header.Vlen()*4*2) | ||||
| 		case kindVar: | ||||
| 			// sizeof(struct btf_variable) | ||||
| 			data = make([]byte, 4) | ||||
| 		case kindDatasec: | ||||
| 			// sizeof(struct btf_var_secinfo) | ||||
| 			data = make([]byte, header.Vlen()*4*3) | ||||
| 		default: | ||||
| 			return nil, errors.Errorf("type id %v: unknown kind: %v", id, header.Kind()) | ||||
| 		} | ||||
|  | ||||
| 		if data == nil { | ||||
| 			types = append(types, rawType{header, nil}) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if err := binary.Read(r, bo, data); err != nil { | ||||
| 			return nil, errors.Wrapf(err, "type id %d: kind %v: can't read %T", id, header.Kind(), data) | ||||
| 		} | ||||
|  | ||||
| 		types = append(types, rawType{header, data}) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										8
									
								
								vendor/github.com/cilium/ebpf/internal/btf/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/cilium/ebpf/internal/btf/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| // Package btf handles data encoded according to the BPF Type Format. | ||||
| // | ||||
| // The canonical documentation lives in the Linux kernel repository and is | ||||
| // available at https://www.kernel.org/doc/html/latest/bpf/btf.html | ||||
| // | ||||
| // The API is very much unstable. You should only use this via the main | ||||
| // ebpf library. | ||||
| package btf | ||||
							
								
								
									
										184
									
								
								vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/asm" | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type btfExtHeader struct { | ||||
| 	Magic   uint16 | ||||
| 	Version uint8 | ||||
| 	Flags   uint8 | ||||
| 	HdrLen  uint32 | ||||
|  | ||||
| 	FuncInfoOff uint32 | ||||
| 	FuncInfoLen uint32 | ||||
| 	LineInfoOff uint32 | ||||
| 	LineInfoLen uint32 | ||||
| } | ||||
|  | ||||
| func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) { | ||||
| 	const expectedMagic = 0xeB9F | ||||
|  | ||||
| 	var header btfExtHeader | ||||
| 	if err := binary.Read(r, bo, &header); err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "can't read header") | ||||
| 	} | ||||
|  | ||||
| 	if header.Magic != expectedMagic { | ||||
| 		return nil, nil, errors.Errorf("incorrect magic value %v", header.Magic) | ||||
| 	} | ||||
|  | ||||
| 	if header.Version != 1 { | ||||
| 		return nil, nil, errors.Errorf("unexpected version %v", header.Version) | ||||
| 	} | ||||
|  | ||||
| 	if header.Flags != 0 { | ||||
| 		return nil, nil, errors.Errorf("unsupported flags %v", header.Flags) | ||||
| 	} | ||||
|  | ||||
| 	remainder := int64(header.HdrLen) - int64(binary.Size(&header)) | ||||
| 	if remainder < 0 { | ||||
| 		return nil, nil, errors.New("header is too short") | ||||
| 	} | ||||
|  | ||||
| 	// Of course, the .BTF.ext header has different semantics than the | ||||
| 	// .BTF ext header. We need to ignore non-null values. | ||||
| 	_, err = io.CopyN(ioutil.Discard, r, remainder) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "header padding") | ||||
| 	} | ||||
|  | ||||
| 	if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "can't seek to function info section") | ||||
| 	} | ||||
|  | ||||
| 	funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "function info") | ||||
| 	} | ||||
|  | ||||
| 	if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "can't seek to line info section") | ||||
| 	} | ||||
|  | ||||
| 	lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, errors.Wrap(err, "line info") | ||||
| 	} | ||||
|  | ||||
| 	return funcInfo, lineInfo, nil | ||||
| } | ||||
|  | ||||
| type btfExtInfoSec struct { | ||||
| 	SecNameOff uint32 | ||||
| 	NumInfo    uint32 | ||||
| } | ||||
|  | ||||
| type extInfoRecord struct { | ||||
| 	InsnOff uint64 | ||||
| 	Opaque  []byte | ||||
| } | ||||
|  | ||||
| type extInfo struct { | ||||
| 	recordSize uint32 | ||||
| 	records    []extInfoRecord | ||||
| } | ||||
|  | ||||
| func (ei extInfo) append(other extInfo, offset uint64) (extInfo, error) { | ||||
| 	if other.recordSize != ei.recordSize { | ||||
| 		return extInfo{}, errors.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize) | ||||
| 	} | ||||
|  | ||||
| 	records := make([]extInfoRecord, 0, len(ei.records)+len(other.records)) | ||||
| 	records = append(records, ei.records...) | ||||
| 	for _, info := range other.records { | ||||
| 		records = append(records, extInfoRecord{ | ||||
| 			InsnOff: info.InsnOff + offset, | ||||
| 			Opaque:  info.Opaque, | ||||
| 		}) | ||||
| 	} | ||||
| 	return extInfo{ei.recordSize, records}, nil | ||||
| } | ||||
|  | ||||
| func (ei extInfo) MarshalBinary() ([]byte, error) { | ||||
| 	if len(ei.records) == 0 { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	buf := bytes.NewBuffer(make([]byte, 0, int(ei.recordSize)*len(ei.records))) | ||||
| 	for _, info := range ei.records { | ||||
| 		// The kernel expects offsets in number of raw bpf instructions, | ||||
| 		// while the ELF tracks it in bytes. | ||||
| 		insnOff := uint32(info.InsnOff / asm.InstructionSize) | ||||
| 		if err := binary.Write(buf, internal.NativeEndian, insnOff); err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't write instruction offset") | ||||
| 		} | ||||
|  | ||||
| 		buf.Write(info.Opaque) | ||||
| 	} | ||||
|  | ||||
| 	return buf.Bytes(), nil | ||||
| } | ||||
|  | ||||
| func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]extInfo, error) { | ||||
| 	var recordSize uint32 | ||||
| 	if err := binary.Read(r, bo, &recordSize); err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read record size") | ||||
| 	} | ||||
|  | ||||
| 	if recordSize < 4 { | ||||
| 		// Need at least insnOff | ||||
| 		return nil, errors.New("record size too short") | ||||
| 	} | ||||
|  | ||||
| 	result := make(map[string]extInfo) | ||||
| 	for { | ||||
| 		var infoHeader btfExtInfoSec | ||||
| 		if err := binary.Read(r, bo, &infoHeader); err == io.EOF { | ||||
| 			return result, nil | ||||
| 		} else if err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't read ext info header") | ||||
| 		} | ||||
|  | ||||
| 		secName, err := strings.Lookup(infoHeader.SecNameOff) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't get section name") | ||||
| 		} | ||||
|  | ||||
| 		if infoHeader.NumInfo == 0 { | ||||
| 			return nil, errors.Errorf("section %s has invalid number of records", secName) | ||||
| 		} | ||||
|  | ||||
| 		var records []extInfoRecord | ||||
| 		for i := uint32(0); i < infoHeader.NumInfo; i++ { | ||||
| 			var byteOff uint32 | ||||
| 			if err := binary.Read(r, bo, &byteOff); err != nil { | ||||
| 				return nil, errors.Wrapf(err, "section %v: can't read extended info offset", secName) | ||||
| 			} | ||||
|  | ||||
| 			buf := make([]byte, int(recordSize-4)) | ||||
| 			if _, err := io.ReadFull(r, buf); err != nil { | ||||
| 				return nil, errors.Wrapf(err, "section %v: can't read record", secName) | ||||
| 			} | ||||
|  | ||||
| 			if byteOff%asm.InstructionSize != 0 { | ||||
| 				return nil, errors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff) | ||||
| 			} | ||||
|  | ||||
| 			records = append(records, extInfoRecord{uint64(byteOff), buf}) | ||||
| 		} | ||||
|  | ||||
| 		result[secName] = extInfo{ | ||||
| 			recordSize, | ||||
| 			records, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										60
									
								
								vendor/github.com/cilium/ebpf/internal/btf/strings.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/cilium/ebpf/internal/btf/strings.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type stringTable []byte | ||||
|  | ||||
| func readStringTable(r io.Reader) (stringTable, error) { | ||||
| 	contents, err := ioutil.ReadAll(r) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't read string table") | ||||
| 	} | ||||
|  | ||||
| 	if len(contents) < 1 { | ||||
| 		return nil, errors.New("string table is empty") | ||||
| 	} | ||||
|  | ||||
| 	if contents[0] != '\x00' { | ||||
| 		return nil, errors.New("first item in string table is non-empty") | ||||
| 	} | ||||
|  | ||||
| 	if contents[len(contents)-1] != '\x00' { | ||||
| 		return nil, errors.New("string table isn't null terminated") | ||||
| 	} | ||||
|  | ||||
| 	return stringTable(contents), nil | ||||
| } | ||||
|  | ||||
| func (st stringTable) Lookup(offset uint32) (string, error) { | ||||
| 	if int64(offset) > int64(^uint(0)>>1) { | ||||
| 		return "", errors.Errorf("offset %d overflows int", offset) | ||||
| 	} | ||||
|  | ||||
| 	pos := int(offset) | ||||
| 	if pos >= len(st) { | ||||
| 		return "", errors.Errorf("offset %d is out of bounds", offset) | ||||
| 	} | ||||
|  | ||||
| 	if pos > 0 && st[pos-1] != '\x00' { | ||||
| 		return "", errors.Errorf("offset %d isn't start of a string", offset) | ||||
| 	} | ||||
|  | ||||
| 	str := st[pos:] | ||||
| 	end := bytes.IndexByte(str, '\x00') | ||||
| 	if end == -1 { | ||||
| 		return "", errors.Errorf("offset %d isn't null terminated", offset) | ||||
| 	} | ||||
|  | ||||
| 	return string(str[:end]), nil | ||||
| } | ||||
|  | ||||
| func (st stringTable) LookupName(offset uint32) (Name, error) { | ||||
| 	str, err := st.Lookup(offset) | ||||
| 	return Name(str), err | ||||
| } | ||||
							
								
								
									
										550
									
								
								vendor/github.com/cilium/ebpf/internal/btf/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										550
									
								
								vendor/github.com/cilium/ebpf/internal/btf/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,550 @@ | ||||
| package btf | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const maxTypeDepth = 32 | ||||
|  | ||||
| // TypeID identifies a type in a BTF section. | ||||
| type TypeID uint32 | ||||
|  | ||||
| // ID implements part of the Type interface. | ||||
| func (tid TypeID) ID() TypeID { | ||||
| 	return tid | ||||
| } | ||||
|  | ||||
| // Type represents a type described by BTF. | ||||
| type Type interface { | ||||
| 	ID() TypeID | ||||
|  | ||||
| 	// Make a copy of the type, without copying Type members. | ||||
| 	copy() Type | ||||
|  | ||||
| 	walk(*copyStack) | ||||
| } | ||||
|  | ||||
| // Name identifies a type. | ||||
| // | ||||
| // Anonymous types have an empty name. | ||||
| type Name string | ||||
|  | ||||
| func (n Name) name() string { | ||||
| 	return string(n) | ||||
| } | ||||
|  | ||||
| // Void is the unit type of BTF. | ||||
| type Void struct{} | ||||
|  | ||||
| func (v Void) ID() TypeID      { return 0 } | ||||
| func (v Void) copy() Type      { return Void{} } | ||||
| func (v Void) walk(*copyStack) {} | ||||
|  | ||||
| // Int is an integer of a given length. | ||||
| type Int struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
|  | ||||
| 	// The size of the integer in bytes. | ||||
| 	Size uint32 | ||||
| } | ||||
|  | ||||
| func (i *Int) size() uint32    { return i.Size } | ||||
| func (i *Int) walk(*copyStack) {} | ||||
| func (i *Int) copy() Type { | ||||
| 	cpy := *i | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Pointer is a pointer to another type. | ||||
| type Pointer struct { | ||||
| 	TypeID | ||||
| 	Target Type | ||||
| } | ||||
|  | ||||
| func (p *Pointer) size() uint32       { return 8 } | ||||
| func (p *Pointer) walk(cs *copyStack) { cs.push(&p.Target) } | ||||
| func (p *Pointer) copy() Type { | ||||
| 	cpy := *p | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Array is an array with a fixed number of elements. | ||||
| type Array struct { | ||||
| 	TypeID | ||||
| 	Type   Type | ||||
| 	Nelems uint32 | ||||
| } | ||||
|  | ||||
| func (arr *Array) walk(cs *copyStack) { cs.push(&arr.Type) } | ||||
| func (arr *Array) copy() Type { | ||||
| 	cpy := *arr | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Struct is a compound type of consecutive members. | ||||
| type Struct struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	// The size of the struct including padding, in bytes | ||||
| 	Size    uint32 | ||||
| 	Members []Member | ||||
| } | ||||
|  | ||||
| func (s *Struct) size() uint32 { return s.Size } | ||||
|  | ||||
| func (s *Struct) walk(cs *copyStack) { | ||||
| 	for i := range s.Members { | ||||
| 		cs.push(&s.Members[i].Type) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *Struct) copy() Type { | ||||
| 	cpy := *s | ||||
| 	cpy.Members = copyMembers(cpy.Members) | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Union is a compound type where members occupy the same memory. | ||||
| type Union struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	// The size of the union including padding, in bytes. | ||||
| 	Size    uint32 | ||||
| 	Members []Member | ||||
| } | ||||
|  | ||||
| func (u *Union) size() uint32 { return u.Size } | ||||
|  | ||||
| func (u *Union) walk(cs *copyStack) { | ||||
| 	for i := range u.Members { | ||||
| 		cs.push(&u.Members[i].Type) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (u *Union) copy() Type { | ||||
| 	cpy := *u | ||||
| 	cpy.Members = copyMembers(cpy.Members) | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Member is part of a Struct or Union. | ||||
| // | ||||
| // It is not a valid Type. | ||||
| type Member struct { | ||||
| 	Name | ||||
| 	Type   Type | ||||
| 	Offset uint32 | ||||
| } | ||||
|  | ||||
| func copyMembers(in []Member) []Member { | ||||
| 	cpy := make([]Member, 0, len(in)) | ||||
| 	for _, member := range in { | ||||
| 		cpy = append(cpy, member) | ||||
| 	} | ||||
| 	return cpy | ||||
| } | ||||
|  | ||||
| // Enum lists possible values. | ||||
| type Enum struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| } | ||||
|  | ||||
| func (e *Enum) size() uint32    { return 4 } | ||||
| func (e *Enum) walk(*copyStack) {} | ||||
| func (e *Enum) copy() Type { | ||||
| 	cpy := *e | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Fwd is a forward declaration of a Type. | ||||
| type Fwd struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| } | ||||
|  | ||||
| func (f *Fwd) walk(*copyStack) {} | ||||
| func (f *Fwd) copy() Type { | ||||
| 	cpy := *f | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Typedef is an alias of a Type. | ||||
| type Typedef struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (td *Typedef) walk(cs *copyStack) { cs.push(&td.Type) } | ||||
| func (td *Typedef) copy() Type { | ||||
| 	cpy := *td | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Volatile is a modifier. | ||||
| type Volatile struct { | ||||
| 	TypeID | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (v *Volatile) walk(cs *copyStack) { cs.push(&v.Type) } | ||||
| func (v *Volatile) copy() Type { | ||||
| 	cpy := *v | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Const is a modifier. | ||||
| type Const struct { | ||||
| 	TypeID | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (c *Const) walk(cs *copyStack) { cs.push(&c.Type) } | ||||
| func (c *Const) copy() Type { | ||||
| 	cpy := *c | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Restrict is a modifier. | ||||
| type Restrict struct { | ||||
| 	TypeID | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (r *Restrict) walk(cs *copyStack) { cs.push(&r.Type) } | ||||
| func (r *Restrict) copy() Type { | ||||
| 	cpy := *r | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Func is a function definition. | ||||
| type Func struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (f *Func) walk(cs *copyStack) { cs.push(&f.Type) } | ||||
| func (f *Func) copy() Type { | ||||
| 	cpy := *f | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // FuncProto is a function declaration. | ||||
| type FuncProto struct { | ||||
| 	TypeID | ||||
| 	Return Type | ||||
| 	// Parameters not supported yet | ||||
| } | ||||
|  | ||||
| func (fp *FuncProto) walk(cs *copyStack) { cs.push(&fp.Return) } | ||||
| func (fp *FuncProto) copy() Type { | ||||
| 	cpy := *fp | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Var is a global variable. | ||||
| type Var struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	Type Type | ||||
| } | ||||
|  | ||||
| func (v *Var) walk(cs *copyStack) { cs.push(&v.Type) } | ||||
| func (v *Var) copy() Type { | ||||
| 	cpy := *v | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| // Datasec is a global program section containing data. | ||||
| type Datasec struct { | ||||
| 	TypeID | ||||
| 	Name | ||||
| 	Size uint32 | ||||
| } | ||||
|  | ||||
| func (ds *Datasec) size() uint32    { return ds.Size } | ||||
| func (ds *Datasec) walk(*copyStack) {} | ||||
| func (ds *Datasec) copy() Type { | ||||
| 	cpy := *ds | ||||
| 	return &cpy | ||||
| } | ||||
|  | ||||
| type sizer interface { | ||||
| 	size() uint32 | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	_ sizer = (*Int)(nil) | ||||
| 	_ sizer = (*Pointer)(nil) | ||||
| 	_ sizer = (*Struct)(nil) | ||||
| 	_ sizer = (*Union)(nil) | ||||
| 	_ sizer = (*Enum)(nil) | ||||
| 	_ sizer = (*Datasec)(nil) | ||||
| ) | ||||
|  | ||||
| // Sizeof returns the size of a type in bytes. | ||||
| // | ||||
| // Returns an error if the size can't be computed. | ||||
| func Sizeof(typ Type) (int, error) { | ||||
| 	var ( | ||||
| 		n    = int64(1) | ||||
| 		elem int64 | ||||
| 	) | ||||
|  | ||||
| 	for i := 0; i < maxTypeDepth; i++ { | ||||
| 		switch v := typ.(type) { | ||||
| 		case *Array: | ||||
| 			if n > 0 && int64(v.Nelems) > math.MaxInt64/n { | ||||
| 				return 0, errors.New("overflow") | ||||
| 			} | ||||
|  | ||||
| 			// Arrays may be of zero length, which allows | ||||
| 			// n to be zero as well. | ||||
| 			n *= int64(v.Nelems) | ||||
| 			typ = v.Type | ||||
| 			continue | ||||
|  | ||||
| 		case sizer: | ||||
| 			elem = int64(v.size()) | ||||
|  | ||||
| 		case *Typedef: | ||||
| 			typ = v.Type | ||||
| 			continue | ||||
| 		case *Volatile: | ||||
| 			typ = v.Type | ||||
| 			continue | ||||
| 		case *Const: | ||||
| 			typ = v.Type | ||||
| 			continue | ||||
| 		case *Restrict: | ||||
| 			typ = v.Type | ||||
| 			continue | ||||
|  | ||||
| 		default: | ||||
| 			return 0, errors.Errorf("unrecognized type %T", typ) | ||||
| 		} | ||||
|  | ||||
| 		if n > 0 && elem > math.MaxInt64/n { | ||||
| 			return 0, errors.New("overflow") | ||||
| 		} | ||||
|  | ||||
| 		size := n * elem | ||||
| 		if int64(int(size)) != size { | ||||
| 			return 0, errors.New("overflow") | ||||
| 		} | ||||
|  | ||||
| 		return int(size), nil | ||||
| 	} | ||||
|  | ||||
| 	return 0, errors.New("exceeded type depth") | ||||
| } | ||||
|  | ||||
| // copy a Type recursively. | ||||
| // | ||||
| // typ may form a cycle. | ||||
| func copyType(typ Type) Type { | ||||
| 	var ( | ||||
| 		copies = make(map[Type]Type) | ||||
| 		work   copyStack | ||||
| 	) | ||||
|  | ||||
| 	for t := &typ; t != nil; t = work.pop() { | ||||
| 		// *t is the identity of the type. | ||||
| 		if cpy := copies[*t]; cpy != nil { | ||||
| 			*t = cpy | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		cpy := (*t).copy() | ||||
| 		copies[*t] = cpy | ||||
| 		*t = cpy | ||||
|  | ||||
| 		// Mark any nested types for copying. | ||||
| 		cpy.walk(&work) | ||||
| 	} | ||||
|  | ||||
| 	return typ | ||||
| } | ||||
|  | ||||
| // copyStack keeps track of pointers to types which still | ||||
| // need to be copied. | ||||
| type copyStack []*Type | ||||
|  | ||||
| // push adds a type to the stack. | ||||
| func (cs *copyStack) push(t *Type) { | ||||
| 	*cs = append(*cs, t) | ||||
| } | ||||
|  | ||||
| // pop returns the topmost Type, or nil. | ||||
| func (cs *copyStack) pop() *Type { | ||||
| 	n := len(*cs) | ||||
| 	if n == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	t := (*cs)[n-1] | ||||
| 	*cs = (*cs)[:n-1] | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| type namer interface { | ||||
| 	name() string | ||||
| } | ||||
|  | ||||
| var _ namer = Name("") | ||||
|  | ||||
| // inflateRawTypes takes a list of raw btf types linked via type IDs, and turns | ||||
| // it into a graph of Types connected via pointers. | ||||
| // | ||||
| // Returns a map of named types (so, where NameOff is non-zero). Since BTF ignores | ||||
| // compilation units, multiple types may share the same name. A Type may form a | ||||
| // cyclic graph by pointing at itself. | ||||
| func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map[string][]Type, err error) { | ||||
| 	type fixup struct { | ||||
| 		id  TypeID | ||||
| 		typ *Type | ||||
| 	} | ||||
|  | ||||
| 	var fixups []fixup | ||||
| 	convertMembers := func(raw []btfMember) ([]Member, error) { | ||||
| 		// NB: The fixup below relies on pre-allocating this array to | ||||
| 		// work, since otherwise append might re-allocate members. | ||||
| 		members := make([]Member, 0, len(raw)) | ||||
| 		for i, btfMember := range raw { | ||||
| 			name, err := rawStrings.LookupName(btfMember.NameOff) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(err, "can't get name for member %d", i) | ||||
| 			} | ||||
| 			members = append(members, Member{ | ||||
| 				Name:   name, | ||||
| 				Offset: btfMember.Offset, | ||||
| 			}) | ||||
| 		} | ||||
| 		for i := range members { | ||||
| 			fixups = append(fixups, fixup{raw[i].Type, &members[i].Type}) | ||||
| 		} | ||||
| 		return members, nil | ||||
| 	} | ||||
|  | ||||
| 	types := make([]Type, 0, len(rawTypes)) | ||||
| 	types = append(types, Void{}) | ||||
| 	namedTypes = make(map[string][]Type) | ||||
|  | ||||
| 	for i, raw := range rawTypes { | ||||
| 		var ( | ||||
| 			// Void is defined to always be type ID 0, and is thus | ||||
| 			// omitted from BTF. | ||||
| 			id  = TypeID(i + 1) | ||||
| 			typ Type | ||||
| 		) | ||||
|  | ||||
| 		name, err := rawStrings.LookupName(raw.NameOff) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "can't get name for type id %d", id) | ||||
| 		} | ||||
|  | ||||
| 		switch raw.Kind() { | ||||
| 		case kindInt: | ||||
| 			typ = &Int{id, name, raw.Size()} | ||||
|  | ||||
| 		case kindPointer: | ||||
| 			ptr := &Pointer{id, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &ptr.Target}) | ||||
| 			typ = ptr | ||||
|  | ||||
| 		case kindArray: | ||||
| 			btfArr := raw.data.(*btfArray) | ||||
|  | ||||
| 			// IndexType is unused according to btf.rst. | ||||
| 			// Don't make it available right now. | ||||
| 			arr := &Array{id, nil, btfArr.Nelems} | ||||
| 			fixups = append(fixups, fixup{btfArr.Type, &arr.Type}) | ||||
| 			typ = arr | ||||
|  | ||||
| 		case kindStruct: | ||||
| 			members, err := convertMembers(raw.data.([]btfMember)) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(err, "struct %s (id %d)", name, id) | ||||
| 			} | ||||
| 			typ = &Struct{id, name, raw.Size(), members} | ||||
|  | ||||
| 		case kindUnion: | ||||
| 			members, err := convertMembers(raw.data.([]btfMember)) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.Wrapf(err, "union %s (id %d)", name, id) | ||||
| 			} | ||||
| 			typ = &Union{id, name, raw.Size(), members} | ||||
|  | ||||
| 		case kindEnum: | ||||
| 			typ = &Enum{id, name} | ||||
|  | ||||
| 		case kindForward: | ||||
| 			typ = &Fwd{id, name} | ||||
|  | ||||
| 		case kindTypedef: | ||||
| 			typedef := &Typedef{id, name, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &typedef.Type}) | ||||
| 			typ = typedef | ||||
|  | ||||
| 		case kindVolatile: | ||||
| 			volatile := &Volatile{id, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &volatile.Type}) | ||||
| 			typ = volatile | ||||
|  | ||||
| 		case kindConst: | ||||
| 			cnst := &Const{id, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &cnst.Type}) | ||||
| 			typ = cnst | ||||
|  | ||||
| 		case kindRestrict: | ||||
| 			restrict := &Restrict{id, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &restrict.Type}) | ||||
| 			typ = restrict | ||||
|  | ||||
| 		case kindFunc: | ||||
| 			fn := &Func{id, name, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &fn.Type}) | ||||
| 			typ = fn | ||||
|  | ||||
| 		case kindFuncProto: | ||||
| 			fp := &FuncProto{id, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &fp.Return}) | ||||
| 			typ = fp | ||||
|  | ||||
| 		case kindVar: | ||||
| 			v := &Var{id, name, nil} | ||||
| 			fixups = append(fixups, fixup{raw.Type(), &v.Type}) | ||||
| 			typ = v | ||||
|  | ||||
| 		case kindDatasec: | ||||
| 			typ = &Datasec{id, name, raw.SizeType} | ||||
|  | ||||
| 		default: | ||||
| 			return nil, errors.Errorf("type id %d: unknown kind: %v", id, raw.Kind()) | ||||
| 		} | ||||
|  | ||||
| 		types = append(types, typ) | ||||
|  | ||||
| 		if namer, ok := typ.(namer); ok { | ||||
| 			if name := namer.name(); name != "" { | ||||
| 				namedTypes[name] = append(namedTypes[name], typ) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, fixup := range fixups { | ||||
| 		i := int(fixup.id) | ||||
| 		if i >= len(types) { | ||||
| 			return nil, errors.Errorf("reference to invalid type id: %d", fixup.id) | ||||
| 		} | ||||
|  | ||||
| 		*fixup.typ = types[i] | ||||
| 	} | ||||
|  | ||||
| 	return namedTypes, nil | ||||
| } | ||||
							
								
								
									
										50
									
								
								vendor/github.com/cilium/ebpf/internal/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/cilium/ebpf/internal/errors.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // ErrorWithLog returns an error that includes logs from the | ||||
| // kernel verifier. | ||||
| // | ||||
| // logErr should be the error returned by the syscall that generated | ||||
| // the log. It is used to check for truncation of the output. | ||||
| func ErrorWithLog(err error, log []byte, logErr error) error { | ||||
| 	logStr := strings.Trim(CString(log), "\t\r\n ") | ||||
| 	if errors.Cause(logErr) == unix.ENOSPC { | ||||
| 		logStr += " (truncated...)" | ||||
| 	} | ||||
|  | ||||
| 	return &loadError{err, logStr} | ||||
| } | ||||
|  | ||||
| type loadError struct { | ||||
| 	cause error | ||||
| 	log   string | ||||
| } | ||||
|  | ||||
| func (le *loadError) Error() string { | ||||
| 	if le.log == "" { | ||||
| 		return le.cause.Error() | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprintf("%s: %s", le.cause, le.log) | ||||
| } | ||||
|  | ||||
| func (le *loadError) Cause() error { | ||||
| 	return le.cause | ||||
| } | ||||
|  | ||||
| // CString turns a NUL / zero terminated byte buffer into a string. | ||||
| func CString(in []byte) string { | ||||
| 	inLen := bytes.IndexByte(in, 0) | ||||
| 	if inLen == -1 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return string(in[:inLen]) | ||||
| } | ||||
							
								
								
									
										63
									
								
								vendor/github.com/cilium/ebpf/internal/fd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/cilium/ebpf/internal/fd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| var ErrClosedFd = errors.New("use of closed file descriptor") | ||||
|  | ||||
| type FD struct { | ||||
| 	raw int64 | ||||
| } | ||||
|  | ||||
| func NewFD(value uint32) *FD { | ||||
| 	fd := &FD{int64(value)} | ||||
| 	runtime.SetFinalizer(fd, (*FD).Close) | ||||
| 	return fd | ||||
| } | ||||
|  | ||||
| func (fd *FD) String() string { | ||||
| 	return strconv.FormatInt(fd.raw, 10) | ||||
| } | ||||
|  | ||||
| func (fd *FD) Value() (uint32, error) { | ||||
| 	if fd.raw < 0 { | ||||
| 		return 0, ErrClosedFd | ||||
| 	} | ||||
|  | ||||
| 	return uint32(fd.raw), nil | ||||
| } | ||||
|  | ||||
| func (fd *FD) Close() error { | ||||
| 	if fd.raw < 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	value := int(fd.raw) | ||||
| 	fd.raw = -1 | ||||
|  | ||||
| 	fd.Forget() | ||||
| 	return unix.Close(value) | ||||
| } | ||||
|  | ||||
| func (fd *FD) Forget() { | ||||
| 	runtime.SetFinalizer(fd, nil) | ||||
| } | ||||
|  | ||||
| func (fd *FD) Dup() (*FD, error) { | ||||
| 	if fd.raw < 0 { | ||||
| 		return nil, ErrClosedFd | ||||
| 	} | ||||
|  | ||||
| 	dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't dup fd") | ||||
| 	} | ||||
|  | ||||
| 	return NewFD(uint32(dup)), nil | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/github.com/cilium/ebpf/internal/io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/cilium/ebpf/internal/io.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| package internal | ||||
|  | ||||
| import "github.com/pkg/errors" | ||||
|  | ||||
| // DiscardZeroes makes sure that all written bytes are zero | ||||
| // before discarding them. | ||||
| type DiscardZeroes struct{} | ||||
|  | ||||
| func (DiscardZeroes) Write(p []byte) (int, error) { | ||||
| 	for _, b := range p { | ||||
| 		if b != 0 { | ||||
| 			return 0, errors.New("encountered non-zero byte") | ||||
| 		} | ||||
| 	} | ||||
| 	return len(p), nil | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/github.com/cilium/ebpf/internal/ptr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/cilium/ebpf/internal/ptr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| package internal | ||||
|  | ||||
| import "unsafe" | ||||
|  | ||||
| // NewPointer creates a 64-bit pointer from an unsafe Pointer. | ||||
| func NewPointer(ptr unsafe.Pointer) Pointer { | ||||
| 	return Pointer{ptr: ptr} | ||||
| } | ||||
|  | ||||
| // NewSlicePointer creates a 64-bit pointer from a byte slice. | ||||
| func NewSlicePointer(buf []byte) Pointer { | ||||
| 	if len(buf) == 0 { | ||||
| 		return Pointer{} | ||||
| 	} | ||||
|  | ||||
| 	return Pointer{ptr: unsafe.Pointer(&buf[0])} | ||||
| } | ||||
|  | ||||
| // NewStringPointer creates a 64-bit pointer from a string. | ||||
| func NewStringPointer(str string) Pointer { | ||||
| 	if str == "" { | ||||
| 		return Pointer{} | ||||
| 	} | ||||
|  | ||||
| 	return Pointer{ptr: unsafe.Pointer(&[]byte(str)[0])} | ||||
| } | ||||
| @@ -1,14 +1,14 @@ | ||||
| // +build armbe mips mips64p32 | ||||
| 
 | ||||
| package ebpf | ||||
| package internal | ||||
| 
 | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| // ptr wraps an unsafe.Pointer to be 64bit to | ||||
| // Pointer wraps an unsafe.Pointer to be 64bit to | ||||
| // conform to the syscall specification. | ||||
| type syscallPtr struct { | ||||
| type Pointer struct { | ||||
| 	pad uint32 | ||||
| 	ptr unsafe.Pointer | ||||
| } | ||||
| @@ -1,14 +1,14 @@ | ||||
| // +build 386 amd64p32 arm mipsle mips64p32le | ||||
| 
 | ||||
| package ebpf | ||||
| package internal | ||||
| 
 | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| // ptr wraps an unsafe.Pointer to be 64bit to | ||||
| // Pointer wraps an unsafe.Pointer to be 64bit to | ||||
| // conform to the syscall specification. | ||||
| type syscallPtr struct { | ||||
| type Pointer struct { | ||||
| 	ptr unsafe.Pointer | ||||
| 	pad uint32 | ||||
| } | ||||
| @@ -1,14 +1,14 @@ | ||||
| // +build !386,!amd64p32,!arm,!mipsle,!mips64p32le | ||||
| // +build !armbe,!mips,!mips64p32 | ||||
| 
 | ||||
| package ebpf | ||||
| package internal | ||||
| 
 | ||||
| import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
| 
 | ||||
| // ptr wraps an unsafe.Pointer to be 64bit to | ||||
| // Pointer wraps an unsafe.Pointer to be 64bit to | ||||
| // conform to the syscall specification. | ||||
| type syscallPtr struct { | ||||
| type Pointer struct { | ||||
| 	ptr unsafe.Pointer | ||||
| } | ||||
							
								
								
									
										23
									
								
								vendor/github.com/cilium/ebpf/internal/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/cilium/ebpf/internal/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"runtime" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
| ) | ||||
|  | ||||
| // BPF wraps SYS_BPF. | ||||
| // | ||||
| // Any pointers contained in attr must use the Pointer type from this package. | ||||
| func BPF(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) { | ||||
| 	r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) | ||||
| 	runtime.KeepAlive(attr) | ||||
|  | ||||
| 	var err error | ||||
| 	if errNo != 0 { | ||||
| 		err = errNo | ||||
| 	} | ||||
|  | ||||
| 	return r1, err | ||||
| } | ||||
							
								
								
									
										28
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,23 +2,35 @@ package ebpf | ||||
|  | ||||
| import ( | ||||
| 	"github.com/cilium/ebpf/asm" | ||||
| 	"github.com/cilium/ebpf/internal/btf" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // link resolves bpf-to-bpf calls. | ||||
| // | ||||
| // Each section may contain multiple functions / labels, and is only linked | ||||
| // Each library may contain multiple functions / labels, and is only linked | ||||
| // if the program being edited references one of these functions. | ||||
| // | ||||
| // Sections must not require linking themselves. | ||||
| func link(insns asm.Instructions, sections ...asm.Instructions) (asm.Instructions, error) { | ||||
| 	for _, section := range sections { | ||||
| 		var err error | ||||
| 		insns, err = linkSection(insns, section) | ||||
| // Libraries must not require linking themselves. | ||||
| func link(prog *ProgramSpec, libs []*ProgramSpec) error { | ||||
| 	for _, lib := range libs { | ||||
| 		insns, err := linkSection(prog.Instructions, lib.Instructions) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 			return errors.Wrapf(err, "linking %s", lib.Name) | ||||
| 		} | ||||
|  | ||||
| 		if len(insns) == len(prog.Instructions) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		prog.Instructions = insns | ||||
| 		if prog.BTF != nil && lib.BTF != nil { | ||||
| 			if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil { | ||||
| 				return errors.Wrapf(err, "linking BTF of %s", lib.Name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return insns, nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func linkSection(insns, section asm.Instructions) (asm.Instructions, error) { | ||||
|   | ||||
							
								
								
									
										83
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,9 +2,9 @@ package ebpf | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| 	"github.com/cilium/ebpf/internal/btf" | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -20,8 +20,12 @@ type MapSpec struct { | ||||
| 	ValueSize  uint32 | ||||
| 	MaxEntries uint32 | ||||
| 	Flags      uint32 | ||||
|  | ||||
| 	// InnerMap is used as a template for ArrayOfMaps and HashOfMaps | ||||
| 	InnerMap *MapSpec | ||||
|  | ||||
| 	// The BTF associated with this map. | ||||
| 	BTF *btf.Map | ||||
| } | ||||
|  | ||||
| func (ms *MapSpec) String() string { | ||||
| @@ -50,7 +54,7 @@ func (ms *MapSpec) Copy() *MapSpec { | ||||
| // if you require custom encoding. | ||||
| type Map struct { | ||||
| 	name string | ||||
| 	fd   *bpfFD | ||||
| 	fd   *internal.FD | ||||
| 	abi  MapABI | ||||
| 	// Per CPU maps return values larger than the size in the spec | ||||
| 	fullValueSize int | ||||
| @@ -63,11 +67,11 @@ func NewMapFromFD(fd int) (*Map, error) { | ||||
| 	if fd < 0 { | ||||
| 		return nil, errors.New("invalid fd") | ||||
| 	} | ||||
| 	bpfFd := newBPFFD(uint32(fd)) | ||||
| 	bpfFd := internal.NewFD(uint32(fd)) | ||||
|  | ||||
| 	name, abi, err := newMapABIFromFd(bpfFd) | ||||
| 	if err != nil { | ||||
| 		bpfFd.forget() | ||||
| 		bpfFd.Forget() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return newMap(bpfFd, name, abi) | ||||
| @@ -78,24 +82,37 @@ func NewMapFromFD(fd int) (*Map, error) { | ||||
| // Creating a map for the first time will perform feature detection | ||||
| // by creating small, temporary maps. | ||||
| func NewMap(spec *MapSpec) (*Map, error) { | ||||
| 	if spec.BTF == nil { | ||||
| 		return newMapWithBTF(spec, nil) | ||||
| 	} | ||||
|  | ||||
| 	handle, err := btf.NewHandle(btf.MapSpec(spec.BTF)) | ||||
| 	if err != nil && !btf.IsNotSupported(err) { | ||||
| 		return nil, errors.Wrap(err, "can't load BTF") | ||||
| 	} | ||||
|  | ||||
| 	return newMapWithBTF(spec, handle) | ||||
| } | ||||
|  | ||||
| func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) { | ||||
| 	if spec.Type != ArrayOfMaps && spec.Type != HashOfMaps { | ||||
| 		return createMap(spec, nil) | ||||
| 		return createMap(spec, nil, handle) | ||||
| 	} | ||||
|  | ||||
| 	if spec.InnerMap == nil { | ||||
| 		return nil, errors.Errorf("%s requires InnerMap", spec.Type) | ||||
| 	} | ||||
|  | ||||
| 	template, err := createMap(spec.InnerMap, nil) | ||||
| 	template, err := createMap(spec.InnerMap, nil, handle) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer template.Close() | ||||
|  | ||||
| 	return createMap(spec, template.fd) | ||||
| 	return createMap(spec, template.fd, handle) | ||||
| } | ||||
|  | ||||
| func createMap(spec *MapSpec, inner *bpfFD) (*Map, error) { | ||||
| func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, error) { | ||||
| 	spec = spec.Copy() | ||||
|  | ||||
| 	switch spec.Type { | ||||
| @@ -140,12 +157,18 @@ func createMap(spec *MapSpec, inner *bpfFD) (*Map, error) { | ||||
|  | ||||
| 	if inner != nil { | ||||
| 		var err error | ||||
| 		attr.innerMapFd, err = inner.value() | ||||
| 		attr.innerMapFd, err = inner.Value() | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "map create") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if handle != nil && spec.BTF != nil { | ||||
| 		attr.btfFd = uint32(handle.FD()) | ||||
| 		attr.btfKeyTypeID = btf.MapKey(spec.BTF).ID() | ||||
| 		attr.btfValueTypeID = btf.MapValue(spec.BTF).ID() | ||||
| 	} | ||||
|  | ||||
| 	name, err := newBPFObjName(spec.Name) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "map create") | ||||
| @@ -163,7 +186,7 @@ func createMap(spec *MapSpec, inner *bpfFD) (*Map, error) { | ||||
| 	return newMap(fd, spec.Name, newMapABIFromSpec(spec)) | ||||
| } | ||||
|  | ||||
| func newMap(fd *bpfFD, name string, abi *MapABI) (*Map, error) { | ||||
| func newMap(fd *internal.FD, name string, abi *MapABI) (*Map, error) { | ||||
| 	m := &Map{ | ||||
| 		name, | ||||
| 		fd, | ||||
| @@ -251,12 +274,28 @@ func (m *Map) Lookup(key, valueOut interface{}) error { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // LookupAndDelete retrieves and deletes a value from a Map. | ||||
| func (m *Map) LookupAndDelete(key, valueOut interface{}) error { | ||||
| 	valuePtr, valueBytes := makeBuffer(valueOut, m.fullValueSize) | ||||
|  | ||||
| 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) | ||||
| 	if err != nil { | ||||
| 		return errors.WithMessage(err, "can't marshal key") | ||||
| 	} | ||||
|  | ||||
| 	if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil { | ||||
| 		return errors.WithMessage(err, "lookup and delete and delete failed") | ||||
| 	} | ||||
|  | ||||
| 	return unmarshalBytes(valueOut, valueBytes) | ||||
| } | ||||
|  | ||||
| // LookupBytes gets a value from Map. | ||||
| // | ||||
| // Returns a nil value if a key doesn't exist. | ||||
| func (m *Map) LookupBytes(key interface{}) ([]byte, error) { | ||||
| 	valueBytes := make([]byte, m.fullValueSize) | ||||
| 	valuePtr := newPtr(unsafe.Pointer(&valueBytes[0])) | ||||
| 	valuePtr := internal.NewSlicePointer(valueBytes) | ||||
|  | ||||
| 	err := m.lookup(key, valuePtr) | ||||
| 	if IsNotExist(err) { | ||||
| @@ -266,7 +305,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) { | ||||
| 	return valueBytes, err | ||||
| } | ||||
|  | ||||
| func (m *Map) lookup(key interface{}, valueOut syscallPtr) error { | ||||
| func (m *Map) lookup(key interface{}, valueOut internal.Pointer) error { | ||||
| 	keyPtr, err := marshalPtr(key, int(m.abi.KeySize)) | ||||
| 	if err != nil { | ||||
| 		return errors.WithMessage(err, "can't marshal key") | ||||
| @@ -304,7 +343,7 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error { | ||||
| 		return errors.WithMessage(err, "can't marshal key") | ||||
| 	} | ||||
|  | ||||
| 	var valuePtr syscallPtr | ||||
| 	var valuePtr internal.Pointer | ||||
| 	if m.abi.Type.hasPerCPUValue() { | ||||
| 		valuePtr, err = marshalPerCPUValue(value, int(m.abi.ValueSize)) | ||||
| 	} else { | ||||
| @@ -355,7 +394,7 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error { | ||||
| // Use Iterate if you want to traverse all entries in the map. | ||||
| func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) { | ||||
| 	nextKey := make([]byte, m.abi.KeySize) | ||||
| 	nextKeyPtr := newPtr(unsafe.Pointer(&nextKey[0])) | ||||
| 	nextKeyPtr := internal.NewSlicePointer(nextKey) | ||||
|  | ||||
| 	err := m.nextKey(key, nextKeyPtr) | ||||
| 	if IsNotExist(err) { | ||||
| @@ -365,9 +404,9 @@ func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) { | ||||
| 	return nextKey, err | ||||
| } | ||||
|  | ||||
| func (m *Map) nextKey(key interface{}, nextKeyOut syscallPtr) error { | ||||
| func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error { | ||||
| 	var ( | ||||
| 		keyPtr syscallPtr | ||||
| 		keyPtr internal.Pointer | ||||
| 		err    error | ||||
| 	) | ||||
|  | ||||
| @@ -400,14 +439,14 @@ func (m *Map) Close() error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return m.fd.close() | ||||
| 	return m.fd.Close() | ||||
| } | ||||
|  | ||||
| // FD gets the file descriptor of the Map. | ||||
| // | ||||
| // Calling this function is invalid after Close has been called. | ||||
| func (m *Map) FD() int { | ||||
| 	fd, err := m.fd.value() | ||||
| 	fd, err := m.fd.Value() | ||||
| 	if err != nil { | ||||
| 		// Best effort: -1 is the number most likely to be an | ||||
| 		// invalid file descriptor. | ||||
| @@ -428,7 +467,7 @@ func (m *Map) Clone() (*Map, error) { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	dup, err := m.fd.dup() | ||||
| 	dup, err := m.fd.Dup() | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't clone map") | ||||
| 	} | ||||
| @@ -454,7 +493,7 @@ func LoadPinnedMap(fileName string) (*Map, error) { | ||||
| 	} | ||||
| 	name, abi, err := newMapABIFromFd(fd) | ||||
| 	if err != nil { | ||||
| 		_ = fd.close() | ||||
| 		_ = fd.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return newMap(fd, name, abi) | ||||
| @@ -484,7 +523,7 @@ func unmarshalMap(buf []byte) (*Map, error) { | ||||
|  | ||||
| 	name, abi, err := newMapABIFromFd(fd) | ||||
| 	if err != nil { | ||||
| 		_ = fd.close() | ||||
| 		_ = fd.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @@ -493,7 +532,7 @@ func unmarshalMap(buf []byte) (*Map, error) { | ||||
|  | ||||
| // MarshalBinary implements BinaryMarshaler. | ||||
| func (m *Map) MarshalBinary() ([]byte, error) { | ||||
| 	fd, err := m.fd.value() | ||||
| 	fd, err := m.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										33
									
								
								vendor/github.com/cilium/ebpf/marshalers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/cilium/ebpf/marshalers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,17 +13,24 @@ import ( | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| func marshalPtr(data interface{}, length int) (syscallPtr, error) { | ||||
| func marshalPtr(data interface{}, length int) (internal.Pointer, error) { | ||||
| 	if data == nil { | ||||
| 		if length == 0 { | ||||
| 			return internal.NewPointer(nil), nil | ||||
| 		} | ||||
| 		return internal.Pointer{}, errors.New("can't use nil as key of map") | ||||
| 	} | ||||
|  | ||||
| 	if ptr, ok := data.(unsafe.Pointer); ok { | ||||
| 		return newPtr(ptr), nil | ||||
| 		return internal.NewPointer(ptr), nil | ||||
| 	} | ||||
|  | ||||
| 	buf, err := marshalBytes(data, length) | ||||
| 	if err != nil { | ||||
| 		return syscallPtr{}, err | ||||
| 		return internal.Pointer{}, err | ||||
| 	} | ||||
|  | ||||
| 	return newPtr(unsafe.Pointer(&buf[0])), nil | ||||
| 	return internal.NewSlicePointer(buf), nil | ||||
| } | ||||
|  | ||||
| func marshalBytes(data interface{}, length int) (buf []byte, err error) { | ||||
| @@ -52,13 +59,13 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) { | ||||
| 	return buf, nil | ||||
| } | ||||
|  | ||||
| func makeBuffer(dst interface{}, length int) (syscallPtr, []byte) { | ||||
| func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) { | ||||
| 	if ptr, ok := dst.(unsafe.Pointer); ok { | ||||
| 		return newPtr(ptr), nil | ||||
| 		return internal.NewPointer(ptr), nil | ||||
| 	} | ||||
|  | ||||
| 	buf := make([]byte, length) | ||||
| 	return newPtr(unsafe.Pointer(&buf[0])), buf | ||||
| 	return internal.NewSlicePointer(buf), buf | ||||
| } | ||||
|  | ||||
| func unmarshalBytes(data interface{}, buf []byte) error { | ||||
| @@ -99,21 +106,21 @@ func unmarshalBytes(data interface{}, buf []byte) error { | ||||
| // Values are initialized to zero if the slice has less elements than CPUs. | ||||
| // | ||||
| // slice must have a type like []elementType. | ||||
| func marshalPerCPUValue(slice interface{}, elemLength int) (syscallPtr, error) { | ||||
| func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) { | ||||
| 	sliceType := reflect.TypeOf(slice) | ||||
| 	if sliceType.Kind() != reflect.Slice { | ||||
| 		return syscallPtr{}, errors.New("per-CPU value requires slice") | ||||
| 		return internal.Pointer{}, errors.New("per-CPU value requires slice") | ||||
| 	} | ||||
|  | ||||
| 	possibleCPUs, err := internal.PossibleCPUs() | ||||
| 	if err != nil { | ||||
| 		return syscallPtr{}, err | ||||
| 		return internal.Pointer{}, err | ||||
| 	} | ||||
|  | ||||
| 	sliceValue := reflect.ValueOf(slice) | ||||
| 	sliceLen := sliceValue.Len() | ||||
| 	if sliceLen > possibleCPUs { | ||||
| 		return syscallPtr{}, errors.Errorf("per-CPU value exceeds number of CPUs") | ||||
| 		return internal.Pointer{}, errors.Errorf("per-CPU value exceeds number of CPUs") | ||||
| 	} | ||||
|  | ||||
| 	alignedElemLength := align(elemLength, 8) | ||||
| @@ -123,14 +130,14 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (syscallPtr, error) { | ||||
| 		elem := sliceValue.Index(i).Interface() | ||||
| 		elemBytes, err := marshalBytes(elem, elemLength) | ||||
| 		if err != nil { | ||||
| 			return syscallPtr{}, err | ||||
| 			return internal.Pointer{}, err | ||||
| 		} | ||||
|  | ||||
| 		offset := i * alignedElemLength | ||||
| 		copy(buf[offset:offset+elemLength], elemBytes) | ||||
| 	} | ||||
|  | ||||
| 	return newPtr(unsafe.Pointer(&buf[0])), nil | ||||
| 	return internal.NewSlicePointer(buf), nil | ||||
| } | ||||
|  | ||||
| // unmarshalPerCPUValue decodes a buffer into a slice containing one value per | ||||
|   | ||||
							
								
								
									
										120
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										120
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -10,6 +10,7 @@ import ( | ||||
|  | ||||
| 	"github.com/cilium/ebpf/asm" | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| 	"github.com/cilium/ebpf/internal/btf" | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -46,6 +47,11 @@ type ProgramSpec struct { | ||||
| 	Instructions  asm.Instructions | ||||
| 	License       string | ||||
| 	KernelVersion uint32 | ||||
|  | ||||
| 	// The BTF associated with this program. Changing Instructions | ||||
| 	// will most likely invalidate the contained data, and may | ||||
| 	// result in errors when attempting to load it into the kernel. | ||||
| 	BTF *btf.Program | ||||
| } | ||||
|  | ||||
| // Copy returns a copy of the spec. | ||||
| @@ -68,7 +74,7 @@ type Program struct { | ||||
| 	// otherwise it is empty. | ||||
| 	VerifierLog string | ||||
|  | ||||
| 	fd   *bpfFD | ||||
| 	fd   *internal.FD | ||||
| 	name string | ||||
| 	abi  ProgramABI | ||||
| } | ||||
| @@ -86,7 +92,20 @@ func NewProgram(spec *ProgramSpec) (*Program, error) { | ||||
| // Loading a program for the first time will perform | ||||
| // feature detection by loading small, temporary programs. | ||||
| func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, error) { | ||||
| 	attr, err := convertProgramSpec(spec) | ||||
| 	if spec.BTF == nil { | ||||
| 		return newProgramWithBTF(spec, nil, opts) | ||||
| 	} | ||||
|  | ||||
| 	handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF)) | ||||
| 	if err != nil && !btf.IsNotSupported(err) { | ||||
| 		return nil, errors.Wrap(err, "can't load BTF") | ||||
| 	} | ||||
|  | ||||
| 	return newProgramWithBTF(spec, handle, opts) | ||||
| } | ||||
|  | ||||
| func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions) (*Program, error) { | ||||
| 	attr, err := convertProgramSpec(spec, btf) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -101,34 +120,28 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er | ||||
| 		logBuf = make([]byte, logSize) | ||||
| 		attr.logLevel = opts.LogLevel | ||||
| 		attr.logSize = uint32(len(logBuf)) | ||||
| 		attr.logBuf = newPtr(unsafe.Pointer(&logBuf[0])) | ||||
| 		attr.logBuf = internal.NewSlicePointer(logBuf) | ||||
| 	} | ||||
|  | ||||
| 	fd, err := bpfProgLoad(attr) | ||||
| 	if err == nil { | ||||
| 		prog := newProgram(fd, spec.Name, &ProgramABI{spec.Type}) | ||||
| 		prog.VerifierLog = convertCString(logBuf) | ||||
| 		prog.VerifierLog = internal.CString(logBuf) | ||||
| 		return prog, nil | ||||
| 	} | ||||
|  | ||||
| 	truncated := errors.Cause(err) == unix.ENOSPC | ||||
| 	if opts.LogLevel == 0 { | ||||
| 		// Re-run with the verifier enabled to get better error messages. | ||||
| 		logBuf = make([]byte, logSize) | ||||
| 		attr.logLevel = 1 | ||||
| 		attr.logSize = uint32(len(logBuf)) | ||||
| 		attr.logBuf = newPtr(unsafe.Pointer(&logBuf[0])) | ||||
| 		attr.logBuf = internal.NewSlicePointer(logBuf) | ||||
|  | ||||
| 		_, nerr := bpfProgLoad(attr) | ||||
| 		truncated = errors.Cause(nerr) == unix.ENOSPC | ||||
| 		_, logErr := bpfProgLoad(attr) | ||||
| 		err = internal.ErrorWithLog(err, logBuf, logErr) | ||||
| 	} | ||||
|  | ||||
| 	logs := convertCString(logBuf) | ||||
| 	if truncated { | ||||
| 		logs += "\n(truncated...)" | ||||
| 	} | ||||
|  | ||||
| 	return nil, &loadError{err, logs} | ||||
| 	return nil, errors.Wrap(err, "can't load program") | ||||
| } | ||||
|  | ||||
| // NewProgramFromFD creates a program from a raw fd. | ||||
| @@ -140,18 +153,18 @@ func NewProgramFromFD(fd int) (*Program, error) { | ||||
| 	if fd < 0 { | ||||
| 		return nil, errors.New("invalid fd") | ||||
| 	} | ||||
| 	bpfFd := newBPFFD(uint32(fd)) | ||||
| 	bpfFd := internal.NewFD(uint32(fd)) | ||||
|  | ||||
| 	name, abi, err := newProgramABIFromFd(bpfFd) | ||||
| 	if err != nil { | ||||
| 		bpfFd.forget() | ||||
| 		bpfFd.Forget() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return newProgram(bpfFd, name, abi), nil | ||||
| } | ||||
|  | ||||
| func newProgram(fd *bpfFD, name string, abi *ProgramABI) *Program { | ||||
| func newProgram(fd *internal.FD, name string, abi *ProgramABI) *Program { | ||||
| 	return &Program{ | ||||
| 		name: name, | ||||
| 		fd:   fd, | ||||
| @@ -159,7 +172,7 @@ func newProgram(fd *bpfFD, name string, abi *ProgramABI) *Program { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func convertProgramSpec(spec *ProgramSpec) (*bpfProgLoadAttr, error) { | ||||
| func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr, error) { | ||||
| 	if len(spec.Instructions) == 0 { | ||||
| 		return nil, errors.New("Instructions cannot be empty") | ||||
| 	} | ||||
| @@ -176,13 +189,12 @@ func convertProgramSpec(spec *ProgramSpec) (*bpfProgLoadAttr, error) { | ||||
|  | ||||
| 	bytecode := buf.Bytes() | ||||
| 	insCount := uint32(len(bytecode) / asm.InstructionSize) | ||||
| 	lic := []byte(spec.License) | ||||
| 	attr := &bpfProgLoadAttr{ | ||||
| 		progType:           spec.Type, | ||||
| 		expectedAttachType: spec.AttachType, | ||||
| 		insCount:           insCount, | ||||
| 		instructions:       newPtr(unsafe.Pointer(&bytecode[0])), | ||||
| 		license:            newPtr(unsafe.Pointer(&lic[0])), | ||||
| 		instructions:       internal.NewSlicePointer(bytecode), | ||||
| 		license:            internal.NewStringPointer(spec.License), | ||||
| 	} | ||||
|  | ||||
| 	name, err := newBPFObjName(spec.Name) | ||||
| @@ -194,6 +206,26 @@ func convertProgramSpec(spec *ProgramSpec) (*bpfProgLoadAttr, error) { | ||||
| 		attr.progName = name | ||||
| 	} | ||||
|  | ||||
| 	if handle != nil && spec.BTF != nil { | ||||
| 		attr.progBTFFd = uint32(handle.FD()) | ||||
|  | ||||
| 		recSize, bytes, err := btf.ProgramLineInfos(spec.BTF) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't get BTF line infos") | ||||
| 		} | ||||
| 		attr.lineInfoRecSize = recSize | ||||
| 		attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | ||||
| 		attr.lineInfo = internal.NewSlicePointer(bytes) | ||||
|  | ||||
| 		recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrap(err, "can't get BTF function infos") | ||||
| 		} | ||||
| 		attr.funcInfoRecSize = recSize | ||||
| 		attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize)) | ||||
| 		attr.funcInfo = internal.NewSlicePointer(bytes) | ||||
| 	} | ||||
|  | ||||
| 	return attr, nil | ||||
| } | ||||
|  | ||||
| @@ -213,7 +245,7 @@ func (p *Program) ABI() ProgramABI { | ||||
| // | ||||
| // It is invalid to call this function after Close has been called. | ||||
| func (p *Program) FD() int { | ||||
| 	fd, err := p.fd.value() | ||||
| 	fd, err := p.fd.Value() | ||||
| 	if err != nil { | ||||
| 		// Best effort: -1 is the number most likely to be an | ||||
| 		// invalid file descriptor. | ||||
| @@ -233,7 +265,7 @@ func (p *Program) Clone() (*Program, error) { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	dup, err := p.fd.dup() | ||||
| 	dup, err := p.fd.Dup() | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't clone program") | ||||
| 	} | ||||
| @@ -254,7 +286,7 @@ func (p *Program) Close() error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return p.fd.close() | ||||
| 	return p.fd.Close() | ||||
| } | ||||
|  | ||||
| // Test runs the Program in the kernel with the given input and returns the | ||||
| @@ -296,7 +328,7 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() b | ||||
| 	} | ||||
| 	defer prog.Close() | ||||
|  | ||||
| 	fd, err := prog.fd.value() | ||||
| 	fd, err := prog.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| @@ -306,10 +338,10 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() b | ||||
| 	attr := bpfProgTestRunAttr{ | ||||
| 		fd:         fd, | ||||
| 		dataSizeIn: uint32(len(in)), | ||||
| 		dataIn:     newPtr(unsafe.Pointer(&in[0])), | ||||
| 		dataIn:     internal.NewSlicePointer(in), | ||||
| 	} | ||||
|  | ||||
| 	_, err = bpfCall(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
|  | ||||
| 	// Check for EINVAL specifically, rather than err != nil since we | ||||
| 	// otherwise misdetect due to insufficient permissions. | ||||
| @@ -340,7 +372,7 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, | ||||
| 	// See https://patchwork.ozlabs.org/cover/1006822/ | ||||
| 	out := make([]byte, len(in)+outputPad) | ||||
|  | ||||
| 	fd, err := p.fd.value() | ||||
| 	fd, err := p.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return 0, nil, 0, err | ||||
| 	} | ||||
| @@ -349,12 +381,12 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, | ||||
| 		fd:          fd, | ||||
| 		dataSizeIn:  uint32(len(in)), | ||||
| 		dataSizeOut: uint32(len(out)), | ||||
| 		dataIn:      newPtr(unsafe.Pointer(&in[0])), | ||||
| 		dataOut:     newPtr(unsafe.Pointer(&out[0])), | ||||
| 		dataIn:      internal.NewSlicePointer(in), | ||||
| 		dataOut:     internal.NewSlicePointer(out), | ||||
| 		repeat:      uint32(repeat), | ||||
| 	} | ||||
|  | ||||
| 	_, err = bpfCall(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	if err != nil { | ||||
| 		return 0, nil, 0, errors.Wrap(err, "can't run test") | ||||
| 	} | ||||
| @@ -385,7 +417,7 @@ func unmarshalProgram(buf []byte) (*Program, error) { | ||||
|  | ||||
| 	name, abi, err := newProgramABIFromFd(fd) | ||||
| 	if err != nil { | ||||
| 		_ = fd.close() | ||||
| 		_ = fd.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| @@ -394,7 +426,7 @@ func unmarshalProgram(buf []byte) (*Program, error) { | ||||
|  | ||||
| // MarshalBinary implements BinaryMarshaler. | ||||
| func (p *Program) MarshalBinary() ([]byte, error) { | ||||
| 	value, err := p.fd.value() | ||||
| 	value, err := p.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -410,7 +442,7 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error { | ||||
| 		return errors.New("invalid fd") | ||||
| 	} | ||||
|  | ||||
| 	pfd, err := p.fd.value() | ||||
| 	pfd, err := p.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -431,7 +463,7 @@ func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error { | ||||
| 		return errors.New("invalid fd") | ||||
| 	} | ||||
|  | ||||
| 	pfd, err := p.fd.value() | ||||
| 	pfd, err := p.fd.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -457,7 +489,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) { | ||||
|  | ||||
| 	name, abi, err := newProgramABIFromFd(fd) | ||||
| 	if err != nil { | ||||
| 		_ = fd.close() | ||||
| 		_ = fd.Close() | ||||
| 		return nil, errors.Wrapf(err, "can't get ABI for %s", fileName) | ||||
| 	} | ||||
|  | ||||
| @@ -480,22 +512,6 @@ func SanitizeName(name string, replacement rune) string { | ||||
| 	}, name) | ||||
| } | ||||
|  | ||||
| type loadError struct { | ||||
| 	cause       error | ||||
| 	verifierLog string | ||||
| } | ||||
|  | ||||
| func (le *loadError) Error() string { | ||||
| 	if le.verifierLog == "" { | ||||
| 		return fmt.Sprintf("failed to load program: %s", le.cause) | ||||
| 	} | ||||
| 	return fmt.Sprintf("failed to load program: %s: %s", le.cause, le.verifierLog) | ||||
| } | ||||
|  | ||||
| func (le *loadError) Cause() error { | ||||
| 	return le.cause | ||||
| } | ||||
|  | ||||
| // IsNotSupported returns true if an error occurred because | ||||
| // the kernel does not have support for a specific feature. | ||||
| func IsNotSupported(err error) bool { | ||||
|   | ||||
							
								
								
									
										235
									
								
								vendor/github.com/cilium/ebpf/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										235
									
								
								vendor/github.com/cilium/ebpf/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,72 +1,17 @@ | ||||
| package ebpf | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"unsafe" | ||||
|  | ||||
| 	"github.com/cilium/ebpf/internal" | ||||
| 	"github.com/cilium/ebpf/internal/btf" | ||||
| 	"github.com/cilium/ebpf/internal/unix" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| var errClosedFd = errors.New("use of closed file descriptor") | ||||
|  | ||||
| type bpfFD struct { | ||||
| 	raw int64 | ||||
| } | ||||
|  | ||||
| func newBPFFD(value uint32) *bpfFD { | ||||
| 	fd := &bpfFD{int64(value)} | ||||
| 	runtime.SetFinalizer(fd, (*bpfFD).close) | ||||
| 	return fd | ||||
| } | ||||
|  | ||||
| func (fd *bpfFD) String() string { | ||||
| 	return strconv.FormatInt(fd.raw, 10) | ||||
| } | ||||
|  | ||||
| func (fd *bpfFD) value() (uint32, error) { | ||||
| 	if fd.raw < 0 { | ||||
| 		return 0, errClosedFd | ||||
| 	} | ||||
|  | ||||
| 	return uint32(fd.raw), nil | ||||
| } | ||||
|  | ||||
| func (fd *bpfFD) close() error { | ||||
| 	if fd.raw < 0 { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	value := int(fd.raw) | ||||
| 	fd.raw = -1 | ||||
|  | ||||
| 	fd.forget() | ||||
| 	return unix.Close(value) | ||||
| } | ||||
|  | ||||
| func (fd *bpfFD) forget() { | ||||
| 	runtime.SetFinalizer(fd, nil) | ||||
| } | ||||
|  | ||||
| func (fd *bpfFD) dup() (*bpfFD, error) { | ||||
| 	if fd.raw < 0 { | ||||
| 		return nil, errClosedFd | ||||
| 	} | ||||
|  | ||||
| 	dup, err := unix.FcntlInt(uintptr(fd.raw), unix.F_DUPFD_CLOEXEC, 0) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "can't dup fd") | ||||
| 	} | ||||
|  | ||||
| 	return newBPFFD(uint32(dup)), nil | ||||
| } | ||||
|  | ||||
| // bpfObjName is a null-terminated string made up of | ||||
| // 'A-Za-z0-9_' characters. | ||||
| type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte | ||||
| @@ -99,21 +44,25 @@ func invalidBPFObjNameChar(char rune) bool { | ||||
| } | ||||
|  | ||||
| type bpfMapCreateAttr struct { | ||||
| 	mapType    MapType | ||||
| 	keySize    uint32 | ||||
| 	valueSize  uint32 | ||||
| 	maxEntries uint32 | ||||
| 	flags      uint32 | ||||
| 	innerMapFd uint32     // since 4.12 56f668dfe00d | ||||
| 	numaNode   uint32     // since 4.14 96eabe7a40aa | ||||
| 	mapName    bpfObjName // since 4.15 ad5b177bd73f | ||||
| 	mapType        MapType | ||||
| 	keySize        uint32 | ||||
| 	valueSize      uint32 | ||||
| 	maxEntries     uint32 | ||||
| 	flags          uint32 | ||||
| 	innerMapFd     uint32     // since 4.12 56f668dfe00d | ||||
| 	numaNode       uint32     // since 4.14 96eabe7a40aa | ||||
| 	mapName        bpfObjName // since 4.15 ad5b177bd73f | ||||
| 	mapIfIndex     uint32 | ||||
| 	btfFd          uint32 | ||||
| 	btfKeyTypeID   btf.TypeID | ||||
| 	btfValueTypeID btf.TypeID | ||||
| } | ||||
|  | ||||
| type bpfMapOpAttr struct { | ||||
| 	mapFd   uint32 | ||||
| 	padding uint32 | ||||
| 	key     syscallPtr | ||||
| 	value   syscallPtr | ||||
| 	key     internal.Pointer | ||||
| 	value   internal.Pointer | ||||
| 	flags   uint64 | ||||
| } | ||||
|  | ||||
| @@ -128,7 +77,7 @@ type bpfMapInfo struct { | ||||
| } | ||||
|  | ||||
| type bpfPinObjAttr struct { | ||||
| 	fileName syscallPtr | ||||
| 	fileName internal.Pointer | ||||
| 	fd       uint32 | ||||
| 	padding  uint32 | ||||
| } | ||||
| @@ -136,16 +85,23 @@ type bpfPinObjAttr struct { | ||||
| type bpfProgLoadAttr struct { | ||||
| 	progType           ProgramType | ||||
| 	insCount           uint32 | ||||
| 	instructions       syscallPtr | ||||
| 	license            syscallPtr | ||||
| 	instructions       internal.Pointer | ||||
| 	license            internal.Pointer | ||||
| 	logLevel           uint32 | ||||
| 	logSize            uint32 | ||||
| 	logBuf             syscallPtr | ||||
| 	logBuf             internal.Pointer | ||||
| 	kernelVersion      uint32     // since 4.1  2541517c32be | ||||
| 	progFlags          uint32     // since 4.11 e07b98d9bffe | ||||
| 	progName           bpfObjName // since 4.15 067cae47771c | ||||
| 	progIfIndex        uint32     // since 4.15 1f6f4cb7ba21 | ||||
| 	expectedAttachType AttachType // since 4.17 5e43f899b03a | ||||
| 	progBTFFd          uint32 | ||||
| 	funcInfoRecSize    uint32 | ||||
| 	funcInfo           internal.Pointer | ||||
| 	funcInfoCnt        uint32 | ||||
| 	lineInfoRecSize    uint32 | ||||
| 	lineInfo           internal.Pointer | ||||
| 	lineInfoCnt        uint32 | ||||
| } | ||||
|  | ||||
| type bpfProgInfo struct { | ||||
| @@ -154,12 +110,12 @@ type bpfProgInfo struct { | ||||
| 	tag          [unix.BPF_TAG_SIZE]byte | ||||
| 	jitedLen     uint32 | ||||
| 	xlatedLen    uint32 | ||||
| 	jited        syscallPtr | ||||
| 	xlated       syscallPtr | ||||
| 	jited        internal.Pointer | ||||
| 	xlated       internal.Pointer | ||||
| 	loadTime     uint64 // since 4.15 cb4d2b3f03d8 | ||||
| 	createdByUID uint32 | ||||
| 	nrMapIDs     uint32 | ||||
| 	mapIds       syscallPtr | ||||
| 	mapIds       internal.Pointer | ||||
| 	name         bpfObjName | ||||
| } | ||||
|  | ||||
| @@ -168,8 +124,8 @@ type bpfProgTestRunAttr struct { | ||||
| 	retval      uint32 | ||||
| 	dataSizeIn  uint32 | ||||
| 	dataSizeOut uint32 | ||||
| 	dataIn      syscallPtr | ||||
| 	dataOut     syscallPtr | ||||
| 	dataIn      internal.Pointer | ||||
| 	dataOut     internal.Pointer | ||||
| 	repeat      uint32 | ||||
| 	duration    uint32 | ||||
| } | ||||
| @@ -184,7 +140,7 @@ type bpfProgAlterAttr struct { | ||||
| type bpfObjGetInfoByFDAttr struct { | ||||
| 	fd      uint32 | ||||
| 	infoLen uint32 | ||||
| 	info    syscallPtr // May be either bpfMapInfo or bpfProgInfo | ||||
| 	info    internal.Pointer // May be either bpfMapInfo or bpfProgInfo | ||||
| } | ||||
|  | ||||
| type bpfGetFDByIDAttr struct { | ||||
| @@ -192,13 +148,9 @@ type bpfGetFDByIDAttr struct { | ||||
| 	next uint32 | ||||
| } | ||||
|  | ||||
| func newPtr(ptr unsafe.Pointer) syscallPtr { | ||||
| 	return syscallPtr{ptr: ptr} | ||||
| } | ||||
|  | ||||
| func bpfProgLoad(attr *bpfProgLoadAttr) (*bpfFD, error) { | ||||
| func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) { | ||||
| 	for { | ||||
| 		fd, err := bpfCall(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 		fd, err := internal.BPF(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 		// As of ~4.20 the verifier can be interrupted by a signal, | ||||
| 		// and returns EAGAIN in that case. | ||||
| 		if err == unix.EAGAIN { | ||||
| @@ -209,22 +161,22 @@ func bpfProgLoad(attr *bpfProgLoadAttr) (*bpfFD, error) { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return newBPFFD(uint32(fd)), nil | ||||
| 		return internal.NewFD(uint32(fd)), nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error { | ||||
| 	_, err := bpfCall(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 	_, err := internal.BPF(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func bpfMapCreate(attr *bpfMapCreateAttr) (*bpfFD, error) { | ||||
| 	fd, err := bpfCall(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) { | ||||
| 	fd, err := internal.BPF(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return newBPFFD(uint32(fd)), nil | ||||
| 	return internal.NewFD(uint32(fd)), nil | ||||
| } | ||||
|  | ||||
| var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { | ||||
| @@ -237,9 +189,9 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	defer inner.close() | ||||
| 	defer inner.Close() | ||||
|  | ||||
| 	innerFd, _ := inner.value() | ||||
| 	innerFd, _ := inner.Value() | ||||
| 	nested, err := bpfMapCreate(&bpfMapCreateAttr{ | ||||
| 		mapType:    ArrayOfMaps, | ||||
| 		keySize:    4, | ||||
| @@ -251,12 +203,12 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	_ = nested.close() | ||||
| 	_ = nested.Close() | ||||
| 	return true | ||||
| }) | ||||
|  | ||||
| func bpfMapLookupElem(m *bpfFD, key, valueOut syscallPtr) error { | ||||
| 	fd, err := m.value() | ||||
| func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error { | ||||
| 	fd, err := m.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -266,12 +218,27 @@ func bpfMapLookupElem(m *bpfFD, key, valueOut syscallPtr) error { | ||||
| 		key:   key, | ||||
| 		value: valueOut, | ||||
| 	} | ||||
| 	_, err = bpfCall(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func bpfMapUpdateElem(m *bpfFD, key, valueOut syscallPtr, flags uint64) error { | ||||
| 	fd, err := m.value() | ||||
| func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error { | ||||
| 	fd, err := m.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	attr := bpfMapOpAttr{ | ||||
| 		mapFd: fd, | ||||
| 		key:   key, | ||||
| 		value: valueOut, | ||||
| 	} | ||||
| 	_, err = internal.BPF(_MapLookupAndDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint64) error { | ||||
| 	fd, err := m.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -282,12 +249,12 @@ func bpfMapUpdateElem(m *bpfFD, key, valueOut syscallPtr, flags uint64) error { | ||||
| 		value: valueOut, | ||||
| 		flags: flags, | ||||
| 	} | ||||
| 	_, err = bpfCall(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func bpfMapDeleteElem(m *bpfFD, key syscallPtr) error { | ||||
| 	fd, err := m.value() | ||||
| func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error { | ||||
| 	fd, err := m.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -296,12 +263,12 @@ func bpfMapDeleteElem(m *bpfFD, key syscallPtr) error { | ||||
| 		mapFd: fd, | ||||
| 		key:   key, | ||||
| 	} | ||||
| 	_, err = bpfCall(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func bpfMapGetNextKey(m *bpfFD, key, nextKeyOut syscallPtr) error { | ||||
| 	fd, err := m.value() | ||||
| func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error { | ||||
| 	fd, err := m.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -311,13 +278,13 @@ func bpfMapGetNextKey(m *bpfFD, key, nextKeyOut syscallPtr) error { | ||||
| 		key:   key, | ||||
| 		value: nextKeyOut, | ||||
| 	} | ||||
| 	_, err = bpfCall(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	_, err = internal.BPF(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| const bpfFSType = 0xcafe4a11 | ||||
|  | ||||
| func bpfPinObject(fileName string, fd *bpfFD) error { | ||||
| func bpfPinObject(fileName string, fd *internal.FD) error { | ||||
| 	dirName := filepath.Dir(fileName) | ||||
| 	var statfs unix.Statfs_t | ||||
| 	if err := unix.Statfs(dirName, &statfs); err != nil { | ||||
| @@ -327,30 +294,30 @@ func bpfPinObject(fileName string, fd *bpfFD) error { | ||||
| 		return errors.Errorf("%s is not on a bpf filesystem", fileName) | ||||
| 	} | ||||
|  | ||||
| 	value, err := fd.value() | ||||
| 	value, err := fd.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = bpfCall(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{ | ||||
| 		fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])), | ||||
| 	_, err = internal.BPF(_ObjPin, unsafe.Pointer(&bpfPinObjAttr{ | ||||
| 		fileName: internal.NewStringPointer(fileName), | ||||
| 		fd:       value, | ||||
| 	}), 16) | ||||
| 	return errors.Wrapf(err, "pin object %s", fileName) | ||||
| } | ||||
|  | ||||
| func bpfGetObject(fileName string) (*bpfFD, error) { | ||||
| 	ptr, err := bpfCall(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{ | ||||
| 		fileName: newPtr(unsafe.Pointer(&[]byte(fileName)[0])), | ||||
| func bpfGetObject(fileName string) (*internal.FD, error) { | ||||
| 	ptr, err := internal.BPF(_ObjGet, unsafe.Pointer(&bpfPinObjAttr{ | ||||
| 		fileName: internal.NewStringPointer(fileName), | ||||
| 	}), 16) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrapf(err, "get object %s", fileName) | ||||
| 	} | ||||
| 	return newBPFFD(uint32(ptr)), nil | ||||
| 	return internal.NewFD(uint32(ptr)), nil | ||||
| } | ||||
|  | ||||
| func bpfGetObjectInfoByFD(fd *bpfFD, info unsafe.Pointer, size uintptr) error { | ||||
| 	value, err := fd.value() | ||||
| func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) error { | ||||
| 	value, err := fd.Value() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -359,19 +326,19 @@ func bpfGetObjectInfoByFD(fd *bpfFD, info unsafe.Pointer, size uintptr) error { | ||||
| 	attr := bpfObjGetInfoByFDAttr{ | ||||
| 		fd:      value, | ||||
| 		infoLen: uint32(size), | ||||
| 		info:    newPtr(info), | ||||
| 		info:    internal.NewPointer(info), | ||||
| 	} | ||||
| 	_, err = bpfCall(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return errors.Wrapf(err, "fd %d", value) | ||||
| 	_, err = internal.BPF(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	return errors.Wrapf(err, "fd %d", fd) | ||||
| } | ||||
|  | ||||
| func bpfGetProgInfoByFD(fd *bpfFD) (*bpfProgInfo, error) { | ||||
| func bpfGetProgInfoByFD(fd *internal.FD) (*bpfProgInfo, error) { | ||||
| 	var info bpfProgInfo | ||||
| 	err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) | ||||
| 	return &info, errors.Wrap(err, "can't get program info") | ||||
| } | ||||
|  | ||||
| func bpfGetMapInfoByFD(fd *bpfFD) (*bpfMapInfo, error) { | ||||
| func bpfGetMapInfoByFD(fd *internal.FD) (*bpfMapInfo, error) { | ||||
| 	var info bpfMapInfo | ||||
| 	err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)) | ||||
| 	return &info, errors.Wrap(err, "can't get map info") | ||||
| @@ -398,50 +365,30 @@ var haveObjName = internal.FeatureTest("object names", "4.15", func() bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	_ = fd.close() | ||||
| 	_ = fd.Close() | ||||
| 	return true | ||||
| }) | ||||
|  | ||||
| func bpfGetMapFDByID(id uint32) (*bpfFD, error) { | ||||
| func bpfGetMapFDByID(id uint32) (*internal.FD, error) { | ||||
| 	// available from 4.13 | ||||
| 	attr := bpfGetFDByIDAttr{ | ||||
| 		id: id, | ||||
| 	} | ||||
| 	ptr, err := bpfCall(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	ptr, err := internal.BPF(_MapGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrapf(err, "can't get fd for map id %d", id) | ||||
| 	} | ||||
| 	return newBPFFD(uint32(ptr)), nil | ||||
| 	return internal.NewFD(uint32(ptr)), nil | ||||
| } | ||||
|  | ||||
| func bpfGetProgramFDByID(id uint32) (*bpfFD, error) { | ||||
| func bpfGetProgramFDByID(id uint32) (*internal.FD, error) { | ||||
| 	// available from 4.13 | ||||
| 	attr := bpfGetFDByIDAttr{ | ||||
| 		id: id, | ||||
| 	} | ||||
| 	ptr, err := bpfCall(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	ptr, err := internal.BPF(_ProgGetFDByID, unsafe.Pointer(&attr), unsafe.Sizeof(attr)) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrapf(err, "can't get fd for program id %d", id) | ||||
| 	} | ||||
| 	return newBPFFD(uint32(ptr)), nil | ||||
| } | ||||
|  | ||||
| func bpfCall(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) { | ||||
| 	r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size) | ||||
| 	runtime.KeepAlive(attr) | ||||
|  | ||||
| 	var err error | ||||
| 	if errNo != 0 { | ||||
| 		err = errNo | ||||
| 	} | ||||
|  | ||||
| 	return r1, err | ||||
| } | ||||
|  | ||||
| func convertCString(in []byte) string { | ||||
| 	inLen := bytes.IndexByte(in, 0) | ||||
| 	if inLen == -1 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return string(in[:inLen]) | ||||
| 	return internal.NewFD(uint32(ptr)), nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										36
									
								
								vendor/github.com/cilium/ebpf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/cilium/ebpf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -57,6 +57,30 @@ const ( | ||||
| 	// HashOfMaps - Each item in the hash map is another map. The inner map mustn't be a map of maps | ||||
| 	// itself. | ||||
| 	HashOfMaps | ||||
| 	// DevMap - Specialized map to store references to network devices. | ||||
| 	DevMap | ||||
| 	// SockMap - Specialized map to store references to sockets. | ||||
| 	SockMap | ||||
| 	// CPUMap - Specialized map to store references to CPUs. | ||||
| 	CPUMap | ||||
| 	// XSKMap - Specialized map for XDP programs to store references to open sockets. | ||||
| 	XSKMap | ||||
| 	// SockHash - Specialized hash to store references to sockets. | ||||
| 	SockHash | ||||
| 	// CGroupStorage - Special map for CGroups. | ||||
| 	CGroupStorage | ||||
| 	// ReusePortSockArray - Specialized map to store references to sockets that can be reused. | ||||
| 	ReusePortSockArray | ||||
| 	// PerCPUCGroupStorage - Special per CPU map for CGroups. | ||||
| 	PerCPUCGroupStorage | ||||
| 	// Queue - FIFO storage for BPF programs. | ||||
| 	Queue | ||||
| 	// Stack - LIFO storage for BPF programs. | ||||
| 	Stack | ||||
| 	// SkStorage - Specialized map for local storage at SK for BPF programs. | ||||
| 	SkStorage | ||||
| 	// DevMapHash - Hash-based indexing scheme for references to network devices. | ||||
| 	DevMapHash | ||||
| ) | ||||
|  | ||||
| // hasPerCPUValue returns true if the Map stores a value per CPU. | ||||
| @@ -84,6 +108,13 @@ const ( | ||||
| 	_ProgGetFDByID | ||||
| 	_MapGetFDByID | ||||
| 	_ObjGetInfoByFD | ||||
| 	_ProgQuery | ||||
| 	_RawTracepointOpen | ||||
| 	_BTFLoad | ||||
| 	_BTFGetFDByID | ||||
| 	_TaskFDQuery | ||||
| 	_MapLookupAndDeleteElem | ||||
| 	_MapFreeze | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -149,6 +180,8 @@ const ( | ||||
| 	RawTracepointWritable | ||||
| 	// CGroupSockopt program | ||||
| 	CGroupSockopt | ||||
| 	// Tracing program | ||||
| 	Tracing | ||||
| ) | ||||
|  | ||||
| // AttachType of the eBPF program, needed to differentiate allowed context accesses in | ||||
| @@ -183,6 +216,9 @@ const ( | ||||
| 	AttachCGroupUDP6Recvmsg | ||||
| 	AttachCGroupGetsockopt | ||||
| 	AttachCGroupSetsockopt | ||||
| 	AttachTraceRawTp | ||||
| 	AttachTraceFEntry | ||||
| 	AttachTraceFExit | ||||
| ) | ||||
|  | ||||
| // AttachFlags of the eBPF program used in BPF_PROG_ATTACH command | ||||
|   | ||||
							
								
								
									
										21
									
								
								vendor/github.com/cilium/ebpf/types_string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/cilium/ebpf/types_string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -22,11 +22,23 @@ func _() { | ||||
| 	_ = x[LPMTrie-11] | ||||
| 	_ = x[ArrayOfMaps-12] | ||||
| 	_ = x[HashOfMaps-13] | ||||
| 	_ = x[DevMap-14] | ||||
| 	_ = x[SockMap-15] | ||||
| 	_ = x[CPUMap-16] | ||||
| 	_ = x[XSKMap-17] | ||||
| 	_ = x[SockHash-18] | ||||
| 	_ = x[CGroupStorage-19] | ||||
| 	_ = x[ReusePortSockArray-20] | ||||
| 	_ = x[PerCPUCGroupStorage-21] | ||||
| 	_ = x[Queue-22] | ||||
| 	_ = x[Stack-23] | ||||
| 	_ = x[SkStorage-24] | ||||
| 	_ = x[DevMapHash-25] | ||||
| } | ||||
|  | ||||
| const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMaps" | ||||
| const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHash" | ||||
|  | ||||
| var _MapType_index = [...]uint8{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136} | ||||
| var _MapType_index = [...]uint8{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248} | ||||
|  | ||||
| func (i MapType) String() string { | ||||
| 	if i >= MapType(len(_MapType_index)-1) { | ||||
| @@ -64,11 +76,12 @@ func _() { | ||||
| 	_ = x[CGroupSysctl-23] | ||||
| 	_ = x[RawTracepointWritable-24] | ||||
| 	_ = x[CGroupSockopt-25] | ||||
| 	_ = x[Tracing-26] | ||||
| } | ||||
|  | ||||
| const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockopt" | ||||
| const _ProgramType_name = "UnspecifiedProgramSocketFilterKprobeSchedCLSSchedACTTracePointXDPPerfEventCGroupSKBCGroupSockLWTInLWTOutLWTXmitSockOpsSkSKBCGroupDeviceSkMsgRawTracepointCGroupSockAddrLWTSeg6LocalLircMode2SkReuseportFlowDissectorCGroupSysctlRawTracepointWritableCGroupSockoptTracing" | ||||
|  | ||||
| var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258} | ||||
| var _ProgramType_index = [...]uint16{0, 18, 30, 36, 44, 52, 62, 65, 74, 83, 93, 98, 104, 111, 118, 123, 135, 140, 153, 167, 179, 188, 199, 212, 224, 245, 258, 265} | ||||
|  | ||||
| func (i ProgramType) String() string { | ||||
| 	if i >= ProgramType(len(_ProgramType_index)-1) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sebastiaan van Stijn
					Sebastiaan van Stijn