Update runc to v1.0.0-rc91
https://github.com/opencontainers/runc/releases/tag/v1.0.0-rc91 Signed-off-by: Davanum Srinivas <davanum@gmail.com>
This commit is contained in:
		
							
								
								
									
										16
									
								
								vendor/github.com/cilium/ebpf/abi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/cilium/ebpf/abi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -3,14 +3,13 @@ package ebpf
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MapABI are the attributes of a Map which are available across all supported kernels.
 | 
			
		||||
@@ -35,7 +34,7 @@ func newMapABIFromSpec(spec *MapSpec) *MapABI {
 | 
			
		||||
func newMapABIFromFd(fd *internal.FD) (string, *MapABI, error) {
 | 
			
		||||
	info, err := bpfGetMapInfoByFD(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Cause(err) == syscall.EINVAL {
 | 
			
		||||
		if errors.Is(err, syscall.EINVAL) {
 | 
			
		||||
			abi, err := newMapABIFromProc(fd)
 | 
			
		||||
			return "", abi, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -98,7 +97,7 @@ func newProgramABIFromSpec(spec *ProgramSpec) *ProgramABI {
 | 
			
		||||
func newProgramABIFromFd(fd *internal.FD) (string, *ProgramABI, error) {
 | 
			
		||||
	info, err := bpfGetProgInfoByFD(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if errors.Cause(err) == syscall.EINVAL {
 | 
			
		||||
		if errors.Is(err, syscall.EINVAL) {
 | 
			
		||||
			return newProgramABIFromProc(fd)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +126,7 @@ func newProgramABIFromProc(fd *internal.FD) (string, *ProgramABI, error) {
 | 
			
		||||
		"prog_type": &abi.Type,
 | 
			
		||||
		"prog_tag":  &name,
 | 
			
		||||
	})
 | 
			
		||||
	if errors.Cause(err) == errMissingFields {
 | 
			
		||||
	if errors.Is(err, errMissingFields) {
 | 
			
		||||
		return "", nil, &internal.UnsupportedFeatureError{
 | 
			
		||||
			Name:           "reading ABI from /proc/self/fdinfo",
 | 
			
		||||
			MinimumVersion: internal.Version{4, 11, 0},
 | 
			
		||||
@@ -152,7 +151,10 @@ func scanFdInfo(fd *internal.FD, fields map[string]interface{}) error {
 | 
			
		||||
	}
 | 
			
		||||
	defer fh.Close()
 | 
			
		||||
 | 
			
		||||
	return errors.Wrap(scanFdInfoReader(fh, fields), fh.Name())
 | 
			
		||||
	if err := scanFdInfoReader(fh, fields); err != nil {
 | 
			
		||||
		return fmt.Errorf("%s: %w", fh.Name(), err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errMissingFields = errors.New("missing fields")
 | 
			
		||||
@@ -176,7 +178,7 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if n, err := fmt.Fscanln(bytes.NewReader(parts[1]), field); err != nil || n != 1 {
 | 
			
		||||
			return errors.Wrapf(err, "can't parse field %s", name)
 | 
			
		||||
			return fmt.Errorf("can't parse field %s: %v", name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		scanned++
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										114
									
								
								vendor/github.com/cilium/ebpf/asm/instruction.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										114
									
								
								vendor/github.com/cilium/ebpf/asm/instruction.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,12 +2,11 @@ package asm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// InstructionSize is the size of a BPF instruction in bytes
 | 
			
		||||
@@ -39,10 +38,12 @@ func (ins *Instruction) Unmarshal(r io.Reader, bo binary.ByteOrder) (uint64, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ins.OpCode = bi.OpCode
 | 
			
		||||
	ins.Dst = bi.Registers.Dst()
 | 
			
		||||
	ins.Src = bi.Registers.Src()
 | 
			
		||||
	ins.Offset = bi.Offset
 | 
			
		||||
	ins.Constant = int64(bi.Constant)
 | 
			
		||||
	ins.Dst, ins.Src, err = bi.Registers.Unmarshal(bo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("can't unmarshal registers: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !bi.OpCode.isDWordLoad() {
 | 
			
		||||
		return InstructionSize, nil
 | 
			
		||||
@@ -75,9 +76,14 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
 | 
			
		||||
		cons = int32(uint32(ins.Constant))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	regs, err := newBPFRegisters(ins.Dst, ins.Src, bo)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("can't marshal registers: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bpfi := bpfInstruction{
 | 
			
		||||
		ins.OpCode,
 | 
			
		||||
		newBPFRegisters(ins.Dst, ins.Src),
 | 
			
		||||
		regs,
 | 
			
		||||
		ins.Offset,
 | 
			
		||||
		cons,
 | 
			
		||||
	}
 | 
			
		||||
@@ -103,22 +109,52 @@ func (ins Instruction) Marshal(w io.Writer, bo binary.ByteOrder) (uint64, error)
 | 
			
		||||
 | 
			
		||||
// RewriteMapPtr changes an instruction to use a new map fd.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if the fd is invalid, or the instruction
 | 
			
		||||
// is incorrect.
 | 
			
		||||
// Returns an error if the instruction doesn't load a map.
 | 
			
		||||
func (ins *Instruction) RewriteMapPtr(fd int) error {
 | 
			
		||||
	if !ins.OpCode.isDWordLoad() {
 | 
			
		||||
		return errors.Errorf("%s is not a 64 bit load", ins.OpCode)
 | 
			
		||||
		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fd < 0 {
 | 
			
		||||
		return errors.New("invalid fd")
 | 
			
		||||
	if ins.Src != PseudoMapFD && ins.Src != PseudoMapValue {
 | 
			
		||||
		return errors.New("not a load from a map")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ins.Src = R1
 | 
			
		||||
	ins.Constant = int64(fd)
 | 
			
		||||
	// Preserve the offset value for direct map loads.
 | 
			
		||||
	offset := uint64(ins.Constant) & (math.MaxUint32 << 32)
 | 
			
		||||
	rawFd := uint64(uint32(fd))
 | 
			
		||||
	ins.Constant = int64(offset | rawFd)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ins *Instruction) mapPtr() uint32 {
 | 
			
		||||
	return uint32(uint64(ins.Constant) & math.MaxUint32)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RewriteMapOffset changes the offset of a direct load from a map.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if the instruction is not a direct load.
 | 
			
		||||
func (ins *Instruction) RewriteMapOffset(offset uint32) error {
 | 
			
		||||
	if !ins.OpCode.isDWordLoad() {
 | 
			
		||||
		return fmt.Errorf("%s is not a 64 bit load", ins.OpCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ins.Src != PseudoMapValue {
 | 
			
		||||
		return errors.New("not a direct load from a map")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd := uint64(ins.Constant) & math.MaxUint32
 | 
			
		||||
	ins.Constant = int64(uint64(offset)<<32 | fd)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ins *Instruction) mapOffset() uint32 {
 | 
			
		||||
	return uint32(uint64(ins.Constant) >> 32)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ins *Instruction) isLoadFromMap() bool {
 | 
			
		||||
	return ins.OpCode == LoadImmOp(DWord) && (ins.Src == PseudoMapFD || ins.Src == PseudoMapValue)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Format implements fmt.Formatter.
 | 
			
		||||
func (ins Instruction) Format(f fmt.State, c rune) {
 | 
			
		||||
	if c != 'v' {
 | 
			
		||||
@@ -139,6 +175,19 @@ func (ins Instruction) Format(f fmt.State, c rune) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ins.isLoadFromMap() {
 | 
			
		||||
		fd := int32(ins.mapPtr())
 | 
			
		||||
		switch ins.Src {
 | 
			
		||||
		case PseudoMapFD:
 | 
			
		||||
			fmt.Fprintf(f, "LoadMapPtr dst: %s fd: %d", ins.Dst, fd)
 | 
			
		||||
 | 
			
		||||
		case PseudoMapValue:
 | 
			
		||||
			fmt.Fprintf(f, "LoadMapValue dst: %s, fd: %d off: %d", ins.Dst, fd, ins.mapOffset())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		goto ref
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Fprintf(f, "%v ", op)
 | 
			
		||||
	switch cls := op.Class(); cls {
 | 
			
		||||
	case LdClass, LdXClass, StClass, StXClass:
 | 
			
		||||
@@ -166,7 +215,7 @@ func (ins Instruction) Format(f fmt.State, c rune) {
 | 
			
		||||
	case JumpClass:
 | 
			
		||||
		switch jop := op.JumpOp(); jop {
 | 
			
		||||
		case Call:
 | 
			
		||||
			if ins.Src == R1 {
 | 
			
		||||
			if ins.Src == PseudoCall {
 | 
			
		||||
				// bpf-to-bpf call
 | 
			
		||||
				fmt.Fprint(f, ins.Constant)
 | 
			
		||||
			} else {
 | 
			
		||||
@@ -183,6 +232,7 @@ func (ins Instruction) Format(f fmt.State, c rune) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
ref:
 | 
			
		||||
	if ins.Reference != "" {
 | 
			
		||||
		fmt.Fprintf(f, " <%s>", ins.Reference)
 | 
			
		||||
	}
 | 
			
		||||
@@ -235,7 +285,7 @@ func (insns Instructions) SymbolOffsets() (map[string]int, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, ok := offsets[ins.Symbol]; ok {
 | 
			
		||||
			return nil, errors.Errorf("duplicate symbol %s", ins.Symbol)
 | 
			
		||||
			return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		offsets[ins.Symbol] = i
 | 
			
		||||
@@ -273,7 +323,7 @@ func (insns Instructions) marshalledOffsets() (map[string]int, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if _, ok := symbols[ins.Symbol]; ok {
 | 
			
		||||
			return nil, errors.Errorf("duplicate symbol %s", ins.Symbol)
 | 
			
		||||
			return nil, fmt.Errorf("duplicate symbol %s", ins.Symbol)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		symbols[ins.Symbol] = currentPos
 | 
			
		||||
@@ -350,11 +400,11 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 | 
			
		||||
	num := 0
 | 
			
		||||
	for i, ins := range insns {
 | 
			
		||||
		switch {
 | 
			
		||||
		case ins.OpCode.JumpOp() == Call && ins.Constant == -1:
 | 
			
		||||
		case ins.OpCode.JumpOp() == Call && ins.Src == PseudoCall && ins.Constant == -1:
 | 
			
		||||
			// Rewrite bpf to bpf call
 | 
			
		||||
			offset, ok := absoluteOffsets[ins.Reference]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return errors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 | 
			
		||||
				return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ins.Constant = int64(offset - num - 1)
 | 
			
		||||
@@ -363,7 +413,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 | 
			
		||||
			// Rewrite jump to label
 | 
			
		||||
			offset, ok := absoluteOffsets[ins.Reference]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return errors.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 | 
			
		||||
				return fmt.Errorf("instruction %d: reference to missing symbol %s", i, ins.Reference)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ins.Offset = int16(offset - num - 1)
 | 
			
		||||
@@ -371,7 +421,7 @@ func (insns Instructions) Marshal(w io.Writer, bo binary.ByteOrder) error {
 | 
			
		||||
 | 
			
		||||
		n, err := ins.Marshal(w, bo)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "instruction %d", i)
 | 
			
		||||
			return fmt.Errorf("instruction %d: %w", i, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		num += int(n / InstructionSize)
 | 
			
		||||
@@ -388,16 +438,26 @@ type bpfInstruction struct {
 | 
			
		||||
 | 
			
		||||
type bpfRegisters uint8
 | 
			
		||||
 | 
			
		||||
func newBPFRegisters(dst, src Register) bpfRegisters {
 | 
			
		||||
	return bpfRegisters((src << 4) | (dst & 0xF))
 | 
			
		||||
func newBPFRegisters(dst, src Register, bo binary.ByteOrder) (bpfRegisters, error) {
 | 
			
		||||
	switch bo {
 | 
			
		||||
	case binary.LittleEndian:
 | 
			
		||||
		return bpfRegisters((src << 4) | (dst & 0xF)), nil
 | 
			
		||||
	case binary.BigEndian:
 | 
			
		||||
		return bpfRegisters((dst << 4) | (src & 0xF)), nil
 | 
			
		||||
	default:
 | 
			
		||||
		return 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r bpfRegisters) Dst() Register {
 | 
			
		||||
	return Register(r & 0xF)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r bpfRegisters) Src() Register {
 | 
			
		||||
	return Register(r >> 4)
 | 
			
		||||
func (r bpfRegisters) Unmarshal(bo binary.ByteOrder) (dst, src Register, err error) {
 | 
			
		||||
	switch bo {
 | 
			
		||||
	case binary.LittleEndian:
 | 
			
		||||
		return Register(r & 0xF), Register(r >> 4), nil
 | 
			
		||||
	case binary.BigEndian:
 | 
			
		||||
		return Register(r >> 4), Register(r & 0xf), nil
 | 
			
		||||
	default:
 | 
			
		||||
		return 0, 0, fmt.Errorf("unrecognized ByteOrder %T", bo)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unreferencedSymbolError struct {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/jump.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/jump.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -95,7 +95,7 @@ func (op JumpOp) Label(label string) Instruction {
 | 
			
		||||
	if op == Call {
 | 
			
		||||
		return Instruction{
 | 
			
		||||
			OpCode:    OpCode(JumpClass).SetJumpOp(Call),
 | 
			
		||||
			Src:       R1,
 | 
			
		||||
			Src:       PseudoCall,
 | 
			
		||||
			Constant:  -1,
 | 
			
		||||
			Reference: label,
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/cilium/ebpf/asm/load_store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/cilium/ebpf/asm/load_store.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -110,11 +110,26 @@ func LoadMapPtr(dst Register, fd int) Instruction {
 | 
			
		||||
	return Instruction{
 | 
			
		||||
		OpCode:   LoadImmOp(DWord),
 | 
			
		||||
		Dst:      dst,
 | 
			
		||||
		Src:      R1,
 | 
			
		||||
		Src:      PseudoMapFD,
 | 
			
		||||
		Constant: int64(fd),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadMapValue stores a pointer to the value at a certain offset of a map.
 | 
			
		||||
func LoadMapValue(dst Register, fd int, offset uint32) Instruction {
 | 
			
		||||
	if fd < 0 {
 | 
			
		||||
		return Instruction{OpCode: InvalidOpCode}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fdAndOffset := (uint64(offset) << 32) | uint64(uint32(fd))
 | 
			
		||||
	return Instruction{
 | 
			
		||||
		OpCode:   LoadImmOp(DWord),
 | 
			
		||||
		Dst:      dst,
 | 
			
		||||
		Src:      PseudoMapValue,
 | 
			
		||||
		Constant: int64(fdAndOffset),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadIndOp returns the OpCode for loading a value of given size from an sk_buff.
 | 
			
		||||
func LoadIndOp(size Size) OpCode {
 | 
			
		||||
	return OpCode(LdClass).SetMode(IndMode).SetSize(size)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/opcode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/cilium/ebpf/asm/opcode.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -225,7 +225,7 @@ func (op OpCode) String() string {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Fprintf(&f, "%#x", op)
 | 
			
		||||
		fmt.Fprintf(&f, "OpCode(%#x)", uint8(op))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return f.String()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/cilium/ebpf/asm/register.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/cilium/ebpf/asm/register.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -33,6 +33,13 @@ const (
 | 
			
		||||
	RFP          = R10
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Pseudo registers used by 64bit loads and jumps
 | 
			
		||||
const (
 | 
			
		||||
	PseudoMapFD    = R1 // BPF_PSEUDO_MAP_FD
 | 
			
		||||
	PseudoMapValue = R2 // BPF_PSEUDO_MAP_VALUE
 | 
			
		||||
	PseudoCall     = R1 // BPF_PSEUDO_CALL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (r Register) String() string {
 | 
			
		||||
	v := uint8(r)
 | 
			
		||||
	if v == 10 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										117
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										117
									
								
								vendor/github.com/cilium/ebpf/collection.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,9 +1,13 @@
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/asm"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CollectionOptions control loading a collection into the kernel.
 | 
			
		||||
@@ -39,6 +43,89 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
 | 
			
		||||
	return &cpy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RewriteMaps replaces all references to specific maps.
 | 
			
		||||
//
 | 
			
		||||
// Use this function to use pre-existing maps instead of creating new ones
 | 
			
		||||
// when calling NewCollection. Any named maps are removed from CollectionSpec.Maps.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if a named map isn't used in at least one program.
 | 
			
		||||
func (cs *CollectionSpec) RewriteMaps(maps map[string]*Map) error {
 | 
			
		||||
	for symbol, m := range maps {
 | 
			
		||||
		// have we seen a program that uses this symbol / map
 | 
			
		||||
		seen := false
 | 
			
		||||
		fd := m.FD()
 | 
			
		||||
		for progName, progSpec := range cs.Programs {
 | 
			
		||||
			err := progSpec.Instructions.RewriteMapPtr(symbol, fd)
 | 
			
		||||
 | 
			
		||||
			switch {
 | 
			
		||||
			case err == nil:
 | 
			
		||||
				seen = true
 | 
			
		||||
 | 
			
		||||
			case asm.IsUnreferencedSymbol(err):
 | 
			
		||||
				// Not all programs need to use the map
 | 
			
		||||
 | 
			
		||||
			default:
 | 
			
		||||
				return fmt.Errorf("program %s: %w", progName, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !seen {
 | 
			
		||||
			return fmt.Errorf("map %s not referenced by any programs", symbol)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Prevent NewCollection from creating rewritten maps
 | 
			
		||||
		delete(cs.Maps, symbol)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RewriteConstants replaces the value of multiple constants.
 | 
			
		||||
//
 | 
			
		||||
// The constant must be defined like so in the C program:
 | 
			
		||||
//
 | 
			
		||||
//    static volatile const type foobar;
 | 
			
		||||
//    static volatile const type foobar = default;
 | 
			
		||||
//
 | 
			
		||||
// Replacement values must be of the same length as the C sizeof(type).
 | 
			
		||||
// If necessary, they are marshalled according to the same rules as
 | 
			
		||||
// map values.
 | 
			
		||||
//
 | 
			
		||||
// From Linux 5.5 the verifier will use constants to eliminate dead code.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if a constant doesn't exist.
 | 
			
		||||
func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error {
 | 
			
		||||
	rodata := cs.Maps[".rodata"]
 | 
			
		||||
	if rodata == nil {
 | 
			
		||||
		return errors.New("missing .rodata section")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if rodata.BTF == nil {
 | 
			
		||||
		return errors.New(".rodata section has no BTF")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if n := len(rodata.Contents); n != 1 {
 | 
			
		||||
		return fmt.Errorf("expected one key in .rodata, found %d", n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kv := rodata.Contents[0]
 | 
			
		||||
	value, ok := kv.Value.([]byte)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return fmt.Errorf("first value in .rodata is %T not []byte", kv.Value)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf := make([]byte, len(value))
 | 
			
		||||
	copy(buf, value)
 | 
			
		||||
 | 
			
		||||
	err := patchValue(buf, btf.MapValue(rodata.BTF), consts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rodata.Contents[0] = MapKV{kv.Key, buf}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Collection is a collection of Programs and Maps associated
 | 
			
		||||
// with their symbols
 | 
			
		||||
type Collection struct {
 | 
			
		||||
@@ -99,14 +186,14 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
 | 
			
		||||
		var handle *btf.Handle
 | 
			
		||||
		if mapSpec.BTF != nil {
 | 
			
		||||
			handle, err = loadBTF(btf.MapSpec(mapSpec.BTF))
 | 
			
		||||
			if err != nil && !btf.IsNotSupported(err) {
 | 
			
		||||
			if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		m, err := newMapWithBTF(mapSpec, handle)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrapf(err, "map %s", mapName)
 | 
			
		||||
			return nil, fmt.Errorf("map %s: %w", mapName, err)
 | 
			
		||||
		}
 | 
			
		||||
		maps[mapName] = m
 | 
			
		||||
	}
 | 
			
		||||
@@ -116,37 +203,43 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (col
 | 
			
		||||
 | 
			
		||||
		// Rewrite any reference to a valid map.
 | 
			
		||||
		for i := range progSpec.Instructions {
 | 
			
		||||
			var (
 | 
			
		||||
				ins = &progSpec.Instructions[i]
 | 
			
		||||
				m   = maps[ins.Reference]
 | 
			
		||||
			)
 | 
			
		||||
			ins := &progSpec.Instructions[i]
 | 
			
		||||
 | 
			
		||||
			if ins.Reference == "" || m == nil {
 | 
			
		||||
			if ins.OpCode != asm.LoadImmOp(asm.DWord) || ins.Reference == "" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if ins.Src == asm.R1 {
 | 
			
		||||
			if uint32(ins.Constant) != math.MaxUint32 {
 | 
			
		||||
				// Don't overwrite maps already rewritten, users can
 | 
			
		||||
				// rewrite programs in the spec themselves
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m := maps[ins.Reference]
 | 
			
		||||
			if m == nil {
 | 
			
		||||
				return nil, fmt.Errorf("program %s: missing map %s", progName, ins.Reference)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fd := m.FD()
 | 
			
		||||
			if fd < 0 {
 | 
			
		||||
				return nil, fmt.Errorf("map %s: %w", ins.Reference, internal.ErrClosedFd)
 | 
			
		||||
			}
 | 
			
		||||
			if err := ins.RewriteMapPtr(m.FD()); err != nil {
 | 
			
		||||
				return nil, errors.Wrapf(err, "progam %s: map %s", progName, ins.Reference)
 | 
			
		||||
				return nil, fmt.Errorf("progam %s: map %s: %w", progName, ins.Reference, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var handle *btf.Handle
 | 
			
		||||
		if progSpec.BTF != nil {
 | 
			
		||||
			handle, err = loadBTF(btf.ProgramSpec(progSpec.BTF))
 | 
			
		||||
			if err != nil && !btf.IsNotSupported(err) {
 | 
			
		||||
			if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		prog, err := newProgramWithBTF(progSpec, handle, opts.Programs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrapf(err, "program %s", progName)
 | 
			
		||||
			return nil, fmt.Errorf("program %s: %w", progName, err)
 | 
			
		||||
		}
 | 
			
		||||
		progs[progName] = prog
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										607
									
								
								vendor/github.com/cilium/ebpf/elf_reader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										607
									
								
								vendor/github.com/cilium/ebpf/elf_reader.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,21 +4,23 @@ import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"debug/elf"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/asm"
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type elfCode struct {
 | 
			
		||||
	*elf.File
 | 
			
		||||
	symbols           []elf.Symbol
 | 
			
		||||
	symbolsPerSection map[elf.SectionIndex]map[uint64]string
 | 
			
		||||
	symbolsPerSection map[elf.SectionIndex]map[uint64]elf.Symbol
 | 
			
		||||
	license           string
 | 
			
		||||
	version           uint32
 | 
			
		||||
}
 | 
			
		||||
@@ -32,7 +34,10 @@ func LoadCollectionSpec(file string) (*CollectionSpec, error) {
 | 
			
		||||
	defer f.Close()
 | 
			
		||||
 | 
			
		||||
	spec, err := LoadCollectionSpecFromReader(f)
 | 
			
		||||
	return spec, errors.Wrapf(err, "file %s", file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("file %s: %w", file, err)
 | 
			
		||||
	}
 | 
			
		||||
	return spec, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadCollectionSpecFromReader parses an ELF file into a CollectionSpec.
 | 
			
		||||
@@ -45,7 +50,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 | 
			
		||||
 | 
			
		||||
	symbols, err := f.Symbols()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load symbols")
 | 
			
		||||
		return nil, fmt.Errorf("load symbols: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ec := &elfCode{f, symbols, symbolsPerSection(symbols), "", 0}
 | 
			
		||||
@@ -57,6 +62,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 | 
			
		||||
		progSections   = make(map[elf.SectionIndex]*elf.Section)
 | 
			
		||||
		relSections    = make(map[elf.SectionIndex]*elf.Section)
 | 
			
		||||
		mapSections    = make(map[elf.SectionIndex]*elf.Section)
 | 
			
		||||
		dataSections   = make(map[elf.SectionIndex]*elf.Section)
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for i, sec := range ec.Sections {
 | 
			
		||||
@@ -69,15 +75,17 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 | 
			
		||||
			mapSections[elf.SectionIndex(i)] = sec
 | 
			
		||||
		case sec.Name == ".maps":
 | 
			
		||||
			btfMaps[elf.SectionIndex(i)] = sec
 | 
			
		||||
		case sec.Name == ".bss" || sec.Name == ".rodata" || sec.Name == ".data":
 | 
			
		||||
			dataSections[elf.SectionIndex(i)] = sec
 | 
			
		||||
		case sec.Type == elf.SHT_REL:
 | 
			
		||||
			if int(sec.Info) >= len(ec.Sections) {
 | 
			
		||||
				return nil, errors.Errorf("found relocation section %v for missing section %v", i, sec.Info)
 | 
			
		||||
				return nil, fmt.Errorf("found relocation section %v for missing section %v", i, sec.Info)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 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", sec.Info)
 | 
			
		||||
				return nil, fmt.Errorf("section %d has multiple relocation sections", sec.Info)
 | 
			
		||||
			}
 | 
			
		||||
			relSections[idx] = sec
 | 
			
		||||
		case sec.Type == elf.SHT_PROGBITS && (sec.Flags&elf.SHF_EXECINSTR) != 0 && sec.Size > 0:
 | 
			
		||||
@@ -87,34 +95,52 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 | 
			
		||||
 | 
			
		||||
	ec.license, err = loadLicense(licenseSection)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load license")
 | 
			
		||||
		return nil, fmt.Errorf("load license: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ec.version, err = loadVersion(versionSection, ec.ByteOrder)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load version")
 | 
			
		||||
		return nil, fmt.Errorf("load version: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	btf, err := btf.LoadSpecFromReader(rd)
 | 
			
		||||
	btfSpec, err := btf.LoadSpecFromReader(rd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load BTF")
 | 
			
		||||
		return nil, fmt.Errorf("load BTF: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	relocations, referencedSections, err := ec.loadRelocations(relSections)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("load relocations: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	maps := make(map[string]*MapSpec)
 | 
			
		||||
 | 
			
		||||
	if err := ec.loadMaps(maps, mapSections); err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load maps")
 | 
			
		||||
		return nil, fmt.Errorf("load maps: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(btfMaps) > 0 {
 | 
			
		||||
		if err := ec.loadBTFMaps(maps, btfMaps, btf); err != nil {
 | 
			
		||||
			return nil, errors.Wrap(err, "load BTF maps")
 | 
			
		||||
		if err := ec.loadBTFMaps(maps, btfMaps, btfSpec); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("load BTF maps: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	progs, err := ec.loadPrograms(progSections, relSections, btf)
 | 
			
		||||
	if len(dataSections) > 0 {
 | 
			
		||||
		for idx := range dataSections {
 | 
			
		||||
			if !referencedSections[idx] {
 | 
			
		||||
				// Prune data sections which are not referenced by any
 | 
			
		||||
				// instructions.
 | 
			
		||||
				delete(dataSections, idx)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := ec.loadDataSections(maps, dataSections, btfSpec); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("load data sections: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	progs, err := ec.loadPrograms(progSections, relocations, btfSpec)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "load programs")
 | 
			
		||||
		return nil, fmt.Errorf("load programs: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &CollectionSpec{maps, progs}, nil
 | 
			
		||||
@@ -122,11 +148,12 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 | 
			
		||||
 | 
			
		||||
func loadLicense(sec *elf.Section) (string, error) {
 | 
			
		||||
	if sec == nil {
 | 
			
		||||
		return "", errors.Errorf("missing license section")
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data, err := sec.Data()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", errors.Wrapf(err, "section %s", sec.Name)
 | 
			
		||||
		return "", fmt.Errorf("section %s: %v", sec.Name, err)
 | 
			
		||||
	}
 | 
			
		||||
	return string(bytes.TrimRight(data, "\000")), nil
 | 
			
		||||
}
 | 
			
		||||
@@ -137,52 +164,51 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var version uint32
 | 
			
		||||
	err := binary.Read(sec.Open(), bo, &version)
 | 
			
		||||
	return version, errors.Wrapf(err, "section %s", sec.Name)
 | 
			
		||||
	if err := binary.Read(sec.Open(), bo, &version); err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("section %s: %v", sec.Name, err)
 | 
			
		||||
	}
 | 
			
		||||
	return version, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*elf.Section, btf *btf.Spec) (map[string]*ProgramSpec, error) {
 | 
			
		||||
func (ec *elfCode) loadPrograms(progSections map[elf.SectionIndex]*elf.Section, relocations map[elf.SectionIndex]map[uint64]elf.Symbol, btfSpec *btf.Spec) (map[string]*ProgramSpec, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		progs []*ProgramSpec
 | 
			
		||||
		libs  []*ProgramSpec
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for idx, prog := range progSections {
 | 
			
		||||
	for idx, sec := range progSections {
 | 
			
		||||
		syms := ec.symbolsPerSection[idx]
 | 
			
		||||
		if len(syms) == 0 {
 | 
			
		||||
			return nil, errors.Errorf("section %v: missing symbols", prog.Name)
 | 
			
		||||
			return nil, fmt.Errorf("section %v: missing symbols", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		funcSym := syms[0]
 | 
			
		||||
		if funcSym == "" {
 | 
			
		||||
			return nil, errors.Errorf("section %v: no label at start", prog.Name)
 | 
			
		||||
		funcSym, ok := syms[0]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil, fmt.Errorf("section %v: no label at start", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rels, err := ec.loadRelocations(relSections[idx])
 | 
			
		||||
		insns, length, err := ec.loadInstructions(sec, syms, relocations[idx])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrapf(err, "program %s: can't load relocations", funcSym)
 | 
			
		||||
			return nil, fmt.Errorf("program %s: can't unmarshal instructions: %w", funcSym.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		insns, length, err := ec.loadInstructions(prog, syms, rels)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrapf(err, "program %s: can't unmarshal instructions", funcSym)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		progType, attachType := getProgType(prog.Name)
 | 
			
		||||
		progType, attachType, attachTo := getProgType(sec.Name)
 | 
			
		||||
 | 
			
		||||
		spec := &ProgramSpec{
 | 
			
		||||
			Name:          funcSym,
 | 
			
		||||
			Name:          funcSym.Name,
 | 
			
		||||
			Type:          progType,
 | 
			
		||||
			AttachType:    attachType,
 | 
			
		||||
			AttachTo:      attachTo,
 | 
			
		||||
			License:       ec.license,
 | 
			
		||||
			KernelVersion: ec.version,
 | 
			
		||||
			Instructions:  insns,
 | 
			
		||||
			ByteOrder:     ec.ByteOrder,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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 btfSpec != nil {
 | 
			
		||||
			spec.BTF, err = btfSpec.Program(sec.Name, length)
 | 
			
		||||
			if err != nil && !errors.Is(err, btf.ErrNoExtendedInfo) {
 | 
			
		||||
				return nil, fmt.Errorf("program %s: %w", funcSym.Name, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -200,7 +226,7 @@ func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*
 | 
			
		||||
	for _, prog := range progs {
 | 
			
		||||
		err := link(prog, libs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrapf(err, "program %s", prog.Name)
 | 
			
		||||
			return nil, fmt.Errorf("program %s: %w", prog.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
		res[prog.Name] = prog
 | 
			
		||||
	}
 | 
			
		||||
@@ -208,39 +234,158 @@ func (ec *elfCode) loadPrograms(progSections, relSections map[elf.SectionIndex]*
 | 
			
		||||
	return res, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]string) (asm.Instructions, uint64, error) {
 | 
			
		||||
func (ec *elfCode) loadInstructions(section *elf.Section, symbols, relocations map[uint64]elf.Symbol) (asm.Instructions, uint64, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		r      = section.Open()
 | 
			
		||||
		insns  asm.Instructions
 | 
			
		||||
		ins    asm.Instruction
 | 
			
		||||
		offset uint64
 | 
			
		||||
	)
 | 
			
		||||
	for {
 | 
			
		||||
		var ins asm.Instruction
 | 
			
		||||
		n, err := ins.Unmarshal(r, ec.ByteOrder)
 | 
			
		||||
		if err == io.EOF {
 | 
			
		||||
			return insns, offset, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, 0, errors.Wrapf(err, "offset %d", offset)
 | 
			
		||||
			return nil, 0, fmt.Errorf("offset %d: %w", offset, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ins.Symbol = symbols[offset]
 | 
			
		||||
		ins.Reference = relocations[offset]
 | 
			
		||||
		ins.Symbol = symbols[offset].Name
 | 
			
		||||
 | 
			
		||||
		if rel, ok := relocations[offset]; ok {
 | 
			
		||||
			if err = ec.relocateInstruction(&ins, rel); err != nil {
 | 
			
		||||
				return nil, 0, fmt.Errorf("offset %d: can't relocate instruction: %w", offset, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		insns = append(insns, ins)
 | 
			
		||||
		offset += n
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) error {
 | 
			
		||||
	var (
 | 
			
		||||
		typ  = elf.ST_TYPE(rel.Info)
 | 
			
		||||
		bind = elf.ST_BIND(rel.Info)
 | 
			
		||||
		name = rel.Name
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if typ == elf.STT_SECTION {
 | 
			
		||||
		// Symbols with section type do not have a name set. Get it
 | 
			
		||||
		// from the section itself.
 | 
			
		||||
		idx := int(rel.Section)
 | 
			
		||||
		if idx > len(ec.Sections) {
 | 
			
		||||
			return errors.New("out-of-bounds section index")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		name = ec.Sections[idx].Name
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
outer:
 | 
			
		||||
	switch {
 | 
			
		||||
	case ins.OpCode == asm.LoadImmOp(asm.DWord):
 | 
			
		||||
		// There are two distinct types of a load from a map:
 | 
			
		||||
		// a direct one, where the value is extracted without
 | 
			
		||||
		// a call to map_lookup_elem in eBPF, and an indirect one
 | 
			
		||||
		// that goes via the helper. They are distinguished by
 | 
			
		||||
		// different relocations.
 | 
			
		||||
		switch typ {
 | 
			
		||||
		case elf.STT_SECTION:
 | 
			
		||||
			// This is a direct load since the referenced symbol is a
 | 
			
		||||
			// section. Weirdly, the offset of the real symbol in the
 | 
			
		||||
			// section is encoded in the instruction stream.
 | 
			
		||||
			if bind != elf.STB_LOCAL {
 | 
			
		||||
				return fmt.Errorf("direct load: %s: unsupported relocation %s", name, bind)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// For some reason, clang encodes the offset of the symbol its
 | 
			
		||||
			// section in the first basic BPF instruction, while the kernel
 | 
			
		||||
			// expects it in the second one.
 | 
			
		||||
			ins.Constant <<= 32
 | 
			
		||||
			ins.Src = asm.PseudoMapValue
 | 
			
		||||
 | 
			
		||||
		case elf.STT_NOTYPE:
 | 
			
		||||
			if bind == elf.STB_GLOBAL && rel.Section == elf.SHN_UNDEF {
 | 
			
		||||
				// This is a relocation generated by inline assembly.
 | 
			
		||||
				// We can't do more than assigning ins.Reference.
 | 
			
		||||
				break outer
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// This is an ELF generated on clang < 8, which doesn't tag
 | 
			
		||||
			// relocations appropriately.
 | 
			
		||||
			fallthrough
 | 
			
		||||
 | 
			
		||||
		case elf.STT_OBJECT:
 | 
			
		||||
			if bind != elf.STB_GLOBAL {
 | 
			
		||||
				return fmt.Errorf("load: %s: unsupported binding: %s", name, bind)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ins.Src = asm.PseudoMapFD
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("load: %s: unsupported relocation: %s", name, typ)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Mark the instruction as needing an update when creating the
 | 
			
		||||
		// collection.
 | 
			
		||||
		if err := ins.RewriteMapPtr(-1); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	case ins.OpCode.JumpOp() == asm.Call:
 | 
			
		||||
		if ins.Src != asm.PseudoCall {
 | 
			
		||||
			return fmt.Errorf("call: %s: incorrect source register", name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch typ {
 | 
			
		||||
		case elf.STT_NOTYPE, elf.STT_FUNC:
 | 
			
		||||
			if bind != elf.STB_GLOBAL {
 | 
			
		||||
				return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case elf.STT_SECTION:
 | 
			
		||||
			if bind != elf.STB_LOCAL {
 | 
			
		||||
				return fmt.Errorf("call: %s: unsupported binding: %s", name, bind)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// The function we want to call is in the indicated section,
 | 
			
		||||
			// at the offset encoded in the instruction itself. Reverse
 | 
			
		||||
			// the calculation to find the real function we're looking for.
 | 
			
		||||
			// A value of -1 references the first instruction in the section.
 | 
			
		||||
			offset := int64(int32(ins.Constant)+1) * asm.InstructionSize
 | 
			
		||||
			if offset < 0 {
 | 
			
		||||
				return fmt.Errorf("call: %s: invalid offset %d", name, offset)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			sym, ok := ec.symbolsPerSection[rel.Section][uint64(offset)]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("call: %s: no symbol at offset %d", name, offset)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			ins.Constant = -1
 | 
			
		||||
			name = sym.Name
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			return fmt.Errorf("call: %s: invalid symbol type %s", name, typ)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("relocation for unsupported instruction: %s", ins.OpCode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ins.Reference = name
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 errors.Errorf("section %v: no symbols", sec.Name)
 | 
			
		||||
			return fmt.Errorf("section %v: no symbols", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sec.Size%uint64(len(syms)) != 0 {
 | 
			
		||||
			return errors.Errorf("section %v: map descriptors are not of equal size", sec.Name)
 | 
			
		||||
			return fmt.Errorf("section %v: map descriptors are not of equal size", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var (
 | 
			
		||||
@@ -248,36 +393,38 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 | 
			
		||||
			size = sec.Size / uint64(len(syms))
 | 
			
		||||
		)
 | 
			
		||||
		for i, offset := 0, uint64(0); i < len(syms); i, offset = i+1, offset+size {
 | 
			
		||||
			mapSym := syms[offset]
 | 
			
		||||
			if mapSym == "" {
 | 
			
		||||
				return errors.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
 | 
			
		||||
			mapSym, ok := syms[offset]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				return fmt.Errorf("section %s: missing symbol for map at offset %d", sec.Name, offset)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if maps[mapSym] != nil {
 | 
			
		||||
				return errors.Errorf("section %v: map %v already exists", sec.Name, mapSym)
 | 
			
		||||
			if maps[mapSym.Name] != nil {
 | 
			
		||||
				return fmt.Errorf("section %v: map %v already exists", sec.Name, mapSym)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			lr := io.LimitReader(r, int64(size))
 | 
			
		||||
 | 
			
		||||
			var spec MapSpec
 | 
			
		||||
			spec := MapSpec{
 | 
			
		||||
				Name: SanitizeName(mapSym.Name, -1),
 | 
			
		||||
			}
 | 
			
		||||
			switch {
 | 
			
		||||
			case binary.Read(lr, ec.ByteOrder, &spec.Type) != nil:
 | 
			
		||||
				return errors.Errorf("map %v: missing type", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: missing type", mapSym)
 | 
			
		||||
			case binary.Read(lr, ec.ByteOrder, &spec.KeySize) != nil:
 | 
			
		||||
				return errors.Errorf("map %v: missing key size", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: missing key size", mapSym)
 | 
			
		||||
			case binary.Read(lr, ec.ByteOrder, &spec.ValueSize) != nil:
 | 
			
		||||
				return errors.Errorf("map %v: missing value size", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: missing value size", mapSym)
 | 
			
		||||
			case binary.Read(lr, ec.ByteOrder, &spec.MaxEntries) != nil:
 | 
			
		||||
				return errors.Errorf("map %v: missing max entries", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: missing max entries", mapSym)
 | 
			
		||||
			case binary.Read(lr, ec.ByteOrder, &spec.Flags) != nil:
 | 
			
		||||
				return errors.Errorf("map %v: missing flags", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: missing flags", mapSym)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, err := io.Copy(internal.DiscardZeroes{}, lr); err != nil {
 | 
			
		||||
				return errors.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
 | 
			
		||||
				return fmt.Errorf("map %v: unknown and non-zero fields in definition", mapSym)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			maps[mapSym] = &spec
 | 
			
		||||
			maps[mapSym.Name] = &spec
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -285,85 +432,117 @@ func (ec *elfCode) loadMaps(maps map[string]*MapSpec, mapSections map[elf.Sectio
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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")
 | 
			
		||||
		return fmt.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)
 | 
			
		||||
			return fmt.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)
 | 
			
		||||
			name := sym.Name
 | 
			
		||||
			if maps[name] != nil {
 | 
			
		||||
				return fmt.Errorf("section %v: map %v already exists", sec.Name, sym)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			btfMap, err := spec.Map(sym)
 | 
			
		||||
			mapSpec, err := mapSpecFromBTF(spec, name)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "map %v: can't get BTF", sym)
 | 
			
		||||
				return fmt.Errorf("map %v: %w", name, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			spec, err := mapSpecFromBTF(btfMap)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "map %v", sym)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			maps[sym] = spec
 | 
			
		||||
			maps[name] = mapSpec
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) {
 | 
			
		||||
func mapSpecFromBTF(spec *btf.Spec, name string) (*MapSpec, error) {
 | 
			
		||||
	btfMap, btfMapMembers, err := spec.Map(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't get BTF: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	keyType := btf.MapKey(btfMap)
 | 
			
		||||
	size, err := btf.Sizeof(keyType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't get size of BTF key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	keySize := uint32(size)
 | 
			
		||||
 | 
			
		||||
	valueType := btf.MapValue(btfMap)
 | 
			
		||||
	size, err = btf.Sizeof(valueType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't get size of BTF value: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	valueSize := uint32(size)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		mapType, flags, maxEntries uint32
 | 
			
		||||
		err                        error
 | 
			
		||||
	)
 | 
			
		||||
	for _, member := range btf.MapType(btfMap).Members {
 | 
			
		||||
	for _, member := range btfMapMembers {
 | 
			
		||||
		switch member.Name {
 | 
			
		||||
		case "type":
 | 
			
		||||
			mapType, err = uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, errors.Wrap(err, "can't get type")
 | 
			
		||||
				return nil, fmt.Errorf("can't get type: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "map_flags":
 | 
			
		||||
			flags, err = uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, errors.Wrap(err, "can't get BTF map flags")
 | 
			
		||||
				return nil, fmt.Errorf("can't get BTF map flags: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "max_entries":
 | 
			
		||||
			maxEntries, err = uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, errors.Wrap(err, "can't get BTF map max entries")
 | 
			
		||||
				return nil, fmt.Errorf("can't get BTF map max entries: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "key":
 | 
			
		||||
		case "value":
 | 
			
		||||
		case "key_size":
 | 
			
		||||
			if _, isVoid := keyType.(*btf.Void); !isVoid {
 | 
			
		||||
				return nil, errors.New("both key and key_size given")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			keySize, err = uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("can't get BTF key size: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "value_size":
 | 
			
		||||
			if _, isVoid := valueType.(*btf.Void); !isVoid {
 | 
			
		||||
				return nil, errors.New("both value and value_size given")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			valueSize, err = uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("can't get BTF value size: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "pinning":
 | 
			
		||||
			pinning, err := uintFromBTF(member.Type)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("can't get pinning: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if pinning != 0 {
 | 
			
		||||
				return nil, fmt.Errorf("'pinning' attribute not supported: %w", ErrNotSupported)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		case "key", "value":
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, errors.Errorf("unrecognized field %s in BTF map definition", member.Name)
 | 
			
		||||
			return nil, fmt.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),
 | 
			
		||||
		KeySize:    keySize,
 | 
			
		||||
		ValueSize:  valueSize,
 | 
			
		||||
		MaxEntries: maxEntries,
 | 
			
		||||
		Flags:      flags,
 | 
			
		||||
		BTF:        btfMap,
 | 
			
		||||
@@ -375,127 +554,163 @@ func mapSpecFromBTF(btfMap *btf.Map) (*MapSpec, error) {
 | 
			
		||||
func uintFromBTF(typ btf.Type) (uint32, error) {
 | 
			
		||||
	ptr, ok := typ.(*btf.Pointer)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, errors.Errorf("not a pointer: %v", typ)
 | 
			
		||||
		return 0, fmt.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 0, fmt.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,
 | 
			
		||||
		"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,
 | 
			
		||||
		"cgroup/skb":        CGroupSKB,
 | 
			
		||||
		"cgroup/sock":       CGroupSock,
 | 
			
		||||
		"cgroup/post_bind":  CGroupSock,
 | 
			
		||||
		"cgroup/bind":       CGroupSockAddr,
 | 
			
		||||
		"cgroup/connect":    CGroupSockAddr,
 | 
			
		||||
		"cgroup/sendmsg":    CGroupSockAddr,
 | 
			
		||||
		"cgroup/recvmsg":    CGroupSockAddr,
 | 
			
		||||
		"cgroup/sysctl":     CGroupSysctl,
 | 
			
		||||
		"cgroup/getsockopt": CGroupSockopt,
 | 
			
		||||
		"cgroup/setsockopt": CGroupSockopt,
 | 
			
		||||
		"classifier":        SchedCLS,
 | 
			
		||||
		"action":            SchedACT,
 | 
			
		||||
	}
 | 
			
		||||
	attachTypes := map[string]AttachType{
 | 
			
		||||
		"cgroup_skb/ingress":    AttachCGroupInetIngress,
 | 
			
		||||
		"cgroup_skb/egress":     AttachCGroupInetEgress,
 | 
			
		||||
		"cgroup/sock":           AttachCGroupInetSockCreate,
 | 
			
		||||
		"cgroup/post_bind4":     AttachCGroupInet4PostBind,
 | 
			
		||||
		"cgroup/post_bind6":     AttachCGroupInet6PostBind,
 | 
			
		||||
		"cgroup/dev":            AttachCGroupDevice,
 | 
			
		||||
		"sockops":               AttachCGroupSockOps,
 | 
			
		||||
		"sk_skb/stream_parser":  AttachSkSKBStreamParser,
 | 
			
		||||
		"sk_skb/stream_verdict": AttachSkSKBStreamVerdict,
 | 
			
		||||
		"sk_msg":                AttachSkSKBStreamVerdict,
 | 
			
		||||
		"lirc_mode2":            AttachLircMode2,
 | 
			
		||||
		"flow_dissector":        AttachFlowDissector,
 | 
			
		||||
		"cgroup/bind4":          AttachCGroupInet4Bind,
 | 
			
		||||
		"cgroup/bind6":          AttachCGroupInet6Bind,
 | 
			
		||||
		"cgroup/connect4":       AttachCGroupInet4Connect,
 | 
			
		||||
		"cgroup/connect6":       AttachCGroupInet6Connect,
 | 
			
		||||
		"cgroup/sendmsg4":       AttachCGroupUDP4Sendmsg,
 | 
			
		||||
		"cgroup/sendmsg6":       AttachCGroupUDP6Sendmsg,
 | 
			
		||||
		"cgroup/recvmsg4":       AttachCGroupUDP4Recvmsg,
 | 
			
		||||
		"cgroup/recvmsg6":       AttachCGroupUDP6Recvmsg,
 | 
			
		||||
		"cgroup/sysctl":         AttachCGroupSysctl,
 | 
			
		||||
		"cgroup/getsockopt":     AttachCGroupGetsockopt,
 | 
			
		||||
		"cgroup/setsockopt":     AttachCGroupSetsockopt,
 | 
			
		||||
	}
 | 
			
		||||
	attachType := AttachNone
 | 
			
		||||
	for k, t := range attachTypes {
 | 
			
		||||
		if strings.HasPrefix(v, k) {
 | 
			
		||||
			attachType = t
 | 
			
		||||
		}
 | 
			
		||||
func (ec *elfCode) loadDataSections(maps map[string]*MapSpec, dataSections map[elf.SectionIndex]*elf.Section, spec *btf.Spec) error {
 | 
			
		||||
	if spec == nil {
 | 
			
		||||
		return errors.New("data sections require BTF, make sure all consts are marked as static")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, t := range types {
 | 
			
		||||
		if strings.HasPrefix(v, k) {
 | 
			
		||||
			return t, attachType
 | 
			
		||||
	for _, sec := range dataSections {
 | 
			
		||||
		btfMap, err := spec.Datasec(sec.Name)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		data, err := sec.Data()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if uint64(len(data)) > math.MaxUint32 {
 | 
			
		||||
			return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mapSpec := &MapSpec{
 | 
			
		||||
			Name:       SanitizeName(sec.Name, -1),
 | 
			
		||||
			Type:       Array,
 | 
			
		||||
			KeySize:    4,
 | 
			
		||||
			ValueSize:  uint32(len(data)),
 | 
			
		||||
			MaxEntries: 1,
 | 
			
		||||
			Contents:   []MapKV{{uint32(0), data}},
 | 
			
		||||
			BTF:        btfMap,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch sec.Name {
 | 
			
		||||
		case ".rodata":
 | 
			
		||||
			mapSpec.Flags = unix.BPF_F_RDONLY_PROG
 | 
			
		||||
			mapSpec.Freeze = true
 | 
			
		||||
		case ".bss":
 | 
			
		||||
			// The kernel already zero-initializes the map
 | 
			
		||||
			mapSpec.Contents = nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		maps[sec.Name] = mapSpec
 | 
			
		||||
	}
 | 
			
		||||
	return UnspecifiedProgram, AttachNone
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ec *elfCode) loadRelocations(sec *elf.Section) (map[uint64]string, error) {
 | 
			
		||||
	rels := make(map[uint64]string)
 | 
			
		||||
	if sec == nil {
 | 
			
		||||
		return rels, nil
 | 
			
		||||
func getProgType(sectionName string) (ProgramType, AttachType, string) {
 | 
			
		||||
	types := map[string]struct {
 | 
			
		||||
		progType   ProgramType
 | 
			
		||||
		attachType AttachType
 | 
			
		||||
	}{
 | 
			
		||||
		// From https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/bpf/libbpf.c
 | 
			
		||||
		"socket":                {SocketFilter, AttachNone},
 | 
			
		||||
		"seccomp":               {SocketFilter, AttachNone},
 | 
			
		||||
		"kprobe/":               {Kprobe, AttachNone},
 | 
			
		||||
		"uprobe/":               {Kprobe, AttachNone},
 | 
			
		||||
		"kretprobe/":            {Kprobe, AttachNone},
 | 
			
		||||
		"uretprobe/":            {Kprobe, AttachNone},
 | 
			
		||||
		"tracepoint/":           {TracePoint, AttachNone},
 | 
			
		||||
		"raw_tracepoint/":       {RawTracepoint, AttachNone},
 | 
			
		||||
		"xdp":                   {XDP, AttachNone},
 | 
			
		||||
		"perf_event":            {PerfEvent, AttachNone},
 | 
			
		||||
		"lwt_in":                {LWTIn, AttachNone},
 | 
			
		||||
		"lwt_out":               {LWTOut, AttachNone},
 | 
			
		||||
		"lwt_xmit":              {LWTXmit, AttachNone},
 | 
			
		||||
		"lwt_seg6local":         {LWTSeg6Local, AttachNone},
 | 
			
		||||
		"sockops":               {SockOps, AttachCGroupSockOps},
 | 
			
		||||
		"sk_skb/stream_parser":  {SkSKB, AttachSkSKBStreamParser},
 | 
			
		||||
		"sk_skb/stream_verdict": {SkSKB, AttachSkSKBStreamParser},
 | 
			
		||||
		"sk_msg":                {SkMsg, AttachSkSKBStreamVerdict},
 | 
			
		||||
		"lirc_mode2":            {LircMode2, AttachLircMode2},
 | 
			
		||||
		"flow_dissector":        {FlowDissector, AttachFlowDissector},
 | 
			
		||||
		"iter/":                 {Tracing, AttachTraceIter},
 | 
			
		||||
 | 
			
		||||
		"cgroup_skb/ingress": {CGroupSKB, AttachCGroupInetIngress},
 | 
			
		||||
		"cgroup_skb/egress":  {CGroupSKB, AttachCGroupInetEgress},
 | 
			
		||||
		"cgroup/dev":         {CGroupDevice, AttachCGroupDevice},
 | 
			
		||||
		"cgroup/skb":         {CGroupSKB, AttachNone},
 | 
			
		||||
		"cgroup/sock":        {CGroupSock, AttachCGroupInetSockCreate},
 | 
			
		||||
		"cgroup/post_bind4":  {CGroupSock, AttachCGroupInet4PostBind},
 | 
			
		||||
		"cgroup/post_bind6":  {CGroupSock, AttachCGroupInet6PostBind},
 | 
			
		||||
		"cgroup/bind4":       {CGroupSockAddr, AttachCGroupInet4Bind},
 | 
			
		||||
		"cgroup/bind6":       {CGroupSockAddr, AttachCGroupInet6Bind},
 | 
			
		||||
		"cgroup/connect4":    {CGroupSockAddr, AttachCGroupInet4Connect},
 | 
			
		||||
		"cgroup/connect6":    {CGroupSockAddr, AttachCGroupInet6Connect},
 | 
			
		||||
		"cgroup/sendmsg4":    {CGroupSockAddr, AttachCGroupUDP4Sendmsg},
 | 
			
		||||
		"cgroup/sendmsg6":    {CGroupSockAddr, AttachCGroupUDP6Sendmsg},
 | 
			
		||||
		"cgroup/recvmsg4":    {CGroupSockAddr, AttachCGroupUDP4Recvmsg},
 | 
			
		||||
		"cgroup/recvmsg6":    {CGroupSockAddr, AttachCGroupUDP6Recvmsg},
 | 
			
		||||
		"cgroup/sysctl":      {CGroupSysctl, AttachCGroupSysctl},
 | 
			
		||||
		"cgroup/getsockopt":  {CGroupSockopt, AttachCGroupGetsockopt},
 | 
			
		||||
		"cgroup/setsockopt":  {CGroupSockopt, AttachCGroupSetsockopt},
 | 
			
		||||
		"classifier":         {SchedCLS, AttachNone},
 | 
			
		||||
		"action":             {SchedACT, AttachNone},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if sec.Entsize < 16 {
 | 
			
		||||
		return nil, errors.New("rels are less than 16 bytes")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r := sec.Open()
 | 
			
		||||
	for off := uint64(0); off < sec.Size; off += sec.Entsize {
 | 
			
		||||
		ent := io.LimitReader(r, int64(sec.Entsize))
 | 
			
		||||
 | 
			
		||||
		var rel elf.Rel64
 | 
			
		||||
		if binary.Read(ent, ec.ByteOrder, &rel) != nil {
 | 
			
		||||
			return nil, errors.Errorf("can't parse relocation at offset %v", off)
 | 
			
		||||
	for prefix, t := range types {
 | 
			
		||||
		if !strings.HasPrefix(sectionName, prefix) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		symNo := int(elf.R_SYM64(rel.Info) - 1)
 | 
			
		||||
		if symNo >= len(ec.symbols) {
 | 
			
		||||
			return nil, errors.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
 | 
			
		||||
		if !strings.HasSuffix(prefix, "/") {
 | 
			
		||||
			return t.progType, t.attachType, ""
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rels[rel.Off] = ec.symbols[symNo].Name
 | 
			
		||||
		return t.progType, t.attachType, sectionName[len(prefix):]
 | 
			
		||||
	}
 | 
			
		||||
	return rels, nil
 | 
			
		||||
 | 
			
		||||
	return UnspecifiedProgram, AttachNone, ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]string {
 | 
			
		||||
	result := make(map[elf.SectionIndex]map[uint64]string)
 | 
			
		||||
	for i, sym := range symbols {
 | 
			
		||||
func (ec *elfCode) loadRelocations(sections map[elf.SectionIndex]*elf.Section) (map[elf.SectionIndex]map[uint64]elf.Symbol, map[elf.SectionIndex]bool, error) {
 | 
			
		||||
	result := make(map[elf.SectionIndex]map[uint64]elf.Symbol)
 | 
			
		||||
	targets := make(map[elf.SectionIndex]bool)
 | 
			
		||||
	for idx, sec := range sections {
 | 
			
		||||
		rels := make(map[uint64]elf.Symbol)
 | 
			
		||||
 | 
			
		||||
		if sec.Entsize < 16 {
 | 
			
		||||
			return nil, nil, fmt.Errorf("section %s: relocations are less than 16 bytes", sec.Name)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r := sec.Open()
 | 
			
		||||
		for off := uint64(0); off < sec.Size; off += sec.Entsize {
 | 
			
		||||
			ent := io.LimitReader(r, int64(sec.Entsize))
 | 
			
		||||
 | 
			
		||||
			var rel elf.Rel64
 | 
			
		||||
			if binary.Read(ent, ec.ByteOrder, &rel) != nil {
 | 
			
		||||
				return nil, nil, fmt.Errorf("can't parse relocation at offset %v", off)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			symNo := int(elf.R_SYM64(rel.Info) - 1)
 | 
			
		||||
			if symNo >= len(ec.symbols) {
 | 
			
		||||
				return nil, nil, fmt.Errorf("relocation at offset %d: symbol %v doesnt exist", off, symNo)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			symbol := ec.symbols[symNo]
 | 
			
		||||
			targets[symbol.Section] = true
 | 
			
		||||
			rels[rel.Off] = ec.symbols[symNo]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result[idx] = rels
 | 
			
		||||
	}
 | 
			
		||||
	return result, targets, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]elf.Symbol {
 | 
			
		||||
	result := make(map[elf.SectionIndex]map[uint64]elf.Symbol)
 | 
			
		||||
	for _, sym := range symbols {
 | 
			
		||||
		switch elf.ST_TYPE(sym.Info) {
 | 
			
		||||
		case elf.STT_NOTYPE:
 | 
			
		||||
			// Older versions of LLVM doesn't tag
 | 
			
		||||
@@ -509,15 +724,19 @@ func symbolsPerSection(symbols []elf.Symbol) map[elf.SectionIndex]map[uint64]str
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sym.Section == elf.SHN_UNDEF || sym.Section >= elf.SHN_LORESERVE {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if sym.Name == "" {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		idx := sym.Section
 | 
			
		||||
		if _, ok := result[idx]; !ok {
 | 
			
		||||
			result[idx] = make(map[uint64]string)
 | 
			
		||||
			result[idx] = make(map[uint64]elf.Symbol)
 | 
			
		||||
		}
 | 
			
		||||
		result[idx][sym.Value] = symbols[i].Name
 | 
			
		||||
		result[idx][sym.Value] = sym
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								vendor/github.com/cilium/ebpf/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/cilium/ebpf/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,8 +1,5 @@
 | 
			
		||||
module github.com/cilium/ebpf
 | 
			
		||||
 | 
			
		||||
go 1.12
 | 
			
		||||
go 1.13
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/pkg/errors v0.8.1
 | 
			
		||||
	golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7
 | 
			
		||||
)
 | 
			
		||||
require golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/cilium/ebpf/linker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,43 +1,60 @@
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/asm"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// link resolves bpf-to-bpf calls.
 | 
			
		||||
//
 | 
			
		||||
// Each library may contain multiple functions / labels, and is only linked
 | 
			
		||||
// if the program being edited references one of these functions.
 | 
			
		||||
// if prog references one of these functions.
 | 
			
		||||
//
 | 
			
		||||
// Libraries must not require linking themselves.
 | 
			
		||||
// Libraries also linked.
 | 
			
		||||
func link(prog *ProgramSpec, libs []*ProgramSpec) error {
 | 
			
		||||
	for _, lib := range libs {
 | 
			
		||||
		insns, err := linkSection(prog.Instructions, lib.Instructions)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "linking %s", lib.Name)
 | 
			
		||||
		}
 | 
			
		||||
	var (
 | 
			
		||||
		linked  = make(map[*ProgramSpec]bool)
 | 
			
		||||
		pending = []asm.Instructions{prog.Instructions}
 | 
			
		||||
		insns   asm.Instructions
 | 
			
		||||
	)
 | 
			
		||||
	for len(pending) > 0 {
 | 
			
		||||
		insns, pending = pending[0], pending[1:]
 | 
			
		||||
		for _, lib := range libs {
 | 
			
		||||
			if linked[lib] {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		if len(insns) == len(prog.Instructions) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
			needed, err := needSection(insns, lib.Instructions)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return fmt.Errorf("linking %s: %w", lib.Name, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		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)
 | 
			
		||||
			if !needed {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			linked[lib] = true
 | 
			
		||||
			prog.Instructions = append(prog.Instructions, lib.Instructions...)
 | 
			
		||||
			pending = append(pending, lib.Instructions)
 | 
			
		||||
 | 
			
		||||
			if prog.BTF != nil && lib.BTF != nil {
 | 
			
		||||
				if err := btf.ProgramAppend(prog.BTF, lib.BTF); err != nil {
 | 
			
		||||
					return fmt.Errorf("linking BTF of %s: %w", lib.Name, err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func linkSection(insns, section asm.Instructions) (asm.Instructions, error) {
 | 
			
		||||
func needSection(insns, section asm.Instructions) (bool, error) {
 | 
			
		||||
	// A map of symbols to the libraries which contain them.
 | 
			
		||||
	symbols, err := section.SymbolOffsets()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, ins := range insns {
 | 
			
		||||
@@ -45,7 +62,7 @@ func linkSection(insns, section asm.Instructions) (asm.Instructions, error) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ins.OpCode.JumpOp() != asm.Call || ins.Src != asm.R1 {
 | 
			
		||||
		if ins.OpCode.JumpOp() != asm.Call || ins.Src != asm.PseudoCall {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -60,11 +77,10 @@ func linkSection(insns, section asm.Instructions) (asm.Instructions, error) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// At this point we know that at least one function in the
 | 
			
		||||
		// library is called from insns. Merge the two sections.
 | 
			
		||||
		// The rewrite of ins.Constant happens in asm.Instruction.Marshal.
 | 
			
		||||
		return append(insns, section...), nil
 | 
			
		||||
		// library is called from insns, so we have to link it.
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// None of the functions in the section are called. Do nothing.
 | 
			
		||||
	return insns, nil
 | 
			
		||||
	// None of the functions in the section are called.
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										331
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										331
									
								
								vendor/github.com/cilium/ebpf/map.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,15 +1,25 @@
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Errors returned by Map and MapIterator methods.
 | 
			
		||||
var (
 | 
			
		||||
	ErrKeyNotExist      = errors.New("key does not exist")
 | 
			
		||||
	ErrKeyExist         = errors.New("key already exists")
 | 
			
		||||
	ErrIterationAborted = errors.New("iteration aborted")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MapID represents the unique ID of an eBPF map
 | 
			
		||||
type MapID uint32
 | 
			
		||||
 | 
			
		||||
// MapSpec defines a Map.
 | 
			
		||||
type MapSpec struct {
 | 
			
		||||
	// Name is passed to the kernel as a debug aid. Must only contain
 | 
			
		||||
@@ -21,6 +31,12 @@ type MapSpec struct {
 | 
			
		||||
	MaxEntries uint32
 | 
			
		||||
	Flags      uint32
 | 
			
		||||
 | 
			
		||||
	// The initial contents of the map. May be nil.
 | 
			
		||||
	Contents []MapKV
 | 
			
		||||
 | 
			
		||||
	// Whether to freeze a map after setting its initial contents.
 | 
			
		||||
	Freeze bool
 | 
			
		||||
 | 
			
		||||
	// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
 | 
			
		||||
	InnerMap *MapSpec
 | 
			
		||||
 | 
			
		||||
@@ -33,16 +49,26 @@ func (ms *MapSpec) String() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy returns a copy of the spec.
 | 
			
		||||
//
 | 
			
		||||
// MapSpec.Contents is a shallow copy.
 | 
			
		||||
func (ms *MapSpec) Copy() *MapSpec {
 | 
			
		||||
	if ms == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cpy := *ms
 | 
			
		||||
	cpy.Contents = make([]MapKV, len(ms.Contents))
 | 
			
		||||
	copy(cpy.Contents, ms.Contents)
 | 
			
		||||
	cpy.InnerMap = ms.InnerMap.Copy()
 | 
			
		||||
	return &cpy
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapKV is used to initialize the contents of a Map.
 | 
			
		||||
type MapKV struct {
 | 
			
		||||
	Key   interface{}
 | 
			
		||||
	Value interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Map represents a Map file descriptor.
 | 
			
		||||
//
 | 
			
		||||
// It is not safe to close a map which is used by other goroutines.
 | 
			
		||||
@@ -81,14 +107,18 @@ func NewMapFromFD(fd int) (*Map, error) {
 | 
			
		||||
//
 | 
			
		||||
// Creating a map for the first time will perform feature detection
 | 
			
		||||
// by creating small, temporary maps.
 | 
			
		||||
//
 | 
			
		||||
// The caller is responsible for ensuring the process' rlimit is set
 | 
			
		||||
// sufficiently high for locking memory during map creation. This can be done
 | 
			
		||||
// by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMap.
 | 
			
		||||
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")
 | 
			
		||||
	if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 | 
			
		||||
		return nil, fmt.Errorf("can't load BTF: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newMapWithBTF(spec, handle)
 | 
			
		||||
@@ -100,7 +130,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if spec.InnerMap == nil {
 | 
			
		||||
		return nil, errors.Errorf("%s requires InnerMap", spec.Type)
 | 
			
		||||
		return nil, fmt.Errorf("%s requires InnerMap", spec.Type)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	template, err := createMap(spec.InnerMap, nil, handle)
 | 
			
		||||
@@ -113,7 +143,7 @@ func newMapWithBTF(spec *MapSpec, handle *btf.Handle) (*Map, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, error) {
 | 
			
		||||
	spec = spec.Copy()
 | 
			
		||||
	abi := newMapABIFromSpec(spec)
 | 
			
		||||
 | 
			
		||||
	switch spec.Type {
 | 
			
		||||
	case ArrayOfMaps:
 | 
			
		||||
@@ -123,43 +153,50 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if spec.ValueSize != 0 && spec.ValueSize != 4 {
 | 
			
		||||
			return nil, errors.Errorf("ValueSize must be zero or four for map of map")
 | 
			
		||||
		if abi.ValueSize != 0 && abi.ValueSize != 4 {
 | 
			
		||||
			return nil, errors.New("ValueSize must be zero or four for map of map")
 | 
			
		||||
		}
 | 
			
		||||
		spec.ValueSize = 4
 | 
			
		||||
		abi.ValueSize = 4
 | 
			
		||||
 | 
			
		||||
	case PerfEventArray:
 | 
			
		||||
		if spec.KeySize != 0 {
 | 
			
		||||
			return nil, errors.Errorf("KeySize must be zero for perf event array")
 | 
			
		||||
		}
 | 
			
		||||
		if spec.ValueSize != 0 {
 | 
			
		||||
			return nil, errors.Errorf("ValueSize must be zero for perf event array")
 | 
			
		||||
		}
 | 
			
		||||
		if spec.MaxEntries == 0 {
 | 
			
		||||
			n, err := internal.OnlineCPUs()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, errors.Wrap(err, "perf event array")
 | 
			
		||||
			}
 | 
			
		||||
			spec.MaxEntries = uint32(n)
 | 
			
		||||
		if abi.KeySize != 0 && abi.KeySize != 4 {
 | 
			
		||||
			return nil, errors.New("KeySize must be zero or four for perf event array")
 | 
			
		||||
		}
 | 
			
		||||
		abi.KeySize = 4
 | 
			
		||||
 | 
			
		||||
		spec.KeySize = 4
 | 
			
		||||
		spec.ValueSize = 4
 | 
			
		||||
		if abi.ValueSize != 0 && abi.ValueSize != 4 {
 | 
			
		||||
			return nil, errors.New("ValueSize must be zero or four for perf event array")
 | 
			
		||||
		}
 | 
			
		||||
		abi.ValueSize = 4
 | 
			
		||||
 | 
			
		||||
		if abi.MaxEntries == 0 {
 | 
			
		||||
			n, err := internal.PossibleCPUs()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, fmt.Errorf("perf event array: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			abi.MaxEntries = uint32(n)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if abi.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze {
 | 
			
		||||
		if err := haveMapMutabilityModifiers(); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("map create: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfMapCreateAttr{
 | 
			
		||||
		mapType:    spec.Type,
 | 
			
		||||
		keySize:    spec.KeySize,
 | 
			
		||||
		valueSize:  spec.ValueSize,
 | 
			
		||||
		maxEntries: spec.MaxEntries,
 | 
			
		||||
		flags:      spec.Flags,
 | 
			
		||||
		mapType:    abi.Type,
 | 
			
		||||
		keySize:    abi.KeySize,
 | 
			
		||||
		valueSize:  abi.ValueSize,
 | 
			
		||||
		maxEntries: abi.MaxEntries,
 | 
			
		||||
		flags:      abi.Flags,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if inner != nil {
 | 
			
		||||
		var err error
 | 
			
		||||
		attr.innerMapFd, err = inner.Value()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrap(err, "map create")
 | 
			
		||||
			return nil, fmt.Errorf("map create: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -169,21 +206,33 @@ func createMap(spec *MapSpec, inner *internal.FD, handle *btf.Handle) (*Map, err
 | 
			
		||||
		attr.btfValueTypeID = btf.MapValue(spec.BTF).ID()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, err := newBPFObjName(spec.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "map create")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if haveObjName() == nil {
 | 
			
		||||
		attr.mapName = name
 | 
			
		||||
		attr.mapName = newBPFObjName(spec.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfMapCreate(&attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "map create")
 | 
			
		||||
		return nil, fmt.Errorf("map create: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newMap(fd, spec.Name, newMapABIFromSpec(spec))
 | 
			
		||||
	m, err := newMap(fd, spec.Name, abi)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := m.populate(spec.Contents); err != nil {
 | 
			
		||||
		m.Close()
 | 
			
		||||
		return nil, fmt.Errorf("map create: can't set initial contents: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if spec.Freeze {
 | 
			
		||||
		if err := m.Freeze(); err != nil {
 | 
			
		||||
			m.Close()
 | 
			
		||||
			return nil, fmt.Errorf("can't freeze map: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return m, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newMap(fd *internal.FD, name string, abi *MapABI) (*Map, error) {
 | 
			
		||||
@@ -251,9 +300,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
 | 
			
		||||
		*value = m
 | 
			
		||||
		return nil
 | 
			
		||||
	case *Map:
 | 
			
		||||
		return errors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 | 
			
		||||
		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 | 
			
		||||
	case Map:
 | 
			
		||||
		return errors.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 | 
			
		||||
		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Map)(nil))
 | 
			
		||||
 | 
			
		||||
	case **Program:
 | 
			
		||||
		p, err := unmarshalProgram(valueBytes)
 | 
			
		||||
@@ -265,9 +314,9 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
 | 
			
		||||
		*value = p
 | 
			
		||||
		return nil
 | 
			
		||||
	case *Program:
 | 
			
		||||
		return errors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 | 
			
		||||
		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 | 
			
		||||
	case Program:
 | 
			
		||||
		return errors.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 | 
			
		||||
		return fmt.Errorf("can't unmarshal into %T, need %T", value, (**Program)(nil))
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return unmarshalBytes(valueOut, valueBytes)
 | 
			
		||||
@@ -275,16 +324,18 @@ func (m *Map) Lookup(key, valueOut interface{}) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupAndDelete retrieves and deletes a value from a Map.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrKeyNotExist if the key doesn't exist.
 | 
			
		||||
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")
 | 
			
		||||
		return fmt.Errorf("can't marshal key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := bpfMapLookupAndDelete(m.fd, keyPtr, valuePtr); err != nil {
 | 
			
		||||
		return errors.WithMessage(err, "lookup and delete and delete failed")
 | 
			
		||||
		return fmt.Errorf("lookup and delete failed: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return unmarshalBytes(valueOut, valueBytes)
 | 
			
		||||
@@ -298,7 +349,7 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, error) {
 | 
			
		||||
	valuePtr := internal.NewSlicePointer(valueBytes)
 | 
			
		||||
 | 
			
		||||
	err := m.lookup(key, valuePtr)
 | 
			
		||||
	if IsNotExist(err) {
 | 
			
		||||
	if errors.Is(err, ErrKeyNotExist) {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -308,11 +359,13 @@ func (m *Map) LookupBytes(key interface{}) ([]byte, 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")
 | 
			
		||||
		return fmt.Errorf("can't marshal key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bpfMapLookupElem(m.fd, keyPtr, valueOut)
 | 
			
		||||
	return errors.WithMessage(err, "lookup failed")
 | 
			
		||||
	if err = bpfMapLookupElem(m.fd, keyPtr, valueOut); err != nil {
 | 
			
		||||
		return fmt.Errorf("lookup failed: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapUpdateFlags controls the behaviour of the Map.Update call.
 | 
			
		||||
@@ -340,7 +393,7 @@ func (m *Map) Put(key, value interface{}) error {
 | 
			
		||||
func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
 | 
			
		||||
	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.WithMessage(err, "can't marshal key")
 | 
			
		||||
		return fmt.Errorf("can't marshal key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var valuePtr internal.Pointer
 | 
			
		||||
@@ -350,28 +403,36 @@ func (m *Map) Update(key, value interface{}, flags MapUpdateFlags) error {
 | 
			
		||||
		valuePtr, err = marshalPtr(value, int(m.abi.ValueSize))
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.WithMessage(err, "can't marshal value")
 | 
			
		||||
		return fmt.Errorf("can't marshal value: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags))
 | 
			
		||||
	if err = bpfMapUpdateElem(m.fd, keyPtr, valuePtr, uint64(flags)); err != nil {
 | 
			
		||||
		return fmt.Errorf("update failed: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Delete removes a value.
 | 
			
		||||
//
 | 
			
		||||
// Returns an error if the key does not exist, see IsNotExist.
 | 
			
		||||
// Returns ErrKeyNotExist if the key does not exist.
 | 
			
		||||
func (m *Map) Delete(key interface{}) error {
 | 
			
		||||
	keyPtr, err := marshalPtr(key, int(m.abi.KeySize))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.WithMessage(err, "can't marshal key")
 | 
			
		||||
		return fmt.Errorf("can't marshal key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bpfMapDeleteElem(m.fd, keyPtr)
 | 
			
		||||
	return errors.WithMessage(err, "can't delete key")
 | 
			
		||||
	if err = bpfMapDeleteElem(m.fd, keyPtr); err != nil {
 | 
			
		||||
		return fmt.Errorf("delete failed: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextKey finds the key following an initial key.
 | 
			
		||||
//
 | 
			
		||||
// See NextKeyBytes for details.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrKeyNotExist if there is no next key.
 | 
			
		||||
func (m *Map) NextKey(key, nextKeyOut interface{}) error {
 | 
			
		||||
	nextKeyPtr, nextKeyBytes := makeBuffer(nextKeyOut, int(m.abi.KeySize))
 | 
			
		||||
 | 
			
		||||
@@ -383,8 +444,10 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := unmarshalBytes(nextKeyOut, nextKeyBytes)
 | 
			
		||||
	return errors.WithMessage(err, "can't unmarshal next key")
 | 
			
		||||
	if err := unmarshalBytes(nextKeyOut, nextKeyBytes); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't unmarshal next key: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextKeyBytes returns the key following an initial key as a byte slice.
 | 
			
		||||
@@ -392,12 +455,14 @@ func (m *Map) NextKey(key, nextKeyOut interface{}) error {
 | 
			
		||||
// Passing nil will return the first key.
 | 
			
		||||
//
 | 
			
		||||
// Use Iterate if you want to traverse all entries in the map.
 | 
			
		||||
//
 | 
			
		||||
// Returns nil if there are no more keys.
 | 
			
		||||
func (m *Map) NextKeyBytes(key interface{}) ([]byte, error) {
 | 
			
		||||
	nextKey := make([]byte, m.abi.KeySize)
 | 
			
		||||
	nextKeyPtr := internal.NewSlicePointer(nextKey)
 | 
			
		||||
 | 
			
		||||
	err := m.nextKey(key, nextKeyPtr)
 | 
			
		||||
	if IsNotExist(err) {
 | 
			
		||||
	if errors.Is(err, ErrKeyNotExist) {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -413,12 +478,14 @@ func (m *Map) nextKey(key interface{}, nextKeyOut internal.Pointer) error {
 | 
			
		||||
	if key != nil {
 | 
			
		||||
		keyPtr, err = marshalPtr(key, int(m.abi.KeySize))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.WithMessage(err, "can't marshal key")
 | 
			
		||||
			return fmt.Errorf("can't marshal key: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut)
 | 
			
		||||
	return errors.WithMessage(err, "can't get next key")
 | 
			
		||||
	if err = bpfMapGetNextKey(m.fd, keyPtr, nextKeyOut); err != nil {
 | 
			
		||||
		return fmt.Errorf("next key failed: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Iterate traverses a map.
 | 
			
		||||
@@ -469,7 +536,7 @@ func (m *Map) Clone() (*Map, error) {
 | 
			
		||||
 | 
			
		||||
	dup, err := m.fd.Dup()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "can't clone map")
 | 
			
		||||
		return nil, fmt.Errorf("can't clone map: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newMap(dup, m.name, &m.abi)
 | 
			
		||||
@@ -479,7 +546,30 @@ func (m *Map) Clone() (*Map, error) {
 | 
			
		||||
//
 | 
			
		||||
// This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
 | 
			
		||||
func (m *Map) Pin(fileName string) error {
 | 
			
		||||
	return bpfPinObject(fileName, m.fd)
 | 
			
		||||
	return internal.BPFObjPin(fileName, m.fd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Freeze prevents a map to be modified from user space.
 | 
			
		||||
//
 | 
			
		||||
// It makes no changes to kernel-side restrictions.
 | 
			
		||||
func (m *Map) Freeze() error {
 | 
			
		||||
	if err := haveMapMutabilityModifiers(); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't freeze map: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := bpfMapFreeze(m.fd); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't freeze map: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Map) populate(contents []MapKV) error {
 | 
			
		||||
	for _, kv := range contents {
 | 
			
		||||
		if err := m.Put(kv.Key, kv.Value); err != nil {
 | 
			
		||||
			return fmt.Errorf("key %v: %w", kv.Key, err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedMap load a Map from a BPF file.
 | 
			
		||||
@@ -487,7 +577,7 @@ func (m *Map) Pin(fileName string) error {
 | 
			
		||||
// The function is not compatible with nested maps.
 | 
			
		||||
// Use LoadPinnedMapExplicit in these situations.
 | 
			
		||||
func LoadPinnedMap(fileName string) (*Map, error) {
 | 
			
		||||
	fd, err := bpfGetObject(fileName)
 | 
			
		||||
	fd, err := internal.BPFObjGet(fileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -501,7 +591,7 @@ func LoadPinnedMap(fileName string) (*Map, error) {
 | 
			
		||||
 | 
			
		||||
// LoadPinnedMapExplicit loads a map with explicit parameters.
 | 
			
		||||
func LoadPinnedMapExplicit(fileName string, abi *MapABI) (*Map, error) {
 | 
			
		||||
	fd, err := bpfGetObject(fileName)
 | 
			
		||||
	fd, err := internal.BPFObjGet(fileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -516,18 +606,7 @@ func unmarshalMap(buf []byte) (*Map, error) {
 | 
			
		||||
	// Looking up an entry in a nested map or prog array returns an id,
 | 
			
		||||
	// not an fd.
 | 
			
		||||
	id := internal.NativeEndian.Uint32(buf)
 | 
			
		||||
	fd, err := bpfGetMapFDByID(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, abi, err := newMapABIFromFd(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = fd.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newMap(fd, name, abi)
 | 
			
		||||
	return NewMapFromID(MapID(id))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBinary implements BinaryMarshaler.
 | 
			
		||||
@@ -542,6 +621,60 @@ func (m *Map) MarshalBinary() ([]byte, error) {
 | 
			
		||||
	return buf, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func patchValue(value []byte, typ btf.Type, replacements map[string]interface{}) error {
 | 
			
		||||
	replaced := make(map[string]bool)
 | 
			
		||||
	replace := func(name string, offset, size int, replacement interface{}) error {
 | 
			
		||||
		if offset+size > len(value) {
 | 
			
		||||
			return fmt.Errorf("%s: offset %d(+%d) is out of bounds", name, offset, size)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		buf, err := marshalBytes(replacement, size)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("marshal %s: %w", name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		copy(value[offset:offset+size], buf)
 | 
			
		||||
		replaced[name] = true
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch parent := typ.(type) {
 | 
			
		||||
	case *btf.Datasec:
 | 
			
		||||
		for _, secinfo := range parent.Vars {
 | 
			
		||||
			name := string(secinfo.Type.(*btf.Var).Name)
 | 
			
		||||
			replacement, ok := replacements[name]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err := replace(name, int(secinfo.Offset), int(secinfo.Size), replacement)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return fmt.Errorf("patching %T is not supported", typ)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(replaced) == len(replacements) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var missing []string
 | 
			
		||||
	for name := range replacements {
 | 
			
		||||
		if !replaced[name] {
 | 
			
		||||
			missing = append(missing, name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(missing) == 1 {
 | 
			
		||||
		return fmt.Errorf("unknown field: %s", missing[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Errorf("unknown fields: %s", strings.Join(missing, ","))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapIterator iterates a Map.
 | 
			
		||||
//
 | 
			
		||||
// See Map.Iterate.
 | 
			
		||||
@@ -562,8 +695,6 @@ func newMapIterator(target *Map) *MapIterator {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errIterationAborted = errors.New("iteration aborted")
 | 
			
		||||
 | 
			
		||||
// Next decodes the next key and value.
 | 
			
		||||
//
 | 
			
		||||
// Iterating a hash map from which keys are being deleted is not
 | 
			
		||||
@@ -599,7 +730,7 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
 | 
			
		||||
		mi.prevKey = mi.prevBytes
 | 
			
		||||
 | 
			
		||||
		mi.err = mi.target.Lookup(nextBytes, valueOut)
 | 
			
		||||
		if IsNotExist(mi.err) {
 | 
			
		||||
		if errors.Is(mi.err, ErrKeyNotExist) {
 | 
			
		||||
			// Even though the key should be valid, we couldn't look up
 | 
			
		||||
			// its value. If we're iterating a hash map this is probably
 | 
			
		||||
			// because a concurrent delete removed the value before we
 | 
			
		||||
@@ -618,26 +749,50 @@ func (mi *MapIterator) Next(keyOut, valueOut interface{}) bool {
 | 
			
		||||
		return mi.err == nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mi.err = errIterationAborted
 | 
			
		||||
	mi.err = fmt.Errorf("%w", ErrIterationAborted)
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Err returns any encountered error.
 | 
			
		||||
//
 | 
			
		||||
// The method must be called after Next returns nil.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrIterationAborted if it wasn't possible to do a full iteration.
 | 
			
		||||
func (mi *MapIterator) Err() error {
 | 
			
		||||
	return mi.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNotExist returns true if the error indicates that a
 | 
			
		||||
// key doesn't exist.
 | 
			
		||||
func IsNotExist(err error) bool {
 | 
			
		||||
	return errors.Cause(err) == unix.ENOENT
 | 
			
		||||
// MapGetNextID returns the ID of the next eBPF map.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrNotExist, if there is no next eBPF map.
 | 
			
		||||
func MapGetNextID(startID MapID) (MapID, error) {
 | 
			
		||||
	id, err := objGetNextID(internal.BPF_MAP_GET_NEXT_ID, uint32(startID))
 | 
			
		||||
	return MapID(id), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsIterationAborted returns true if the iteration was aborted.
 | 
			
		||||
// NewMapFromID returns the map for a given id.
 | 
			
		||||
//
 | 
			
		||||
// This occurs when keys are deleted from a hash map during iteration.
 | 
			
		||||
func IsIterationAborted(err error) bool {
 | 
			
		||||
	return errors.Cause(err) == errIterationAborted
 | 
			
		||||
// Returns ErrNotExist, if there is no eBPF map with the given id.
 | 
			
		||||
func NewMapFromID(id MapID) (*Map, error) {
 | 
			
		||||
	fd, err := bpfObjGetFDByID(internal.BPF_MAP_GET_FD_BY_ID, uint32(id))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, abi, err := newMapABIFromFd(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = fd.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newMap(fd, name, abi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID returns the systemwide unique ID of the map.
 | 
			
		||||
func (m *Map) ID() (MapID, error) {
 | 
			
		||||
	info, err := bpfGetMapInfoByFD(m.fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return MapID(0), err
 | 
			
		||||
	}
 | 
			
		||||
	return MapID(info.id), nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/cilium/ebpf/marshalers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/cilium/ebpf/marshalers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -4,13 +4,13 @@ import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
 | 
			
		||||
@@ -46,7 +46,9 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
 | 
			
		||||
	default:
 | 
			
		||||
		var wr bytes.Buffer
 | 
			
		||||
		err = binary.Write(&wr, internal.NativeEndian, value)
 | 
			
		||||
		err = errors.Wrapf(err, "encoding %T", value)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = fmt.Errorf("encoding %T: %v", value, err)
 | 
			
		||||
		}
 | 
			
		||||
		buf = wr.Bytes()
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -54,7 +56,7 @@ func marshalBytes(data interface{}, length int) (buf []byte, err error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(buf) != length {
 | 
			
		||||
		return nil, errors.Errorf("%T doesn't marshal to %d bytes", data, length)
 | 
			
		||||
		return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
 | 
			
		||||
	}
 | 
			
		||||
	return buf, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -95,8 +97,10 @@ func unmarshalBytes(data interface{}, buf []byte) error {
 | 
			
		||||
		return errors.New("require pointer to []byte")
 | 
			
		||||
	default:
 | 
			
		||||
		rd := bytes.NewReader(buf)
 | 
			
		||||
		err := binary.Read(rd, internal.NativeEndian, value)
 | 
			
		||||
		return errors.Wrapf(err, "decoding %T", value)
 | 
			
		||||
		if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
 | 
			
		||||
			return fmt.Errorf("decoding %T: %v", value, err)
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -120,7 +124,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
 | 
			
		||||
	sliceValue := reflect.ValueOf(slice)
 | 
			
		||||
	sliceLen := sliceValue.Len()
 | 
			
		||||
	if sliceLen > possibleCPUs {
 | 
			
		||||
		return internal.Pointer{}, errors.Errorf("per-CPU value exceeds number of CPUs")
 | 
			
		||||
		return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	alignedElemLength := align(elemLength, 8)
 | 
			
		||||
@@ -147,7 +151,7 @@ func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, er
 | 
			
		||||
func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
 | 
			
		||||
	slicePtrType := reflect.TypeOf(slicePtr)
 | 
			
		||||
	if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
 | 
			
		||||
		return errors.Errorf("per-cpu value requires pointer to slice")
 | 
			
		||||
		return fmt.Errorf("per-cpu value requires pointer to slice")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	possibleCPUs, err := internal.PossibleCPUs()
 | 
			
		||||
@@ -166,7 +170,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
 | 
			
		||||
 | 
			
		||||
	step := len(buf) / possibleCPUs
 | 
			
		||||
	if step < elemLength {
 | 
			
		||||
		return errors.Errorf("per-cpu element length is larger than available data")
 | 
			
		||||
		return fmt.Errorf("per-cpu element length is larger than available data")
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < possibleCPUs; i++ {
 | 
			
		||||
		var elem interface{}
 | 
			
		||||
@@ -184,7 +188,7 @@ func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) erro
 | 
			
		||||
 | 
			
		||||
		err := unmarshalBytes(elem, elemBytes)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "cpu %d", i)
 | 
			
		||||
			return fmt.Errorf("cpu %d: %w", i, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		buf = buf[step:]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										262
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										262
									
								
								vendor/github.com/cilium/ebpf/prog.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -2,20 +2,25 @@ package ebpf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrNotSupported is returned whenever the kernel doesn't support a feature.
 | 
			
		||||
var ErrNotSupported = internal.ErrNotSupported
 | 
			
		||||
 | 
			
		||||
// ProgramID represents the unique ID of an eBPF program
 | 
			
		||||
type ProgramID uint32
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Number of bytes to pad the output buffer for BPF_PROG_TEST_RUN.
 | 
			
		||||
	// This is currently the maximum of spare space allocated for SKB
 | 
			
		||||
@@ -41,17 +46,33 @@ type ProgramOptions struct {
 | 
			
		||||
type ProgramSpec struct {
 | 
			
		||||
	// Name is passed to the kernel as a debug aid. Must only contain
 | 
			
		||||
	// alpha numeric and '_' characters.
 | 
			
		||||
	Name          string
 | 
			
		||||
	Type          ProgramType
 | 
			
		||||
	AttachType    AttachType
 | 
			
		||||
	Instructions  asm.Instructions
 | 
			
		||||
	License       string
 | 
			
		||||
	Name string
 | 
			
		||||
	// Type determines at which hook in the kernel a program will run.
 | 
			
		||||
	Type       ProgramType
 | 
			
		||||
	AttachType AttachType
 | 
			
		||||
	// Name of a kernel data structure to attach to. It's interpretation
 | 
			
		||||
	// depends on Type and AttachType.
 | 
			
		||||
	AttachTo     string
 | 
			
		||||
	Instructions asm.Instructions
 | 
			
		||||
 | 
			
		||||
	// License of the program. Some helpers are only available if
 | 
			
		||||
	// the license is deemed compatible with the GPL.
 | 
			
		||||
	//
 | 
			
		||||
	// See https://www.kernel.org/doc/html/latest/process/license-rules.html#id1
 | 
			
		||||
	License string
 | 
			
		||||
 | 
			
		||||
	// Version used by tracing programs.
 | 
			
		||||
	//
 | 
			
		||||
	// Deprecated: superseded by BTF.
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
	// The byte order this program was compiled for, may be nil.
 | 
			
		||||
	ByteOrder binary.ByteOrder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy returns a copy of the spec.
 | 
			
		||||
@@ -74,9 +95,10 @@ type Program struct {
 | 
			
		||||
	// otherwise it is empty.
 | 
			
		||||
	VerifierLog string
 | 
			
		||||
 | 
			
		||||
	fd   *internal.FD
 | 
			
		||||
	name string
 | 
			
		||||
	abi  ProgramABI
 | 
			
		||||
	fd         *internal.FD
 | 
			
		||||
	name       string
 | 
			
		||||
	abi        ProgramABI
 | 
			
		||||
	attachType AttachType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewProgram creates a new Program.
 | 
			
		||||
@@ -97,8 +119,8 @@ func NewProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	handle, err := btf.NewHandle(btf.ProgramSpec(spec.BTF))
 | 
			
		||||
	if err != nil && !btf.IsNotSupported(err) {
 | 
			
		||||
		return nil, errors.Wrap(err, "can't load BTF")
 | 
			
		||||
	if err != nil && !errors.Is(err, btf.ErrNotSupported) {
 | 
			
		||||
		return nil, fmt.Errorf("can't load BTF: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newProgramWithBTF(spec, handle, opts)
 | 
			
		||||
@@ -130,6 +152,7 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
 | 
			
		||||
		return prog, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logErr := err
 | 
			
		||||
	if opts.LogLevel == 0 {
 | 
			
		||||
		// Re-run with the verifier enabled to get better error messages.
 | 
			
		||||
		logBuf = make([]byte, logSize)
 | 
			
		||||
@@ -137,11 +160,11 @@ func newProgramWithBTF(spec *ProgramSpec, btf *btf.Handle, opts ProgramOptions)
 | 
			
		||||
		attr.logSize = uint32(len(logBuf))
 | 
			
		||||
		attr.logBuf = internal.NewSlicePointer(logBuf)
 | 
			
		||||
 | 
			
		||||
		_, logErr := bpfProgLoad(attr)
 | 
			
		||||
		err = internal.ErrorWithLog(err, logBuf, logErr)
 | 
			
		||||
		_, logErr = bpfProgLoad(attr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.Wrap(err, "can't load program")
 | 
			
		||||
	err = internal.ErrorWithLog(err, logBuf, logErr)
 | 
			
		||||
	return nil, fmt.Errorf("can't load program: %w", err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewProgramFromFD creates a program from a raw fd.
 | 
			
		||||
@@ -181,6 +204,10 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 | 
			
		||||
		return nil, errors.New("License cannot be empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if spec.ByteOrder != nil && spec.ByteOrder != internal.NativeEndian {
 | 
			
		||||
		return nil, fmt.Errorf("can't load %s program on %s", spec.ByteOrder, internal.NativeEndian)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf := bytes.NewBuffer(make([]byte, 0, len(spec.Instructions)*asm.InstructionSize))
 | 
			
		||||
	err := spec.Instructions.Marshal(buf, internal.NativeEndian)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -195,15 +222,11 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 | 
			
		||||
		insCount:           insCount,
 | 
			
		||||
		instructions:       internal.NewSlicePointer(bytecode),
 | 
			
		||||
		license:            internal.NewStringPointer(spec.License),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, err := newBPFObjName(spec.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		kernelVersion:      spec.KernelVersion,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if haveObjName() == nil {
 | 
			
		||||
		attr.progName = name
 | 
			
		||||
		attr.progName = newBPFObjName(spec.Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if handle != nil && spec.BTF != nil {
 | 
			
		||||
@@ -211,7 +234,7 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 | 
			
		||||
 | 
			
		||||
		recSize, bytes, err := btf.ProgramLineInfos(spec.BTF)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrap(err, "can't get BTF line infos")
 | 
			
		||||
			return nil, fmt.Errorf("can't get BTF line infos: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		attr.lineInfoRecSize = recSize
 | 
			
		||||
		attr.lineInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
 | 
			
		||||
@@ -219,13 +242,23 @@ func convertProgramSpec(spec *ProgramSpec, handle *btf.Handle) (*bpfProgLoadAttr
 | 
			
		||||
 | 
			
		||||
		recSize, bytes, err = btf.ProgramFuncInfos(spec.BTF)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.Wrap(err, "can't get BTF function infos")
 | 
			
		||||
			return nil, fmt.Errorf("can't get BTF function infos: %w", err)
 | 
			
		||||
		}
 | 
			
		||||
		attr.funcInfoRecSize = recSize
 | 
			
		||||
		attr.funcInfoCnt = uint32(uint64(len(bytes)) / uint64(recSize))
 | 
			
		||||
		attr.funcInfo = internal.NewSlicePointer(bytes)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if spec.AttachTo != "" {
 | 
			
		||||
		target, err := resolveBTFType(spec.AttachTo, spec.Type, spec.AttachType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if target != nil {
 | 
			
		||||
			attr.attachBTFID = target.ID()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return attr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -267,7 +300,7 @@ func (p *Program) Clone() (*Program, error) {
 | 
			
		||||
 | 
			
		||||
	dup, err := p.fd.Dup()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.Wrap(err, "can't clone program")
 | 
			
		||||
		return nil, fmt.Errorf("can't clone program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newProgram(dup, p.name, &p.abi), nil
 | 
			
		||||
@@ -277,7 +310,10 @@ func (p *Program) Clone() (*Program, error) {
 | 
			
		||||
//
 | 
			
		||||
// This requires bpffs to be mounted above fileName. See http://cilium.readthedocs.io/en/doc-1.0/kubernetes/install/#mounting-the-bpf-fs-optional
 | 
			
		||||
func (p *Program) Pin(fileName string) error {
 | 
			
		||||
	return errors.Wrap(bpfPinObject(fileName, p.fd), "can't pin program")
 | 
			
		||||
	if err := internal.BPFObjPin(fileName, p.fd); err != nil {
 | 
			
		||||
		return fmt.Errorf("can't pin program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close unloads the program from the kernel.
 | 
			
		||||
@@ -297,23 +333,33 @@ func (p *Program) Close() error {
 | 
			
		||||
//
 | 
			
		||||
// This function requires at least Linux 4.12.
 | 
			
		||||
func (p *Program) Test(in []byte) (uint32, []byte, error) {
 | 
			
		||||
	ret, out, _, err := p.testRun(in, 1)
 | 
			
		||||
	return ret, out, errors.Wrap(err, "can't test program")
 | 
			
		||||
	ret, out, _, err := p.testRun(in, 1, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ret, nil, fmt.Errorf("can't test program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return ret, out, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Benchmark runs the Program with the given input for a number of times
 | 
			
		||||
// and returns the time taken per iteration.
 | 
			
		||||
//
 | 
			
		||||
// The returned value is the return value of the last execution of
 | 
			
		||||
// the program.
 | 
			
		||||
// Returns the result of the last execution of the program and the time per
 | 
			
		||||
// run or an error. reset is called whenever the benchmark syscall is
 | 
			
		||||
// interrupted, and should be set to testing.B.ResetTimer or similar.
 | 
			
		||||
//
 | 
			
		||||
// Note: profiling a call to this function will skew it's results, see
 | 
			
		||||
// https://github.com/cilium/ebpf/issues/24
 | 
			
		||||
//
 | 
			
		||||
// This function requires at least Linux 4.12.
 | 
			
		||||
func (p *Program) Benchmark(in []byte, repeat int) (uint32, time.Duration, error) {
 | 
			
		||||
	ret, _, total, err := p.testRun(in, repeat)
 | 
			
		||||
	return ret, total, errors.Wrap(err, "can't benchmark program")
 | 
			
		||||
func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.Duration, error) {
 | 
			
		||||
	ret, _, total, err := p.testRun(in, repeat, reset)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ret, total, fmt.Errorf("can't benchmark program: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return ret, total, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() bool {
 | 
			
		||||
var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() (bool, error) {
 | 
			
		||||
	prog, err := NewProgram(&ProgramSpec{
 | 
			
		||||
		Type: SocketFilter,
 | 
			
		||||
		Instructions: asm.Instructions{
 | 
			
		||||
@@ -324,31 +370,26 @@ var haveProgTestRun = internal.FeatureTest("BPF_PROG_TEST_RUN", "4.12", func() b
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// This may be because we lack sufficient permissions, etc.
 | 
			
		||||
		return false
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer prog.Close()
 | 
			
		||||
 | 
			
		||||
	fd, err := prog.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Programs require at least 14 bytes input
 | 
			
		||||
	in := make([]byte, 14)
 | 
			
		||||
	attr := bpfProgTestRunAttr{
 | 
			
		||||
		fd:         fd,
 | 
			
		||||
		fd:         uint32(prog.FD()),
 | 
			
		||||
		dataSizeIn: uint32(len(in)),
 | 
			
		||||
		dataIn:     internal.NewSlicePointer(in),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	err = bpfProgTestRun(&attr)
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration, error) {
 | 
			
		||||
func (p *Program) testRun(in []byte, repeat int, reset func()) (uint32, []byte, time.Duration, error) {
 | 
			
		||||
	if uint(repeat) > math.MaxUint32 {
 | 
			
		||||
		return 0, nil, 0, fmt.Errorf("repeat is too high")
 | 
			
		||||
	}
 | 
			
		||||
@@ -386,9 +427,20 @@ func (p *Program) testRun(in []byte, repeat int) (uint32, []byte, time.Duration,
 | 
			
		||||
		repeat:      uint32(repeat),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = internal.BPF(_ProgTestRun, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, nil, 0, errors.Wrap(err, "can't run test")
 | 
			
		||||
	for {
 | 
			
		||||
		err = bpfProgTestRun(&attr)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if errors.Is(err, unix.EINTR) {
 | 
			
		||||
			if reset != nil {
 | 
			
		||||
				reset()
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return 0, nil, 0, fmt.Errorf("can't run test: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if int(attr.dataSizeOut) > cap(out) {
 | 
			
		||||
@@ -410,18 +462,7 @@ func unmarshalProgram(buf []byte) (*Program, error) {
 | 
			
		||||
	// Looking up an entry in a nested map or prog array returns an id,
 | 
			
		||||
	// not an fd.
 | 
			
		||||
	id := internal.NativeEndian.Uint32(buf)
 | 
			
		||||
	fd, err := bpfGetProgramFDByID(id)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, abi, err := newProgramABIFromFd(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = fd.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newProgram(fd, name, abi), nil
 | 
			
		||||
	return NewProgramFromID(ProgramID(id))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalBinary implements BinaryMarshaler.
 | 
			
		||||
@@ -436,7 +477,9 @@ func (p *Program) MarshalBinary() ([]byte, error) {
 | 
			
		||||
	return buf, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Attach a Program to a container object fd
 | 
			
		||||
// Attach a Program.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use link.RawAttachProgram instead.
 | 
			
		||||
func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
 | 
			
		||||
	if fd < 0 {
 | 
			
		||||
		return errors.New("invalid fd")
 | 
			
		||||
@@ -447,42 +490,47 @@ func (p *Program) Attach(fd int, typ AttachType, flags AttachFlags) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfProgAlterAttr{
 | 
			
		||||
		targetFd:    uint32(fd),
 | 
			
		||||
		attachBpfFd: pfd,
 | 
			
		||||
		attachType:  uint32(typ),
 | 
			
		||||
		attachFlags: uint32(flags),
 | 
			
		||||
	attr := internal.BPFProgAttachAttr{
 | 
			
		||||
		TargetFd:    uint32(fd),
 | 
			
		||||
		AttachBpfFd: pfd,
 | 
			
		||||
		AttachType:  uint32(typ),
 | 
			
		||||
		AttachFlags: uint32(flags),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bpfProgAlter(_ProgAttach, &attr)
 | 
			
		||||
	return internal.BPFProgAttach(&attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Detach a Program from a container object fd
 | 
			
		||||
// Detach a Program.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: use link.RawDetachProgram instead.
 | 
			
		||||
func (p *Program) Detach(fd int, typ AttachType, flags AttachFlags) error {
 | 
			
		||||
	if fd < 0 {
 | 
			
		||||
		return errors.New("invalid fd")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if flags != 0 {
 | 
			
		||||
		return errors.New("flags must be zero")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pfd, err := p.fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfProgAlterAttr{
 | 
			
		||||
		targetFd:    uint32(fd),
 | 
			
		||||
		attachBpfFd: pfd,
 | 
			
		||||
		attachType:  uint32(typ),
 | 
			
		||||
		attachFlags: uint32(flags),
 | 
			
		||||
	attr := internal.BPFProgDetachAttr{
 | 
			
		||||
		TargetFd:    uint32(fd),
 | 
			
		||||
		AttachBpfFd: pfd,
 | 
			
		||||
		AttachType:  uint32(typ),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bpfProgAlter(_ProgDetach, &attr)
 | 
			
		||||
	return internal.BPFProgDetach(&attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadPinnedProgram loads a Program from a BPF file.
 | 
			
		||||
//
 | 
			
		||||
// Requires at least Linux 4.11.
 | 
			
		||||
func LoadPinnedProgram(fileName string) (*Program, error) {
 | 
			
		||||
	fd, err := bpfGetObject(fileName)
 | 
			
		||||
	fd, err := internal.BPFObjGet(fileName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -490,7 +538,7 @@ func LoadPinnedProgram(fileName string) (*Program, error) {
 | 
			
		||||
	name, abi, err := newProgramABIFromFd(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = fd.Close()
 | 
			
		||||
		return nil, errors.Wrapf(err, "can't get ABI for %s", fileName)
 | 
			
		||||
		return nil, fmt.Errorf("can't get ABI for %s: %w", fileName, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newProgram(fd, name, abi), nil
 | 
			
		||||
@@ -512,9 +560,63 @@ func SanitizeName(name string, replacement rune) string {
 | 
			
		||||
	}, name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNotSupported returns true if an error occurred because
 | 
			
		||||
// the kernel does not have support for a specific feature.
 | 
			
		||||
func IsNotSupported(err error) bool {
 | 
			
		||||
	_, notSupported := errors.Cause(err).(*internal.UnsupportedFeatureError)
 | 
			
		||||
	return notSupported
 | 
			
		||||
// ProgramGetNextID returns the ID of the next eBPF program.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrNotExist, if there is no next eBPF program.
 | 
			
		||||
func ProgramGetNextID(startID ProgramID) (ProgramID, error) {
 | 
			
		||||
	id, err := objGetNextID(internal.BPF_PROG_GET_NEXT_ID, uint32(startID))
 | 
			
		||||
	return ProgramID(id), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewProgramFromID returns the program for a given id.
 | 
			
		||||
//
 | 
			
		||||
// Returns ErrNotExist, if there is no eBPF program with the given id.
 | 
			
		||||
func NewProgramFromID(id ProgramID) (*Program, error) {
 | 
			
		||||
	fd, err := bpfObjGetFDByID(internal.BPF_PROG_GET_FD_BY_ID, uint32(id))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name, abi, err := newProgramABIFromFd(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		_ = fd.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return newProgram(fd, name, abi), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ID returns the systemwide unique ID of the program.
 | 
			
		||||
func (p *Program) ID() (ProgramID, error) {
 | 
			
		||||
	info, err := bpfGetProgInfoByFD(p.fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return ProgramID(0), err
 | 
			
		||||
	}
 | 
			
		||||
	return ProgramID(info.id), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resolveBTFType(name string, progType ProgramType, attachType AttachType) (btf.Type, error) {
 | 
			
		||||
	kernel, err := btf.LoadKernelSpec()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't resolve BTF type %s: %w", name, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type match struct {
 | 
			
		||||
		p ProgramType
 | 
			
		||||
		a AttachType
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	target := match{progType, attachType}
 | 
			
		||||
	switch target {
 | 
			
		||||
	case match{Tracing, AttachTraceIter}:
 | 
			
		||||
		var target btf.Func
 | 
			
		||||
		if err := kernel.FindType("bpf_iter_"+name, &target); err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("can't resolve BTF for iterator %s: %w", name, err)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return &target, nil
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/cilium/ebpf/readme.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/cilium/ebpf/readme.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -13,6 +13,11 @@ The library is maintained by [Cloudflare](https://www.cloudflare.com) and [Ciliu
 | 
			
		||||
The package is production ready, but **the API is explicitly unstable
 | 
			
		||||
right now**. Expect to update your code if you want to follow along.
 | 
			
		||||
 | 
			
		||||
## Requirements
 | 
			
		||||
 | 
			
		||||
* A version of Go that is [supported by upstream](https://golang.org/doc/devel/release.html#policy)
 | 
			
		||||
* Linux 4.9, 4.19 or 5.4 (versions in-between should work, but are not tested)
 | 
			
		||||
 | 
			
		||||
## Useful resources
 | 
			
		||||
 | 
			
		||||
* [Cilium eBPF documentation](https://cilium.readthedocs.io/en/latest/bpf/#bpf-guide) (recommended)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										256
									
								
								vendor/github.com/cilium/ebpf/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										256
									
								
								vendor/github.com/cilium/ebpf/syscalls.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,15 +1,19 @@
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/cilium/ebpf/internal"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/btf"
 | 
			
		||||
	"github.com/cilium/ebpf/internal/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
// Generic errors returned by BPF syscalls.
 | 
			
		||||
var (
 | 
			
		||||
	ErrNotExist = errors.New("requested object does not exist")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// bpfObjName is a null-terminated string made up of
 | 
			
		||||
@@ -17,18 +21,15 @@ import (
 | 
			
		||||
type bpfObjName [unix.BPF_OBJ_NAME_LEN]byte
 | 
			
		||||
 | 
			
		||||
// newBPFObjName truncates the result if it is too long.
 | 
			
		||||
func newBPFObjName(name string) (bpfObjName, error) {
 | 
			
		||||
	idx := strings.IndexFunc(name, invalidBPFObjNameChar)
 | 
			
		||||
	if idx != -1 {
 | 
			
		||||
		return bpfObjName{}, errors.Errorf("invalid character '%c' in name '%s'", name[idx], name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
func newBPFObjName(name string) bpfObjName {
 | 
			
		||||
	var result bpfObjName
 | 
			
		||||
	copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
 | 
			
		||||
	return result, nil
 | 
			
		||||
	return result
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func invalidBPFObjNameChar(char rune) bool {
 | 
			
		||||
	dotAllowed := objNameAllowsDot() == nil
 | 
			
		||||
 | 
			
		||||
	switch {
 | 
			
		||||
	case char >= 'A' && char <= 'Z':
 | 
			
		||||
		fallthrough
 | 
			
		||||
@@ -36,6 +37,8 @@ func invalidBPFObjNameChar(char rune) bool {
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case char >= '0' && char <= '9':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case dotAllowed && char == '.':
 | 
			
		||||
		fallthrough
 | 
			
		||||
	case char == '_':
 | 
			
		||||
		return false
 | 
			
		||||
	default:
 | 
			
		||||
@@ -76,12 +79,6 @@ type bpfMapInfo struct {
 | 
			
		||||
	mapName    bpfObjName // since 4.15 ad5b177bd73f
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfPinObjAttr struct {
 | 
			
		||||
	fileName internal.Pointer
 | 
			
		||||
	fd       uint32
 | 
			
		||||
	padding  uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfProgLoadAttr struct {
 | 
			
		||||
	progType           ProgramType
 | 
			
		||||
	insCount           uint32
 | 
			
		||||
@@ -102,6 +99,8 @@ type bpfProgLoadAttr struct {
 | 
			
		||||
	lineInfoRecSize    uint32
 | 
			
		||||
	lineInfo           internal.Pointer
 | 
			
		||||
	lineInfoCnt        uint32
 | 
			
		||||
	attachBTFID        btf.TypeID
 | 
			
		||||
	attachProgFd       uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfProgInfo struct {
 | 
			
		||||
@@ -130,13 +129,6 @@ type bpfProgTestRunAttr struct {
 | 
			
		||||
	duration    uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfProgAlterAttr struct {
 | 
			
		||||
	targetFd    uint32
 | 
			
		||||
	attachBpfFd uint32
 | 
			
		||||
	attachType  uint32
 | 
			
		||||
	attachFlags uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfObjGetInfoByFDAttr struct {
 | 
			
		||||
	fd      uint32
 | 
			
		||||
	infoLen uint32
 | 
			
		||||
@@ -148,9 +140,19 @@ type bpfGetFDByIDAttr struct {
 | 
			
		||||
	next uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfMapFreezeAttr struct {
 | 
			
		||||
	mapFd uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type bpfObjGetNextIDAttr struct {
 | 
			
		||||
	startID   uint32
 | 
			
		||||
	nextID    uint32
 | 
			
		||||
	openFlags uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
 | 
			
		||||
	for {
 | 
			
		||||
		fd, err := internal.BPF(_ProgLoad, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
		fd, err := internal.BPF(internal.BPF_PROG_LOAD, 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 {
 | 
			
		||||
@@ -165,13 +167,17 @@ func bpfProgLoad(attr *bpfProgLoadAttr) (*internal.FD, error) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfProgAlter(cmd int, attr *bpfProgAlterAttr) error {
 | 
			
		||||
	_, err := internal.BPF(cmd, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
func bpfProgTestRun(attr *bpfProgTestRunAttr) error {
 | 
			
		||||
	_, err := internal.BPF(internal.BPF_PROG_TEST_RUN, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
 | 
			
		||||
	fd, err := internal.BPF(_MapCreate, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	fd, err := internal.BPF(internal.BPF_MAP_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
 | 
			
		||||
	if errors.Is(err, os.ErrPermission) {
 | 
			
		||||
		return nil, errors.New("permission denied or insufficient rlimit to lock memory for map")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -179,7 +185,7 @@ func bpfMapCreate(attr *bpfMapCreateAttr) (*internal.FD, error) {
 | 
			
		||||
	return internal.NewFD(uint32(fd)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool {
 | 
			
		||||
var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() (bool, error) {
 | 
			
		||||
	inner, err := bpfMapCreate(&bpfMapCreateAttr{
 | 
			
		||||
		mapType:    Array,
 | 
			
		||||
		keySize:    4,
 | 
			
		||||
@@ -187,7 +193,7 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool {
 | 
			
		||||
		maxEntries: 1,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer inner.Close()
 | 
			
		||||
 | 
			
		||||
@@ -200,11 +206,28 @@ var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() bool {
 | 
			
		||||
		innerMapFd: innerFd,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_ = nested.Close()
 | 
			
		||||
	return true
 | 
			
		||||
	return true, nil
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() (bool, error) {
 | 
			
		||||
	// This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
 | 
			
		||||
	// BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
 | 
			
		||||
	m, err := bpfMapCreate(&bpfMapCreateAttr{
 | 
			
		||||
		mapType:    Array,
 | 
			
		||||
		keySize:    4,
 | 
			
		||||
		valueSize:  4,
 | 
			
		||||
		maxEntries: 1,
 | 
			
		||||
		flags:      unix.BPF_F_RDONLY_PROG,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	_ = m.Close()
 | 
			
		||||
	return true, nil
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error {
 | 
			
		||||
@@ -218,8 +241,8 @@ func bpfMapLookupElem(m *internal.FD, key, valueOut internal.Pointer) error {
 | 
			
		||||
		key:   key,
 | 
			
		||||
		value: valueOut,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_MapLookupElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return err
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_LOOKUP_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return wrapMapError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error {
 | 
			
		||||
@@ -233,8 +256,8 @@ func bpfMapLookupAndDelete(m *internal.FD, key, valueOut internal.Pointer) error
 | 
			
		||||
		key:   key,
 | 
			
		||||
		value: valueOut,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_MapLookupAndDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return err
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_LOOKUP_AND_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return wrapMapError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint64) error {
 | 
			
		||||
@@ -249,8 +272,8 @@ func bpfMapUpdateElem(m *internal.FD, key, valueOut internal.Pointer, flags uint
 | 
			
		||||
		value: valueOut,
 | 
			
		||||
		flags: flags,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_MapUpdateElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return err
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_UPDATE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return wrapMapError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error {
 | 
			
		||||
@@ -263,8 +286,8 @@ func bpfMapDeleteElem(m *internal.FD, key internal.Pointer) error {
 | 
			
		||||
		mapFd: fd,
 | 
			
		||||
		key:   key,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_MapDeleteElem, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return err
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_DELETE_ELEM, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return wrapMapError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error {
 | 
			
		||||
@@ -278,44 +301,58 @@ func bpfMapGetNextKey(m *internal.FD, key, nextKeyOut internal.Pointer) error {
 | 
			
		||||
		key:   key,
 | 
			
		||||
		value: nextKeyOut,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_MapGetNextKey, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_GET_NEXT_KEY, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return wrapMapError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func objGetNextID(cmd internal.BPFCmd, start uint32) (uint32, error) {
 | 
			
		||||
	attr := bpfObjGetNextIDAttr{
 | 
			
		||||
		startID: start,
 | 
			
		||||
	}
 | 
			
		||||
	_, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return attr.nextID, wrapObjError(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wrapObjError(err error) error {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if errors.Is(err, unix.ENOENT) {
 | 
			
		||||
		return fmt.Errorf("%w", ErrNotExist)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errors.New(err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wrapMapError(err error) error {
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if errors.Is(err, unix.ENOENT) {
 | 
			
		||||
		return ErrKeyNotExist
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if errors.Is(err, unix.EEXIST) {
 | 
			
		||||
		return ErrKeyExist
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errors.New(err.Error())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfMapFreeze(m *internal.FD) error {
 | 
			
		||||
	fd, err := m.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfMapFreezeAttr{
 | 
			
		||||
		mapFd: fd,
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_MAP_FREEZE, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const bpfFSType = 0xcafe4a11
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if uint64(statfs.Type) != bpfFSType {
 | 
			
		||||
		return errors.Errorf("%s is not on a bpf filesystem", fileName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	value, err := fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, 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) (*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 internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) error {
 | 
			
		||||
	value, err := fd.Value()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -328,28 +365,51 @@ func bpfGetObjectInfoByFD(fd *internal.FD, info unsafe.Pointer, size uintptr) er
 | 
			
		||||
		infoLen: uint32(size),
 | 
			
		||||
		info:    internal.NewPointer(info),
 | 
			
		||||
	}
 | 
			
		||||
	_, err = internal.BPF(_ObjGetInfoByFD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return errors.Wrapf(err, "fd %d", fd)
 | 
			
		||||
	_, err = internal.BPF(internal.BPF_OBJ_GET_INFO_BY_FD, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("fd %d: %w", fd, err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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")
 | 
			
		||||
	if err := bpfGetObjectInfoByFD(fd, unsafe.Pointer(&info), unsafe.Sizeof(info)); err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't get program info: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return &info, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("can't get map info: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return &info, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var haveObjName = internal.FeatureTest("object names", "4.15", func() bool {
 | 
			
		||||
	name, err := newBPFObjName("feature_test")
 | 
			
		||||
var haveObjName = internal.FeatureTest("object names", "4.15", func() (bool, error) {
 | 
			
		||||
	attr := bpfMapCreateAttr{
 | 
			
		||||
		mapType:    Array,
 | 
			
		||||
		keySize:    4,
 | 
			
		||||
		valueSize:  4,
 | 
			
		||||
		maxEntries: 1,
 | 
			
		||||
		mapName:    newBPFObjName("feature_test"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfMapCreate(&attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// This really is a fatal error, but it should be caught
 | 
			
		||||
		// by the unit tests not working.
 | 
			
		||||
		return false
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_ = fd.Close()
 | 
			
		||||
	return true, nil
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() (bool, error) {
 | 
			
		||||
	if err := haveObjName(); err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attr := bpfMapCreateAttr{
 | 
			
		||||
@@ -357,38 +417,22 @@ var haveObjName = internal.FeatureTest("object names", "4.15", func() bool {
 | 
			
		||||
		keySize:    4,
 | 
			
		||||
		valueSize:  4,
 | 
			
		||||
		maxEntries: 1,
 | 
			
		||||
		mapName:    name,
 | 
			
		||||
		mapName:    newBPFObjName(".test"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fd, err := bpfMapCreate(&attr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_ = fd.Close()
 | 
			
		||||
	return true
 | 
			
		||||
	return true, nil
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
func bpfGetMapFDByID(id uint32) (*internal.FD, error) {
 | 
			
		||||
	// available from 4.13
 | 
			
		||||
func bpfObjGetFDByID(cmd internal.BPFCmd, id uint32) (*internal.FD, error) {
 | 
			
		||||
	attr := bpfGetFDByIDAttr{
 | 
			
		||||
		id: id,
 | 
			
		||||
	}
 | 
			
		||||
	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 internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bpfGetProgramFDByID(id uint32) (*internal.FD, error) {
 | 
			
		||||
	// available from 4.13
 | 
			
		||||
	attr := bpfGetFDByIDAttr{
 | 
			
		||||
		id: id,
 | 
			
		||||
	}
 | 
			
		||||
	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 internal.NewFD(uint32(ptr)), nil
 | 
			
		||||
	ptr, err := internal.BPF(cmd, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
 | 
			
		||||
	return internal.NewFD(uint32(ptr)), wrapObjError(err)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								vendor/github.com/cilium/ebpf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/cilium/ebpf/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
//go:generate stringer -output types_string.go -type=MapType,ProgramType
 | 
			
		||||
//go:generate stringer -output types_string.go -type=MapType,ProgramType,AttachType
 | 
			
		||||
 | 
			
		||||
// MapType indicates the type map structure
 | 
			
		||||
// that will be initialized in the kernel.
 | 
			
		||||
@@ -85,44 +85,12 @@ const (
 | 
			
		||||
 | 
			
		||||
// hasPerCPUValue returns true if the Map stores a value per CPU.
 | 
			
		||||
func (mt MapType) hasPerCPUValue() bool {
 | 
			
		||||
	if mt == PerCPUHash || mt == PerCPUArray {
 | 
			
		||||
	if mt == PerCPUHash || mt == PerCPUArray || mt == LRUCPUHash {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	_MapCreate = iota
 | 
			
		||||
	_MapLookupElem
 | 
			
		||||
	_MapUpdateElem
 | 
			
		||||
	_MapDeleteElem
 | 
			
		||||
	_MapGetNextKey
 | 
			
		||||
	_ProgLoad
 | 
			
		||||
	_ObjPin
 | 
			
		||||
	_ObjGet
 | 
			
		||||
	_ProgAttach
 | 
			
		||||
	_ProgDetach
 | 
			
		||||
	_ProgTestRun
 | 
			
		||||
	_ProgGetNextID
 | 
			
		||||
	_MapGetNextID
 | 
			
		||||
	_ProgGetFDByID
 | 
			
		||||
	_MapGetFDByID
 | 
			
		||||
	_ObjGetInfoByFD
 | 
			
		||||
	_ProgQuery
 | 
			
		||||
	_RawTracepointOpen
 | 
			
		||||
	_BTFLoad
 | 
			
		||||
	_BTFGetFDByID
 | 
			
		||||
	_TaskFDQuery
 | 
			
		||||
	_MapLookupAndDeleteElem
 | 
			
		||||
	_MapFreeze
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	_Any = iota
 | 
			
		||||
	_NoExist
 | 
			
		||||
	_Exist
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ProgramType of the eBPF program
 | 
			
		||||
type ProgramType uint32
 | 
			
		||||
 | 
			
		||||
@@ -219,6 +187,9 @@ const (
 | 
			
		||||
	AttachTraceRawTp
 | 
			
		||||
	AttachTraceFEntry
 | 
			
		||||
	AttachTraceFExit
 | 
			
		||||
	AttachModifyReturn
 | 
			
		||||
	AttachLSMMac
 | 
			
		||||
	AttachTraceIter
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AttachFlags of the eBPF program used in BPF_PROG_ATTACH command
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/cilium/ebpf/types_string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/cilium/ebpf/types_string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
// Code generated by "stringer -output types_string.go -type=MapType,ProgramType"; DO NOT EDIT.
 | 
			
		||||
// Code generated by "stringer -output types_string.go -type=MapType,ProgramType,AttachType"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package ebpf
 | 
			
		||||
 | 
			
		||||
@@ -89,3 +89,49 @@ func (i ProgramType) String() string {
 | 
			
		||||
	}
 | 
			
		||||
	return _ProgramType_name[_ProgramType_index[i]:_ProgramType_index[i+1]]
 | 
			
		||||
}
 | 
			
		||||
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[AttachNone-0]
 | 
			
		||||
	_ = x[AttachCGroupInetIngress-0]
 | 
			
		||||
	_ = x[AttachCGroupInetEgress-1]
 | 
			
		||||
	_ = x[AttachCGroupInetSockCreate-2]
 | 
			
		||||
	_ = x[AttachCGroupSockOps-3]
 | 
			
		||||
	_ = x[AttachSkSKBStreamParser-4]
 | 
			
		||||
	_ = x[AttachSkSKBStreamVerdict-5]
 | 
			
		||||
	_ = x[AttachCGroupDevice-6]
 | 
			
		||||
	_ = x[AttachSkMsgVerdict-7]
 | 
			
		||||
	_ = x[AttachCGroupInet4Bind-8]
 | 
			
		||||
	_ = x[AttachCGroupInet6Bind-9]
 | 
			
		||||
	_ = x[AttachCGroupInet4Connect-10]
 | 
			
		||||
	_ = x[AttachCGroupInet6Connect-11]
 | 
			
		||||
	_ = x[AttachCGroupInet4PostBind-12]
 | 
			
		||||
	_ = x[AttachCGroupInet6PostBind-13]
 | 
			
		||||
	_ = x[AttachCGroupUDP4Sendmsg-14]
 | 
			
		||||
	_ = x[AttachCGroupUDP6Sendmsg-15]
 | 
			
		||||
	_ = x[AttachLircMode2-16]
 | 
			
		||||
	_ = x[AttachFlowDissector-17]
 | 
			
		||||
	_ = x[AttachCGroupSysctl-18]
 | 
			
		||||
	_ = x[AttachCGroupUDP4Recvmsg-19]
 | 
			
		||||
	_ = x[AttachCGroupUDP6Recvmsg-20]
 | 
			
		||||
	_ = x[AttachCGroupGetsockopt-21]
 | 
			
		||||
	_ = x[AttachCGroupSetsockopt-22]
 | 
			
		||||
	_ = x[AttachTraceRawTp-23]
 | 
			
		||||
	_ = x[AttachTraceFEntry-24]
 | 
			
		||||
	_ = x[AttachTraceFExit-25]
 | 
			
		||||
	_ = x[AttachModifyReturn-26]
 | 
			
		||||
	_ = x[AttachLSMMac-27]
 | 
			
		||||
	_ = x[AttachTraceIter-28]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const _AttachType_name = "AttachNoneAttachCGroupInetEgressAttachCGroupInetSockCreateAttachCGroupSockOpsAttachSkSKBStreamParserAttachSkSKBStreamVerdictAttachCGroupDeviceAttachSkMsgVerdictAttachCGroupInet4BindAttachCGroupInet6BindAttachCGroupInet4ConnectAttachCGroupInet6ConnectAttachCGroupInet4PostBindAttachCGroupInet6PostBindAttachCGroupUDP4SendmsgAttachCGroupUDP6SendmsgAttachLircMode2AttachFlowDissectorAttachCGroupSysctlAttachCGroupUDP4RecvmsgAttachCGroupUDP6RecvmsgAttachCGroupGetsockoptAttachCGroupSetsockoptAttachTraceRawTpAttachTraceFEntryAttachTraceFExitAttachModifyReturnAttachLSMMacAttachTraceIter"
 | 
			
		||||
 | 
			
		||||
var _AttachType_index = [...]uint16{0, 10, 32, 58, 77, 100, 124, 142, 160, 181, 202, 226, 250, 275, 300, 323, 346, 361, 380, 398, 421, 444, 466, 488, 504, 521, 537, 555, 567, 582}
 | 
			
		||||
 | 
			
		||||
func (i AttachType) String() string {
 | 
			
		||||
	if i >= AttachType(len(_AttachType_index)-1) {
 | 
			
		||||
		return "AttachType(" + strconv.FormatInt(int64(i), 10) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return _AttachType_name[_AttachType_index[i]:_AttachType_index[i+1]]
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user