mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-26 19:35:10 +00:00
vendor: bump runc to rc95
runc rc95 contains a fix for CVE-2021-30465. runc rc94 provides fixes and improvements. One notable change is cgroup manager's Set now accept Resources rather than Cgroup (see https://github.com/opencontainers/runc/pull/2906). Modify the code accordingly. Also update runc dependencies (as hinted by hack/lint-depdendencies.sh): github.com/cilium/ebpf v0.5.0 github.com/containerd/console v1.0.2 github.com/coreos/go-systemd/v22 v22.3.1 github.com/godbus/dbus/v5 v5.0.4 github.com/moby/sys/mountinfo v0.4.1 golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 github.com/google/go-cmp v0.5.4 github.com/kr/pretty v0.2.1 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
170
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
170
vendor/github.com/cilium/ebpf/internal/btf/btf.go
generated
vendored
@@ -29,12 +29,14 @@ var (
|
||||
|
||||
// Spec represents decoded BTF.
|
||||
type Spec struct {
|
||||
rawTypes []rawType
|
||||
strings stringTable
|
||||
types map[string][]namedType
|
||||
funcInfos map[string]extInfo
|
||||
lineInfos map[string]extInfo
|
||||
byteOrder binary.ByteOrder
|
||||
rawTypes []rawType
|
||||
strings stringTable
|
||||
types []Type
|
||||
namedTypes map[string][]namedType
|
||||
funcInfos map[string]extInfo
|
||||
lineInfos map[string]extInfo
|
||||
coreRelos map[string]bpfCoreRelos
|
||||
byteOrder binary.ByteOrder
|
||||
}
|
||||
|
||||
type btfHeader struct {
|
||||
@@ -53,7 +55,7 @@ type btfHeader struct {
|
||||
//
|
||||
// Returns a nil Spec and no error if no BTF was present.
|
||||
func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
file, err := elf.NewFile(rd)
|
||||
file, err := internal.NewSafeELFFile(rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -80,6 +82,10 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
if int(symbol.Section) >= len(file.Sections) {
|
||||
return nil, fmt.Errorf("symbol %s: invalid section %d", symbol.Name, symbol.Section)
|
||||
}
|
||||
|
||||
secName := file.Sections[symbol.Section].Name
|
||||
if _, ok := sectionSizes[secName]; !ok {
|
||||
continue
|
||||
@@ -101,7 +107,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
spec.funcInfos, spec.lineInfos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
||||
spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't read ext info: %w", err)
|
||||
}
|
||||
@@ -109,7 +115,7 @@ func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
|
||||
return spec, nil
|
||||
}
|
||||
|
||||
func findBtfSections(file *elf.File) (*elf.Section, *elf.Section, map[string]uint32, error) {
|
||||
func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, map[string]uint32, error) {
|
||||
var (
|
||||
btfSection *elf.Section
|
||||
btfExtSection *elf.Section
|
||||
@@ -138,7 +144,7 @@ func findBtfSections(file *elf.File) (*elf.Section, *elf.Section, map[string]uin
|
||||
}
|
||||
|
||||
func loadSpecFromVmlinux(rd io.ReaderAt) (*Spec, error) {
|
||||
file, err := elf.NewFile(rd)
|
||||
file, err := internal.NewSafeELFFile(rd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -165,16 +171,17 @@ func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[stri
|
||||
return nil, err
|
||||
}
|
||||
|
||||
types, err := inflateRawTypes(rawTypes, rawStrings)
|
||||
types, typesByName, err := inflateRawTypes(rawTypes, rawStrings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Spec{
|
||||
rawTypes: rawTypes,
|
||||
types: types,
|
||||
strings: rawStrings,
|
||||
byteOrder: bo,
|
||||
rawTypes: rawTypes,
|
||||
namedTypes: typesByName,
|
||||
types: types,
|
||||
strings: rawStrings,
|
||||
byteOrder: bo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -311,10 +318,14 @@ func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[s
|
||||
return err
|
||||
}
|
||||
|
||||
if name == ".kconfig" || name == ".ksym" {
|
||||
if name == ".kconfig" || name == ".ksyms" {
|
||||
return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
|
||||
}
|
||||
|
||||
if rawTypes[i].SizeType != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
size, ok := sectionSizes[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("data section %s: missing size", name)
|
||||
@@ -421,64 +432,19 @@ func (s *Spec) Program(name string, length uint64) (*Program, error) {
|
||||
return nil, errors.New("length musn't be zero")
|
||||
}
|
||||
|
||||
if s.funcInfos == nil && s.lineInfos == nil {
|
||||
if s.funcInfos == nil && s.lineInfos == nil && s.coreRelos == nil {
|
||||
return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
|
||||
}
|
||||
|
||||
funcInfos, funcOK := s.funcInfos[name]
|
||||
lineInfos, lineOK := s.lineInfos[name]
|
||||
coreRelos, coreOK := s.coreRelos[name]
|
||||
|
||||
if !funcOK && !lineOK {
|
||||
if !funcOK && !lineOK && !coreOK {
|
||||
return nil, fmt.Errorf("no extended BTF info for section %s", name)
|
||||
}
|
||||
|
||||
return &Program{s, length, funcInfos, lineInfos}, nil
|
||||
}
|
||||
|
||||
// Map finds the BTF for a map.
|
||||
//
|
||||
// Returns an error if there is no BTF for the given name.
|
||||
func (s *Spec) Map(name string) (*Map, []Member, error) {
|
||||
var mapVar Var
|
||||
if err := s.FindType(name, &mapVar); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
mapStruct, ok := mapVar.Type.(*Struct)
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("expected struct, have %s", mapVar.Type)
|
||||
}
|
||||
|
||||
var key, value Type
|
||||
for _, member := range mapStruct.Members {
|
||||
switch member.Name {
|
||||
case "key":
|
||||
key = member.Type
|
||||
if pk, isPtr := key.(*Pointer); !isPtr {
|
||||
return nil, nil, fmt.Errorf("key type is not a pointer: %T", key)
|
||||
} else {
|
||||
key = pk.Target
|
||||
}
|
||||
|
||||
case "value":
|
||||
value = member.Type
|
||||
if vk, isPtr := value.(*Pointer); !isPtr {
|
||||
return nil, nil, fmt.Errorf("value type is not a pointer: %T", value)
|
||||
} else {
|
||||
value = vk.Target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
key = (*Void)(nil)
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
value = (*Void)(nil)
|
||||
}
|
||||
|
||||
return &Map{s, key, value}, mapStruct.Members, nil
|
||||
return &Program{s, length, funcInfos, lineInfos, coreRelos}, nil
|
||||
}
|
||||
|
||||
// Datasec returns the BTF required to create maps which represent data sections.
|
||||
@@ -488,7 +454,8 @@ func (s *Spec) Datasec(name string) (*Map, error) {
|
||||
return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
|
||||
}
|
||||
|
||||
return &Map{s, &Void{}, &datasec}, nil
|
||||
m := NewMap(s, &Void{}, &datasec)
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// FindType searches for a type with a specific name.
|
||||
@@ -503,7 +470,7 @@ func (s *Spec) FindType(name string, typ Type) error {
|
||||
candidate Type
|
||||
)
|
||||
|
||||
for _, typ := range s.types[essentialName(name)] {
|
||||
for _, typ := range s.namedTypes[essentialName(name)] {
|
||||
if reflect.TypeOf(typ) != wanted {
|
||||
continue
|
||||
}
|
||||
@@ -599,6 +566,23 @@ type Map struct {
|
||||
key, value Type
|
||||
}
|
||||
|
||||
// NewMap returns a new Map containing the given values.
|
||||
// The key and value arguments are initialized to Void if nil values are given.
|
||||
func NewMap(spec *Spec, key Type, value Type) Map {
|
||||
if key == nil {
|
||||
key = &Void{}
|
||||
}
|
||||
if value == nil {
|
||||
value = &Void{}
|
||||
}
|
||||
|
||||
return Map{
|
||||
spec: spec,
|
||||
key: key,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// MapSpec should be a method on Map, but is a free function
|
||||
// to hide it from users of the ebpf package.
|
||||
func MapSpec(m *Map) *Spec {
|
||||
@@ -622,6 +606,7 @@ type Program struct {
|
||||
spec *Spec
|
||||
length uint64
|
||||
funcInfos, lineInfos extInfo
|
||||
coreRelos bpfCoreRelos
|
||||
}
|
||||
|
||||
// ProgramSpec returns the Spec needed for loading function and line infos into the kernel.
|
||||
@@ -647,9 +632,10 @@ func ProgramAppend(s, other *Program) error {
|
||||
return fmt.Errorf("line infos: %w", err)
|
||||
}
|
||||
|
||||
s.length += other.length
|
||||
s.funcInfos = funcInfos
|
||||
s.lineInfos = lineInfos
|
||||
s.coreRelos = s.coreRelos.append(other.coreRelos, s.length)
|
||||
s.length += other.length
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -679,6 +665,19 @@ func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
|
||||
return s.lineInfos.recordSize, bytes, nil
|
||||
}
|
||||
|
||||
// ProgramRelocations returns the CO-RE relocations required to adjust the
|
||||
// program to the target.
|
||||
//
|
||||
// This is a free function instead of a method to hide it from users
|
||||
// of package ebpf.
|
||||
func ProgramRelocations(s *Program, target *Spec) (map[uint64]Relocation, error) {
|
||||
if len(s.coreRelos) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return coreRelocate(s.spec, target, s.coreRelos)
|
||||
}
|
||||
|
||||
type bpfLoadBTFAttr struct {
|
||||
btf internal.Pointer
|
||||
logBuf internal.Pointer
|
||||
@@ -718,7 +717,7 @@ func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
|
||||
var haveBTF = internal.FeatureTest("BTF", "5.1", func() error {
|
||||
var (
|
||||
types struct {
|
||||
Integer btfType
|
||||
@@ -742,15 +741,24 @@ var haveBTF = internal.FeatureTest("BTF", "5.1", func() (bool, error) {
|
||||
btf: internal.NewSlicePointer(btf),
|
||||
btfSize: uint32(len(btf)),
|
||||
})
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
|
||||
// Treat both EINVAL and EPERM as not supported: loading the program
|
||||
// might still succeed without BTF.
|
||||
return internal.ErrNotSupported
|
||||
}
|
||||
// Check for EINVAL specifically, rather than err != nil since we
|
||||
// otherwise misdetect due to insufficient permissions.
|
||||
return !errors.Is(err, unix.EINVAL), nil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fd.Close()
|
||||
return nil
|
||||
})
|
||||
|
||||
var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bool, error) {
|
||||
var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() error {
|
||||
if err := haveBTF(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
types struct {
|
||||
FuncProto btfType
|
||||
@@ -771,11 +779,13 @@ var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() (bo
|
||||
btf: internal.NewSlicePointer(btf),
|
||||
btfSize: uint32(len(btf)),
|
||||
})
|
||||
if err == nil {
|
||||
fd.Close()
|
||||
if errors.Is(err, unix.EINVAL) {
|
||||
return internal.ErrNotSupported
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for EINVAL specifically, rather than err != nil since we
|
||||
// otherwise misdetect due to insufficient permissions.
|
||||
return !errors.Is(err, unix.EINVAL), nil
|
||||
fd.Close()
|
||||
return nil
|
||||
})
|
||||
|
||||
4
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
4
vendor/github.com/cilium/ebpf/internal/btf/btf_types.go
generated
vendored
@@ -31,12 +31,14 @@ const (
|
||||
kindDatasec
|
||||
)
|
||||
|
||||
// btfFuncLinkage describes BTF function linkage metadata.
|
||||
type btfFuncLinkage uint8
|
||||
|
||||
// Equivalent of enum btf_func_linkage.
|
||||
const (
|
||||
linkageStatic btfFuncLinkage = iota
|
||||
linkageGlobal
|
||||
linkageExtern
|
||||
// linkageExtern // Currently unused in libbpf.
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
388
vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
Normal file
388
vendor/github.com/cilium/ebpf/internal/btf/core.go
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
package btf
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Code in this file is derived from libbpf, which is available under a BSD
|
||||
// 2-Clause license.
|
||||
|
||||
// Relocation describes a CO-RE relocation.
|
||||
type Relocation struct {
|
||||
Current uint32
|
||||
New uint32
|
||||
}
|
||||
|
||||
func (r Relocation) equal(other Relocation) bool {
|
||||
return r.Current == other.Current && r.New == other.New
|
||||
}
|
||||
|
||||
// coreReloKind is the type of CO-RE relocation
|
||||
type coreReloKind uint32
|
||||
|
||||
const (
|
||||
reloFieldByteOffset coreReloKind = iota /* field byte offset */
|
||||
reloFieldByteSize /* field size in bytes */
|
||||
reloFieldExists /* field existence in target kernel */
|
||||
reloFieldSigned /* field signedness (0 - unsigned, 1 - signed) */
|
||||
reloFieldLShiftU64 /* bitfield-specific left bitshift */
|
||||
reloFieldRShiftU64 /* bitfield-specific right bitshift */
|
||||
reloTypeIDLocal /* type ID in local BPF object */
|
||||
reloTypeIDTarget /* type ID in target kernel */
|
||||
reloTypeExists /* type existence in target kernel */
|
||||
reloTypeSize /* type size in bytes */
|
||||
reloEnumvalExists /* enum value existence in target kernel */
|
||||
reloEnumvalValue /* enum value integer value */
|
||||
)
|
||||
|
||||
func (k coreReloKind) String() string {
|
||||
switch k {
|
||||
case reloFieldByteOffset:
|
||||
return "byte_off"
|
||||
case reloFieldByteSize:
|
||||
return "byte_sz"
|
||||
case reloFieldExists:
|
||||
return "field_exists"
|
||||
case reloFieldSigned:
|
||||
return "signed"
|
||||
case reloFieldLShiftU64:
|
||||
return "lshift_u64"
|
||||
case reloFieldRShiftU64:
|
||||
return "rshift_u64"
|
||||
case reloTypeIDLocal:
|
||||
return "local_type_id"
|
||||
case reloTypeIDTarget:
|
||||
return "target_type_id"
|
||||
case reloTypeExists:
|
||||
return "type_exists"
|
||||
case reloTypeSize:
|
||||
return "type_size"
|
||||
case reloEnumvalExists:
|
||||
return "enumval_exists"
|
||||
case reloEnumvalValue:
|
||||
return "enumval_value"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func coreRelocate(local, target *Spec, coreRelos bpfCoreRelos) (map[uint64]Relocation, error) {
|
||||
if target == nil {
|
||||
var err error
|
||||
target, err = loadKernelSpec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if local.byteOrder != target.byteOrder {
|
||||
return nil, fmt.Errorf("can't relocate %s against %s", local.byteOrder, target.byteOrder)
|
||||
}
|
||||
|
||||
relocations := make(map[uint64]Relocation, len(coreRelos))
|
||||
for _, relo := range coreRelos {
|
||||
accessorStr, err := local.strings.Lookup(relo.AccessStrOff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessor, err := parseCoreAccessor(accessorStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("accessor %q: %s", accessorStr, err)
|
||||
}
|
||||
|
||||
if int(relo.TypeID) >= len(local.types) {
|
||||
return nil, fmt.Errorf("invalid type id %d", relo.TypeID)
|
||||
}
|
||||
|
||||
typ := local.types[relo.TypeID]
|
||||
|
||||
if relo.ReloKind == reloTypeIDLocal {
|
||||
relocations[uint64(relo.InsnOff)] = Relocation{
|
||||
uint32(typ.ID()),
|
||||
uint32(typ.ID()),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
named, ok := typ.(namedType)
|
||||
if !ok || named.name() == "" {
|
||||
return nil, fmt.Errorf("relocate anonymous type %s: %w", typ.String(), ErrNotSupported)
|
||||
}
|
||||
|
||||
name := essentialName(named.name())
|
||||
res, err := coreCalculateRelocation(typ, target.namedTypes[name], relo.ReloKind, accessor)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("relocate %s: %w", name, err)
|
||||
}
|
||||
|
||||
relocations[uint64(relo.InsnOff)] = res
|
||||
}
|
||||
|
||||
return relocations, nil
|
||||
}
|
||||
|
||||
var errAmbiguousRelocation = errors.New("ambiguous relocation")
|
||||
|
||||
func coreCalculateRelocation(local Type, targets []namedType, kind coreReloKind, localAccessor coreAccessor) (Relocation, error) {
|
||||
var relos []Relocation
|
||||
var matches []Type
|
||||
for _, target := range targets {
|
||||
switch kind {
|
||||
case reloTypeIDTarget:
|
||||
if localAccessor[0] != 0 {
|
||||
return Relocation{}, fmt.Errorf("%s: unexpected non-zero accessor", kind)
|
||||
}
|
||||
|
||||
if compat, err := coreAreTypesCompatible(local, target); err != nil {
|
||||
return Relocation{}, fmt.Errorf("%s: %s", kind, err)
|
||||
} else if !compat {
|
||||
continue
|
||||
}
|
||||
|
||||
relos = append(relos, Relocation{uint32(target.ID()), uint32(target.ID())})
|
||||
|
||||
default:
|
||||
return Relocation{}, fmt.Errorf("relocation %s: %w", kind, ErrNotSupported)
|
||||
}
|
||||
matches = append(matches, target)
|
||||
}
|
||||
|
||||
if len(relos) == 0 {
|
||||
// TODO: Add switch for existence checks like reloEnumvalExists here.
|
||||
|
||||
// TODO: This might have to be poisoned.
|
||||
return Relocation{}, fmt.Errorf("no relocation found, tried %v", targets)
|
||||
}
|
||||
|
||||
relo := relos[0]
|
||||
for _, altRelo := range relos[1:] {
|
||||
if !altRelo.equal(relo) {
|
||||
return Relocation{}, fmt.Errorf("multiple types %v match: %w", matches, errAmbiguousRelocation)
|
||||
}
|
||||
}
|
||||
|
||||
return relo, nil
|
||||
}
|
||||
|
||||
/* coreAccessor contains a path through a struct. It contains at least one index.
|
||||
*
|
||||
* The interpretation depends on the kind of the relocation. The following is
|
||||
* taken from struct bpf_core_relo in libbpf_internal.h:
|
||||
*
|
||||
* - for field-based relocations, string encodes an accessed field using
|
||||
* a sequence of field and array indices, separated by colon (:). It's
|
||||
* conceptually very close to LLVM's getelementptr ([0]) instruction's
|
||||
* arguments for identifying offset to a field.
|
||||
* - for type-based relocations, strings is expected to be just "0";
|
||||
* - for enum value-based relocations, string contains an index of enum
|
||||
* value within its enum type;
|
||||
*
|
||||
* Example to provide a better feel.
|
||||
*
|
||||
* struct sample {
|
||||
* int a;
|
||||
* struct {
|
||||
* int b[10];
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* struct sample s = ...;
|
||||
* int x = &s->a; // encoded as "0:0" (a is field #0)
|
||||
* int y = &s->b[5]; // encoded as "0:1:0:5" (anon struct is field #1,
|
||||
* // b is field #0 inside anon struct, accessing elem #5)
|
||||
* int z = &s[10]->b; // encoded as "10:1" (ptr is used as an array)
|
||||
*/
|
||||
type coreAccessor []int
|
||||
|
||||
func parseCoreAccessor(accessor string) (coreAccessor, error) {
|
||||
if accessor == "" {
|
||||
return nil, fmt.Errorf("empty accessor")
|
||||
}
|
||||
|
||||
var result coreAccessor
|
||||
parts := strings.Split(accessor, ":")
|
||||
for _, part := range parts {
|
||||
// 31 bits to avoid overflowing int on 32 bit platforms.
|
||||
index, err := strconv.ParseUint(part, 10, 31)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("accessor index %q: %s", part, err)
|
||||
}
|
||||
|
||||
result = append(result, int(index))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
/* The comment below is from bpf_core_types_are_compat in libbpf.c:
|
||||
*
|
||||
* Check local and target types for compatibility. This check is used for
|
||||
* type-based CO-RE relocations and follow slightly different rules than
|
||||
* field-based relocations. This function assumes that root types were already
|
||||
* checked for name match. Beyond that initial root-level name check, names
|
||||
* are completely ignored. Compatibility rules are as follows:
|
||||
* - any two STRUCTs/UNIONs/FWDs/ENUMs/INTs are considered compatible, but
|
||||
* kind should match for local and target types (i.e., STRUCT is not
|
||||
* compatible with UNION);
|
||||
* - for ENUMs, the size is ignored;
|
||||
* - for INT, size and signedness are ignored;
|
||||
* - for ARRAY, dimensionality is ignored, element types are checked for
|
||||
* compatibility recursively;
|
||||
* - CONST/VOLATILE/RESTRICT modifiers are ignored;
|
||||
* - TYPEDEFs/PTRs are compatible if types they pointing to are compatible;
|
||||
* - FUNC_PROTOs are compatible if they have compatible signature: same
|
||||
* number of input args and compatible return and argument types.
|
||||
* These rules are not set in stone and probably will be adjusted as we get
|
||||
* more experience with using BPF CO-RE relocations.
|
||||
*/
|
||||
func coreAreTypesCompatible(localType Type, targetType Type) (bool, error) {
|
||||
var (
|
||||
localTs, targetTs typeDeque
|
||||
l, t = &localType, &targetType
|
||||
depth = 0
|
||||
)
|
||||
|
||||
for ; l != nil && t != nil; l, t = localTs.shift(), targetTs.shift() {
|
||||
if depth >= maxTypeDepth {
|
||||
return false, errors.New("types are nested too deep")
|
||||
}
|
||||
|
||||
localType = skipQualifierAndTypedef(*l)
|
||||
targetType = skipQualifierAndTypedef(*t)
|
||||
|
||||
if reflect.TypeOf(localType) != reflect.TypeOf(targetType) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch lv := (localType).(type) {
|
||||
case *Void, *Struct, *Union, *Enum, *Fwd:
|
||||
// Nothing to do here
|
||||
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
if lv.isBitfield() || tv.isBitfield() {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
case *Pointer, *Array:
|
||||
depth++
|
||||
localType.walk(&localTs)
|
||||
targetType.walk(&targetTs)
|
||||
|
||||
case *FuncProto:
|
||||
tv := targetType.(*FuncProto)
|
||||
if len(lv.Params) != len(tv.Params) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
depth++
|
||||
localType.walk(&localTs)
|
||||
targetType.walk(&targetTs)
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("unsupported type %T", localType)
|
||||
}
|
||||
}
|
||||
|
||||
if l != nil {
|
||||
return false, fmt.Errorf("dangling local type %T", *l)
|
||||
}
|
||||
|
||||
if t != nil {
|
||||
return false, fmt.Errorf("dangling target type %T", *t)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
/* The comment below is from bpf_core_fields_are_compat in libbpf.c:
|
||||
*
|
||||
* Check two types for compatibility for the purpose of field access
|
||||
* relocation. const/volatile/restrict and typedefs are skipped to ensure we
|
||||
* are relocating semantically compatible entities:
|
||||
* - any two STRUCTs/UNIONs are compatible and can be mixed;
|
||||
* - any two FWDs are compatible, if their names match (modulo flavor suffix);
|
||||
* - any two PTRs are always compatible;
|
||||
* - for ENUMs, names should be the same (ignoring flavor suffix) or at
|
||||
* least one of enums should be anonymous;
|
||||
* - for ENUMs, check sizes, names are ignored;
|
||||
* - for INT, size and signedness are ignored;
|
||||
* - for ARRAY, dimensionality is ignored, element types are checked for
|
||||
* compatibility recursively;
|
||||
* - everything else shouldn't be ever a target of relocation.
|
||||
* These rules are not set in stone and probably will be adjusted as we get
|
||||
* more experience with using BPF CO-RE relocations.
|
||||
*/
|
||||
func coreAreMembersCompatible(localType Type, targetType Type) (bool, error) {
|
||||
doNamesMatch := func(a, b string) bool {
|
||||
if a == "" || b == "" {
|
||||
// allow anonymous and named type to match
|
||||
return true
|
||||
}
|
||||
|
||||
return essentialName(a) == essentialName(b)
|
||||
}
|
||||
|
||||
for depth := 0; depth <= maxTypeDepth; depth++ {
|
||||
localType = skipQualifierAndTypedef(localType)
|
||||
targetType = skipQualifierAndTypedef(targetType)
|
||||
|
||||
_, lok := localType.(composite)
|
||||
_, tok := targetType.(composite)
|
||||
if lok && tok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if reflect.TypeOf(localType) != reflect.TypeOf(targetType) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch lv := localType.(type) {
|
||||
case *Pointer:
|
||||
return true, nil
|
||||
|
||||
case *Enum:
|
||||
tv := targetType.(*Enum)
|
||||
return doNamesMatch(lv.name(), tv.name()), nil
|
||||
|
||||
case *Fwd:
|
||||
tv := targetType.(*Fwd)
|
||||
return doNamesMatch(lv.name(), tv.name()), nil
|
||||
|
||||
case *Int:
|
||||
tv := targetType.(*Int)
|
||||
return !lv.isBitfield() && !tv.isBitfield(), nil
|
||||
|
||||
case *Array:
|
||||
tv := targetType.(*Array)
|
||||
|
||||
localType = lv.Type
|
||||
targetType = tv.Type
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("unsupported type %T", localType)
|
||||
}
|
||||
}
|
||||
|
||||
return false, errors.New("types are nested too deep")
|
||||
}
|
||||
|
||||
func skipQualifierAndTypedef(typ Type) Type {
|
||||
result := typ
|
||||
for depth := 0; depth <= maxTypeDepth; depth++ {
|
||||
switch v := (result).(type) {
|
||||
case qualifier:
|
||||
result = v.qualify()
|
||||
case *Typedef:
|
||||
result = v.Type
|
||||
default:
|
||||
return result
|
||||
}
|
||||
}
|
||||
return typ
|
||||
}
|
||||
141
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
141
vendor/github.com/cilium/ebpf/internal/btf/ext_info.go
generated
vendored
@@ -25,57 +25,82 @@ type btfExtHeader struct {
|
||||
LineInfoLen uint32
|
||||
}
|
||||
|
||||
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, err error) {
|
||||
type btfExtCoreHeader struct {
|
||||
CoreReloOff uint32
|
||||
CoreReloLen uint32
|
||||
}
|
||||
|
||||
func parseExtInfos(r io.ReadSeeker, bo binary.ByteOrder, strings stringTable) (funcInfo, lineInfo map[string]extInfo, coreRelos map[string]bpfCoreRelos, err error) {
|
||||
var header btfExtHeader
|
||||
var coreHeader btfExtCoreHeader
|
||||
if err := binary.Read(r, bo, &header); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't read header: %v", err)
|
||||
return nil, 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)
|
||||
return nil, nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
|
||||
}
|
||||
|
||||
if header.Version != 1 {
|
||||
return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
|
||||
return nil, nil, nil, fmt.Errorf("unexpected version %v", header.Version)
|
||||
}
|
||||
|
||||
if header.Flags != 0 {
|
||||
return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
|
||||
return nil, 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")
|
||||
return nil, nil, nil, errors.New("header is too short")
|
||||
}
|
||||
|
||||
coreHdrSize := int64(binary.Size(&coreHeader))
|
||||
if remainder >= coreHdrSize {
|
||||
if err := binary.Read(r, bo, &coreHeader); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("can't read CO-RE relocation header: %v", err)
|
||||
}
|
||||
remainder -= coreHdrSize
|
||||
}
|
||||
|
||||
// Of course, the .BTF.ext header has different semantics than the
|
||||
// .BTF ext header. We need to ignore non-null values.
|
||||
_, err = io.CopyN(ioutil.Discard, r, remainder)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("header padding: %v", err)
|
||||
return nil, nil, nil, fmt.Errorf("header padding: %v", err)
|
||||
}
|
||||
|
||||
if _, err := r.Seek(int64(header.HdrLen+header.FuncInfoOff), io.SeekStart); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't seek to function info section: %v", err)
|
||||
return nil, nil, nil, fmt.Errorf("can't seek to function info section: %v", err)
|
||||
}
|
||||
|
||||
buf := bufio.NewReader(io.LimitReader(r, int64(header.FuncInfoLen)))
|
||||
funcInfo, err = parseExtInfo(buf, bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("function info: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("function info: %w", err)
|
||||
}
|
||||
|
||||
if _, err := r.Seek(int64(header.HdrLen+header.LineInfoOff), io.SeekStart); err != nil {
|
||||
return nil, nil, fmt.Errorf("can't seek to line info section: %v", err)
|
||||
return nil, nil, nil, fmt.Errorf("can't seek to line info section: %v", err)
|
||||
}
|
||||
|
||||
buf = bufio.NewReader(io.LimitReader(r, int64(header.LineInfoLen)))
|
||||
lineInfo, err = parseExtInfo(buf, bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("line info: %w", err)
|
||||
return nil, nil, nil, fmt.Errorf("line info: %w", err)
|
||||
}
|
||||
|
||||
return funcInfo, lineInfo, nil
|
||||
if coreHeader.CoreReloOff > 0 && coreHeader.CoreReloLen > 0 {
|
||||
if _, err := r.Seek(int64(header.HdrLen+coreHeader.CoreReloOff), io.SeekStart); err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("can't seek to CO-RE relocation section: %v", err)
|
||||
}
|
||||
|
||||
coreRelos, err = parseExtInfoRelos(io.LimitReader(r, int64(coreHeader.CoreReloLen)), bo, strings)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("CO-RE relocation info: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return funcInfo, lineInfo, coreRelos, nil
|
||||
}
|
||||
|
||||
type btfExtInfoSec struct {
|
||||
@@ -147,20 +172,9 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
|
||||
|
||||
result := make(map[string]extInfo)
|
||||
for {
|
||||
var infoHeader btfExtInfoSec
|
||||
if err := binary.Read(r, bo, &infoHeader); err == io.EOF {
|
||||
secName, infoHeader, err := parseExtInfoHeader(r, bo, strings)
|
||||
if errors.Is(err, io.EOF) {
|
||||
return result, nil
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("can't read ext info header: %v", err)
|
||||
}
|
||||
|
||||
secName, err := strings.Lookup(infoHeader.SecNameOff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get section name: %w", err)
|
||||
}
|
||||
|
||||
if infoHeader.NumInfo == 0 {
|
||||
return nil, fmt.Errorf("section %s has invalid number of records", secName)
|
||||
}
|
||||
|
||||
var records []extInfoRecord
|
||||
@@ -188,3 +202,80 @@ func parseExtInfo(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bpfCoreRelo matches `struct bpf_core_relo` from the kernel
|
||||
type bpfCoreRelo struct {
|
||||
InsnOff uint32
|
||||
TypeID TypeID
|
||||
AccessStrOff uint32
|
||||
ReloKind coreReloKind
|
||||
}
|
||||
|
||||
type bpfCoreRelos []bpfCoreRelo
|
||||
|
||||
// append two slices of extInfoRelo to each other. The InsnOff of b are adjusted
|
||||
// by offset.
|
||||
func (r bpfCoreRelos) append(other bpfCoreRelos, offset uint64) bpfCoreRelos {
|
||||
result := make([]bpfCoreRelo, 0, len(r)+len(other))
|
||||
result = append(result, r...)
|
||||
for _, relo := range other {
|
||||
relo.InsnOff += uint32(offset)
|
||||
result = append(result, relo)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
var extInfoReloSize = binary.Size(bpfCoreRelo{})
|
||||
|
||||
func parseExtInfoRelos(r io.Reader, bo binary.ByteOrder, strings stringTable) (map[string]bpfCoreRelos, error) {
|
||||
var recordSize uint32
|
||||
if err := binary.Read(r, bo, &recordSize); err != nil {
|
||||
return nil, fmt.Errorf("read record size: %v", err)
|
||||
}
|
||||
|
||||
if recordSize != uint32(extInfoReloSize) {
|
||||
return nil, fmt.Errorf("expected record size %d, got %d", extInfoReloSize, recordSize)
|
||||
}
|
||||
|
||||
result := make(map[string]bpfCoreRelos)
|
||||
for {
|
||||
secName, infoHeader, err := parseExtInfoHeader(r, bo, strings)
|
||||
if errors.Is(err, io.EOF) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var relos []bpfCoreRelo
|
||||
for i := uint32(0); i < infoHeader.NumInfo; i++ {
|
||||
var relo bpfCoreRelo
|
||||
if err := binary.Read(r, bo, &relo); err != nil {
|
||||
return nil, fmt.Errorf("section %v: read record: %v", secName, err)
|
||||
}
|
||||
|
||||
if relo.InsnOff%asm.InstructionSize != 0 {
|
||||
return nil, fmt.Errorf("section %v: offset %v is not aligned with instruction size", secName, relo.InsnOff)
|
||||
}
|
||||
|
||||
relos = append(relos, relo)
|
||||
}
|
||||
|
||||
result[secName] = relos
|
||||
}
|
||||
}
|
||||
|
||||
func parseExtInfoHeader(r io.Reader, bo binary.ByteOrder, strings stringTable) (string, *btfExtInfoSec, error) {
|
||||
var infoHeader btfExtInfoSec
|
||||
if err := binary.Read(r, bo, &infoHeader); err != nil {
|
||||
return "", nil, fmt.Errorf("read ext info header: %w", err)
|
||||
}
|
||||
|
||||
secName, err := strings.Lookup(infoHeader.SecNameOff)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("get section name: %w", err)
|
||||
}
|
||||
|
||||
if infoHeader.NumInfo == 0 {
|
||||
return "", nil, fmt.Errorf("section %s has zero records", secName)
|
||||
}
|
||||
|
||||
return secName, &infoHeader, nil
|
||||
}
|
||||
|
||||
279
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
279
vendor/github.com/cilium/ebpf/internal/btf/types.go
generated
vendored
@@ -21,12 +21,14 @@ func (tid TypeID) ID() TypeID {
|
||||
type Type interface {
|
||||
ID() TypeID
|
||||
|
||||
String() string
|
||||
|
||||
// Make a copy of the type, without copying Type members.
|
||||
copy() Type
|
||||
|
||||
// Enumerate all nested Types. Repeated calls must visit nested
|
||||
// types in the same order.
|
||||
walk(*copyStack)
|
||||
walk(*typeDeque)
|
||||
}
|
||||
|
||||
// namedType is a type with a name.
|
||||
@@ -50,9 +52,10 @@ func (n Name) name() string {
|
||||
type Void struct{}
|
||||
|
||||
func (v *Void) ID() TypeID { return 0 }
|
||||
func (v *Void) String() string { return "void#0" }
|
||||
func (v *Void) size() uint32 { return 0 }
|
||||
func (v *Void) copy() Type { return (*Void)(nil) }
|
||||
func (v *Void) walk(*copyStack) {}
|
||||
func (v *Void) walk(*typeDeque) {}
|
||||
|
||||
type IntEncoding byte
|
||||
|
||||
@@ -78,21 +81,54 @@ type Int struct {
|
||||
|
||||
var _ namedType = (*Int)(nil)
|
||||
|
||||
func (i *Int) String() string {
|
||||
var s strings.Builder
|
||||
|
||||
switch {
|
||||
case i.Encoding&Char != 0:
|
||||
s.WriteString("char")
|
||||
case i.Encoding&Bool != 0:
|
||||
s.WriteString("bool")
|
||||
default:
|
||||
if i.Encoding&Signed == 0 {
|
||||
s.WriteRune('u')
|
||||
}
|
||||
s.WriteString("int")
|
||||
fmt.Fprintf(&s, "%d", i.Size*8)
|
||||
}
|
||||
|
||||
fmt.Fprintf(&s, "#%d", i.TypeID)
|
||||
|
||||
if i.Bits > 0 {
|
||||
fmt.Fprintf(&s, "[bits=%d]", i.Bits)
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (i *Int) size() uint32 { return i.Size }
|
||||
func (i *Int) walk(*copyStack) {}
|
||||
func (i *Int) walk(*typeDeque) {}
|
||||
func (i *Int) copy() Type {
|
||||
cpy := *i
|
||||
return &cpy
|
||||
}
|
||||
|
||||
func (i *Int) isBitfield() bool {
|
||||
return i.Offset > 0
|
||||
}
|
||||
|
||||
// Pointer is a pointer to another type.
|
||||
type Pointer struct {
|
||||
TypeID
|
||||
Target Type
|
||||
}
|
||||
|
||||
func (p *Pointer) size() uint32 { return 8 }
|
||||
func (p *Pointer) walk(cs *copyStack) { cs.push(&p.Target) }
|
||||
func (p *Pointer) String() string {
|
||||
return fmt.Sprintf("pointer#%d[target=#%d]", p.TypeID, p.Target.ID())
|
||||
}
|
||||
|
||||
func (p *Pointer) size() uint32 { return 8 }
|
||||
func (p *Pointer) walk(tdq *typeDeque) { tdq.push(&p.Target) }
|
||||
func (p *Pointer) copy() Type {
|
||||
cpy := *p
|
||||
return &cpy
|
||||
@@ -105,7 +141,11 @@ type Array struct {
|
||||
Nelems uint32
|
||||
}
|
||||
|
||||
func (arr *Array) walk(cs *copyStack) { cs.push(&arr.Type) }
|
||||
func (arr *Array) String() string {
|
||||
return fmt.Sprintf("array#%d[type=#%d n=%d]", arr.TypeID, arr.Type.ID(), arr.Nelems)
|
||||
}
|
||||
|
||||
func (arr *Array) walk(tdq *typeDeque) { tdq.push(&arr.Type) }
|
||||
func (arr *Array) copy() Type {
|
||||
cpy := *arr
|
||||
return &cpy
|
||||
@@ -120,11 +160,15 @@ type Struct struct {
|
||||
Members []Member
|
||||
}
|
||||
|
||||
func (s *Struct) String() string {
|
||||
return fmt.Sprintf("struct#%d[%q]", s.TypeID, s.Name)
|
||||
}
|
||||
|
||||
func (s *Struct) size() uint32 { return s.Size }
|
||||
|
||||
func (s *Struct) walk(cs *copyStack) {
|
||||
func (s *Struct) walk(tdq *typeDeque) {
|
||||
for i := range s.Members {
|
||||
cs.push(&s.Members[i].Type)
|
||||
tdq.push(&s.Members[i].Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,11 +192,15 @@ type Union struct {
|
||||
Members []Member
|
||||
}
|
||||
|
||||
func (u *Union) String() string {
|
||||
return fmt.Sprintf("union#%d[%q]", u.TypeID, u.Name)
|
||||
}
|
||||
|
||||
func (u *Union) size() uint32 { return u.Size }
|
||||
|
||||
func (u *Union) walk(cs *copyStack) {
|
||||
func (u *Union) walk(tdq *typeDeque) {
|
||||
for i := range u.Members {
|
||||
cs.push(&u.Members[i].Type)
|
||||
tdq.push(&u.Members[i].Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,6 +242,10 @@ type Enum struct {
|
||||
Values []EnumValue
|
||||
}
|
||||
|
||||
func (e *Enum) String() string {
|
||||
return fmt.Sprintf("enum#%d[%q]", e.TypeID, e.Name)
|
||||
}
|
||||
|
||||
// EnumValue is part of an Enum
|
||||
//
|
||||
// Is is not a valid Type
|
||||
@@ -203,7 +255,7 @@ type EnumValue struct {
|
||||
}
|
||||
|
||||
func (e *Enum) size() uint32 { return 4 }
|
||||
func (e *Enum) walk(*copyStack) {}
|
||||
func (e *Enum) walk(*typeDeque) {}
|
||||
func (e *Enum) copy() Type {
|
||||
cpy := *e
|
||||
cpy.Values = make([]EnumValue, len(e.Values))
|
||||
@@ -211,13 +263,38 @@ func (e *Enum) copy() Type {
|
||||
return &cpy
|
||||
}
|
||||
|
||||
// FwdKind is the type of forward declaration.
|
||||
type FwdKind int
|
||||
|
||||
// Valid types of forward declaration.
|
||||
const (
|
||||
FwdStruct FwdKind = iota
|
||||
FwdUnion
|
||||
)
|
||||
|
||||
func (fk FwdKind) String() string {
|
||||
switch fk {
|
||||
case FwdStruct:
|
||||
return "struct"
|
||||
case FwdUnion:
|
||||
return "union"
|
||||
default:
|
||||
return fmt.Sprintf("%T(%d)", fk, int(fk))
|
||||
}
|
||||
}
|
||||
|
||||
// Fwd is a forward declaration of a Type.
|
||||
type Fwd struct {
|
||||
TypeID
|
||||
Name
|
||||
Kind FwdKind
|
||||
}
|
||||
|
||||
func (f *Fwd) walk(*copyStack) {}
|
||||
func (f *Fwd) String() string {
|
||||
return fmt.Sprintf("fwd#%d[%s %q]", f.TypeID, f.Kind, f.Name)
|
||||
}
|
||||
|
||||
func (f *Fwd) walk(*typeDeque) {}
|
||||
func (f *Fwd) copy() Type {
|
||||
cpy := *f
|
||||
return &cpy
|
||||
@@ -230,7 +307,11 @@ type Typedef struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (td *Typedef) walk(cs *copyStack) { cs.push(&td.Type) }
|
||||
func (td *Typedef) String() string {
|
||||
return fmt.Sprintf("typedef#%d[%q #%d]", td.TypeID, td.Name, td.Type.ID())
|
||||
}
|
||||
|
||||
func (td *Typedef) walk(tdq *typeDeque) { tdq.push(&td.Type) }
|
||||
func (td *Typedef) copy() Type {
|
||||
cpy := *td
|
||||
return &cpy
|
||||
@@ -242,8 +323,12 @@ type Volatile struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (v *Volatile) qualify() Type { return v.Type }
|
||||
func (v *Volatile) walk(cs *copyStack) { cs.push(&v.Type) }
|
||||
func (v *Volatile) String() string {
|
||||
return fmt.Sprintf("volatile#%d[#%d]", v.TypeID, v.Type.ID())
|
||||
}
|
||||
|
||||
func (v *Volatile) qualify() Type { return v.Type }
|
||||
func (v *Volatile) walk(tdq *typeDeque) { tdq.push(&v.Type) }
|
||||
func (v *Volatile) copy() Type {
|
||||
cpy := *v
|
||||
return &cpy
|
||||
@@ -255,8 +340,12 @@ type Const struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (c *Const) qualify() Type { return c.Type }
|
||||
func (c *Const) walk(cs *copyStack) { cs.push(&c.Type) }
|
||||
func (c *Const) String() string {
|
||||
return fmt.Sprintf("const#%d[#%d]", c.TypeID, c.Type.ID())
|
||||
}
|
||||
|
||||
func (c *Const) qualify() Type { return c.Type }
|
||||
func (c *Const) walk(tdq *typeDeque) { tdq.push(&c.Type) }
|
||||
func (c *Const) copy() Type {
|
||||
cpy := *c
|
||||
return &cpy
|
||||
@@ -268,8 +357,12 @@ type Restrict struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (r *Restrict) qualify() Type { return r.Type }
|
||||
func (r *Restrict) walk(cs *copyStack) { cs.push(&r.Type) }
|
||||
func (r *Restrict) String() string {
|
||||
return fmt.Sprintf("restrict#%d[#%d]", r.TypeID, r.Type.ID())
|
||||
}
|
||||
|
||||
func (r *Restrict) qualify() Type { return r.Type }
|
||||
func (r *Restrict) walk(tdq *typeDeque) { tdq.push(&r.Type) }
|
||||
func (r *Restrict) copy() Type {
|
||||
cpy := *r
|
||||
return &cpy
|
||||
@@ -282,7 +375,11 @@ type Func struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (f *Func) walk(cs *copyStack) { cs.push(&f.Type) }
|
||||
func (f *Func) String() string {
|
||||
return fmt.Sprintf("func#%d[%q proto=#%d]", f.TypeID, f.Name, f.Type.ID())
|
||||
}
|
||||
|
||||
func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) }
|
||||
func (f *Func) copy() Type {
|
||||
cpy := *f
|
||||
return &cpy
|
||||
@@ -295,10 +392,20 @@ type FuncProto struct {
|
||||
Params []FuncParam
|
||||
}
|
||||
|
||||
func (fp *FuncProto) walk(cs *copyStack) {
|
||||
cs.push(&fp.Return)
|
||||
func (fp *FuncProto) String() string {
|
||||
var s strings.Builder
|
||||
fmt.Fprintf(&s, "proto#%d[", fp.TypeID)
|
||||
for _, param := range fp.Params {
|
||||
fmt.Fprintf(&s, "%q=#%d, ", param.Name, param.Type.ID())
|
||||
}
|
||||
fmt.Fprintf(&s, "return=#%d]", fp.Return.ID())
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func (fp *FuncProto) walk(tdq *typeDeque) {
|
||||
tdq.push(&fp.Return)
|
||||
for i := range fp.Params {
|
||||
cs.push(&fp.Params[i].Type)
|
||||
tdq.push(&fp.Params[i].Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +428,12 @@ type Var struct {
|
||||
Type Type
|
||||
}
|
||||
|
||||
func (v *Var) walk(cs *copyStack) { cs.push(&v.Type) }
|
||||
func (v *Var) String() string {
|
||||
// TODO: Linkage
|
||||
return fmt.Sprintf("var#%d[%q]", v.TypeID, v.Name)
|
||||
}
|
||||
|
||||
func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) }
|
||||
func (v *Var) copy() Type {
|
||||
cpy := *v
|
||||
return &cpy
|
||||
@@ -335,11 +447,15 @@ type Datasec struct {
|
||||
Vars []VarSecinfo
|
||||
}
|
||||
|
||||
func (ds *Datasec) String() string {
|
||||
return fmt.Sprintf("section#%d[%q]", ds.TypeID, ds.Name)
|
||||
}
|
||||
|
||||
func (ds *Datasec) size() uint32 { return ds.Size }
|
||||
|
||||
func (ds *Datasec) walk(cs *copyStack) {
|
||||
func (ds *Datasec) walk(tdq *typeDeque) {
|
||||
for i := range ds.Vars {
|
||||
cs.push(&ds.Vars[i].Type)
|
||||
tdq.push(&ds.Vars[i].Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,6 +467,8 @@ func (ds *Datasec) copy() Type {
|
||||
}
|
||||
|
||||
// VarSecinfo describes variable in a Datasec
|
||||
//
|
||||
// It is not a valid Type.
|
||||
type VarSecinfo struct {
|
||||
Type Type
|
||||
Offset uint32
|
||||
@@ -438,7 +556,7 @@ func Sizeof(typ Type) (int, error) {
|
||||
func copyType(typ Type) Type {
|
||||
var (
|
||||
copies = make(map[Type]Type)
|
||||
work copyStack
|
||||
work typeDeque
|
||||
)
|
||||
|
||||
for t := &typ; t != nil; t = work.pop() {
|
||||
@@ -459,34 +577,83 @@ func copyType(typ Type) Type {
|
||||
return typ
|
||||
}
|
||||
|
||||
// copyStack keeps track of pointers to types which still
|
||||
// typeDeque keeps track of pointers to types which still
|
||||
// need to be visited.
|
||||
type copyStack []*Type
|
||||
|
||||
// push adds a type to the stack.
|
||||
func (cs *copyStack) push(t *Type) {
|
||||
*cs = append(*cs, t)
|
||||
type typeDeque struct {
|
||||
types []*Type
|
||||
read, write uint64
|
||||
mask uint64
|
||||
}
|
||||
|
||||
// pop returns the topmost Type, or nil.
|
||||
func (cs *copyStack) pop() *Type {
|
||||
n := len(*cs)
|
||||
if n == 0 {
|
||||
// push adds a type to the stack.
|
||||
func (dq *typeDeque) push(t *Type) {
|
||||
if dq.write-dq.read < uint64(len(dq.types)) {
|
||||
dq.types[dq.write&dq.mask] = t
|
||||
dq.write++
|
||||
return
|
||||
}
|
||||
|
||||
new := len(dq.types) * 2
|
||||
if new == 0 {
|
||||
new = 8
|
||||
}
|
||||
|
||||
types := make([]*Type, new)
|
||||
pivot := dq.read & dq.mask
|
||||
n := copy(types, dq.types[pivot:])
|
||||
n += copy(types[n:], dq.types[:pivot])
|
||||
types[n] = t
|
||||
|
||||
dq.types = types
|
||||
dq.mask = uint64(new) - 1
|
||||
dq.read, dq.write = 0, uint64(n+1)
|
||||
}
|
||||
|
||||
// shift returns the first element or null.
|
||||
func (dq *typeDeque) shift() *Type {
|
||||
if dq.read == dq.write {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := (*cs)[n-1]
|
||||
*cs = (*cs)[:n-1]
|
||||
index := dq.read & dq.mask
|
||||
t := dq.types[index]
|
||||
dq.types[index] = nil
|
||||
dq.read++
|
||||
return t
|
||||
}
|
||||
|
||||
// pop returns the last element or null.
|
||||
func (dq *typeDeque) pop() *Type {
|
||||
if dq.read == dq.write {
|
||||
return nil
|
||||
}
|
||||
|
||||
dq.write--
|
||||
index := dq.write & dq.mask
|
||||
t := dq.types[index]
|
||||
dq.types[index] = nil
|
||||
return t
|
||||
}
|
||||
|
||||
// all returns all elements.
|
||||
//
|
||||
// The deque is empty after calling this method.
|
||||
func (dq *typeDeque) all() []*Type {
|
||||
length := dq.write - dq.read
|
||||
types := make([]*Type, 0, length)
|
||||
for t := dq.shift(); t != nil; t = dq.shift() {
|
||||
types = append(types, t)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
// inflateRawTypes takes a list of raw btf types linked via type IDs, and turns
|
||||
// it into a graph of Types connected via pointers.
|
||||
//
|
||||
// Returns a map of named types (so, where NameOff is non-zero). Since BTF ignores
|
||||
// compilation units, multiple types may share the same name. A Type may form a
|
||||
// cyclic graph by pointing at itself.
|
||||
func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map[string][]namedType, err error) {
|
||||
// Returns a map of named types (so, where NameOff is non-zero) and a slice of types
|
||||
// indexed by TypeID. Since BTF ignores compilation units, multiple types may share
|
||||
// the same name. A Type may form a cyclic graph by pointing at itself.
|
||||
func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type, namedTypes map[string][]namedType, err error) {
|
||||
type fixupDef struct {
|
||||
id TypeID
|
||||
expectedKind btfKind
|
||||
@@ -523,7 +690,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
return members, nil
|
||||
}
|
||||
|
||||
types := make([]Type, 0, len(rawTypes))
|
||||
types = make([]Type, 0, len(rawTypes))
|
||||
types = append(types, (*Void)(nil))
|
||||
namedTypes = make(map[string][]namedType)
|
||||
|
||||
@@ -537,7 +704,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
|
||||
name, err := rawStrings.LookupName(raw.NameOff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get name for type id %d: %w", id, err)
|
||||
return nil, nil, fmt.Errorf("get name for type id %d: %w", id, err)
|
||||
}
|
||||
|
||||
switch raw.Kind() {
|
||||
@@ -562,14 +729,14 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
case kindStruct:
|
||||
members, err := convertMembers(raw.data.([]btfMember), raw.KindFlag())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
|
||||
return nil, 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), raw.KindFlag())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
|
||||
return nil, nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
|
||||
}
|
||||
typ = &Union{id, name, raw.Size(), members}
|
||||
|
||||
@@ -579,7 +746,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
for i, btfVal := range rawvals {
|
||||
name, err := rawStrings.LookupName(btfVal.NameOff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get name for enum value %d: %s", i, err)
|
||||
return nil, nil, fmt.Errorf("get name for enum value %d: %s", i, err)
|
||||
}
|
||||
vals = append(vals, EnumValue{
|
||||
Name: name,
|
||||
@@ -589,7 +756,11 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
typ = &Enum{id, name, vals}
|
||||
|
||||
case kindForward:
|
||||
typ = &Fwd{id, name}
|
||||
if raw.KindFlag() {
|
||||
typ = &Fwd{id, name, FwdUnion}
|
||||
} else {
|
||||
typ = &Fwd{id, name, FwdStruct}
|
||||
}
|
||||
|
||||
case kindTypedef:
|
||||
typedef := &Typedef{id, name, nil}
|
||||
@@ -622,7 +793,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
for i, param := range rawparams {
|
||||
name, err := rawStrings.LookupName(param.NameOff)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't get name for func proto parameter %d: %s", i, err)
|
||||
return nil, nil, fmt.Errorf("get name for func proto parameter %d: %s", i, err)
|
||||
}
|
||||
params = append(params, FuncParam{
|
||||
Name: name,
|
||||
@@ -656,7 +827,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
typ = &Datasec{id, name, raw.SizeType, vars}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||
return nil, nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
|
||||
}
|
||||
|
||||
types = append(types, typ)
|
||||
@@ -671,7 +842,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
for _, fixup := range fixups {
|
||||
i := int(fixup.id)
|
||||
if i >= len(types) {
|
||||
return nil, fmt.Errorf("reference to invalid type id: %d", fixup.id)
|
||||
return nil, nil, fmt.Errorf("reference to invalid type id: %d", fixup.id)
|
||||
}
|
||||
|
||||
// Default void (id 0) to unknown
|
||||
@@ -681,13 +852,13 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (namedTypes map
|
||||
}
|
||||
|
||||
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)
|
||||
return nil, nil, fmt.Errorf("expected type id %d to have kind %s, found %s", fixup.id, expected, rawKind)
|
||||
}
|
||||
|
||||
*fixup.typ = types[i]
|
||||
}
|
||||
|
||||
return namedTypes, nil
|
||||
return types, namedTypes, nil
|
||||
}
|
||||
|
||||
// essentialName returns name without a ___ suffix.
|
||||
|
||||
52
vendor/github.com/cilium/ebpf/internal/elf.go
generated
vendored
Normal file
52
vendor/github.com/cilium/ebpf/internal/elf.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type SafeELFFile struct {
|
||||
*elf.File
|
||||
}
|
||||
|
||||
// NewSafeELFFile reads an ELF safely.
|
||||
//
|
||||
// Any panic during parsing is turned into an error. This is necessary since
|
||||
// there are a bunch of unfixed bugs in debug/elf.
|
||||
//
|
||||
// https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+debug%2Felf+in%3Atitle
|
||||
func NewSafeELFFile(r io.ReaderAt) (safe *SafeELFFile, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
safe = nil
|
||||
err = fmt.Errorf("reading ELF file panicked: %s", r)
|
||||
}()
|
||||
|
||||
file, err := elf.NewFile(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SafeELFFile{file}, nil
|
||||
}
|
||||
|
||||
// Symbols is the safe version of elf.File.Symbols.
|
||||
func (se *SafeELFFile) Symbols() (syms []elf.Symbol, err error) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
|
||||
syms = nil
|
||||
err = fmt.Errorf("reading ELF symbols panicked: %s", r)
|
||||
}()
|
||||
|
||||
syms, err = se.File.Symbols()
|
||||
return
|
||||
}
|
||||
86
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
86
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
@@ -32,7 +32,7 @@ func (ufe *UnsupportedFeatureError) Is(target error) bool {
|
||||
}
|
||||
|
||||
type featureTest struct {
|
||||
sync.Mutex
|
||||
sync.RWMutex
|
||||
successful bool
|
||||
result error
|
||||
}
|
||||
@@ -42,10 +42,10 @@ type featureTest struct {
|
||||
//
|
||||
// The return values have the following semantics:
|
||||
//
|
||||
// err == ErrNotSupported: the feature is not available
|
||||
// err == nil: the feature is available
|
||||
// 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)
|
||||
type FeatureTestFn func() error
|
||||
|
||||
// FeatureTest wraps a function so that it is run at most once.
|
||||
//
|
||||
@@ -61,70 +61,40 @@ func FeatureTest(name, version string, fn FeatureTestFn) func() error {
|
||||
|
||||
ft := new(featureTest)
|
||||
return func() error {
|
||||
ft.RLock()
|
||||
if ft.successful {
|
||||
defer ft.RUnlock()
|
||||
return ft.result
|
||||
}
|
||||
ft.RUnlock()
|
||||
ft.Lock()
|
||||
defer ft.Unlock()
|
||||
|
||||
// check one more time on the off
|
||||
// chance that two go routines
|
||||
// were able to call into the write
|
||||
// lock
|
||||
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 {
|
||||
err := fn()
|
||||
switch {
|
||||
case errors.Is(err, ErrNotSupported):
|
||||
ft.result = &UnsupportedFeatureError{
|
||||
MinimumVersion: v,
|
||||
Name: name,
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case err == nil:
|
||||
ft.successful = true
|
||||
|
||||
default:
|
||||
// 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("detect support for %s: %w", name, err)
|
||||
}
|
||||
|
||||
return ft.result
|
||||
}
|
||||
}
|
||||
|
||||
// A Version in the form Major.Minor.Patch.
|
||||
type Version [3]uint16
|
||||
|
||||
// NewVersion creates a version from a string like "Major.Minor.Patch".
|
||||
//
|
||||
// Patch is optional.
|
||||
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{}, fmt.Errorf("invalid version: %s", ver)
|
||||
}
|
||||
return Version{major, minor, patch}, nil
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v[2] == 0 {
|
||||
return fmt.Sprintf("v%d.%d", v[0], v[1])
|
||||
}
|
||||
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
|
||||
}
|
||||
|
||||
// Less returns true if the version is less than another version.
|
||||
func (v Version) Less(other Version) bool {
|
||||
for i, a := range v {
|
||||
if a == other[i] {
|
||||
continue
|
||||
}
|
||||
return a < other[i]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unspecified returns true if the version is all zero.
|
||||
func (v Version) Unspecified() bool {
|
||||
return v[0] == 0 && v[1] == 0 && v[2] == 0
|
||||
}
|
||||
|
||||
44
vendor/github.com/cilium/ebpf/internal/pinning.go
generated
vendored
Normal file
44
vendor/github.com/cilium/ebpf/internal/pinning.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
func Pin(currentPath, newPath string, fd *FD) error {
|
||||
if newPath == "" {
|
||||
return errors.New("given pinning path cannot be empty")
|
||||
}
|
||||
if currentPath == newPath {
|
||||
return nil
|
||||
}
|
||||
if currentPath == "" {
|
||||
return BPFObjPin(newPath, fd)
|
||||
}
|
||||
var err error
|
||||
// Renameat2 is used instead of os.Rename to disallow the new path replacing
|
||||
// an existing path.
|
||||
if err = unix.Renameat2(unix.AT_FDCWD, currentPath, unix.AT_FDCWD, newPath, unix.RENAME_NOREPLACE); err == nil {
|
||||
// Object is now moved to the new pinning path.
|
||||
return nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err)
|
||||
}
|
||||
// Internal state not in sync with the file system so let's fix it.
|
||||
return BPFObjPin(newPath, fd)
|
||||
}
|
||||
|
||||
func Unpin(pinnedPath string) error {
|
||||
if pinnedPath == "" {
|
||||
return nil
|
||||
}
|
||||
err := os.Remove(pinnedPath)
|
||||
if err == nil || os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
15
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
15
vendor/github.com/cilium/ebpf/internal/ptr.go
generated
vendored
@@ -1,6 +1,10 @@
|
||||
package internal
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
// NewPointer creates a 64-bit pointer from an unsafe Pointer.
|
||||
func NewPointer(ptr unsafe.Pointer) Pointer {
|
||||
@@ -22,9 +26,10 @@ func NewStringPointer(str string) Pointer {
|
||||
return Pointer{}
|
||||
}
|
||||
|
||||
// The kernel expects strings to be zero terminated
|
||||
buf := make([]byte, len(str)+1)
|
||||
copy(buf, str)
|
||||
p, err := unix.BytePtrFromString(str)
|
||||
if err != nil {
|
||||
return Pointer{}
|
||||
}
|
||||
|
||||
return Pointer{ptr: unsafe.Pointer(&buf[0])}
|
||||
return Pointer{ptr: unsafe.Pointer(p)}
|
||||
}
|
||||
|
||||
18
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
18
vendor/github.com/cilium/ebpf/internal/syscall.go
generated
vendored
@@ -91,6 +91,19 @@ func BPFProgDetach(attr *BPFProgDetachAttr) error {
|
||||
return err
|
||||
}
|
||||
|
||||
type BPFEnableStatsAttr struct {
|
||||
StatsType uint32
|
||||
}
|
||||
|
||||
func BPFEnableStats(attr *BPFEnableStatsAttr) (*FD, error) {
|
||||
ptr, err := BPF(BPF_ENABLE_STATS, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("enable stats: %w", err)
|
||||
}
|
||||
return NewFD(uint32(ptr)), nil
|
||||
|
||||
}
|
||||
|
||||
type bpfObjAttr struct {
|
||||
fileName Pointer
|
||||
fd uint32
|
||||
@@ -127,9 +140,10 @@ func BPFObjPin(fileName string, fd *FD) error {
|
||||
}
|
||||
|
||||
// BPFObjGet wraps BPF_OBJ_GET.
|
||||
func BPFObjGet(fileName string) (*FD, error) {
|
||||
func BPFObjGet(fileName string, flags uint32) (*FD, error) {
|
||||
attr := bpfObjAttr{
|
||||
fileName: NewStringPointer(fileName),
|
||||
fileName: NewStringPointer(fileName),
|
||||
fileFlags: flags,
|
||||
}
|
||||
ptr, err := BPF(BPF_OBJ_GET, unsafe.Pointer(&attr), unsafe.Sizeof(attr))
|
||||
if err != nil {
|
||||
|
||||
57
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
57
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@@ -10,19 +10,27 @@ 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
|
||||
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
|
||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
||||
ENOTSUPP = syscall.Errno(0x20c)
|
||||
|
||||
EBADF = linux.EBADF
|
||||
BPF_F_NO_PREALLOC = linux.BPF_F_NO_PREALLOC
|
||||
BPF_F_NUMA_NODE = linux.BPF_F_NUMA_NODE
|
||||
BPF_F_RDONLY = linux.BPF_F_RDONLY
|
||||
BPF_F_WRONLY = linux.BPF_F_WRONLY
|
||||
BPF_F_RDONLY_PROG = linux.BPF_F_RDONLY_PROG
|
||||
BPF_F_WRONLY_PROG = linux.BPF_F_WRONLY_PROG
|
||||
BPF_F_SLEEPABLE = linux.BPF_F_SLEEPABLE
|
||||
BPF_OBJ_NAME_LEN = linux.BPF_OBJ_NAME_LEN
|
||||
BPF_TAG_SIZE = linux.BPF_TAG_SIZE
|
||||
SYS_BPF = linux.SYS_BPF
|
||||
@@ -35,12 +43,21 @@ const (
|
||||
PROT_WRITE = linux.PROT_WRITE
|
||||
MAP_SHARED = linux.MAP_SHARED
|
||||
PERF_TYPE_SOFTWARE = linux.PERF_TYPE_SOFTWARE
|
||||
PERF_TYPE_TRACEPOINT = linux.PERF_TYPE_TRACEPOINT
|
||||
PERF_COUNT_SW_BPF_OUTPUT = linux.PERF_COUNT_SW_BPF_OUTPUT
|
||||
PERF_EVENT_IOC_DISABLE = linux.PERF_EVENT_IOC_DISABLE
|
||||
PERF_EVENT_IOC_ENABLE = linux.PERF_EVENT_IOC_ENABLE
|
||||
PERF_EVENT_IOC_SET_BPF = linux.PERF_EVENT_IOC_SET_BPF
|
||||
PerfBitWatermark = linux.PerfBitWatermark
|
||||
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
|
||||
BPF_STATS_RUN_TIME = linux.BPF_STATS_RUN_TIME
|
||||
PERF_RECORD_LOST = linux.PERF_RECORD_LOST
|
||||
PERF_RECORD_SAMPLE = linux.PERF_RECORD_SAMPLE
|
||||
AT_FDCWD = linux.AT_FDCWD
|
||||
RENAME_NOREPLACE = linux.RENAME_NOREPLACE
|
||||
)
|
||||
|
||||
// Statfs_t is a wrapper
|
||||
@@ -64,6 +81,11 @@ func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
return linux.FcntlInt(fd, cmd, arg)
|
||||
}
|
||||
|
||||
// IoctlSetInt is a wrapper
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
return linux.IoctlSetInt(fd, req, value)
|
||||
}
|
||||
|
||||
// Statfs is a wrapper
|
||||
func Statfs(path string, buf *Statfs_t) (err error) {
|
||||
return linux.Statfs(path, buf)
|
||||
@@ -151,6 +173,21 @@ func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return linux.Tgkill(tgid, tid, sig)
|
||||
}
|
||||
|
||||
// BytePtrFromString is a wrapper
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
return linux.BytePtrFromString(s)
|
||||
}
|
||||
|
||||
// ByteSliceToString is a wrapper
|
||||
func ByteSliceToString(s []byte) string {
|
||||
return linux.ByteSliceToString(s)
|
||||
}
|
||||
|
||||
// Renameat2 is a wrapper
|
||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||
return linux.Renameat2(olddirfd, oldpath, newdirfd, newpath, flags)
|
||||
}
|
||||
|
||||
func KernelRelease() (string, error) {
|
||||
var uname Utsname
|
||||
err := Uname(&uname)
|
||||
|
||||
56
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
56
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@@ -11,18 +11,26 @@ import (
|
||||
var errNonLinux = fmt.Errorf("unsupported platform %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
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
|
||||
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
|
||||
EBADF = syscall.Errno(0)
|
||||
// ENOTSUPP is not the same as ENOTSUP or EOPNOTSUP
|
||||
ENOTSUPP = syscall.Errno(0x20c)
|
||||
|
||||
BPF_F_NO_PREALLOC = 0
|
||||
BPF_F_NUMA_NODE = 0
|
||||
BPF_F_RDONLY = 0
|
||||
BPF_F_WRONLY = 0
|
||||
BPF_F_RDONLY_PROG = 0
|
||||
BPF_F_WRONLY_PROG = 0
|
||||
BPF_F_SLEEPABLE = 0
|
||||
BPF_OBJ_NAME_LEN = 0x10
|
||||
BPF_TAG_SIZE = 0x8
|
||||
SYS_BPF = 321
|
||||
@@ -36,12 +44,21 @@ const (
|
||||
PROT_WRITE = 0x2
|
||||
MAP_SHARED = 0x1
|
||||
PERF_TYPE_SOFTWARE = 0x1
|
||||
PERF_TYPE_TRACEPOINT = 0
|
||||
PERF_COUNT_SW_BPF_OUTPUT = 0xa
|
||||
PERF_EVENT_IOC_DISABLE = 0
|
||||
PERF_EVENT_IOC_ENABLE = 0
|
||||
PERF_EVENT_IOC_SET_BPF = 0
|
||||
PerfBitWatermark = 0x4000
|
||||
PERF_SAMPLE_RAW = 0x400
|
||||
PERF_FLAG_FD_CLOEXEC = 0x8
|
||||
RLIM_INFINITY = 0x7fffffffffffffff
|
||||
RLIMIT_MEMLOCK = 8
|
||||
BPF_STATS_RUN_TIME = 0
|
||||
PERF_RECORD_LOST = 2
|
||||
PERF_RECORD_SAMPLE = 9
|
||||
AT_FDCWD = -0x2
|
||||
RENAME_NOREPLACE = 0x1
|
||||
)
|
||||
|
||||
// Statfs_t is a wrapper
|
||||
@@ -81,6 +98,11 @@ func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
|
||||
return -1, errNonLinux
|
||||
}
|
||||
|
||||
// IoctlSetInt is a wrapper
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
// Statfs is a wrapper
|
||||
func Statfs(path string, buf *Statfs_t) error {
|
||||
return errNonLinux
|
||||
@@ -195,6 +217,7 @@ func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int
|
||||
// Utsname is a wrapper
|
||||
type Utsname struct {
|
||||
Release [65]byte
|
||||
Version [65]byte
|
||||
}
|
||||
|
||||
// Uname is a wrapper
|
||||
@@ -217,6 +240,21 @@ func Tgkill(tgid int, tid int, sig syscall.Signal) (err error) {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
// BytePtrFromString is a wrapper
|
||||
func BytePtrFromString(s string) (*byte, error) {
|
||||
return nil, errNonLinux
|
||||
}
|
||||
|
||||
// ByteSliceToString is a wrapper
|
||||
func ByteSliceToString(s []byte) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Renameat2 is a wrapper
|
||||
func Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) error {
|
||||
return errNonLinux
|
||||
}
|
||||
|
||||
func KernelRelease() (string, error) {
|
||||
return "", errNonLinux
|
||||
}
|
||||
|
||||
163
vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
Normal file
163
vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"sync"
|
||||
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version constant used in ELF binaries indicating that the loader needs to
|
||||
// substitute the eBPF program's version with the value of the kernel's
|
||||
// KERNEL_VERSION compile-time macro. Used for compatibility with BCC, gobpf
|
||||
// and RedSift.
|
||||
MagicKernelVersion = 0xFFFFFFFE
|
||||
)
|
||||
|
||||
var (
|
||||
// Match between one and three decimals separated by dots, with the last
|
||||
// segment (patch level) being optional on some kernels.
|
||||
// The x.y.z string must appear at the start of a string or right after
|
||||
// whitespace to prevent sequences like 'x.y.z-a.b.c' from matching 'a.b.c'.
|
||||
rgxKernelVersion = regexp.MustCompile(`(?:\A|\s)\d{1,3}\.\d{1,3}(?:\.\d{1,3})?`)
|
||||
|
||||
kernelVersion = struct {
|
||||
once sync.Once
|
||||
version Version
|
||||
err error
|
||||
}{}
|
||||
)
|
||||
|
||||
// A Version in the form Major.Minor.Patch.
|
||||
type Version [3]uint16
|
||||
|
||||
// NewVersion creates a version from a string like "Major.Minor.Patch".
|
||||
//
|
||||
// Patch is optional.
|
||||
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{}, fmt.Errorf("invalid version: %s", ver)
|
||||
}
|
||||
return Version{major, minor, patch}, nil
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v[2] == 0 {
|
||||
return fmt.Sprintf("v%d.%d", v[0], v[1])
|
||||
}
|
||||
return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
|
||||
}
|
||||
|
||||
// Less returns true if the version is less than another version.
|
||||
func (v Version) Less(other Version) bool {
|
||||
for i, a := range v {
|
||||
if a == other[i] {
|
||||
continue
|
||||
}
|
||||
return a < other[i]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Unspecified returns true if the version is all zero.
|
||||
func (v Version) Unspecified() bool {
|
||||
return v[0] == 0 && v[1] == 0 && v[2] == 0
|
||||
}
|
||||
|
||||
// Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h.
|
||||
// It represents the kernel version and patch level as a single value.
|
||||
func (v Version) Kernel() uint32 {
|
||||
|
||||
// Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid
|
||||
// overflowing into PATCHLEVEL.
|
||||
// See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255").
|
||||
s := v[2]
|
||||
if s > 255 {
|
||||
s = 255
|
||||
}
|
||||
|
||||
// Truncate members to uint8 to prevent them from spilling over into
|
||||
// each other when overflowing 8 bits.
|
||||
return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
|
||||
}
|
||||
|
||||
// KernelVersion returns the version of the currently running kernel.
|
||||
func KernelVersion() (Version, error) {
|
||||
kernelVersion.once.Do(func() {
|
||||
kernelVersion.version, kernelVersion.err = detectKernelVersion()
|
||||
})
|
||||
|
||||
if kernelVersion.err != nil {
|
||||
return Version{}, kernelVersion.err
|
||||
}
|
||||
return kernelVersion.version, nil
|
||||
}
|
||||
|
||||
// detectKernelVersion returns the version of the running kernel. It scans the
|
||||
// following sources in order: /proc/version_signature, uname -v, uname -r.
|
||||
// In each of those locations, the last-appearing x.y(.z) value is selected
|
||||
// for parsing. The first location that yields a usable version number is
|
||||
// returned.
|
||||
func detectKernelVersion() (Version, error) {
|
||||
|
||||
// Try reading /proc/version_signature for Ubuntu compatibility.
|
||||
// Example format: Ubuntu 4.15.0-91.92-generic 4.15.18
|
||||
// This method exists in the kernel itself, see d18acd15c
|
||||
// ("perf tools: Fix kernel version error in ubuntu").
|
||||
if pvs, err := ioutil.ReadFile("/proc/version_signature"); err == nil {
|
||||
// If /proc/version_signature exists, failing to parse it is an error.
|
||||
// It only exists on Ubuntu, where the real patch level is not obtainable
|
||||
// through any other method.
|
||||
v, err := findKernelVersion(string(pvs))
|
||||
if err != nil {
|
||||
return Version{}, err
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
var uname unix.Utsname
|
||||
if err := unix.Uname(&uname); err != nil {
|
||||
return Version{}, fmt.Errorf("calling uname: %w", err)
|
||||
}
|
||||
|
||||
// Debian puts the version including the patch level in uname.Version.
|
||||
// It is not an error if there's no version number in uname.Version,
|
||||
// as most distributions don't use it. Parsing can continue on uname.Release.
|
||||
// Example format: #1 SMP Debian 4.19.37-5+deb10u2 (2019-08-08)
|
||||
if v, err := findKernelVersion(unix.ByteSliceToString(uname.Version[:])); err == nil {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Most other distributions have the full kernel version including patch
|
||||
// level in uname.Release.
|
||||
// Example format: 4.19.0-5-amd64, 5.5.10-arch1-1
|
||||
v, err := findKernelVersion(unix.ByteSliceToString(uname.Release[:]))
|
||||
if err != nil {
|
||||
return Version{}, err
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// findKernelVersion matches s against rgxKernelVersion and parses the result
|
||||
// into a Version. If s contains multiple matches, the last entry is selected.
|
||||
func findKernelVersion(s string) (Version, error) {
|
||||
m := rgxKernelVersion.FindAllString(s, -1)
|
||||
if m == nil {
|
||||
return Version{}, fmt.Errorf("no kernel version in string: %s", s)
|
||||
}
|
||||
// Pick the last match of the string in case there are multiple.
|
||||
s = m[len(m)-1]
|
||||
|
||||
v, err := NewVersion(s)
|
||||
if err != nil {
|
||||
return Version{}, fmt.Errorf("parsing version string %s: %w", s, err)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
Reference in New Issue
Block a user