vendor runc v1.0.0-rc91
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
432
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
432
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
@@ -4,20 +4,29 @@ import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const btfMagic = 0xeB9F
|
||||
|
||||
// Errors returned by BTF functions.
|
||||
var (
|
||||
ErrNotSupported = internal.ErrNotSupported
|
||||
ErrNotFound = errors.New("not found")
|
||||
ErrNoExtendedInfo = errors.New("no extended info")
|
||||
)
|
||||
|
||||
// Spec represents decoded BTF.
|
||||
type Spec struct {
|
||||
rawTypes []rawType
|
||||
@@ -25,6 +34,7 @@ type Spec struct {
|
||||
types map[string][]Type
|
||||
funcInfos map[string]extInfo
|
||||
lineInfos map[string]extInfo
|
||||
byteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
type btfHeader struct {
|
||||
@@ -52,6 +62,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
var (
|
||||
btfSection *elf.Section
|
||||
btfExtSection *elf.Section
|
||||
sectionSizes = make(map[string]uint32)
|
||||
)
|
||||
|
||||
for _, sec := range file.Sections {
|
||||
@@ -60,6 +71,16 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
btfSection = sec
|
||||
case ".BTF.ext":
|
||||
btfExtSection = sec
|
||||
default:
|
||||
if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS {
|
||||
break
|
||||
}
|
||||
|
||||
if sec.Size > math.MaxUint32 {
|
||||
return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
|
||||
}
|
||||
|
||||
sectionSizes[sec.Name] = uint32(sec.Size)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,74 +88,59 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
spec, err := parseBTF(btfSection.Open(), file.ByteOrder)
|
||||
symbols, err := file.Symbols()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read symbols: %v", err)
|
||||
}
|
||||
|
||||
variableOffsets := make(map[variable]uint32)
|
||||
for _, symbol := range symbols {
|
||||
if idx := symbol.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE {
|
||||
// Ignore things like SHN_ABS
|
||||
continue
|
||||
}
|
||||
|
||||
secName := file.Sections[symbol.Section].Name
|
||||
if _, ok := sectionSizes[secName]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if symbol.Value > math.MaxUint32 {
|
||||
return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
|
||||
}
|
||||
|
||||
variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
|
||||
}
|
||||
|
||||
spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets)
|
||||
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")
|
||||
}
|
||||
if btfExtSection == nil {
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read ext info: %w", err)
|
||||
}
|
||||
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) {
|
||||
rawBTF, err := ioutil.ReadAll(btf)
|
||||
func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) {
|
||||
rawTypes, rawStrings, err := parseBTF(btf, bo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't read BTF")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)))
|
||||
err = fixupDatasec(rawTypes, rawStrings, sectionSizes, variableOffsets)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't read type names")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
types, err := inflateRawTypes(rawTypes, rawStrings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,13 +148,158 @@ func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) (*Spec, error) {
|
||||
return &Spec{
|
||||
rawTypes: rawTypes,
|
||||
types: types,
|
||||
strings: strings,
|
||||
funcInfos: make(map[string]extInfo),
|
||||
lineInfos: make(map[string]extInfo),
|
||||
strings: rawStrings,
|
||||
byteOrder: bo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
|
||||
var kernelBTF struct {
|
||||
sync.Mutex
|
||||
*Spec
|
||||
}
|
||||
|
||||
// LoadKernelSpec returns the current kernel's BTF information.
|
||||
//
|
||||
// Requires a >= 5.5 kernel with CONFIG_DEBUG_INFO_BTF enabled. Returns
|
||||
// ErrNotSupported if BTF is not enabled.
|
||||
func LoadKernelSpec() (*Spec, error) {
|
||||
kernelBTF.Lock()
|
||||
defer kernelBTF.Unlock()
|
||||
|
||||
if kernelBTF.Spec != nil {
|
||||
return kernelBTF.Spec, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
kernelBTF.Spec, err = loadKernelSpec()
|
||||
return kernelBTF.Spec, err
|
||||
}
|
||||
|
||||
func loadKernelSpec() (*Spec, error) {
|
||||
fh, err := os.Open("/sys/kernel/btf/vmlinux")
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("can't open kernel BTF at /sys/kernel/btf/vmlinux: %w", ErrNotFound)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read kernel BTF: %s", err)
|
||||
}
|
||||
defer fh.Close()
|
||||
|
||||
return loadNakedSpec(fh, internal.NativeEndian, nil, nil)
|
||||
}
|
||||
|
||||
func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
|
||||
rawBTF, err := ioutil.ReadAll(btf)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read BTF: %v", err)
|
||||
}
|
||||
|
||||
rd := bytes.NewReader(rawBTF)
|
||||
|
||||
var header btfHeader
|
||||
if err := binary.Read(rd, bo, &header); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read header: %v", err)
|
||||
}
|
||||
|
||||
if header.Magic != btfMagic {
|
||||
return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
|
||||
}
|
||||
|
||||
if header.Version != 1 {
|
||||
return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
|
||||
}
|
||||
|
||||
if header.Flags != 0 {
|
||||
return nil, nil, fmt.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")
|
||||
}
|
||||
|
||||
if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil {
|
||||
return nil, nil, fmt.Errorf("header padding: %v", err)
|
||||
}
|
||||
|
||||
if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err)
|
||||
}
|
||||
|
||||
rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen)))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read type names: %w", err)
|
||||
}
|
||||
|
||||
if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err)
|
||||
}
|
||||
|
||||
rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read types: %w", err)
|
||||
}
|
||||
|
||||
return rawTypes, rawStrings, nil
|
||||
}
|
||||
|
||||
type variable struct {
|
||||
section string
|
||||
name string
|
||||
}
|
||||
|
||||
func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) error {
|
||||
for i, rawType := range rawTypes {
|
||||
if rawType.Kind() != kindDatasec {
|
||||
continue
|
||||
}
|
||||
|
||||
name, err := rawStrings.Lookup(rawType.NameOff)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if name == ".kconfig" || name == ".ksym" {
|
||||
return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
|
||||
}
|
||||
|
||||
size, ok := sectionSizes[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("data section %s: missing size", name)
|
||||
}
|
||||
|
||||
rawTypes[i].SizeType = size
|
||||
|
||||
secinfos := rawType.data.([]btfVarSecinfo)
|
||||
for j, secInfo := range secinfos {
|
||||
id := int(secInfo.Type - 1)
|
||||
if id >= len(rawTypes) {
|
||||
return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
|
||||
}
|
||||
|
||||
varName, err := rawStrings.Lookup(rawTypes[id].NameOff)
|
||||
if err != nil {
|
||||
return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
|
||||
}
|
||||
|
||||
offset, ok := variableOffsets[variable{name, varName}]
|
||||
if !ok {
|
||||
return fmt.Errorf("data section %s: missing offset for variable %s", name, varName)
|
||||
}
|
||||
|
||||
secinfos[j].Offset = offset
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type marshalOpts struct {
|
||||
ByteOrder binary.ByteOrder
|
||||
StripFuncLinkage bool
|
||||
}
|
||||
|
||||
func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
|
||||
var (
|
||||
buf bytes.Buffer
|
||||
header = new(btfHeader)
|
||||
@@ -160,17 +311,14 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
|
||||
_, _ = 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)
|
||||
for _, raw := range s.rawTypes {
|
||||
switch {
|
||||
case opts.StripFuncLinkage && raw.Kind() == kindFunc:
|
||||
raw.SetLinkage(linkageStatic)
|
||||
}
|
||||
|
||||
if err := typ.Marshal(&buf, bo); err != nil {
|
||||
return nil, errors.Wrap(err, "can't marshal BTF")
|
||||
if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
|
||||
return nil, fmt.Errorf("can't marshal BTF: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,9 +340,9 @@ func (s *Spec) marshal(bo binary.ByteOrder) ([]byte, error) {
|
||||
}
|
||||
|
||||
raw := buf.Bytes()
|
||||
err := binary.Write(sliceWriter(raw[:headerLen]), bo, header)
|
||||
err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't write header")
|
||||
return nil, fmt.Errorf("can't write header: %v", err)
|
||||
}
|
||||
|
||||
return raw, nil
|
||||
@@ -214,17 +362,22 @@ func (sw sliceWriter) Write(p []byte) (int, error) {
|
||||
//
|
||||
// Length is the number of bytes in the raw BPF instruction stream.
|
||||
//
|
||||
// Returns an error if there is no BTF.
|
||||
// Returns an error which may wrap ErrNoExtendedInfo if the Spec doesn't
|
||||
// contain extended BTF info.
|
||||
func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
||||
if length == 0 {
|
||||
return nil, errors.New("length musn't be zero")
|
||||
}
|
||||
|
||||
if s.funcInfos == nil && s.lineInfos == nil {
|
||||
return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
|
||||
}
|
||||
|
||||
funcInfos, funcOK := s.funcInfos[name]
|
||||
lineInfos, lineOK := s.lineInfos[name]
|
||||
|
||||
if !funcOK && !lineOK {
|
||||
return nil, errors.Errorf("no BTF for program %s", name)
|
||||
return nil, fmt.Errorf("no extended BTF info for section %s", name)
|
||||
}
|
||||
|
||||
return &Program{s, length, funcInfos, lineInfos}, nil
|
||||
@@ -233,15 +386,15 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
||||
// 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) {
|
||||
func (s *Spec) Map(name string) (*Map, []Member, error) {
|
||||
var mapVar Var
|
||||
if err := s.FindType(name, &mapVar); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mapStruct, ok := mapVar.Type.(*Struct)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("expected struct, have %s", mapVar.Type)
|
||||
return nil, nil, fmt.Errorf("expected struct, have %s", mapVar.Type)
|
||||
}
|
||||
|
||||
var key, value Type
|
||||
@@ -256,23 +409,32 @@ func (s *Spec) Map(name string) (*Map, error) {
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
return nil, errors.Errorf("map %s: missing 'key' in type", name)
|
||||
key = (*Void)(nil)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
return nil, errors.Errorf("map %s: missing 'value' in type", name)
|
||||
value = (*Void)(nil)
|
||||
}
|
||||
|
||||
return &Map{mapStruct, s, key, value}, nil
|
||||
return &Map{s, key, value}, mapStruct.Members, nil
|
||||
}
|
||||
|
||||
var errNotFound = errors.New("not found")
|
||||
// Datasec returns the BTF required to create maps which represent data sections.
|
||||
func (s *Spec) Datasec(name string) (*Map, error) {
|
||||
var datasec Datasec
|
||||
if err := s.FindType(name, &datasec); err != nil {
|
||||
return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
|
||||
}
|
||||
|
||||
return &Map{s, &Void{}, &datasec}, nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Returns an error wrapping ErrNotFound if no matching
|
||||
// type exists in spec.
|
||||
func (s *Spec) FindType(name string, typ Type) error {
|
||||
var (
|
||||
wanted = reflect.TypeOf(typ)
|
||||
@@ -285,14 +447,14 @@ func (s *Spec) FindType(name string, typ Type) error {
|
||||
}
|
||||
|
||||
if candidate != nil {
|
||||
return errors.Errorf("type %s: multiple candidates for %T", name, typ)
|
||||
return fmt.Errorf("type %s: multiple candidates for %T", name, typ)
|
||||
}
|
||||
|
||||
candidate = typ
|
||||
}
|
||||
|
||||
if candidate == nil {
|
||||
return errors.WithMessagef(errNotFound, "type %s", name)
|
||||
return fmt.Errorf("type %s: %w", name, ErrNotFound)
|
||||
}
|
||||
|
||||
value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
|
||||
@@ -307,16 +469,22 @@ type Handle struct {
|
||||
|
||||
// NewHandle loads BTF into the kernel.
|
||||
//
|
||||
// Returns an error if BTF is not supported, which can
|
||||
// be checked by IsNotSupported.
|
||||
// Returns ErrNotSupported if BTF is not supported.
|
||||
func NewHandle(spec *Spec) (*Handle, error) {
|
||||
if err := haveBTF(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
btf, err := spec.marshal(internal.NativeEndian)
|
||||
if spec.byteOrder != internal.NativeEndian {
|
||||
return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
|
||||
}
|
||||
|
||||
btf, err := spec.marshal(marshalOpts{
|
||||
ByteOrder: internal.NativeEndian,
|
||||
StripFuncLinkage: haveFuncLinkage() != nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't marshal BTF")
|
||||
return nil, fmt.Errorf("can't marshal BTF: %w", err)
|
||||
}
|
||||
|
||||
if uint64(len(btf)) > math.MaxUint32 {
|
||||
@@ -360,7 +528,6 @@ func (h *Handle) FD() int {
|
||||
|
||||
// Map is the BTF for a map.
|
||||
type Map struct {
|
||||
definition *Struct
|
||||
spec *Spec
|
||||
key, value Type
|
||||
}
|
||||
@@ -371,12 +538,6 @@ 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 {
|
||||
@@ -411,12 +572,12 @@ func ProgramSpec(s *Program) *Spec {
|
||||
func ProgramAppend(s, other *Program) error {
|
||||
funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "func infos")
|
||||
return fmt.Errorf("func infos: %w", err)
|
||||
}
|
||||
|
||||
lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "line infos")
|
||||
return fmt.Errorf("line infos: %w", err)
|
||||
}
|
||||
|
||||
s.length += other.length
|
||||
@@ -451,13 +612,6 @@ func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
||||
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
|
||||
@@ -477,26 +631,36 @@ func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) {
|
||||
return internal.NewFD(uint32(fd)), nil
|
||||
}
|
||||
|
||||
func minimalBTF(bo binary.ByteOrder) []byte {
|
||||
func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte {
|
||||
const minHeaderLength = 24
|
||||
|
||||
typesLen := uint32(binary.Size(types))
|
||||
header := btfHeader{
|
||||
Magic: btfMagic,
|
||||
Version: 1,
|
||||
HdrLen: minHeaderLength,
|
||||
TypeOff: 0,
|
||||
TypeLen: typesLen,
|
||||
StringOff: typesLen,
|
||||
StringLen: uint32(len(strings)),
|
||||
}
|
||||
|
||||
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, error) {
|
||||
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
|
||||
@@ -507,16 +671,8 @@ func minimalBTF(bo binary.ByteOrder) []byte {
|
||||
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)
|
||||
btf := marshalBTF(&types, strings, internal.NativeEndian)
|
||||
|
||||
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)),
|
||||
@@ -526,5 +682,35 @@ var haveBTF = internal.FeatureTest("BTF", "5.1", func() bool {
|
||||
}
|
||||
// Check for EINVAL specifically, rather than err != nil since we
|
||||
// otherwise misdetect due to insufficient permissions.
|
||||
return errors.Cause(err) != unix.EINVAL
|
||||
return !errors.Is(err, unix.EINVAL), nil
|
||||
})
|
||||
|
||||
var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bool, error) {
|
||||
var (
|
||||
types struct {
|
||||
FuncProto btfType
|
||||
Func btfType
|
||||
}
|
||||
strings = []byte{0, 'a', 0}
|
||||
)
|
||||
|
||||
types.FuncProto.SetKind(kindFuncProto)
|
||||
types.Func.SetKind(kindFunc)
|
||||
types.Func.SizeType = 1 // aka FuncProto
|
||||
types.Func.NameOff = 1
|
||||
types.Func.SetLinkage(linkageGlobal)
|
||||
|
||||
btf := marshalBTF(&types, strings, 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.Is(err, unix.EINVAL), nil
|
||||
})
|
||||
|
||||
101
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
101
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
@@ -2,9 +2,8 @@ package btf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// btfKind describes a Type.
|
||||
@@ -32,6 +31,14 @@ const (
|
||||
kindDatasec
|
||||
)
|
||||
|
||||
type btfFuncLinkage uint8
|
||||
|
||||
const (
|
||||
linkageStatic btfFuncLinkage = iota
|
||||
linkageGlobal
|
||||
linkageExtern
|
||||
)
|
||||
|
||||
const (
|
||||
btfTypeKindShift = 24
|
||||
btfTypeKindLen = 4
|
||||
@@ -43,7 +50,7 @@ const (
|
||||
type btfType struct {
|
||||
NameOff uint32
|
||||
/* "info" bits arrangement
|
||||
* bits 0-15: vlen (e.g. # of struct's members)
|
||||
* bits 0-15: vlen (e.g. # of struct's members), linkage
|
||||
* bits 16-23: unused
|
||||
* bits 24-27: kind (e.g. int, ptr, array...etc)
|
||||
* bits 28-30: unused
|
||||
@@ -61,6 +68,45 @@ type btfType struct {
|
||||
SizeType uint32
|
||||
}
|
||||
|
||||
func (k btfKind) String() string {
|
||||
switch k {
|
||||
case kindUnknown:
|
||||
return "Unknown"
|
||||
case kindInt:
|
||||
return "Integer"
|
||||
case kindPointer:
|
||||
return "Pointer"
|
||||
case kindArray:
|
||||
return "Array"
|
||||
case kindStruct:
|
||||
return "Struct"
|
||||
case kindUnion:
|
||||
return "Union"
|
||||
case kindEnum:
|
||||
return "Enumeration"
|
||||
case kindForward:
|
||||
return "Forward"
|
||||
case kindTypedef:
|
||||
return "Typedef"
|
||||
case kindVolatile:
|
||||
return "Volatile"
|
||||
case kindConst:
|
||||
return "Const"
|
||||
case kindRestrict:
|
||||
return "Restrict"
|
||||
case kindFunc:
|
||||
return "Function"
|
||||
case kindFuncProto:
|
||||
return "Function Proto"
|
||||
case kindVar:
|
||||
return "Variable"
|
||||
case kindDatasec:
|
||||
return "Section"
|
||||
default:
|
||||
return fmt.Sprintf("Unknown (%d)", k)
|
||||
}
|
||||
}
|
||||
|
||||
func mask(len uint32) uint32 {
|
||||
return (1 << len) - 1
|
||||
}
|
||||
@@ -90,6 +136,14 @@ func (bt *btfType) SetVlen(vlen int) {
|
||||
bt.setInfo(uint32(vlen), btfTypeVlenMask, btfTypeVlenShift)
|
||||
}
|
||||
|
||||
func (bt *btfType) Linkage() btfFuncLinkage {
|
||||
return btfFuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift))
|
||||
}
|
||||
|
||||
func (bt *btfType) SetLinkage(linkage btfFuncLinkage) {
|
||||
bt.setInfo(uint32(linkage), btfTypeVlenMask, btfTypeVlenShift)
|
||||
}
|
||||
|
||||
func (bt *btfType) Type() TypeID {
|
||||
// TODO: Panic here if wrong kind?
|
||||
return TypeID(bt.SizeType)
|
||||
@@ -129,6 +183,26 @@ type btfMember struct {
|
||||
Offset uint32
|
||||
}
|
||||
|
||||
type btfVarSecinfo struct {
|
||||
Type TypeID
|
||||
Offset uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type btfVariable struct {
|
||||
Linkage uint32
|
||||
}
|
||||
|
||||
type btfEnum struct {
|
||||
NameOff uint32
|
||||
Val int32
|
||||
}
|
||||
|
||||
type btfParam struct {
|
||||
NameOff uint32
|
||||
Type TypeID
|
||||
}
|
||||
|
||||
func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
var (
|
||||
header btfType
|
||||
@@ -139,14 +213,13 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
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)
|
||||
return nil, fmt.Errorf("can't read type info for id %v: %v", id, err)
|
||||
}
|
||||
|
||||
var data interface{}
|
||||
switch header.Kind() {
|
||||
case kindInt:
|
||||
// sizeof(uint32)
|
||||
data = make([]byte, 4)
|
||||
data = new(uint32)
|
||||
case kindPointer:
|
||||
case kindArray:
|
||||
data = new(btfArray)
|
||||
@@ -155,8 +228,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
case kindUnion:
|
||||
data = make([]btfMember, header.Vlen())
|
||||
case kindEnum:
|
||||
// sizeof(struct btf_enum)
|
||||
data = make([]byte, header.Vlen()*4*2)
|
||||
data = make([]btfEnum, header.Vlen())
|
||||
case kindForward:
|
||||
case kindTypedef:
|
||||
case kindVolatile:
|
||||
@@ -164,16 +236,13 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
case kindRestrict:
|
||||
case kindFunc:
|
||||
case kindFuncProto:
|
||||
// sizeof(struct btf_param)
|
||||
data = make([]byte, header.Vlen()*4*2)
|
||||
data = make([]btfParam, header.Vlen())
|
||||
case kindVar:
|
||||
// sizeof(struct btf_variable)
|
||||
data = make([]byte, 4)
|
||||
data = new(btfVariable)
|
||||
case kindDatasec:
|
||||
// sizeof(struct btf_var_secinfo)
|
||||
data = make([]byte, header.Vlen()*4*3)
|
||||
data = make([]btfVarSecinfo, header.Vlen())
|
||||
default:
|
||||
return nil, errors.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
||||
return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
|
||||
}
|
||||
|
||||
if data == nil {
|
||||
@@ -182,7 +251,7 @@ func readTypes(r io.Reader, bo binary.ByteOrder) ([]rawType, error) {
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, fmt.Errorf("type id %d: kind %v: can't read %T: %v", id, header.Kind(), data, err)
|
||||
}
|
||||
|
||||
types = append(types, rawType{header, data})
|
||||
|
||||
44
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
44
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
@@ -3,13 +3,13 @@ package btf
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/cilium/ebpf/asm"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type btfExtHeader struct {
|
||||
@@ -25,23 +25,21 @@ type btfExtHeader struct {
|
||||
}
|
||||
|
||||
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")
|
||||
return nil, nil, fmt.Errorf("can't read header: %v", err)
|
||||
}
|
||||
|
||||
if header.Magic != expectedMagic {
|
||||
return nil, nil, errors.Errorf("incorrect magic value %v", header.Magic)
|
||||
if header.Magic != btfMagic {
|
||||
return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
|
||||
}
|
||||
|
||||
if header.Version != 1 {
|
||||
return nil, nil, errors.Errorf("unexpected version %v", header.Version)
|
||||
return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
|
||||
}
|
||||
|
||||
if header.Flags != 0 {
|
||||
return nil, nil, errors.Errorf("unsupported flags %v", header.Flags)
|
||||
return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
|
||||
}
|
||||
|
||||
remainder := int64(header.HdrLen) - int64(binary.Size(&header))
|
||||
@@ -53,25 +51,25 @@ func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (f
|
||||
// .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")
|
||||
return nil, nil, fmt.Errorf("header padding: %v", err)
|
||||
}
|
||||
|
||||
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")
|
||||
return nil, nil, fmt.Errorf("can't seek to function info section: %v", err)
|
||||
}
|
||||
|
||||
funcInfo, err = parseExtInfo(io.LimitReader(r, int64(header.FuncInfoLen)), bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "function info")
|
||||
return nil, nil, fmt.Errorf("function info: %w", err)
|
||||
}
|
||||
|
||||
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")
|
||||
return nil, nil, fmt.Errorf("can't seek to line info section: %v", err)
|
||||
}
|
||||
|
||||
lineInfo, err = parseExtInfo(io.LimitReader(r, int64(header.LineInfoLen)), bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "line info")
|
||||
return nil, nil, fmt.Errorf("line info: %w", err)
|
||||
}
|
||||
|
||||
return funcInfo, lineInfo, nil
|
||||
@@ -94,7 +92,7 @@ type extInfo struct {
|
||||
|
||||
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)
|
||||
return extInfo{}, fmt.Errorf("ext_info record size mismatch, want %d (got %d)", ei.recordSize, other.recordSize)
|
||||
}
|
||||
|
||||
records := make([]extInfoRecord, 0, len(ei.records)+len(other.records))
|
||||
@@ -119,7 +117,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
|
||||
// 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")
|
||||
return nil, fmt.Errorf("can't write instruction offset: %v", err)
|
||||
}
|
||||
|
||||
buf.Write(info.Opaque)
|
||||
@@ -131,7 +129,7 @@ func (ei extInfo) MarshalBinary() ([]byte, error) {
|
||||
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")
|
||||
return nil, fmt.Errorf("can't read record size: %v", err)
|
||||
}
|
||||
|
||||
if recordSize < 4 {
|
||||
@@ -145,32 +143,32 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
|
||||
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")
|
||||
return nil, fmt.Errorf("can't read ext info header: %v", err)
|
||||
}
|
||||
|
||||
secName, err := strings.Lookup(infoHeader.SecNameOff)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't get section name")
|
||||
return nil, fmt.Errorf("can't get section name: %w", err)
|
||||
}
|
||||
|
||||
if infoHeader.NumInfo == 0 {
|
||||
return nil, errors.Errorf("section %s has invalid number of records", secName)
|
||||
return nil, fmt.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)
|
||||
return nil, fmt.Errorf("section %v: can't read extended info offset: %v", secName, err)
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, fmt.Errorf("section %v: can't read record: %v", secName, err)
|
||||
}
|
||||
|
||||
if byteOff%asm.InstructionSize != 0 {
|
||||
return nil, errors.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
|
||||
return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, byteOff)
|
||||
}
|
||||
|
||||
records = append(records, extInfoRecord{uint64(byteOff), buf})
|
||||
|
||||
14
vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
14
vendor/github.com/cilium/ebpf/internal/btf/strings.go
generated
vendored
@@ -2,10 +2,10 @@ package btf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type stringTable []byte
|
||||
@@ -13,7 +13,7 @@ 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")
|
||||
return nil, fmt.Errorf("can't read string table: %v", err)
|
||||
}
|
||||
|
||||
if len(contents) < 1 {
|
||||
@@ -33,22 +33,22 @@ func readStringTable(r io.Reader) (stringTable, error) {
|
||||
|
||||
func (st stringTable) Lookup(offset uint32) (string, error) {
|
||||
if int64(offset) > int64(^uint(0)>>1) {
|
||||
return "", errors.Errorf("offset %d overflows int", offset)
|
||||
return "", fmt.Errorf("offset %d overflows int", offset)
|
||||
}
|
||||
|
||||
pos := int(offset)
|
||||
if pos >= len(st) {
|
||||
return "", errors.Errorf("offset %d is out of bounds", offset)
|
||||
return "", fmt.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)
|
||||
return "", fmt.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 "", fmt.Errorf("offset %d isn't null terminated", offset)
|
||||
}
|
||||
|
||||
return string(str[:end]), nil
|
||||
|
||||
117
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
117
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
@@ -1,9 +1,9 @@
|
||||
package btf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const maxTypeDepth = 32
|
||||
@@ -38,9 +38,10 @@ func (n Name) name() string {
|
||||
// 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) {}
|
||||
func (v *Void) ID() TypeID { return 0 }
|
||||
func (v *Void) size() uint32 { return 0 }
|
||||
func (v *Void) copy() Type { return (*Void)(nil) }
|
||||
func (v *Void) walk(*copyStack) {}
|
||||
|
||||
// Int is an integer of a given length.
|
||||
type Int struct {
|
||||
@@ -103,7 +104,8 @@ func (s *Struct) walk(cs *copyStack) {
|
||||
|
||||
func (s *Struct) copy() Type {
|
||||
cpy := *s
|
||||
cpy.Members = copyMembers(cpy.Members)
|
||||
cpy.Members = make([]Member, len(s.Members))
|
||||
copy(cpy.Members, s.Members)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
@@ -126,7 +128,8 @@ func (u *Union) walk(cs *copyStack) {
|
||||
|
||||
func (u *Union) copy() Type {
|
||||
cpy := *u
|
||||
cpy.Members = copyMembers(cpy.Members)
|
||||
cpy.Members = make([]Member, len(u.Members))
|
||||
copy(cpy.Members, u.Members)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
@@ -139,14 +142,6 @@ type Member struct {
|
||||
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
|
||||
@@ -265,15 +260,31 @@ type Datasec struct {
|
||||
TypeID
|
||||
Name
|
||||
Size uint32
|
||||
Vars []VarSecinfo
|
||||
}
|
||||
|
||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
||||
|
||||
func (ds *Datasec) walk(cs *copyStack) {
|
||||
for i := range ds.Vars {
|
||||
cs.push(&ds.Vars[i].Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
||||
func (ds *Datasec) walk(*copyStack) {}
|
||||
func (ds *Datasec) copy() Type {
|
||||
cpy := *ds
|
||||
cpy.Vars = make([]VarSecinfo, len(ds.Vars))
|
||||
copy(cpy.Vars, ds.Vars)
|
||||
return &cpy
|
||||
}
|
||||
|
||||
// VarSecinfo describes variable in a Datasec
|
||||
type VarSecinfo struct {
|
||||
Type Type
|
||||
Offset uint32
|
||||
Size uint32
|
||||
}
|
||||
|
||||
type sizer interface {
|
||||
size() uint32
|
||||
}
|
||||
@@ -326,7 +337,7 @@ func Sizeof(typ Type) (int, error) {
|
||||
continue
|
||||
|
||||
default:
|
||||
return 0, errors.Errorf("unrecognized type %T", typ)
|
||||
return 0, fmt.Errorf("unrecognized type %T", typ)
|
||||
}
|
||||
|
||||
if n > 0 && elem > math.MaxInt64/n {
|
||||
@@ -405,12 +416,17 @@ var _ namer = Name("")
|
||||
// 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
|
||||
type fixupDef struct {
|
||||
id TypeID
|
||||
expectedKind btfKind
|
||||
typ *Type
|
||||
}
|
||||
|
||||
var fixups []fixupDef
|
||||
fixup := func(id TypeID, expectedKind btfKind, typ *Type) {
|
||||
fixups = append(fixups, fixupDef{id, expectedKind, typ})
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -418,7 +434,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
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)
|
||||
return nil, fmt.Errorf("can't get name for member %d: %w", i, err)
|
||||
}
|
||||
members = append(members, Member{
|
||||
Name: name,
|
||||
@@ -426,13 +442,13 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
})
|
||||
}
|
||||
for i := range members {
|
||||
fixups = append(fixups, fixup{raw[i].Type, &members[i].Type})
|
||||
fixup(raw[i].Type, kindUnknown, &members[i].Type)
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
types := make([]Type, 0, len(rawTypes))
|
||||
types = append(types, Void{})
|
||||
types = append(types, (*Void)(nil))
|
||||
namedTypes = make(map[string][]Type)
|
||||
|
||||
for i, raw := range rawTypes {
|
||||
@@ -445,7 +461,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
|
||||
name, err := rawStrings.LookupName(raw.NameOff)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't get name for type id %d", id)
|
||||
return nil, fmt.Errorf("can't get name for type id %d: %w", id, err)
|
||||
}
|
||||
|
||||
switch raw.Kind() {
|
||||
@@ -454,7 +470,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
|
||||
case kindPointer:
|
||||
ptr := &Pointer{id, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &ptr.Target})
|
||||
fixup(raw.Type(), kindUnknown, &ptr.Target)
|
||||
typ = ptr
|
||||
|
||||
case kindArray:
|
||||
@@ -463,20 +479,20 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
// 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})
|
||||
fixup(btfArr.Type, kindUnknown, &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)
|
||||
return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
|
||||
}
|
||||
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)
|
||||
return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
|
||||
}
|
||||
typ = &Union{id, name, raw.Size(), members}
|
||||
|
||||
@@ -488,44 +504,55 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
|
||||
case kindTypedef:
|
||||
typedef := &Typedef{id, name, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &typedef.Type})
|
||||
fixup(raw.Type(), kindUnknown, &typedef.Type)
|
||||
typ = typedef
|
||||
|
||||
case kindVolatile:
|
||||
volatile := &Volatile{id, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &volatile.Type})
|
||||
fixup(raw.Type(), kindUnknown, &volatile.Type)
|
||||
typ = volatile
|
||||
|
||||
case kindConst:
|
||||
cnst := &Const{id, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &cnst.Type})
|
||||
fixup(raw.Type(), kindUnknown, &cnst.Type)
|
||||
typ = cnst
|
||||
|
||||
case kindRestrict:
|
||||
restrict := &Restrict{id, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &restrict.Type})
|
||||
fixup(raw.Type(), kindUnknown, &restrict.Type)
|
||||
typ = restrict
|
||||
|
||||
case kindFunc:
|
||||
fn := &Func{id, name, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &fn.Type})
|
||||
fixup(raw.Type(), kindFuncProto, &fn.Type)
|
||||
typ = fn
|
||||
|
||||
case kindFuncProto:
|
||||
fp := &FuncProto{id, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &fp.Return})
|
||||
fixup(raw.Type(), kindUnknown, &fp.Return)
|
||||
typ = fp
|
||||
|
||||
case kindVar:
|
||||
v := &Var{id, name, nil}
|
||||
fixups = append(fixups, fixup{raw.Type(), &v.Type})
|
||||
fixup(raw.Type(), kindUnknown, &v.Type)
|
||||
typ = v
|
||||
|
||||
case kindDatasec:
|
||||
typ = &Datasec{id, name, raw.SizeType}
|
||||
btfVars := raw.data.([]btfVarSecinfo)
|
||||
vars := make([]VarSecinfo, 0, len(btfVars))
|
||||
for _, btfVar := range btfVars {
|
||||
vars = append(vars, VarSecinfo{
|
||||
Offset: btfVar.Offset,
|
||||
Size: btfVar.Size,
|
||||
})
|
||||
}
|
||||
for i := range vars {
|
||||
fixup(btfVars[i].Type, kindVar, &vars[i].Type)
|
||||
}
|
||||
typ = &Datasec{id, name, raw.SizeType, vars}
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||
return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||
}
|
||||
|
||||
types = append(types, typ)
|
||||
@@ -540,7 +567,17 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
for _, fixup := range fixups {
|
||||
i := int(fixup.id)
|
||||
if i >= len(types) {
|
||||
return nil, errors.Errorf("reference to invalid type id: %d", fixup.id)
|
||||
return nil, fmt.Errorf("reference to invalid type id: %d", fixup.id)
|
||||
}
|
||||
|
||||
// Default void (id 0) to unknown
|
||||
rawKind := kindUnknown
|
||||
if i > 0 {
|
||||
rawKind = rawTypes[i-1].Kind()
|
||||
}
|
||||
|
||||
if expected := fixup.expectedKind; expected != kindUnknown && rawKind != expected {
|
||||
return nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
|
||||
}
|
||||
|
||||
*fixup.typ = types[i]
|
||||
|
||||
60
vendor/github.com/cilium/ebpf/internal/cpu.go
generated
vendored
60
vendor/github.com/cilium/ebpf/internal/cpu.go
generated
vendored
@@ -2,10 +2,9 @@ package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var sysCPU struct {
|
||||
@@ -18,45 +17,44 @@ var sysCPU struct {
|
||||
// Logical CPU numbers must be of the form 0-n
|
||||
func PossibleCPUs() (int, error) {
|
||||
sysCPU.once.Do(func() {
|
||||
sysCPU.num, sysCPU.err = parseCPUs("/sys/devices/system/cpu/possible")
|
||||
sysCPU.num, sysCPU.err = parseCPUsFromFile("/sys/devices/system/cpu/possible")
|
||||
})
|
||||
|
||||
return sysCPU.num, sysCPU.err
|
||||
}
|
||||
|
||||
var onlineCPU struct {
|
||||
once sync.Once
|
||||
err error
|
||||
num int
|
||||
}
|
||||
|
||||
// OnlineCPUs returns the number of currently online CPUs
|
||||
// Logical CPU numbers must be of the form 0-n
|
||||
func OnlineCPUs() (int, error) {
|
||||
onlineCPU.once.Do(func() {
|
||||
onlineCPU.num, onlineCPU.err = parseCPUs("/sys/devices/system/cpu/online")
|
||||
})
|
||||
|
||||
return onlineCPU.num, onlineCPU.err
|
||||
}
|
||||
|
||||
// parseCPUs parses the number of cpus from sysfs,
|
||||
// in the format of "/sys/devices/system/cpu/{possible,online,..}.
|
||||
// Logical CPU numbers must be of the form 0-n
|
||||
func parseCPUs(path string) (int, error) {
|
||||
file, err := os.Open(path)
|
||||
func parseCPUsFromFile(path string) (int, error) {
|
||||
spec, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
n, err := parseCPUs(string(spec))
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("can't parse %s: %v", path, err)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// parseCPUs parses the number of cpus from a string produced
|
||||
// by bitmap_list_string() in the Linux kernel.
|
||||
// Multiple ranges are rejected, since they can't be unified
|
||||
// into a single number.
|
||||
// This is the format of /sys/devices/system/cpu/possible, it
|
||||
// is not suitable for /sys/devices/system/cpu/online, etc.
|
||||
func parseCPUs(spec string) (int, error) {
|
||||
if strings.Trim(spec, "\n") == "0" {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
var low, high int
|
||||
n, _ := fmt.Fscanf(file, "%d-%d", &low, &high)
|
||||
if n < 1 || low != 0 {
|
||||
return 0, errors.Wrapf(err, "%s has unknown format", path)
|
||||
n, err := fmt.Sscanf(spec, "%d-%d\n", &low, &high)
|
||||
if n != 2 || err != nil {
|
||||
return 0, fmt.Errorf("invalid format: %s", spec)
|
||||
}
|
||||
if n == 1 {
|
||||
high = low
|
||||
if low != 0 {
|
||||
return 0, fmt.Errorf("CPU spec doesn't start at zero: %s", spec)
|
||||
}
|
||||
|
||||
// cpus is 0 indexed
|
||||
|
||||
15
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
15
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
@@ -2,11 +2,11 @@ package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ErrorWithLog returns an error that includes logs from the
|
||||
@@ -16,19 +16,20 @@ import (
|
||||
// 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 {
|
||||
if errors.Is(logErr, unix.ENOSPC) {
|
||||
logStr += " (truncated...)"
|
||||
}
|
||||
|
||||
return &loadError{err, logStr}
|
||||
return &VerifierError{err, logStr}
|
||||
}
|
||||
|
||||
type loadError struct {
|
||||
// VerifierError includes information from the eBPF verifier.
|
||||
type VerifierError struct {
|
||||
cause error
|
||||
log string
|
||||
}
|
||||
|
||||
func (le *loadError) Error() string {
|
||||
func (le *VerifierError) Error() string {
|
||||
if le.log == "" {
|
||||
return le.cause.Error()
|
||||
}
|
||||
@@ -36,10 +37,6 @@ func (le *loadError) Error() string {
|
||||
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)
|
||||
|
||||
12
vendor/github.com/cilium/ebpf/internal/fd.go
generated
vendored
12
vendor/github.com/cilium/ebpf/internal/fd.go
generated
vendored
@@ -1,12 +1,13 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var ErrClosedFd = errors.New("use of closed file descriptor")
|
||||
@@ -56,8 +57,13 @@ func (fd *FD) Dup() (*FD, error) {
|
||||
|
||||
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 nil, fmt.Errorf("can't dup fd: %v", err)
|
||||
}
|
||||
|
||||
return NewFD(uint32(dup)), nil
|
||||
}
|
||||
|
||||
func (fd *FD) File(name string) *os.File {
|
||||
fd.Forget()
|
||||
return os.NewFile(uintptr(fd.raw), name)
|
||||
}
|
||||
|
||||
73
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
73
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
@@ -1,12 +1,14 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ErrNotSupported indicates that a feature is not supported by the current kernel.
|
||||
var ErrNotSupported = errors.New("not supported")
|
||||
|
||||
// UnsupportedFeatureError is returned by FeatureTest() functions.
|
||||
type UnsupportedFeatureError struct {
|
||||
// The minimum Linux mainline version required for this feature.
|
||||
@@ -21,33 +23,68 @@ func (ufe *UnsupportedFeatureError) Error() string {
|
||||
return fmt.Sprintf("%s not supported (requires >= %s)", ufe.Name, ufe.MinimumVersion)
|
||||
}
|
||||
|
||||
// Is indicates that UnsupportedFeatureError is ErrNotSupported.
|
||||
func (ufe *UnsupportedFeatureError) Is(target error) bool {
|
||||
return target == ErrNotSupported
|
||||
}
|
||||
|
||||
type featureTest struct {
|
||||
sync.Mutex
|
||||
successful bool
|
||||
result error
|
||||
}
|
||||
|
||||
// FeatureTestFn is used to determine whether the kernel supports
|
||||
// a certain feature.
|
||||
//
|
||||
// The return values have the following semantics:
|
||||
//
|
||||
// err != nil: the test couldn't be executed
|
||||
// err == nil && available: the feature is available
|
||||
// err == nil && !available: the feature isn't available
|
||||
type FeatureTestFn func() (available bool, err error)
|
||||
|
||||
// FeatureTest wraps a function so that it is run at most once.
|
||||
//
|
||||
// name should identify the tested feature, while version must be in the
|
||||
// form Major.Minor[.Patch].
|
||||
//
|
||||
// Returns a descriptive UnsupportedFeatureError if the feature is not available.
|
||||
func FeatureTest(name, version string, fn func() bool) func() error {
|
||||
// Returns an error wrapping ErrNotSupported if the feature is not supported.
|
||||
func FeatureTest(name, version string, fn FeatureTestFn) func() error {
|
||||
v, err := NewVersion(version)
|
||||
if err != nil {
|
||||
return func() error { return err }
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
result error
|
||||
)
|
||||
|
||||
ft := new(featureTest)
|
||||
return func() error {
|
||||
once.Do(func() {
|
||||
if !fn() {
|
||||
result = &UnsupportedFeatureError{
|
||||
MinimumVersion: v,
|
||||
Name: name,
|
||||
}
|
||||
ft.Lock()
|
||||
defer ft.Unlock()
|
||||
|
||||
if ft.successful {
|
||||
return ft.result
|
||||
}
|
||||
|
||||
available, err := fn()
|
||||
if errors.Is(err, ErrNotSupported) {
|
||||
// The feature test aborted because a dependent feature
|
||||
// is missing, which we should cache.
|
||||
available = false
|
||||
} else if err != nil {
|
||||
// We couldn't execute the feature test to a point
|
||||
// where it could make a determination.
|
||||
// Don't cache the result, just return it.
|
||||
return fmt.Errorf("can't detect support for %s: %w", name, err)
|
||||
}
|
||||
|
||||
ft.successful = true
|
||||
if !available {
|
||||
ft.result = &UnsupportedFeatureError{
|
||||
MinimumVersion: v,
|
||||
Name: name,
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
return ft.result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +98,7 @@ func NewVersion(ver string) (Version, error) {
|
||||
var major, minor, patch uint16
|
||||
n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
|
||||
if n < 2 {
|
||||
return Version{}, errors.Errorf("invalid version: %s", ver)
|
||||
return Version{}, fmt.Errorf("invalid version: %s", ver)
|
||||
}
|
||||
return Version{major, minor, patch}, nil
|
||||
}
|
||||
|
||||
2
vendor/github.com/cilium/ebpf/internal/io.go
generated
vendored
2
vendor/github.com/cilium/ebpf/internal/io.go
generated
vendored
@@ -1,6 +1,6 @@
|
||||
package internal
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
import "errors"
|
||||
|
||||
// DiscardZeroes makes sure that all written bytes are zero
|
||||
// before discarding them.
|
||||
|
||||
6
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
6
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
@@ -22,5 +22,9 @@ func NewStringPointer(str string) Pointer {
|
||||
return Pointer{}
|
||||
}
|
||||
|
||||
return Pointer{ptr: unsafe.Pointer(&[]byte(str)[0])}
|
||||
// The kernel expects strings to be zero terminated
|
||||
buf := make([]byte, len(str)+1)
|
||||
copy(buf, str)
|
||||
|
||||
return Pointer{ptr: unsafe.Pointer(&buf[0])}
|
||||
}
|
||||
|
||||
118
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
118
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
@@ -1,16 +1,61 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
//go:generate stringer -output syscall_string.go -type=BPFCmd
|
||||
|
||||
// BPFCmd identifies a subcommand of the bpf syscall.
|
||||
type BPFCmd int
|
||||
|
||||
// Well known BPF commands.
|
||||
const (
|
||||
BPF_MAP_CREATE BPFCmd = iota
|
||||
BPF_MAP_LOOKUP_ELEM
|
||||
BPF_MAP_UPDATE_ELEM
|
||||
BPF_MAP_DELETE_ELEM
|
||||
BPF_MAP_GET_NEXT_KEY
|
||||
BPF_PROG_LOAD
|
||||
BPF_OBJ_PIN
|
||||
BPF_OBJ_GET
|
||||
BPF_PROG_ATTACH
|
||||
BPF_PROG_DETACH
|
||||
BPF_PROG_TEST_RUN
|
||||
BPF_PROG_GET_NEXT_ID
|
||||
BPF_MAP_GET_NEXT_ID
|
||||
BPF_PROG_GET_FD_BY_ID
|
||||
BPF_MAP_GET_FD_BY_ID
|
||||
BPF_OBJ_GET_INFO_BY_FD
|
||||
BPF_PROG_QUERY
|
||||
BPF_RAW_TRACEPOINT_OPEN
|
||||
BPF_BTF_LOAD
|
||||
BPF_BTF_GET_FD_BY_ID
|
||||
BPF_TASK_FD_QUERY
|
||||
BPF_MAP_LOOKUP_AND_DELETE_ELEM
|
||||
BPF_MAP_FREEZE
|
||||
BPF_BTF_GET_NEXT_ID
|
||||
BPF_MAP_LOOKUP_BATCH
|
||||
BPF_MAP_LOOKUP_AND_DELETE_BATCH
|
||||
BPF_MAP_UPDATE_BATCH
|
||||
BPF_MAP_DELETE_BATCH
|
||||
BPF_LINK_CREATE
|
||||
BPF_LINK_UPDATE
|
||||
BPF_LINK_GET_FD_BY_ID
|
||||
BPF_LINK_GET_NEXT_ID
|
||||
BPF_ENABLE_STATS
|
||||
BPF_ITER_CREATE
|
||||
)
|
||||
|
||||
// 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) {
|
||||
func BPF(cmd BPFCmd, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
||||
r1, _, errNo := unix.Syscall(unix.SYS_BPF, uintptr(cmd), uintptr(attr), size)
|
||||
runtime.KeepAlive(attr)
|
||||
|
||||
@@ -21,3 +66,74 @@ func BPF(cmd int, attr unsafe.Pointer, size uintptr) (uintptr, error) {
|
||||
|
||||
return r1, err
|
||||
}
|
||||
|
||||
type BPFProgAttachAttr struct {
|
||||
TargetFd uint32
|
||||
AttachBpfFd uint32
|
||||
AttachType uint32
|
||||
AttachFlags uint32
|
||||
ReplaceBpfFd uint32
|
||||
}
|
||||
|
||||
func BPFProgAttach(attr *BPFProgAttachAttr) error {
|
||||
_, err := BPF(BPF_PROG_ATTACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
return err
|
||||
}
|
||||
|
||||
type BPFProgDetachAttr struct {
|
||||
TargetFd uint32
|
||||
AttachBpfFd uint32
|
||||
AttachType uint32
|
||||
}
|
||||
|
||||
func BPFProgDetach(attr *BPFProgDetachAttr) error {
|
||||
_, err := BPF(BPF_PROG_DETACH, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
return err
|
||||
}
|
||||
|
||||
type bpfObjAttr struct {
|
||||
fileName Pointer
|
||||
fd uint32
|
||||
fileFlags uint32
|
||||
}
|
||||
|
||||
const bpfFSType = 0xcafe4a11
|
||||
|
||||
// BPFObjPin wraps BPF_OBJ_PIN.
|
||||
func BPFObjPin(fileName string, fd *FD) error {
|
||||
dirName := filepath.Dir(fileName)
|
||||
var statfs unix.Statfs_t
|
||||
if err := unix.Statfs(dirName, &statfs); err != nil {
|
||||
return err
|
||||
}
|
||||
if uint64(statfs.Type) != bpfFSType {
|
||||
return fmt.Errorf("%s is not on a bpf filesystem", fileName)
|
||||
}
|
||||
|
||||
value, err := fd.Value()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attr := bpfObjAttr{
|
||||
fileName: NewStringPointer(fileName),
|
||||
fd: value,
|
||||
}
|
||||
_, err = BPF(BPF_OBJ_PIN, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||
if err != nil {
|
||||
return fmt.Errorf("pin object %s: %w", fileName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BPFObjGet wraps BPF_OBJ_GET.
|
||||
func BPFObjGet(fileName string) (*FD, error) {
|
||||
attr := bpfObjAttr{
|
||||
fileName: NewStringPointer(fileName),
|
||||
}
|
||||
ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get object %s: %w", fileName, err)
|
||||
}
|
||||
return NewFD(uint32(ptr)), nil
|
||||
}
|
||||
|
||||
56
vendor/github.com/cilium/ebpf/internal/syscall_string.go
generated
vendored
Normal file
56
vendor/github.com/cilium/ebpf/internal/syscall_string.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Code generated by "stringer -output syscall_string.go -type=BPFCmd"; DO NOT EDIT.
|
||||
|
||||
package internal
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[BPF_MAP_CREATE-0]
|
||||
_ = x[BPF_MAP_LOOKUP_ELEM-1]
|
||||
_ = x[BPF_MAP_UPDATE_ELEM-2]
|
||||
_ = x[BPF_MAP_DELETE_ELEM-3]
|
||||
_ = x[BPF_MAP_GET_NEXT_KEY-4]
|
||||
_ = x[BPF_PROG_LOAD-5]
|
||||
_ = x[BPF_OBJ_PIN-6]
|
||||
_ = x[BPF_OBJ_GET-7]
|
||||
_ = x[BPF_PROG_ATTACH-8]
|
||||
_ = x[BPF_PROG_DETACH-9]
|
||||
_ = x[BPF_PROG_TEST_RUN-10]
|
||||
_ = x[BPF_PROG_GET_NEXT_ID-11]
|
||||
_ = x[BPF_MAP_GET_NEXT_ID-12]
|
||||
_ = x[BPF_PROG_GET_FD_BY_ID-13]
|
||||
_ = x[BPF_MAP_GET_FD_BY_ID-14]
|
||||
_ = x[BPF_OBJ_GET_INFO_BY_FD-15]
|
||||
_ = x[BPF_PROG_QUERY-16]
|
||||
_ = x[BPF_RAW_TRACEPOINT_OPEN-17]
|
||||
_ = x[BPF_BTF_LOAD-18]
|
||||
_ = x[BPF_BTF_GET_FD_BY_ID-19]
|
||||
_ = x[BPF_TASK_FD_QUERY-20]
|
||||
_ = x[BPF_MAP_LOOKUP_AND_DELETE_ELEM-21]
|
||||
_ = x[BPF_MAP_FREEZE-22]
|
||||
_ = x[BPF_BTF_GET_NEXT_ID-23]
|
||||
_ = x[BPF_MAP_LOOKUP_BATCH-24]
|
||||
_ = x[BPF_MAP_LOOKUP_AND_DELETE_BATCH-25]
|
||||
_ = x[BPF_MAP_UPDATE_BATCH-26]
|
||||
_ = x[BPF_MAP_DELETE_BATCH-27]
|
||||
_ = x[BPF_LINK_CREATE-28]
|
||||
_ = x[BPF_LINK_UPDATE-29]
|
||||
_ = x[BPF_LINK_GET_FD_BY_ID-30]
|
||||
_ = x[BPF_LINK_GET_NEXT_ID-31]
|
||||
_ = x[BPF_ENABLE_STATS-32]
|
||||
_ = x[BPF_ITER_CREATE-33]
|
||||
}
|
||||
|
||||
const _BPFCmd_name = "BPF_MAP_CREATEBPF_MAP_LOOKUP_ELEMBPF_MAP_UPDATE_ELEMBPF_MAP_DELETE_ELEMBPF_MAP_GET_NEXT_KEYBPF_PROG_LOADBPF_OBJ_PINBPF_OBJ_GETBPF_PROG_ATTACHBPF_PROG_DETACHBPF_PROG_TEST_RUNBPF_PROG_GET_NEXT_IDBPF_MAP_GET_NEXT_IDBPF_PROG_GET_FD_BY_IDBPF_MAP_GET_FD_BY_IDBPF_OBJ_GET_INFO_BY_FDBPF_PROG_QUERYBPF_RAW_TRACEPOINT_OPENBPF_BTF_LOADBPF_BTF_GET_FD_BY_IDBPF_TASK_FD_QUERYBPF_MAP_LOOKUP_AND_DELETE_ELEMBPF_MAP_FREEZEBPF_BTF_GET_NEXT_IDBPF_MAP_LOOKUP_BATCHBPF_MAP_LOOKUP_AND_DELETE_BATCHBPF_MAP_UPDATE_BATCHBPF_MAP_DELETE_BATCHBPF_LINK_CREATEBPF_LINK_UPDATEBPF_LINK_GET_FD_BY_IDBPF_LINK_GET_NEXT_IDBPF_ENABLE_STATSBPF_ITER_CREATE"
|
||||
|
||||
var _BPFCmd_index = [...]uint16{0, 14, 33, 52, 71, 91, 104, 115, 126, 141, 156, 173, 193, 212, 233, 253, 275, 289, 312, 324, 344, 361, 391, 405, 424, 444, 475, 495, 515, 530, 545, 566, 586, 602, 617}
|
||||
|
||||
func (i BPFCmd) String() string {
|
||||
if i < 0 || i >= BPFCmd(len(_BPFCmd_index)-1) {
|
||||
return "BPFCmd(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BPFCmd_name[_BPFCmd_index[i]:_BPFCmd_index[i+1]]
|
||||
}
|
||||
23
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
23
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@@ -10,10 +10,17 @@ import (
|
||||
|
||||
const (
|
||||
ENOENT = linux.ENOENT
|
||||
EEXIST = linux.EEXIST
|
||||
EAGAIN = linux.EAGAIN
|
||||
ENOSPC = linux.ENOSPC
|
||||
EINVAL = linux.EINVAL
|
||||
EPOLLIN = linux.EPOLLIN
|
||||
EINTR = linux.EINTR
|
||||
EPERM = linux.EPERM
|
||||
ESRCH = linux.ESRCH
|
||||
ENODEV = linux.ENODEV
|
||||
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
|
||||
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
|
||||
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
||||
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
||||
SYS_BPF = linux.SYS_BPF
|
||||
@@ -31,6 +38,7 @@ const (
|
||||
PERF_SAMPLE_RAW = linux.PERF_SAMPLE_RAW
|
||||
PERF_FLAG_FD_CLOEXEC = linux.PERF_FLAG_FD_CLOEXEC
|
||||
RLIM_INFINITY = linux.RLIM_INFINITY
|
||||
RLIMIT_MEMLOCK = linux.RLIMIT_MEMLOCK
|
||||
)
|
||||
|
||||
// Statfs_t is a wrapper
|
||||
@@ -125,3 +133,18 @@ type Utsname = linux.Utsname
|
||||
func Uname(buf *Utsname) (err error) {
|
||||
return linux.Uname(buf)
|
||||
}
|
||||
|
||||
// Getpid is a wrapper
|
||||
func Getpid() int {
|
||||
return linux.Getpid()
|
||||
}
|
||||
|
||||
// Gettid is a wrapper
|
||||
func Gettid() int {
|
||||
return linux.Gettid()
|
||||
}
|
||||
|
||||
// Tgkill is a wrapper
|
||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return linux.Tgkill(tgid, tid, sig)
|
||||
}
|
||||
|
||||
26
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
26
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@@ -12,9 +12,16 @@ var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime
|
||||
|
||||
const (
|
||||
ENOENT = syscall.ENOENT
|
||||
EEXIST = syscall.EEXIST
|
||||
EAGAIN = syscall.EAGAIN
|
||||
ENOSPC = syscall.ENOSPC
|
||||
EINVAL = syscall.EINVAL
|
||||
EINTR = syscall.EINTR
|
||||
EPERM = syscall.EPERM
|
||||
ESRCH = syscall.ESRCH
|
||||
ENODEV = syscall.ENODEV
|
||||
BPF_F_RDONLY_PROG = 0
|
||||
BPF_F_WRONLY_PROG = 0
|
||||
BPF_OBJ_NAME_LEN = 0x10
|
||||
BPF_TAG_SIZE = 0x8
|
||||
SYS_BPF = 321
|
||||
@@ -32,6 +39,8 @@ const (
|
||||
PerfBitWatermark = 0x4000
|
||||
PERF_SAMPLE_RAW = 0x400
|
||||
PERF_FLAG_FD_CLOEXEC = 0x8
|
||||
RLIM_INFINITY = 0x7fffffffffffffff
|
||||
RLIMIT_MEMLOCK = 8
|
||||
)
|
||||
|
||||
// Statfs_t is a wrapper
|
||||
@@ -184,10 +193,25 @@ func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int
|
||||
|
||||
// Utsname is a wrapper
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
Release [65]byte
|
||||
}
|
||||
|
||||
// Uname is a wrapper
|
||||
func Uname(buf *Utsname) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
// Getpid is a wrapper
|
||||
func Getpid() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Gettid is a wrapper
|
||||
func Gettid() int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// Tgkill is a wrapper
|
||||
func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user