mirror of
https://github.com/opencontainers/runc.git
synced 2025-11-01 19:42:43 +08:00
build(deps): bump github.com/cilium/ebpf from 0.16.0 to 0.17.0
Bumps [github.com/cilium/ebpf](https://github.com/cilium/ebpf) from 0.16.0 to 0.17.0. - [Release notes](https://github.com/cilium/ebpf/releases) - [Commits](https://github.com/cilium/ebpf/compare/v0.16.0...v0.17.0) --- updated-dependencies: - dependency-name: github.com/cilium/ebpf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
3
go.mod
3
go.mod
@@ -9,7 +9,7 @@ toolchain go1.22.4
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.3.0
|
github.com/checkpoint-restore/go-criu/v6 v6.3.0
|
||||||
github.com/cilium/ebpf v0.16.0
|
github.com/cilium/ebpf v0.17.0
|
||||||
github.com/containerd/console v1.0.4
|
github.com/containerd/console v1.0.4
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0
|
github.com/coreos/go-systemd/v22 v22.5.0
|
||||||
github.com/cyphar/filepath-securejoin v0.3.6
|
github.com/cyphar/filepath-securejoin v0.3.6
|
||||||
@@ -35,5 +35,4 @@ require (
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/vishvananda/netns v0.0.4 // indirect
|
github.com/vishvananda/netns v0.0.4 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
6
go.sum
6
go.sum
@@ -1,8 +1,8 @@
|
|||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA=
|
github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA=
|
||||||
github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI=
|
github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI=
|
||||||
github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
|
github.com/cilium/ebpf v0.17.0 h1:wAgiAWE86w8DxbR/UJ9KsaaoUfjrO0yhg5yE7f898As=
|
||||||
github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
|
github.com/cilium/ebpf v0.17.0/go.mod h1:vay2FaYSmIlv3r8dNACd4mW/OCaZLJKJOo+IHBvCIO8=
|
||||||
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
|
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
|
||||||
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
@@ -81,8 +81,6 @@ github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQ
|
|||||||
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
github.com/vishvananda/netlink v1.3.0/go.mod h1:i6NetklAujEcC6fK0JPjT8qSwWyO0HLn4UKG+hGqeJs=
|
||||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI=
|
|
||||||
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
|||||||
6
vendor/github.com/cilium/ebpf/.golangci.yaml
generated
vendored
6
vendor/github.com/cilium/ebpf/.golangci.yaml
generated
vendored
@@ -11,3 +11,9 @@ linters:
|
|||||||
- typecheck
|
- typecheck
|
||||||
- unused
|
- unused
|
||||||
- gofmt
|
- gofmt
|
||||||
|
linters-settings:
|
||||||
|
goimports:
|
||||||
|
# A comma-separated list of prefixes, which, if set, checks import paths
|
||||||
|
# with the given prefixes are grouped after 3rd-party packages.
|
||||||
|
# Default: ""
|
||||||
|
local-prefixes: github.com/cilium/ebpf
|
||||||
|
|||||||
2
vendor/github.com/cilium/ebpf/CODEOWNERS
generated
vendored
2
vendor/github.com/cilium/ebpf/CODEOWNERS
generated
vendored
@@ -9,3 +9,5 @@ ringbuf/ @florianl
|
|||||||
btf/ @dylandreimerink
|
btf/ @dylandreimerink
|
||||||
|
|
||||||
cmd/bpf2go/ @mejedi
|
cmd/bpf2go/ @mejedi
|
||||||
|
|
||||||
|
docs/ @ti-mo
|
||||||
|
|||||||
6
vendor/github.com/cilium/ebpf/Makefile
generated
vendored
6
vendor/github.com/cilium/ebpf/Makefile
generated
vendored
@@ -39,16 +39,18 @@ TARGETS := \
|
|||||||
testdata/subprog_reloc \
|
testdata/subprog_reloc \
|
||||||
testdata/fwd_decl \
|
testdata/fwd_decl \
|
||||||
testdata/kconfig \
|
testdata/kconfig \
|
||||||
testdata/kconfig_config \
|
testdata/ksym \
|
||||||
testdata/kfunc \
|
testdata/kfunc \
|
||||||
testdata/invalid-kfunc \
|
testdata/invalid-kfunc \
|
||||||
testdata/kfunc-kmod \
|
testdata/kfunc-kmod \
|
||||||
testdata/constants \
|
testdata/constants \
|
||||||
testdata/errors \
|
testdata/errors \
|
||||||
|
testdata/variables \
|
||||||
btf/testdata/relocs \
|
btf/testdata/relocs \
|
||||||
btf/testdata/relocs_read \
|
btf/testdata/relocs_read \
|
||||||
btf/testdata/relocs_read_tgt \
|
btf/testdata/relocs_read_tgt \
|
||||||
btf/testdata/relocs_enum \
|
btf/testdata/relocs_enum \
|
||||||
|
btf/testdata/tags \
|
||||||
cmd/bpf2go/testdata/minimal
|
cmd/bpf2go/testdata/minimal
|
||||||
|
|
||||||
.PHONY: all clean container-all container-shell generate
|
.PHONY: all clean container-all container-shell generate
|
||||||
@@ -57,7 +59,7 @@ TARGETS := \
|
|||||||
|
|
||||||
# Build all ELF binaries using a containerized LLVM toolchain.
|
# Build all ELF binaries using a containerized LLVM toolchain.
|
||||||
container-all:
|
container-all:
|
||||||
+${CONTAINER_ENGINE} run --rm -t ${CONTAINER_RUN_ARGS} \
|
+${CONTAINER_ENGINE} run --rm -ti ${CONTAINER_RUN_ARGS} \
|
||||||
-v "${REPODIR}":/ebpf -w /ebpf --env MAKEFLAGS \
|
-v "${REPODIR}":/ebpf -w /ebpf --env MAKEFLAGS \
|
||||||
--env HOME="/tmp" \
|
--env HOME="/tmp" \
|
||||||
--env BPF2GO_CC="$(CLANG)" \
|
--env BPF2GO_CC="$(CLANG)" \
|
||||||
|
|||||||
1
vendor/github.com/cilium/ebpf/README.md
generated
vendored
1
vendor/github.com/cilium/ebpf/README.md
generated
vendored
@@ -53,6 +53,7 @@ This library includes the following packages:
|
|||||||
* [rlimit](https://pkg.go.dev/github.com/cilium/ebpf/rlimit) provides a convenient API to lift
|
* [rlimit](https://pkg.go.dev/github.com/cilium/ebpf/rlimit) provides a convenient API to lift
|
||||||
the `RLIMIT_MEMLOCK` constraint on kernels before 5.11.
|
the `RLIMIT_MEMLOCK` constraint on kernels before 5.11.
|
||||||
* [btf](https://pkg.go.dev/github.com/cilium/ebpf/btf) allows reading the BPF Type Format.
|
* [btf](https://pkg.go.dev/github.com/cilium/ebpf/btf) allows reading the BPF Type Format.
|
||||||
|
* [pin](https://pkg.go.dev/github.com/cilium/ebpf/pin) provides APIs for working with pinned objects on bpffs.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|||||||
3
vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
3
vendor/github.com/cilium/ebpf/asm/instruction.go
generated
vendored
@@ -12,7 +12,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// InstructionSize is the size of a BPF instruction in bytes
|
// InstructionSize is the size of a BPF instruction in bytes
|
||||||
@@ -804,7 +803,7 @@ func (insns Instructions) Tag(bo binary.ByteOrder) (string, error) {
|
|||||||
return "", fmt.Errorf("instruction %d: %w", i, err)
|
return "", fmt.Errorf("instruction %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hex.EncodeToString(h.Sum(nil)[:unix.BPF_TAG_SIZE]), nil
|
return hex.EncodeToString(h.Sum(nil)[:sys.BPF_TAG_SIZE]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeFunctionReferences populates the Offset (or Constant, depending on
|
// encodeFunctionReferences populates the Offset (or Constant, depending on
|
||||||
|
|||||||
24
vendor/github.com/cilium/ebpf/btf/btf.go
generated
vendored
24
vendor/github.com/cilium/ebpf/btf/btf.go
generated
vendored
@@ -443,13 +443,19 @@ func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symb
|
|||||||
// Some Datasecs are virtual and don't have corresponding ELF sections.
|
// Some Datasecs are virtual and don't have corresponding ELF sections.
|
||||||
switch name {
|
switch name {
|
||||||
case ".ksyms":
|
case ".ksyms":
|
||||||
// .ksyms describes forward declarations of kfunc signatures.
|
// .ksyms describes forward declarations of kfunc signatures, as well as
|
||||||
|
// references to kernel symbols.
|
||||||
// Nothing to fix up, all sizes and offsets are 0.
|
// Nothing to fix up, all sizes and offsets are 0.
|
||||||
for _, vsi := range ds.Vars {
|
for _, vsi := range ds.Vars {
|
||||||
_, ok := vsi.Type.(*Func)
|
switch t := vsi.Type.(type) {
|
||||||
if !ok {
|
case *Func:
|
||||||
// Only Funcs are supported in the .ksyms Datasec.
|
continue
|
||||||
return fmt.Errorf("data section %s: expected *btf.Func, not %T: %w", name, vsi.Type, ErrNotSupported)
|
case *Var:
|
||||||
|
if _, ok := t.Type.(*Void); !ok {
|
||||||
|
return fmt.Errorf("data section %s: expected %s to be *Void, not %T: %w", name, vsi.Type.TypeName(), vsi.Type, ErrNotSupported)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("data section %s: expected to be either *btf.Func or *btf.Var, not %T: %w", name, vsi.Type, ErrNotSupported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -695,5 +701,13 @@ func (iter *TypesIterator) Next() bool {
|
|||||||
iter.Type, ok = iter.spec.typeByID(iter.id)
|
iter.Type, ok = iter.spec.typeByID(iter.id)
|
||||||
iter.id++
|
iter.id++
|
||||||
iter.done = !ok
|
iter.done = !ok
|
||||||
|
if !iter.done {
|
||||||
|
// Skip declTags, during unmarshaling declTags become `Tags` fields of other types.
|
||||||
|
// We keep them in the spec to avoid holes in the ID space, but for the purposes of
|
||||||
|
// iteration, they are not useful to the user.
|
||||||
|
if _, ok := iter.Type.(*declTag); ok {
|
||||||
|
return iter.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
return !iter.done
|
return !iter.done
|
||||||
}
|
}
|
||||||
|
|||||||
1
vendor/github.com/cilium/ebpf/btf/btf_types.go
generated
vendored
1
vendor/github.com/cilium/ebpf/btf/btf_types.go
generated
vendored
@@ -39,6 +39,7 @@ const (
|
|||||||
kindFloat // Float
|
kindFloat // Float
|
||||||
// Added 5.16
|
// Added 5.16
|
||||||
kindDeclTag // DeclTag
|
kindDeclTag // DeclTag
|
||||||
|
// Added 5.17
|
||||||
kindTypeTag // TypeTag
|
kindTypeTag // TypeTag
|
||||||
// Added 6.0
|
// Added 6.0
|
||||||
kindEnum64 // Enum64
|
kindEnum64 // Enum64
|
||||||
|
|||||||
150
vendor/github.com/cilium/ebpf/btf/ext_info.go
generated
vendored
150
vendor/github.com/cilium/ebpf/btf/ext_info.go
generated
vendored
@@ -16,8 +16,8 @@ import (
|
|||||||
// ExtInfos contains ELF section metadata.
|
// ExtInfos contains ELF section metadata.
|
||||||
type ExtInfos struct {
|
type ExtInfos struct {
|
||||||
// The slices are sorted by offset in ascending order.
|
// The slices are sorted by offset in ascending order.
|
||||||
funcInfos map[string]FuncInfos
|
funcInfos map[string]FuncOffsets
|
||||||
lineInfos map[string]LineInfos
|
lineInfos map[string]LineOffsets
|
||||||
relocationInfos map[string]CORERelocationInfos
|
relocationInfos map[string]CORERelocationInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,9 +58,9 @@ func loadExtInfos(r io.ReaderAt, bo binary.ByteOrder, spec *Spec) (*ExtInfos, er
|
|||||||
return nil, fmt.Errorf("parsing BTF function info: %w", err)
|
return nil, fmt.Errorf("parsing BTF function info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
funcInfos := make(map[string]FuncInfos, len(btfFuncInfos))
|
funcInfos := make(map[string]FuncOffsets, len(btfFuncInfos))
|
||||||
for section, bfis := range btfFuncInfos {
|
for section, bfis := range btfFuncInfos {
|
||||||
funcInfos[section], err = newFuncInfos(bfis, spec)
|
funcInfos[section], err = newFuncOffsets(bfis, spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("section %s: func infos: %w", section, err)
|
return nil, fmt.Errorf("section %s: func infos: %w", section, err)
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ func loadExtInfos(r io.ReaderAt, bo binary.ByteOrder, spec *Spec) (*ExtInfos, er
|
|||||||
return nil, fmt.Errorf("parsing BTF line info: %w", err)
|
return nil, fmt.Errorf("parsing BTF line info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lineInfos := make(map[string]LineInfos, len(btfLineInfos))
|
lineInfos := make(map[string]LineOffsets, len(btfLineInfos))
|
||||||
for section, blis := range btfLineInfos {
|
for section, blis := range btfLineInfos {
|
||||||
lineInfos[section], err = newLineInfos(blis, spec.strings)
|
lineInfos[section], err = newLineInfos(blis, spec.strings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -102,8 +102,10 @@ func loadExtInfos(r io.ReaderAt, bo binary.ByteOrder, spec *Spec) (*ExtInfos, er
|
|||||||
return &ExtInfos{funcInfos, lineInfos, coreRelos}, nil
|
return &ExtInfos{funcInfos, lineInfos, coreRelos}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type funcInfoMeta struct{}
|
type (
|
||||||
type coreRelocationMeta struct{}
|
funcInfoMeta struct{}
|
||||||
|
coreRelocationMeta struct{}
|
||||||
|
)
|
||||||
|
|
||||||
// Assign per-section metadata from BTF to a section's instructions.
|
// Assign per-section metadata from BTF to a section's instructions.
|
||||||
func (ei *ExtInfos) Assign(insns asm.Instructions, section string) {
|
func (ei *ExtInfos) Assign(insns asm.Instructions, section string) {
|
||||||
@@ -117,20 +119,20 @@ func (ei *ExtInfos) Assign(insns asm.Instructions, section string) {
|
|||||||
// Assign per-instruction metadata to the instructions in insns.
|
// Assign per-instruction metadata to the instructions in insns.
|
||||||
func AssignMetadataToInstructions(
|
func AssignMetadataToInstructions(
|
||||||
insns asm.Instructions,
|
insns asm.Instructions,
|
||||||
funcInfos FuncInfos,
|
funcInfos FuncOffsets,
|
||||||
lineInfos LineInfos,
|
lineInfos LineOffsets,
|
||||||
reloInfos CORERelocationInfos,
|
reloInfos CORERelocationInfos,
|
||||||
) {
|
) {
|
||||||
iter := insns.Iterate()
|
iter := insns.Iterate()
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
if len(funcInfos.infos) > 0 && funcInfos.infos[0].offset == iter.Offset {
|
if len(funcInfos) > 0 && funcInfos[0].Offset == iter.Offset {
|
||||||
*iter.Ins = WithFuncMetadata(*iter.Ins, funcInfos.infos[0].fn)
|
*iter.Ins = WithFuncMetadata(*iter.Ins, funcInfos[0].Func)
|
||||||
funcInfos.infos = funcInfos.infos[1:]
|
funcInfos = funcInfos[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(lineInfos.infos) > 0 && lineInfos.infos[0].offset == iter.Offset {
|
if len(lineInfos) > 0 && lineInfos[0].Offset == iter.Offset {
|
||||||
*iter.Ins = iter.Ins.WithSource(lineInfos.infos[0].line)
|
*iter.Ins = iter.Ins.WithSource(lineInfos[0].Line)
|
||||||
lineInfos.infos = lineInfos.infos[1:]
|
lineInfos = lineInfos[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(reloInfos.infos) > 0 && reloInfos.infos[0].offset == iter.Offset {
|
if len(reloInfos.infos) > 0 && reloInfos.infos[0].offset == iter.Offset {
|
||||||
@@ -159,9 +161,9 @@ marshal:
|
|||||||
var fiBuf, liBuf bytes.Buffer
|
var fiBuf, liBuf bytes.Buffer
|
||||||
for {
|
for {
|
||||||
if fn := FuncMetadata(iter.Ins); fn != nil {
|
if fn := FuncMetadata(iter.Ins); fn != nil {
|
||||||
fi := &funcInfo{
|
fi := &FuncOffset{
|
||||||
fn: fn,
|
Func: fn,
|
||||||
offset: iter.Offset,
|
Offset: iter.Offset,
|
||||||
}
|
}
|
||||||
if err := fi.marshal(&fiBuf, b); err != nil {
|
if err := fi.marshal(&fiBuf, b); err != nil {
|
||||||
return nil, nil, fmt.Errorf("write func info: %w", err)
|
return nil, nil, fmt.Errorf("write func info: %w", err)
|
||||||
@@ -178,9 +180,9 @@ marshal:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
li := &lineInfo{
|
li := &LineOffset{
|
||||||
line: line,
|
Offset: iter.Offset,
|
||||||
offset: iter.Offset,
|
Line: line,
|
||||||
}
|
}
|
||||||
if err := li.marshal(&liBuf, b); err != nil {
|
if err := li.marshal(&liBuf, b); err != nil {
|
||||||
return nil, nil, fmt.Errorf("write line info: %w", err)
|
return nil, nil, fmt.Errorf("write line info: %w", err)
|
||||||
@@ -333,17 +335,17 @@ func parseExtInfoRecordSize(r io.Reader, bo binary.ByteOrder) (uint32, error) {
|
|||||||
return recordSize, nil
|
return recordSize, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncInfos contains a sorted list of func infos.
|
// FuncOffsets is a sorted slice of FuncOffset.
|
||||||
type FuncInfos struct {
|
type FuncOffsets []FuncOffset
|
||||||
infos []funcInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
// The size of a FuncInfo in BTF wire format.
|
// The size of a FuncInfo in BTF wire format.
|
||||||
var FuncInfoSize = uint32(binary.Size(bpfFuncInfo{}))
|
var FuncInfoSize = uint32(binary.Size(bpfFuncInfo{}))
|
||||||
|
|
||||||
type funcInfo struct {
|
// FuncOffset represents a [btf.Func] and its raw instruction offset within a
|
||||||
fn *Func
|
// BPF program.
|
||||||
offset asm.RawInstructionOffset
|
type FuncOffset struct {
|
||||||
|
Offset asm.RawInstructionOffset
|
||||||
|
Func *Func
|
||||||
}
|
}
|
||||||
|
|
||||||
type bpfFuncInfo struct {
|
type bpfFuncInfo struct {
|
||||||
@@ -352,7 +354,7 @@ type bpfFuncInfo struct {
|
|||||||
TypeID TypeID
|
TypeID TypeID
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFuncInfo(fi bpfFuncInfo, spec *Spec) (*funcInfo, error) {
|
func newFuncOffset(fi bpfFuncInfo, spec *Spec) (*FuncOffset, error) {
|
||||||
typ, err := spec.TypeByID(fi.TypeID)
|
typ, err := spec.TypeByID(fi.TypeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -368,31 +370,32 @@ func newFuncInfo(fi bpfFuncInfo, spec *Spec) (*funcInfo, error) {
|
|||||||
return nil, fmt.Errorf("func with type ID %d doesn't have a name", fi.TypeID)
|
return nil, fmt.Errorf("func with type ID %d doesn't have a name", fi.TypeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &funcInfo{
|
return &FuncOffset{
|
||||||
fn,
|
|
||||||
asm.RawInstructionOffset(fi.InsnOff),
|
asm.RawInstructionOffset(fi.InsnOff),
|
||||||
|
fn,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFuncInfos(bfis []bpfFuncInfo, spec *Spec) (FuncInfos, error) {
|
func newFuncOffsets(bfis []bpfFuncInfo, spec *Spec) (FuncOffsets, error) {
|
||||||
fis := FuncInfos{
|
fos := make(FuncOffsets, 0, len(bfis))
|
||||||
infos: make([]funcInfo, 0, len(bfis)),
|
|
||||||
}
|
|
||||||
for _, bfi := range bfis {
|
for _, bfi := range bfis {
|
||||||
fi, err := newFuncInfo(bfi, spec)
|
fi, err := newFuncOffset(bfi, spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FuncInfos{}, fmt.Errorf("offset %d: %w", bfi.InsnOff, err)
|
return FuncOffsets{}, fmt.Errorf("offset %d: %w", bfi.InsnOff, err)
|
||||||
}
|
}
|
||||||
fis.infos = append(fis.infos, *fi)
|
fos = append(fos, *fi)
|
||||||
}
|
}
|
||||||
sort.Slice(fis.infos, func(i, j int) bool {
|
sort.Slice(fos, func(i, j int) bool {
|
||||||
return fis.infos[i].offset <= fis.infos[j].offset
|
return fos[i].Offset <= fos[j].Offset
|
||||||
})
|
})
|
||||||
return fis, nil
|
return fos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadFuncInfos parses BTF func info in kernel wire format.
|
// LoadFuncInfos parses BTF func info from kernel wire format into a
|
||||||
func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (FuncInfos, error) {
|
// [FuncOffsets], a sorted slice of [btf.Func]s of (sub)programs within a BPF
|
||||||
|
// program with their corresponding raw instruction offsets.
|
||||||
|
func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (FuncOffsets, error) {
|
||||||
fis, err := parseFuncInfoRecords(
|
fis, err := parseFuncInfoRecords(
|
||||||
reader,
|
reader,
|
||||||
bo,
|
bo,
|
||||||
@@ -401,20 +404,20 @@ func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec
|
|||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return FuncInfos{}, fmt.Errorf("parsing BTF func info: %w", err)
|
return FuncOffsets{}, fmt.Errorf("parsing BTF func info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newFuncInfos(fis, spec)
|
return newFuncOffsets(fis, spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// marshal into the BTF wire format.
|
// marshal into the BTF wire format.
|
||||||
func (fi *funcInfo) marshal(w *bytes.Buffer, b *Builder) error {
|
func (fi *FuncOffset) marshal(w *bytes.Buffer, b *Builder) error {
|
||||||
id, err := b.Add(fi.fn)
|
id, err := b.Add(fi.Func)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
bfi := bpfFuncInfo{
|
bfi := bpfFuncInfo{
|
||||||
InsnOff: uint32(fi.offset),
|
InsnOff: uint32(fi.Offset),
|
||||||
TypeID: id,
|
TypeID: id,
|
||||||
}
|
}
|
||||||
buf := make([]byte, FuncInfoSize)
|
buf := make([]byte, FuncInfoSize)
|
||||||
@@ -515,14 +518,13 @@ func (li *Line) String() string {
|
|||||||
return li.line
|
return li.line
|
||||||
}
|
}
|
||||||
|
|
||||||
// LineInfos contains a sorted list of line infos.
|
// LineOffsets contains a sorted list of line infos.
|
||||||
type LineInfos struct {
|
type LineOffsets []LineOffset
|
||||||
infos []lineInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
type lineInfo struct {
|
// LineOffset represents a line info and its raw instruction offset.
|
||||||
line *Line
|
type LineOffset struct {
|
||||||
offset asm.RawInstructionOffset
|
Offset asm.RawInstructionOffset
|
||||||
|
Line *Line
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants for the format of bpfLineInfo.LineCol.
|
// Constants for the format of bpfLineInfo.LineCol.
|
||||||
@@ -541,7 +543,7 @@ type bpfLineInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadLineInfos parses BTF line info in kernel wire format.
|
// LoadLineInfos parses BTF line info in kernel wire format.
|
||||||
func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (LineInfos, error) {
|
func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (LineOffsets, error) {
|
||||||
lis, err := parseLineInfoRecords(
|
lis, err := parseLineInfoRecords(
|
||||||
reader,
|
reader,
|
||||||
bo,
|
bo,
|
||||||
@@ -550,57 +552,55 @@ func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec
|
|||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return LineInfos{}, fmt.Errorf("parsing BTF line info: %w", err)
|
return LineOffsets{}, fmt.Errorf("parsing BTF line info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLineInfos(lis, spec.strings)
|
return newLineInfos(lis, spec.strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLineInfo(li bpfLineInfo, strings *stringTable) (lineInfo, error) {
|
func newLineInfo(li bpfLineInfo, strings *stringTable) (LineOffset, error) {
|
||||||
line, err := strings.Lookup(li.LineOff)
|
line, err := strings.Lookup(li.LineOff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lineInfo{}, fmt.Errorf("lookup of line: %w", err)
|
return LineOffset{}, fmt.Errorf("lookup of line: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName, err := strings.Lookup(li.FileNameOff)
|
fileName, err := strings.Lookup(li.FileNameOff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lineInfo{}, fmt.Errorf("lookup of filename: %w", err)
|
return LineOffset{}, fmt.Errorf("lookup of filename: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lineNumber := li.LineCol >> bpfLineShift
|
lineNumber := li.LineCol >> bpfLineShift
|
||||||
lineColumn := li.LineCol & bpfColumnMax
|
lineColumn := li.LineCol & bpfColumnMax
|
||||||
|
|
||||||
return lineInfo{
|
return LineOffset{
|
||||||
|
asm.RawInstructionOffset(li.InsnOff),
|
||||||
&Line{
|
&Line{
|
||||||
fileName,
|
fileName,
|
||||||
line,
|
line,
|
||||||
lineNumber,
|
lineNumber,
|
||||||
lineColumn,
|
lineColumn,
|
||||||
},
|
},
|
||||||
asm.RawInstructionOffset(li.InsnOff),
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineInfos, error) {
|
func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineOffsets, error) {
|
||||||
lis := LineInfos{
|
lis := make([]LineOffset, 0, len(blis))
|
||||||
infos: make([]lineInfo, 0, len(blis)),
|
|
||||||
}
|
|
||||||
for _, bli := range blis {
|
for _, bli := range blis {
|
||||||
li, err := newLineInfo(bli, strings)
|
li, err := newLineInfo(bli, strings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return LineInfos{}, fmt.Errorf("offset %d: %w", bli.InsnOff, err)
|
return LineOffsets{}, fmt.Errorf("offset %d: %w", bli.InsnOff, err)
|
||||||
}
|
}
|
||||||
lis.infos = append(lis.infos, li)
|
lis = append(lis, li)
|
||||||
}
|
}
|
||||||
sort.Slice(lis.infos, func(i, j int) bool {
|
sort.Slice(lis, func(i, j int) bool {
|
||||||
return lis.infos[i].offset <= lis.infos[j].offset
|
return lis[i].Offset <= lis[j].Offset
|
||||||
})
|
})
|
||||||
return lis, nil
|
return lis, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// marshal writes the binary representation of the LineInfo to w.
|
// marshal writes the binary representation of the LineInfo to w.
|
||||||
func (li *lineInfo) marshal(w *bytes.Buffer, b *Builder) error {
|
func (li *LineOffset) marshal(w *bytes.Buffer, b *Builder) error {
|
||||||
line := li.line
|
line := li.Line
|
||||||
if line.lineNumber > bpfLineMax {
|
if line.lineNumber > bpfLineMax {
|
||||||
return fmt.Errorf("line %d exceeds %d", line.lineNumber, bpfLineMax)
|
return fmt.Errorf("line %d exceeds %d", line.lineNumber, bpfLineMax)
|
||||||
}
|
}
|
||||||
@@ -620,7 +620,7 @@ func (li *lineInfo) marshal(w *bytes.Buffer, b *Builder) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bli := bpfLineInfo{
|
bli := bpfLineInfo{
|
||||||
uint32(li.offset),
|
uint32(li.Offset),
|
||||||
fileNameOff,
|
fileNameOff,
|
||||||
lineOff,
|
lineOff,
|
||||||
(line.lineNumber << bpfLineShift) | line.lineColumn,
|
(line.lineNumber << bpfLineShift) | line.lineColumn,
|
||||||
@@ -799,7 +799,7 @@ func parseCORERelos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := parseCOREReloRecords(r, bo, recordSize, infoHeader.NumInfo)
|
records, err := parseCOREReloRecords(r, bo, infoHeader.NumInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("section %v: %w", secName, err)
|
return nil, fmt.Errorf("section %v: %w", secName, err)
|
||||||
}
|
}
|
||||||
@@ -811,7 +811,7 @@ func parseCORERelos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
|
|||||||
// parseCOREReloRecords parses a stream of CO-RE relocation entries into a
|
// parseCOREReloRecords parses a stream of CO-RE relocation entries into a
|
||||||
// coreRelos. These records appear after a btf_ext_info_sec header in the
|
// coreRelos. These records appear after a btf_ext_info_sec header in the
|
||||||
// core_relos sub-section of .BTF.ext.
|
// core_relos sub-section of .BTF.ext.
|
||||||
func parseCOREReloRecords(r io.Reader, bo binary.ByteOrder, recordSize uint32, recordNum uint32) ([]bpfCORERelo, error) {
|
func parseCOREReloRecords(r io.Reader, bo binary.ByteOrder, recordNum uint32) ([]bpfCORERelo, error) {
|
||||||
var out []bpfCORERelo
|
var out []bpfCORERelo
|
||||||
|
|
||||||
var relo bpfCORERelo
|
var relo bpfCORERelo
|
||||||
|
|||||||
55
vendor/github.com/cilium/ebpf/btf/feature.go
generated
vendored
55
vendor/github.com/cilium/ebpf/btf/feature.go
generated
vendored
@@ -11,19 +11,19 @@ import (
|
|||||||
|
|
||||||
// haveBTF attempts to load a BTF blob containing an Int. It should pass on any
|
// haveBTF attempts to load a BTF blob containing an Int. It should pass on any
|
||||||
// kernel that supports BPF_BTF_LOAD.
|
// kernel that supports BPF_BTF_LOAD.
|
||||||
var haveBTF = internal.NewFeatureTest("BTF", "4.18", func() error {
|
var haveBTF = internal.NewFeatureTest("BTF", func() error {
|
||||||
// 0-length anonymous integer
|
// 0-length anonymous integer
|
||||||
err := probeBTF(&Int{})
|
err := probeBTF(&Int{})
|
||||||
if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
|
if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "4.18")
|
||||||
|
|
||||||
// haveMapBTF attempts to load a minimal BTF blob containing a Var. It is
|
// haveMapBTF attempts to load a minimal BTF blob containing a Var. It is
|
||||||
// used as a proxy for .bss, .data and .rodata map support, which generally
|
// used as a proxy for .bss, .data and .rodata map support, which generally
|
||||||
// come with a Var and Datasec. These were introduced in Linux 5.2.
|
// come with a Var and Datasec. These were introduced in Linux 5.2.
|
||||||
var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func() error {
|
var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", func() error {
|
||||||
if err := haveBTF(); err != nil {
|
if err := haveBTF(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -40,12 +40,12 @@ var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func()
|
|||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.2")
|
||||||
|
|
||||||
// haveProgBTF attempts to load a BTF blob containing a Func and FuncProto. It
|
// haveProgBTF attempts to load a BTF blob containing a Func and FuncProto. It
|
||||||
// is used as a proxy for ext_info (func_info) support, which depends on
|
// is used as a proxy for ext_info (func_info) support, which depends on
|
||||||
// Func(Proto) by definition.
|
// Func(Proto) by definition.
|
||||||
var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0", func() error {
|
var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", func() error {
|
||||||
if err := haveBTF(); err != nil {
|
if err := haveBTF(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -60,9 +60,9 @@ var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0",
|
|||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.0")
|
||||||
|
|
||||||
var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func() error {
|
var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", func() error {
|
||||||
if err := haveProgBTF(); err != nil {
|
if err := haveProgBTF(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -78,9 +78,44 @@ var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func()
|
|||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.6")
|
||||||
|
|
||||||
var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error {
|
var haveDeclTags = internal.NewFeatureTest("BTF decl tags", func() error {
|
||||||
|
if err := haveBTF(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := &Typedef{
|
||||||
|
Name: "a",
|
||||||
|
Type: &Int{},
|
||||||
|
Tags: []string{"a"},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := probeBTF(t)
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
|
return internal.ErrNotSupported
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}, "5.16")
|
||||||
|
|
||||||
|
var haveTypeTags = internal.NewFeatureTest("BTF type tags", func() error {
|
||||||
|
if err := haveBTF(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := &TypeTag{
|
||||||
|
Type: &Int{},
|
||||||
|
Value: "a",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := probeBTF(t)
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
|
return internal.ErrNotSupported
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}, "5.17")
|
||||||
|
|
||||||
|
var haveEnum64 = internal.NewFeatureTest("ENUM64", func() error {
|
||||||
if err := haveBTF(); err != nil {
|
if err := haveBTF(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -97,7 +132,7 @@ var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error {
|
|||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "6.0")
|
||||||
|
|
||||||
func probeBTF(typ Type) error {
|
func probeBTF(typ Type) error {
|
||||||
b, err := NewBuilder([]Type{typ})
|
b, err := NewBuilder([]Type{typ})
|
||||||
|
|||||||
3
vendor/github.com/cilium/ebpf/btf/format.go
generated
vendored
3
vendor/github.com/cilium/ebpf/btf/format.go
generated
vendored
@@ -161,6 +161,9 @@ func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
|
|||||||
case *Datasec:
|
case *Datasec:
|
||||||
err = gf.writeDatasecLit(v, depth)
|
err = gf.writeDatasecLit(v, depth)
|
||||||
|
|
||||||
|
case *Var:
|
||||||
|
err = gf.writeTypeLit(v.Type, depth)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("type %T: %w", v, ErrNotSupported)
|
return fmt.Errorf("type %T: %w", v, ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|||||||
6
vendor/github.com/cilium/ebpf/btf/kernel.go
generated
vendored
6
vendor/github.com/cilium/ebpf/btf/kernel.go
generated
vendored
@@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/kallsyms"
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
)
|
)
|
||||||
|
|
||||||
var kernelBTF = struct {
|
var kernelBTF = struct {
|
||||||
@@ -21,8 +21,6 @@ var kernelBTF = struct {
|
|||||||
|
|
||||||
// FlushKernelSpec removes any cached kernel type information.
|
// FlushKernelSpec removes any cached kernel type information.
|
||||||
func FlushKernelSpec() {
|
func FlushKernelSpec() {
|
||||||
kallsyms.FlushKernelModuleCache()
|
|
||||||
|
|
||||||
kernelBTF.Lock()
|
kernelBTF.Lock()
|
||||||
defer kernelBTF.Unlock()
|
defer kernelBTF.Unlock()
|
||||||
|
|
||||||
@@ -130,7 +128,7 @@ func loadKernelModuleSpec(module string, base *Spec) (*Spec, error) {
|
|||||||
|
|
||||||
// findVMLinux scans multiple well-known paths for vmlinux kernel images.
|
// findVMLinux scans multiple well-known paths for vmlinux kernel images.
|
||||||
func findVMLinux() (*os.File, error) {
|
func findVMLinux() (*os.File, error) {
|
||||||
release, err := internal.KernelRelease()
|
release, err := linux.KernelRelease()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
83
vendor/github.com/cilium/ebpf/btf/marshal.go
generated
vendored
83
vendor/github.com/cilium/ebpf/btf/marshal.go
generated
vendored
@@ -18,6 +18,10 @@ type MarshalOptions struct {
|
|||||||
Order binary.ByteOrder
|
Order binary.ByteOrder
|
||||||
// Remove function linkage information for compatibility with <5.6 kernels.
|
// Remove function linkage information for compatibility with <5.6 kernels.
|
||||||
StripFuncLinkage bool
|
StripFuncLinkage bool
|
||||||
|
// Replace decl tags with a placeholder for compatibility with <5.16 kernels.
|
||||||
|
ReplaceDeclTags bool
|
||||||
|
// Replace TypeTags with a placeholder for compatibility with <5.17 kernels.
|
||||||
|
ReplaceTypeTags bool
|
||||||
// Replace Enum64 with a placeholder for compatibility with <6.0 kernels.
|
// Replace Enum64 with a placeholder for compatibility with <6.0 kernels.
|
||||||
ReplaceEnum64 bool
|
ReplaceEnum64 bool
|
||||||
// Prevent the "No type found" error when loading BTF without any types.
|
// Prevent the "No type found" error when loading BTF without any types.
|
||||||
@@ -29,6 +33,8 @@ func KernelMarshalOptions() *MarshalOptions {
|
|||||||
return &MarshalOptions{
|
return &MarshalOptions{
|
||||||
Order: internal.NativeEndian,
|
Order: internal.NativeEndian,
|
||||||
StripFuncLinkage: haveFuncLinkage() != nil,
|
StripFuncLinkage: haveFuncLinkage() != nil,
|
||||||
|
ReplaceDeclTags: haveDeclTags() != nil,
|
||||||
|
ReplaceTypeTags: haveTypeTags() != nil,
|
||||||
ReplaceEnum64: haveEnum64() != nil,
|
ReplaceEnum64: haveEnum64() != nil,
|
||||||
PreventNoTypeFound: true, // All current kernels require this.
|
PreventNoTypeFound: true, // All current kernels require this.
|
||||||
}
|
}
|
||||||
@@ -318,15 +324,7 @@ func (e *encoder) deflateType(typ Type) (err error) {
|
|||||||
return errors.New("Void is implicit in BTF wire format")
|
return errors.New("Void is implicit in BTF wire format")
|
||||||
|
|
||||||
case *Int:
|
case *Int:
|
||||||
raw.SetKind(kindInt)
|
e.deflateInt(&raw, v)
|
||||||
raw.SetSize(v.Size)
|
|
||||||
|
|
||||||
var bi btfInt
|
|
||||||
bi.SetEncoding(v.Encoding)
|
|
||||||
// We need to set bits in addition to size, since btf_type_int_is_regular
|
|
||||||
// otherwise flags this as a bitfield.
|
|
||||||
bi.SetBits(byte(v.Size) * 8)
|
|
||||||
raw.data = bi
|
|
||||||
|
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
raw.SetKind(kindPointer)
|
raw.SetKind(kindPointer)
|
||||||
@@ -368,8 +366,7 @@ func (e *encoder) deflateType(typ Type) (err error) {
|
|||||||
raw.SetType(e.id(v.Type))
|
raw.SetType(e.id(v.Type))
|
||||||
|
|
||||||
case *Const:
|
case *Const:
|
||||||
raw.SetKind(kindConst)
|
e.deflateConst(&raw, v)
|
||||||
raw.SetType(e.id(v.Type))
|
|
||||||
|
|
||||||
case *Restrict:
|
case *Restrict:
|
||||||
raw.SetKind(kindRestrict)
|
raw.SetKind(kindRestrict)
|
||||||
@@ -404,15 +401,10 @@ func (e *encoder) deflateType(typ Type) (err error) {
|
|||||||
raw.SetSize(v.Size)
|
raw.SetSize(v.Size)
|
||||||
|
|
||||||
case *declTag:
|
case *declTag:
|
||||||
raw.SetKind(kindDeclTag)
|
err = e.deflateDeclTag(&raw, v)
|
||||||
raw.SetType(e.id(v.Type))
|
|
||||||
raw.data = &btfDeclTag{uint32(v.Index)}
|
|
||||||
raw.NameOff, err = e.strings.Add(v.Value)
|
|
||||||
|
|
||||||
case *typeTag:
|
case *TypeTag:
|
||||||
raw.SetKind(kindTypeTag)
|
err = e.deflateTypeTag(&raw, v)
|
||||||
raw.SetType(e.id(v.Type))
|
|
||||||
raw.NameOff, err = e.strings.Add(v.Value)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("don't know how to deflate %T", v)
|
return fmt.Errorf("don't know how to deflate %T", v)
|
||||||
@@ -425,6 +417,57 @@ func (e *encoder) deflateType(typ Type) (err error) {
|
|||||||
return raw.Marshal(e.buf, e.Order)
|
return raw.Marshal(e.buf, e.Order)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *encoder) deflateInt(raw *rawType, i *Int) {
|
||||||
|
raw.SetKind(kindInt)
|
||||||
|
raw.SetSize(i.Size)
|
||||||
|
|
||||||
|
var bi btfInt
|
||||||
|
bi.SetEncoding(i.Encoding)
|
||||||
|
// We need to set bits in addition to size, since btf_type_int_is_regular
|
||||||
|
// otherwise flags this as a bitfield.
|
||||||
|
bi.SetBits(byte(i.Size) * 8)
|
||||||
|
raw.data = bi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) deflateDeclTag(raw *rawType, tag *declTag) (err error) {
|
||||||
|
// Replace a decl tag with an integer for compatibility with <5.16 kernels,
|
||||||
|
// following libbpf behaviour.
|
||||||
|
if e.ReplaceDeclTags {
|
||||||
|
typ := &Int{"decl_tag_placeholder", 1, Unsigned}
|
||||||
|
e.deflateInt(raw, typ)
|
||||||
|
|
||||||
|
// Add the placeholder type name to the string table. The encoder added the
|
||||||
|
// original type name before this call.
|
||||||
|
raw.NameOff, err = e.strings.Add(typ.TypeName())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
raw.SetKind(kindDeclTag)
|
||||||
|
raw.SetType(e.id(tag.Type))
|
||||||
|
raw.data = &btfDeclTag{uint32(tag.Index)}
|
||||||
|
raw.NameOff, err = e.strings.Add(tag.Value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) deflateConst(raw *rawType, c *Const) {
|
||||||
|
raw.SetKind(kindConst)
|
||||||
|
raw.SetType(e.id(c.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) deflateTypeTag(raw *rawType, tag *TypeTag) (err error) {
|
||||||
|
// Replace a type tag with a const qualifier for compatibility with <5.17
|
||||||
|
// kernels, following libbpf behaviour.
|
||||||
|
if e.ReplaceTypeTags {
|
||||||
|
e.deflateConst(raw, &Const{tag.Type})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
raw.SetKind(kindTypeTag)
|
||||||
|
raw.SetType(e.id(tag.Type))
|
||||||
|
raw.NameOff, err = e.strings.Add(tag.Value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (e *encoder) deflateUnion(raw *rawType, union *Union) (err error) {
|
func (e *encoder) deflateUnion(raw *rawType, union *Union) (err error) {
|
||||||
raw.SetKind(kindUnion)
|
raw.SetKind(kindUnion)
|
||||||
raw.SetSize(union.Size)
|
raw.SetSize(union.Size)
|
||||||
@@ -521,7 +564,7 @@ func (e *encoder) deflateEnum64(raw *rawType, enum *Enum) (err error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.deflateUnion(raw, &Union{enum.Name, enum.Size, members})
|
return e.deflateUnion(raw, &Union{enum.Name, enum.Size, members, nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
raw.SetKind(kindEnum64)
|
raw.SetKind(kindEnum64)
|
||||||
|
|||||||
48
vendor/github.com/cilium/ebpf/btf/traversal.go
generated
vendored
48
vendor/github.com/cilium/ebpf/btf/traversal.go
generated
vendored
@@ -40,9 +40,12 @@ func children(typ Type, yield func(child *Type) bool) bool {
|
|||||||
// Explicitly type switch on the most common types to allow the inliner to
|
// Explicitly type switch on the most common types to allow the inliner to
|
||||||
// do its work. This avoids allocating intermediate slices from walk() on
|
// do its work. This avoids allocating intermediate slices from walk() on
|
||||||
// the heap.
|
// the heap.
|
||||||
|
var tags []string
|
||||||
switch v := typ.(type) {
|
switch v := typ.(type) {
|
||||||
case *Void, *Int, *Enum, *Fwd, *Float:
|
case *Void, *Int, *Enum, *Fwd, *Float, *declTag:
|
||||||
// No children to traverse.
|
// No children to traverse.
|
||||||
|
// declTags is declared as a leaf type since it's parsed into .Tags fields of other types
|
||||||
|
// during unmarshaling.
|
||||||
case *Pointer:
|
case *Pointer:
|
||||||
if !yield(&v.Target) {
|
if !yield(&v.Target) {
|
||||||
return false
|
return false
|
||||||
@@ -59,17 +62,32 @@ func children(typ Type, yield func(child *Type) bool) bool {
|
|||||||
if !yield(&v.Members[i].Type) {
|
if !yield(&v.Members[i].Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
for _, t := range v.Members[i].Tags {
|
||||||
|
var tag Type = &declTag{v, t, i}
|
||||||
|
if !yield(&tag) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags = v.Tags
|
||||||
case *Union:
|
case *Union:
|
||||||
for i := range v.Members {
|
for i := range v.Members {
|
||||||
if !yield(&v.Members[i].Type) {
|
if !yield(&v.Members[i].Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
for _, t := range v.Members[i].Tags {
|
||||||
|
var tag Type = &declTag{v, t, i}
|
||||||
|
if !yield(&tag) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags = v.Tags
|
||||||
case *Typedef:
|
case *Typedef:
|
||||||
if !yield(&v.Type) {
|
if !yield(&v.Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
tags = v.Tags
|
||||||
case *Volatile:
|
case *Volatile:
|
||||||
if !yield(&v.Type) {
|
if !yield(&v.Type) {
|
||||||
return false
|
return false
|
||||||
@@ -86,6 +104,20 @@ func children(typ Type, yield func(child *Type) bool) bool {
|
|||||||
if !yield(&v.Type) {
|
if !yield(&v.Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if fp, ok := v.Type.(*FuncProto); ok {
|
||||||
|
for i := range fp.Params {
|
||||||
|
if len(v.ParamTags) <= i {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, t := range v.ParamTags[i] {
|
||||||
|
var tag Type = &declTag{v, t, i}
|
||||||
|
if !yield(&tag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags = v.Tags
|
||||||
case *FuncProto:
|
case *FuncProto:
|
||||||
if !yield(&v.Return) {
|
if !yield(&v.Return) {
|
||||||
return false
|
return false
|
||||||
@@ -99,17 +131,14 @@ func children(typ Type, yield func(child *Type) bool) bool {
|
|||||||
if !yield(&v.Type) {
|
if !yield(&v.Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
tags = v.Tags
|
||||||
case *Datasec:
|
case *Datasec:
|
||||||
for i := range v.Vars {
|
for i := range v.Vars {
|
||||||
if !yield(&v.Vars[i].Type) {
|
if !yield(&v.Vars[i].Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *declTag:
|
case *TypeTag:
|
||||||
if !yield(&v.Type) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case *typeTag:
|
|
||||||
if !yield(&v.Type) {
|
if !yield(&v.Type) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -119,5 +148,12 @@ func children(typ Type, yield func(child *Type) bool) bool {
|
|||||||
panic(fmt.Sprintf("don't know how to walk Type %T", v))
|
panic(fmt.Sprintf("don't know how to walk Type %T", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, t := range tags {
|
||||||
|
var tag Type = &declTag{typ, t, -1}
|
||||||
|
if !yield(&tag) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
138
vendor/github.com/cilium/ebpf/btf/types.go
generated
vendored
138
vendor/github.com/cilium/ebpf/btf/types.go
generated
vendored
@@ -67,7 +67,7 @@ var (
|
|||||||
_ Type = (*Datasec)(nil)
|
_ Type = (*Datasec)(nil)
|
||||||
_ Type = (*Float)(nil)
|
_ Type = (*Float)(nil)
|
||||||
_ Type = (*declTag)(nil)
|
_ Type = (*declTag)(nil)
|
||||||
_ Type = (*typeTag)(nil)
|
_ Type = (*TypeTag)(nil)
|
||||||
_ Type = (*cycle)(nil)
|
_ Type = (*cycle)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -169,6 +169,7 @@ type Struct struct {
|
|||||||
// The size of the struct including padding, in bytes
|
// The size of the struct including padding, in bytes
|
||||||
Size uint32
|
Size uint32
|
||||||
Members []Member
|
Members []Member
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Struct) Format(fs fmt.State, verb rune) {
|
func (s *Struct) Format(fs fmt.State, verb rune) {
|
||||||
@@ -182,6 +183,7 @@ func (s *Struct) size() uint32 { return s.Size }
|
|||||||
func (s *Struct) copy() Type {
|
func (s *Struct) copy() Type {
|
||||||
cpy := *s
|
cpy := *s
|
||||||
cpy.Members = copyMembers(s.Members)
|
cpy.Members = copyMembers(s.Members)
|
||||||
|
cpy.Tags = copyTags(cpy.Tags)
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +197,7 @@ type Union struct {
|
|||||||
// The size of the union including padding, in bytes.
|
// The size of the union including padding, in bytes.
|
||||||
Size uint32
|
Size uint32
|
||||||
Members []Member
|
Members []Member
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Union) Format(fs fmt.State, verb rune) {
|
func (u *Union) Format(fs fmt.State, verb rune) {
|
||||||
@@ -208,6 +211,7 @@ func (u *Union) size() uint32 { return u.Size }
|
|||||||
func (u *Union) copy() Type {
|
func (u *Union) copy() Type {
|
||||||
cpy := *u
|
cpy := *u
|
||||||
cpy.Members = copyMembers(u.Members)
|
cpy.Members = copyMembers(u.Members)
|
||||||
|
cpy.Tags = copyTags(cpy.Tags)
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +222,18 @@ func (u *Union) members() []Member {
|
|||||||
func copyMembers(orig []Member) []Member {
|
func copyMembers(orig []Member) []Member {
|
||||||
cpy := make([]Member, len(orig))
|
cpy := make([]Member, len(orig))
|
||||||
copy(cpy, orig)
|
copy(cpy, orig)
|
||||||
|
for i, member := range cpy {
|
||||||
|
cpy[i].Tags = copyTags(member.Tags)
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyTags(orig []string) []string {
|
||||||
|
if orig == nil { // preserve nil vs zero-len slice distinction
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
cpy := make([]string, len(orig))
|
||||||
|
copy(cpy, orig)
|
||||||
return cpy
|
return cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +263,7 @@ type Member struct {
|
|||||||
Type Type
|
Type Type
|
||||||
Offset Bits
|
Offset Bits
|
||||||
BitfieldSize Bits
|
BitfieldSize Bits
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum lists possible values.
|
// Enum lists possible values.
|
||||||
@@ -334,6 +351,7 @@ func (f *Fwd) matches(typ Type) bool {
|
|||||||
type Typedef struct {
|
type Typedef struct {
|
||||||
Name string
|
Name string
|
||||||
Type Type
|
Type Type
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (td *Typedef) Format(fs fmt.State, verb rune) {
|
func (td *Typedef) Format(fs fmt.State, verb rune) {
|
||||||
@@ -344,6 +362,7 @@ func (td *Typedef) TypeName() string { return td.Name }
|
|||||||
|
|
||||||
func (td *Typedef) copy() Type {
|
func (td *Typedef) copy() Type {
|
||||||
cpy := *td
|
cpy := *td
|
||||||
|
cpy.Tags = copyTags(td.Tags)
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +422,12 @@ type Func struct {
|
|||||||
Name string
|
Name string
|
||||||
Type Type
|
Type Type
|
||||||
Linkage FuncLinkage
|
Linkage FuncLinkage
|
||||||
|
Tags []string
|
||||||
|
// ParamTags holds a list of tags for each parameter of the FuncProto to which `Type` points.
|
||||||
|
// If no tags are present for any param, the outer slice will be nil/len(ParamTags)==0.
|
||||||
|
// If at least 1 param has a tag, the outer slice will have the same length as the number of params.
|
||||||
|
// The inner slice contains the tags and may be nil/len(ParamTags[i])==0 if no tags are present for that param.
|
||||||
|
ParamTags [][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func FuncMetadata(ins *asm.Instruction) *Func {
|
func FuncMetadata(ins *asm.Instruction) *Func {
|
||||||
@@ -424,6 +449,14 @@ func (f *Func) TypeName() string { return f.Name }
|
|||||||
|
|
||||||
func (f *Func) copy() Type {
|
func (f *Func) copy() Type {
|
||||||
cpy := *f
|
cpy := *f
|
||||||
|
cpy.Tags = copyTags(f.Tags)
|
||||||
|
if f.ParamTags != nil { // preserve nil vs zero-len slice distinction
|
||||||
|
ptCopy := make([][]string, len(f.ParamTags))
|
||||||
|
for i, tags := range f.ParamTags {
|
||||||
|
ptCopy[i] = copyTags(tags)
|
||||||
|
}
|
||||||
|
cpy.ParamTags = ptCopy
|
||||||
|
}
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,6 +489,7 @@ type Var struct {
|
|||||||
Name string
|
Name string
|
||||||
Type Type
|
Type Type
|
||||||
Linkage VarLinkage
|
Linkage VarLinkage
|
||||||
|
Tags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Var) Format(fs fmt.State, verb rune) {
|
func (v *Var) Format(fs fmt.State, verb rune) {
|
||||||
@@ -466,6 +500,7 @@ func (v *Var) TypeName() string { return v.Name }
|
|||||||
|
|
||||||
func (v *Var) copy() Type {
|
func (v *Var) copy() Type {
|
||||||
cpy := *v
|
cpy := *v
|
||||||
|
cpy.Tags = copyTags(v.Tags)
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,19 +575,25 @@ func (dt *declTag) copy() Type {
|
|||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeTag associates metadata with a type.
|
// TypeTag associates metadata with a pointer type. Tag types act as a custom
|
||||||
type typeTag struct {
|
// modifier(const, restrict, volatile) for the target type. Unlike declTags,
|
||||||
|
// TypeTags are ordered so the order in which they are added matters.
|
||||||
|
//
|
||||||
|
// One of their uses is to mark pointers as `__kptr` meaning a pointer points
|
||||||
|
// to kernel memory. Adding a `__kptr` to pointers in map values allows you
|
||||||
|
// to store pointers to kernel memory in maps.
|
||||||
|
type TypeTag struct {
|
||||||
Type Type
|
Type Type
|
||||||
Value string
|
Value string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt *typeTag) Format(fs fmt.State, verb rune) {
|
func (tt *TypeTag) Format(fs fmt.State, verb rune) {
|
||||||
formatType(fs, verb, tt, "type=", tt.Type, "value=", tt.Value)
|
formatType(fs, verb, tt, "type=", tt.Type, "value=", tt.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tt *typeTag) TypeName() string { return "" }
|
func (tt *TypeTag) TypeName() string { return "" }
|
||||||
func (tt *typeTag) qualify() Type { return tt.Type }
|
func (tt *TypeTag) qualify() Type { return tt.Type }
|
||||||
func (tt *typeTag) copy() Type {
|
func (tt *TypeTag) copy() Type {
|
||||||
cpy := *tt
|
cpy := *tt
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
@@ -591,7 +632,7 @@ var (
|
|||||||
_ qualifier = (*Const)(nil)
|
_ qualifier = (*Const)(nil)
|
||||||
_ qualifier = (*Restrict)(nil)
|
_ qualifier = (*Restrict)(nil)
|
||||||
_ qualifier = (*Volatile)(nil)
|
_ qualifier = (*Volatile)(nil)
|
||||||
_ qualifier = (*typeTag)(nil)
|
_ qualifier = (*TypeTag)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
var errUnsizedType = errors.New("type is unsized")
|
var errUnsizedType = errors.New("type is unsized")
|
||||||
@@ -918,7 +959,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
|
return nil, fmt.Errorf("struct %s (id %d): %w", name, id, err)
|
||||||
}
|
}
|
||||||
typ = &Struct{name, header.Size(), members}
|
typ = &Struct{name, header.Size(), members, nil}
|
||||||
|
|
||||||
case kindUnion:
|
case kindUnion:
|
||||||
vlen := header.Vlen()
|
vlen := header.Vlen()
|
||||||
@@ -935,7 +976,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
|
return nil, fmt.Errorf("union %s (id %d): %w", name, id, err)
|
||||||
}
|
}
|
||||||
typ = &Union{name, header.Size(), members}
|
typ = &Union{name, header.Size(), members, nil}
|
||||||
|
|
||||||
case kindEnum:
|
case kindEnum:
|
||||||
vlen := header.Vlen()
|
vlen := header.Vlen()
|
||||||
@@ -968,7 +1009,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
typ = &Fwd{name, header.FwdKind()}
|
typ = &Fwd{name, header.FwdKind()}
|
||||||
|
|
||||||
case kindTypedef:
|
case kindTypedef:
|
||||||
typedef := &Typedef{name, nil}
|
typedef := &Typedef{name, nil, nil}
|
||||||
fixup(header.Type(), &typedef.Type)
|
fixup(header.Type(), &typedef.Type)
|
||||||
typ = typedef
|
typ = typedef
|
||||||
|
|
||||||
@@ -988,7 +1029,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
typ = restrict
|
typ = restrict
|
||||||
|
|
||||||
case kindFunc:
|
case kindFunc:
|
||||||
fn := &Func{name, nil, header.Linkage()}
|
fn := &Func{name, nil, header.Linkage(), nil, nil}
|
||||||
fixup(header.Type(), &fn.Type)
|
fixup(header.Type(), &fn.Type)
|
||||||
typ = fn
|
typ = fn
|
||||||
|
|
||||||
@@ -1030,7 +1071,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
return nil, fmt.Errorf("can't read btfVariable, id: %d: %w", id, err)
|
return nil, fmt.Errorf("can't read btfVariable, id: %d: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &Var{name, nil, VarLinkage(bVariable.Linkage)}
|
v := &Var{name, nil, VarLinkage(bVariable.Linkage), nil}
|
||||||
fixup(header.Type(), &v.Type)
|
fixup(header.Type(), &v.Type)
|
||||||
typ = v
|
typ = v
|
||||||
|
|
||||||
@@ -1081,7 +1122,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
declTags = append(declTags, dt)
|
declTags = append(declTags, dt)
|
||||||
|
|
||||||
case kindTypeTag:
|
case kindTypeTag:
|
||||||
tt := &typeTag{nil, name}
|
tt := &TypeTag{nil, name}
|
||||||
fixup(header.Type(), &tt.Type)
|
fixup(header.Type(), &tt.Type)
|
||||||
typ = tt
|
typ = tt
|
||||||
|
|
||||||
@@ -1142,26 +1183,69 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
|
|||||||
|
|
||||||
for _, dt := range declTags {
|
for _, dt := range declTags {
|
||||||
switch t := dt.Type.(type) {
|
switch t := dt.Type.(type) {
|
||||||
case *Var, *Typedef:
|
case *Var:
|
||||||
if dt.Index != -1 {
|
if dt.Index != -1 {
|
||||||
return nil, fmt.Errorf("type %s: index %d is not -1", dt, dt.Index)
|
return nil, fmt.Errorf("type %s: component idx %d is not -1", dt, dt.Index)
|
||||||
}
|
}
|
||||||
|
t.Tags = append(t.Tags, dt.Value)
|
||||||
|
|
||||||
|
case *Typedef:
|
||||||
|
if dt.Index != -1 {
|
||||||
|
return nil, fmt.Errorf("type %s: component idx %d is not -1", dt, dt.Index)
|
||||||
|
}
|
||||||
|
t.Tags = append(t.Tags, dt.Value)
|
||||||
|
|
||||||
case composite:
|
case composite:
|
||||||
if dt.Index >= len(t.members()) {
|
if dt.Index >= 0 {
|
||||||
return nil, fmt.Errorf("type %s: index %d exceeds members of %s", dt, dt.Index, t)
|
members := t.members()
|
||||||
|
if dt.Index >= len(members) {
|
||||||
|
return nil, fmt.Errorf("type %s: component idx %d exceeds members of %s", dt, dt.Index, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
members[dt.Index].Tags = append(members[dt.Index].Tags, dt.Value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if dt.Index == -1 {
|
||||||
|
switch t2 := t.(type) {
|
||||||
|
case *Struct:
|
||||||
|
t2.Tags = append(t2.Tags, dt.Value)
|
||||||
|
case *Union:
|
||||||
|
t2.Tags = append(t2.Tags, dt.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("type %s: decl tag for type %s has invalid component idx", dt, t)
|
||||||
|
|
||||||
case *Func:
|
case *Func:
|
||||||
fp, ok := t.Type.(*FuncProto)
|
fp, ok := t.Type.(*FuncProto)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("type %s: %s is not a FuncProto", dt, t.Type)
|
return nil, fmt.Errorf("type %s: %s is not a FuncProto", dt, t.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dt.Index >= len(fp.Params) {
|
// Ensure the number of argument tag lists equals the number of arguments
|
||||||
return nil, fmt.Errorf("type %s: index %d exceeds params of %s", dt, dt.Index, t)
|
if len(t.ParamTags) == 0 {
|
||||||
|
t.ParamTags = make([][]string, len(fp.Params))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dt.Index >= 0 {
|
||||||
|
if dt.Index >= len(fp.Params) {
|
||||||
|
return nil, fmt.Errorf("type %s: component idx %d exceeds params of %s", dt, dt.Index, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.ParamTags[dt.Index] = append(t.ParamTags[dt.Index], dt.Value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if dt.Index == -1 {
|
||||||
|
t.Tags = append(t.Tags, dt.Value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("type %s: decl tag for type %s has invalid component idx", dt, t)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("type %s: decl tag for type %s is not supported", dt, t)
|
return nil, fmt.Errorf("type %s: decl tag for type %s is not supported", dt, t)
|
||||||
}
|
}
|
||||||
@@ -1207,6 +1291,20 @@ func UnderlyingType(typ Type) Type {
|
|||||||
return &cycle{typ}
|
return &cycle{typ}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QualifiedType returns the type with all qualifiers removed.
|
||||||
|
func QualifiedType(typ Type) Type {
|
||||||
|
result := typ
|
||||||
|
for depth := 0; depth <= maxResolveDepth; depth++ {
|
||||||
|
switch v := (result).(type) {
|
||||||
|
case qualifier:
|
||||||
|
result = v.qualify()
|
||||||
|
default:
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &cycle{typ}
|
||||||
|
}
|
||||||
|
|
||||||
// As returns typ if is of type T. Otherwise it peels qualifiers and Typedefs
|
// As returns typ if is of type T. Otherwise it peels qualifiers and Typedefs
|
||||||
// until it finds a T.
|
// until it finds a T.
|
||||||
//
|
//
|
||||||
|
|||||||
2
vendor/github.com/cilium/ebpf/btf/workarounds.go
generated
vendored
2
vendor/github.com/cilium/ebpf/btf/workarounds.go
generated
vendored
@@ -12,7 +12,7 @@ func datasecResolveWorkaround(b *Builder, ds *Datasec) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch v.Type.(type) {
|
switch v.Type.(type) {
|
||||||
case *Typedef, *Volatile, *Const, *Restrict, *typeTag:
|
case *Typedef, *Volatile, *Const, *Restrict, *TypeTag:
|
||||||
// NB: We must never call Add on a Datasec, otherwise we risk
|
// NB: We must never call Add on a Datasec, otherwise we risk
|
||||||
// infinite recursion.
|
// infinite recursion.
|
||||||
_, err := b.Add(v.Type)
|
_, err := b.Add(v.Type)
|
||||||
|
|||||||
257
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
257
vendor/github.com/cilium/ebpf/collection.go
generated
vendored
@@ -10,8 +10,10 @@ import (
|
|||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/kallsyms"
|
||||||
"github.com/cilium/ebpf/internal/kconfig"
|
"github.com/cilium/ebpf/internal/kconfig"
|
||||||
"github.com/cilium/ebpf/internal/sysenc"
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CollectionOptions control loading a collection into the kernel.
|
// CollectionOptions control loading a collection into the kernel.
|
||||||
@@ -38,6 +40,11 @@ type CollectionSpec struct {
|
|||||||
Maps map[string]*MapSpec
|
Maps map[string]*MapSpec
|
||||||
Programs map[string]*ProgramSpec
|
Programs map[string]*ProgramSpec
|
||||||
|
|
||||||
|
// Variables refer to global variables declared in the ELF. They can be read
|
||||||
|
// and modified freely before loading the Collection. Modifying them after
|
||||||
|
// loading has no effect on a running eBPF program.
|
||||||
|
Variables map[string]*VariableSpec
|
||||||
|
|
||||||
// Types holds type information about Maps and Programs.
|
// Types holds type information about Maps and Programs.
|
||||||
// Modifications to Types are currently undefined behaviour.
|
// Modifications to Types are currently undefined behaviour.
|
||||||
Types *btf.Spec
|
Types *btf.Spec
|
||||||
@@ -56,6 +63,7 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
|
|||||||
cpy := CollectionSpec{
|
cpy := CollectionSpec{
|
||||||
Maps: make(map[string]*MapSpec, len(cs.Maps)),
|
Maps: make(map[string]*MapSpec, len(cs.Maps)),
|
||||||
Programs: make(map[string]*ProgramSpec, len(cs.Programs)),
|
Programs: make(map[string]*ProgramSpec, len(cs.Programs)),
|
||||||
|
Variables: make(map[string]*VariableSpec, len(cs.Variables)),
|
||||||
ByteOrder: cs.ByteOrder,
|
ByteOrder: cs.ByteOrder,
|
||||||
Types: cs.Types.Copy(),
|
Types: cs.Types.Copy(),
|
||||||
}
|
}
|
||||||
@@ -68,6 +76,10 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
|
|||||||
cpy.Programs[name] = spec.Copy()
|
cpy.Programs[name] = spec.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, spec := range cs.Variables {
|
||||||
|
cpy.Variables[name] = spec.copy(&cpy)
|
||||||
|
}
|
||||||
|
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,65 +146,24 @@ func (m *MissingConstantsError) Error() string {
|
|||||||
// From Linux 5.5 the verifier will use constants to eliminate dead code.
|
// From Linux 5.5 the verifier will use constants to eliminate dead code.
|
||||||
//
|
//
|
||||||
// Returns an error wrapping [MissingConstantsError] if a constant doesn't exist.
|
// Returns an error wrapping [MissingConstantsError] if a constant doesn't exist.
|
||||||
|
//
|
||||||
|
// Deprecated: Use [CollectionSpec.Variables] to interact with constants instead.
|
||||||
|
// RewriteConstants is now a wrapper around the VariableSpec API.
|
||||||
func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error {
|
func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error {
|
||||||
replaced := make(map[string]bool)
|
|
||||||
|
|
||||||
for name, spec := range cs.Maps {
|
|
||||||
if !strings.HasPrefix(name, ".rodata") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
b, ds, err := spec.dataSection()
|
|
||||||
if errors.Is(err, errMapNoBTFValue) {
|
|
||||||
// Data sections without a BTF Datasec are valid, but don't support
|
|
||||||
// constant replacements.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("map %s: %w", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapSpec.Copy() performs a shallow copy. Fully copy the byte slice
|
|
||||||
// to avoid any changes affecting other copies of the MapSpec.
|
|
||||||
cpy := make([]byte, len(b))
|
|
||||||
copy(cpy, b)
|
|
||||||
|
|
||||||
for _, v := range ds.Vars {
|
|
||||||
vname := v.Type.TypeName()
|
|
||||||
replacement, ok := consts[vname]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := v.Type.(*btf.Var); !ok {
|
|
||||||
return fmt.Errorf("section %s: unexpected type %T for variable %s", name, v.Type, vname)
|
|
||||||
}
|
|
||||||
|
|
||||||
if replaced[vname] {
|
|
||||||
return fmt.Errorf("section %s: duplicate variable %s", name, vname)
|
|
||||||
}
|
|
||||||
|
|
||||||
if int(v.Offset+v.Size) > len(cpy) {
|
|
||||||
return fmt.Errorf("section %s: offset %d(+%d) for variable %s is out of bounds", name, v.Offset, v.Size, vname)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := sysenc.Marshal(replacement, int(v.Size))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("marshaling constant replacement %s: %w", vname, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.CopyTo(cpy[v.Offset : v.Offset+v.Size])
|
|
||||||
|
|
||||||
replaced[vname] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
spec.Contents[0] = MapKV{Key: uint32(0), Value: cpy}
|
|
||||||
}
|
|
||||||
|
|
||||||
var missing []string
|
var missing []string
|
||||||
for c := range consts {
|
for n, c := range consts {
|
||||||
if !replaced[c] {
|
v, ok := cs.Variables[n]
|
||||||
missing = append(missing, c)
|
if !ok {
|
||||||
|
missing = append(missing, n)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.Constant() {
|
||||||
|
return fmt.Errorf("variable %s is not a constant", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.Set(c); err != nil {
|
||||||
|
return fmt.Errorf("rewriting constant %s: %w", n, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,25 +181,23 @@ func (cs *CollectionSpec) RewriteConstants(consts map[string]interface{}) error
|
|||||||
// if this sounds useful.
|
// if this sounds useful.
|
||||||
//
|
//
|
||||||
// 'to' must be a pointer to a struct. A field of the
|
// 'to' must be a pointer to a struct. A field of the
|
||||||
// struct is updated with values from Programs or Maps if it
|
// struct is updated with values from Programs, Maps or Variables if it
|
||||||
// has an `ebpf` tag and its type is *ProgramSpec or *MapSpec.
|
// has an `ebpf` tag and its type is *ProgramSpec, *MapSpec or *VariableSpec.
|
||||||
// The tag's value specifies the name of the program or map as
|
// The tag's value specifies the name of the program or map as
|
||||||
// found in the CollectionSpec.
|
// found in the CollectionSpec.
|
||||||
//
|
//
|
||||||
// struct {
|
// struct {
|
||||||
// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"`
|
// Foo *ebpf.ProgramSpec `ebpf:"xdp_foo"`
|
||||||
// Bar *ebpf.MapSpec `ebpf:"bar_map"`
|
// Bar *ebpf.MapSpec `ebpf:"bar_map"`
|
||||||
|
// Var *ebpf.VariableSpec `ebpf:"some_var"`
|
||||||
// Ignored int
|
// Ignored int
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Returns an error if any of the eBPF objects can't be found, or
|
// Returns an error if any of the eBPF objects can't be found, or
|
||||||
// if the same MapSpec or ProgramSpec is assigned multiple times.
|
// if the same Spec is assigned multiple times.
|
||||||
func (cs *CollectionSpec) Assign(to interface{}) error {
|
func (cs *CollectionSpec) Assign(to interface{}) error {
|
||||||
// Assign() only supports assigning ProgramSpecs and MapSpecs,
|
|
||||||
// so doesn't load any resources into the kernel.
|
|
||||||
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
||||||
switch typ {
|
switch typ {
|
||||||
|
|
||||||
case reflect.TypeOf((*ProgramSpec)(nil)):
|
case reflect.TypeOf((*ProgramSpec)(nil)):
|
||||||
if p := cs.Programs[name]; p != nil {
|
if p := cs.Programs[name]; p != nil {
|
||||||
return p, nil
|
return p, nil
|
||||||
@@ -241,6 +210,12 @@ func (cs *CollectionSpec) Assign(to interface{}) error {
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("missing map %q", name)
|
return nil, fmt.Errorf("missing map %q", name)
|
||||||
|
|
||||||
|
case reflect.TypeOf((*VariableSpec)(nil)):
|
||||||
|
if v := cs.Variables[name]; v != nil {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("missing variable %q", name)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported type %s", typ)
|
return nil, fmt.Errorf("unsupported type %s", typ)
|
||||||
}
|
}
|
||||||
@@ -286,6 +261,7 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
|
|||||||
// Support assigning Programs and Maps, lazy-loading the required objects.
|
// Support assigning Programs and Maps, lazy-loading the required objects.
|
||||||
assignedMaps := make(map[string]bool)
|
assignedMaps := make(map[string]bool)
|
||||||
assignedProgs := make(map[string]bool)
|
assignedProgs := make(map[string]bool)
|
||||||
|
assignedVars := make(map[string]bool)
|
||||||
|
|
||||||
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
getValue := func(typ reflect.Type, name string) (interface{}, error) {
|
||||||
switch typ {
|
switch typ {
|
||||||
@@ -298,6 +274,10 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
|
|||||||
assignedMaps[name] = true
|
assignedMaps[name] = true
|
||||||
return loader.loadMap(name)
|
return loader.loadMap(name)
|
||||||
|
|
||||||
|
case reflect.TypeOf((*Variable)(nil)):
|
||||||
|
assignedVars[name] = true
|
||||||
|
return loader.loadVariable(name)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported type %s", typ)
|
return nil, fmt.Errorf("unsupported type %s", typ)
|
||||||
}
|
}
|
||||||
@@ -338,15 +318,22 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
|
|||||||
for p := range assignedProgs {
|
for p := range assignedProgs {
|
||||||
delete(loader.programs, p)
|
delete(loader.programs, p)
|
||||||
}
|
}
|
||||||
|
for p := range assignedVars {
|
||||||
|
delete(loader.vars, p)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collection is a collection of Programs and Maps associated
|
// Collection is a collection of live BPF resources present in the kernel.
|
||||||
// with their symbols
|
|
||||||
type Collection struct {
|
type Collection struct {
|
||||||
Programs map[string]*Program
|
Programs map[string]*Program
|
||||||
Maps map[string]*Map
|
Maps map[string]*Map
|
||||||
|
|
||||||
|
// Variables contains global variables used by the Collection's program(s). On
|
||||||
|
// kernels older than 5.5, most interactions with Variables return
|
||||||
|
// [ErrNotSupported].
|
||||||
|
Variables map[string]*Variable
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCollection creates a Collection from the given spec, creating and
|
// NewCollection creates a Collection from the given spec, creating and
|
||||||
@@ -387,19 +374,26 @@ func NewCollectionWithOptions(spec *CollectionSpec, opts CollectionOptions) (*Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for varName := range spec.Variables {
|
||||||
|
if _, err := loader.loadVariable(varName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Maps can contain Program and Map stubs, so populate them after
|
// Maps can contain Program and Map stubs, so populate them after
|
||||||
// all Maps and Programs have been successfully loaded.
|
// all Maps and Programs have been successfully loaded.
|
||||||
if err := loader.populateDeferredMaps(); err != nil {
|
if err := loader.populateDeferredMaps(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent loader.cleanup from closing maps and programs.
|
// Prevent loader.cleanup from closing maps, programs and vars.
|
||||||
maps, progs := loader.maps, loader.programs
|
maps, progs, vars := loader.maps, loader.programs, loader.vars
|
||||||
loader.maps, loader.programs = nil, nil
|
loader.maps, loader.programs, loader.vars = nil, nil, nil
|
||||||
|
|
||||||
return &Collection{
|
return &Collection{
|
||||||
progs,
|
progs,
|
||||||
maps,
|
maps,
|
||||||
|
vars,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +402,7 @@ type collectionLoader struct {
|
|||||||
opts *CollectionOptions
|
opts *CollectionOptions
|
||||||
maps map[string]*Map
|
maps map[string]*Map
|
||||||
programs map[string]*Program
|
programs map[string]*Program
|
||||||
|
vars map[string]*Variable
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collectionLoader, error) {
|
func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collectionLoader, error) {
|
||||||
@@ -427,14 +422,58 @@ func newCollectionLoader(coll *CollectionSpec, opts *CollectionOptions) (*collec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := populateKallsyms(coll.Programs); err != nil {
|
||||||
|
return nil, fmt.Errorf("populating kallsyms caches: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return &collectionLoader{
|
return &collectionLoader{
|
||||||
coll,
|
coll,
|
||||||
opts,
|
opts,
|
||||||
make(map[string]*Map),
|
make(map[string]*Map),
|
||||||
make(map[string]*Program),
|
make(map[string]*Program),
|
||||||
|
make(map[string]*Variable),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// populateKallsyms populates kallsyms caches, making lookups cheaper later on
|
||||||
|
// during individual program loading. Since we have less context available
|
||||||
|
// at those stages, we batch the lookups here instead to avoid redundant work.
|
||||||
|
func populateKallsyms(progs map[string]*ProgramSpec) error {
|
||||||
|
// Look up associated kernel modules for all symbols referenced by
|
||||||
|
// ProgramSpec.AttachTo for program types that support attaching to kmods.
|
||||||
|
mods := make(map[string]string)
|
||||||
|
for _, p := range progs {
|
||||||
|
if p.AttachTo != "" && p.targetsKernelModule() {
|
||||||
|
mods[p.AttachTo] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(mods) != 0 {
|
||||||
|
if err := kallsyms.AssignModules(mods); err != nil {
|
||||||
|
return fmt.Errorf("getting modules from kallsyms: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up addresses of all kernel symbols referenced by all programs.
|
||||||
|
addrs := make(map[string]uint64)
|
||||||
|
for _, p := range progs {
|
||||||
|
iter := p.Instructions.Iterate()
|
||||||
|
for iter.Next() {
|
||||||
|
ins := iter.Ins
|
||||||
|
meta, _ := ins.Metadata.Get(ksymMetaKey{}).(*ksymMeta)
|
||||||
|
if meta != nil {
|
||||||
|
addrs[meta.Name] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(addrs) != 0 {
|
||||||
|
if err := kallsyms.AssignAddresses(addrs); err != nil {
|
||||||
|
return fmt.Errorf("getting addresses from kallsyms: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// close all resources left over in the collectionLoader.
|
// close all resources left over in the collectionLoader.
|
||||||
func (cl *collectionLoader) close() {
|
func (cl *collectionLoader) close() {
|
||||||
for _, m := range cl.maps {
|
for _, m := range cl.maps {
|
||||||
@@ -466,6 +505,13 @@ func (cl *collectionLoader) loadMap(mapName string) (*Map, error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defer setting the mmapable flag on maps until load time. This avoids the
|
||||||
|
// MapSpec having different flags on some kernel versions. Also avoid running
|
||||||
|
// syscalls during ELF loading, so platforms like wasm can also parse an ELF.
|
||||||
|
if isDataSection(mapSpec.Name) && haveMmapableMaps() == nil {
|
||||||
|
mapSpec.Flags |= sys.BPF_F_MMAPABLE
|
||||||
|
}
|
||||||
|
|
||||||
m, err := newMapWithOptions(mapSpec, cl.opts.Maps)
|
m, err := newMapWithOptions(mapSpec, cl.opts.Maps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("map %s: %w", mapName, err)
|
return nil, fmt.Errorf("map %s: %w", mapName, err)
|
||||||
@@ -537,6 +583,58 @@ func (cl *collectionLoader) loadProgram(progName string) (*Program, error) {
|
|||||||
return prog, nil
|
return prog, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cl *collectionLoader) loadVariable(varName string) (*Variable, error) {
|
||||||
|
if v := cl.vars[varName]; v != nil {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
varSpec := cl.coll.Variables[varName]
|
||||||
|
if varSpec == nil {
|
||||||
|
return nil, fmt.Errorf("unknown variable %s", varName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the key of the VariableSpec's MapSpec in the CollectionSpec.
|
||||||
|
var mapName string
|
||||||
|
for n, ms := range cl.coll.Maps {
|
||||||
|
if ms == varSpec.m {
|
||||||
|
mapName = n
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mapName == "" {
|
||||||
|
return nil, fmt.Errorf("variable %s: underlying MapSpec %s was removed from CollectionSpec", varName, varSpec.m.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := cl.loadMap(mapName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("variable %s: %w", varName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the kernel is too old or the underlying map was created without
|
||||||
|
// BPF_F_MMAPABLE, [Map.Memory] will return ErrNotSupported. In this case,
|
||||||
|
// emit a Variable with a nil Memory. This keeps Collection{Spec}.Variables
|
||||||
|
// consistent across systems with different feature sets without breaking
|
||||||
|
// LoadAndAssign.
|
||||||
|
mm, err := m.Memory()
|
||||||
|
if err != nil && !errors.Is(err, ErrNotSupported) {
|
||||||
|
return nil, fmt.Errorf("variable %s: getting memory for map %s: %w", varName, mapName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := newVariable(
|
||||||
|
varSpec.name,
|
||||||
|
varSpec.offset,
|
||||||
|
varSpec.size,
|
||||||
|
varSpec.t,
|
||||||
|
mm,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("variable %s: %w", varName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cl.vars[varName] = v
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
// populateDeferredMaps iterates maps holding programs or other maps and loads
|
// populateDeferredMaps iterates maps holding programs or other maps and loads
|
||||||
// any dependencies. Populates all maps in cl and freezes them if specified.
|
// any dependencies. Populates all maps in cl and freezes them if specified.
|
||||||
func (cl *collectionLoader) populateDeferredMaps() error {
|
func (cl *collectionLoader) populateDeferredMaps() error {
|
||||||
@@ -603,6 +701,7 @@ func resolveKconfig(m *MapSpec) error {
|
|||||||
|
|
||||||
type configInfo struct {
|
type configInfo struct {
|
||||||
offset uint32
|
offset uint32
|
||||||
|
size uint32
|
||||||
typ btf.Type
|
typ btf.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +718,7 @@ func resolveKconfig(m *MapSpec) error {
|
|||||||
return fmt.Errorf("variable %s must be a 32 bits integer, got %s", n, v.Type)
|
return fmt.Errorf("variable %s must be a 32 bits integer, got %s", n, v.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
kv, err := internal.KernelVersion()
|
kv, err := linux.KernelVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting kernel version: %w", err)
|
return fmt.Errorf("getting kernel version: %w", err)
|
||||||
}
|
}
|
||||||
@@ -644,6 +743,7 @@ func resolveKconfig(m *MapSpec) error {
|
|||||||
default: // Catch CONFIG_*.
|
default: // Catch CONFIG_*.
|
||||||
configs[n] = configInfo{
|
configs[n] = configInfo{
|
||||||
offset: vsi.Offset,
|
offset: vsi.Offset,
|
||||||
|
size: vsi.Size,
|
||||||
typ: v.Type,
|
typ: v.Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -651,7 +751,7 @@ func resolveKconfig(m *MapSpec) error {
|
|||||||
|
|
||||||
// We only parse kconfig file if a CONFIG_* variable was found.
|
// We only parse kconfig file if a CONFIG_* variable was found.
|
||||||
if len(configs) > 0 {
|
if len(configs) > 0 {
|
||||||
f, err := kconfig.Find()
|
f, err := linux.FindKConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot find a kconfig file: %w", err)
|
return fmt.Errorf("cannot find a kconfig file: %w", err)
|
||||||
}
|
}
|
||||||
@@ -670,10 +770,10 @@ func resolveKconfig(m *MapSpec) error {
|
|||||||
for n, info := range configs {
|
for n, info := range configs {
|
||||||
value, ok := kernelConfig[n]
|
value, ok := kernelConfig[n]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("config option %q does not exists for this kernel", n)
|
return fmt.Errorf("config option %q does not exist on this kernel", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := kconfig.PutValue(data[info.offset:], info.typ, value)
|
err := kconfig.PutValue(data[info.offset:info.offset+info.size], info.typ, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("problem adding value for %s: %w", n, err)
|
return fmt.Errorf("problem adding value for %s: %w", n, err)
|
||||||
}
|
}
|
||||||
@@ -723,6 +823,7 @@ func LoadCollection(file string) (*Collection, error) {
|
|||||||
func (coll *Collection) Assign(to interface{}) error {
|
func (coll *Collection) Assign(to interface{}) error {
|
||||||
assignedMaps := make(map[string]bool)
|
assignedMaps := make(map[string]bool)
|
||||||
assignedProgs := make(map[string]bool)
|
assignedProgs := make(map[string]bool)
|
||||||
|
assignedVars := make(map[string]bool)
|
||||||
|
|
||||||
// Assign() only transfers already-loaded Maps and Programs. No extra
|
// Assign() only transfers already-loaded Maps and Programs. No extra
|
||||||
// loading is done.
|
// loading is done.
|
||||||
@@ -743,6 +844,13 @@ func (coll *Collection) Assign(to interface{}) error {
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("missing map %q", name)
|
return nil, fmt.Errorf("missing map %q", name)
|
||||||
|
|
||||||
|
case reflect.TypeOf((*Variable)(nil)):
|
||||||
|
if v := coll.Variables[name]; v != nil {
|
||||||
|
assignedVars[name] = true
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("missing variable %q", name)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported type %s", typ)
|
return nil, fmt.Errorf("unsupported type %s", typ)
|
||||||
}
|
}
|
||||||
@@ -759,6 +867,9 @@ func (coll *Collection) Assign(to interface{}) error {
|
|||||||
for m := range assignedMaps {
|
for m := range assignedMaps {
|
||||||
delete(coll.Maps, m)
|
delete(coll.Maps, m)
|
||||||
}
|
}
|
||||||
|
for s := range assignedVars {
|
||||||
|
delete(coll.Variables, s)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
170
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
170
vendor/github.com/cilium/ebpf/elf_reader.go
generated
vendored
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type kconfigMetaKey struct{}
|
type kconfigMetaKey struct{}
|
||||||
@@ -33,6 +32,13 @@ type kfuncMeta struct {
|
|||||||
Func *btf.Func
|
Func *btf.Func
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ksymMetaKey struct{}
|
||||||
|
|
||||||
|
type ksymMeta struct {
|
||||||
|
Binding elf.SymBind
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
// elfCode is a convenience to reduce the amount of arguments that have to
|
// elfCode is a convenience to reduce the amount of arguments that have to
|
||||||
// be passed around explicitly. You should treat its contents as immutable.
|
// be passed around explicitly. You should treat its contents as immutable.
|
||||||
type elfCode struct {
|
type elfCode struct {
|
||||||
@@ -43,7 +49,9 @@ type elfCode struct {
|
|||||||
btf *btf.Spec
|
btf *btf.Spec
|
||||||
extInfo *btf.ExtInfos
|
extInfo *btf.ExtInfos
|
||||||
maps map[string]*MapSpec
|
maps map[string]*MapSpec
|
||||||
|
vars map[string]*VariableSpec
|
||||||
kfuncs map[string]*btf.Func
|
kfuncs map[string]*btf.Func
|
||||||
|
ksyms map[string]struct{}
|
||||||
kconfig *MapSpec
|
kconfig *MapSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +79,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
|
|
||||||
// Checks if the ELF file is for BPF data.
|
// Checks if the ELF file is for BPF data.
|
||||||
// Old LLVM versions set e_machine to EM_NONE.
|
// Old LLVM versions set e_machine to EM_NONE.
|
||||||
if f.File.Machine != unix.EM_NONE && f.File.Machine != elf.EM_BPF {
|
if f.File.Machine != elf.EM_NONE && f.File.Machine != elf.EM_BPF {
|
||||||
return nil, fmt.Errorf("unexpected machine type for BPF ELF: %s", f.File.Machine)
|
return nil, fmt.Errorf("unexpected machine type for BPF ELF: %s", f.File.Machine)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +109,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
sections[idx] = newElfSection(sec, mapSection)
|
sections[idx] = newElfSection(sec, mapSection)
|
||||||
case sec.Name == ".maps":
|
case sec.Name == ".maps":
|
||||||
sections[idx] = newElfSection(sec, btfMapSection)
|
sections[idx] = newElfSection(sec, btfMapSection)
|
||||||
case sec.Name == ".bss" || sec.Name == ".data" || strings.HasPrefix(sec.Name, ".rodata"):
|
case isDataSection(sec.Name):
|
||||||
sections[idx] = newElfSection(sec, dataSection)
|
sections[idx] = newElfSection(sec, dataSection)
|
||||||
case sec.Type == elf.SHT_REL:
|
case sec.Type == elf.SHT_REL:
|
||||||
// Store relocations under the section index of the target
|
// Store relocations under the section index of the target
|
||||||
@@ -134,7 +142,9 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
btf: btfSpec,
|
btf: btfSpec,
|
||||||
extInfo: btfExtInfo,
|
extInfo: btfExtInfo,
|
||||||
maps: make(map[string]*MapSpec),
|
maps: make(map[string]*MapSpec),
|
||||||
|
vars: make(map[string]*VariableSpec),
|
||||||
kfuncs: make(map[string]*btf.Func),
|
kfuncs: make(map[string]*btf.Func),
|
||||||
|
ksyms: make(map[string]struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
symbols, err := f.Symbols()
|
symbols, err := f.Symbols()
|
||||||
@@ -174,7 +184,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
|
|||||||
return nil, fmt.Errorf("load programs: %w", err)
|
return nil, fmt.Errorf("load programs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &CollectionSpec{ec.maps, progs, btfSpec, ec.ByteOrder}, nil
|
return &CollectionSpec{ec.maps, progs, ec.vars, btfSpec, ec.ByteOrder}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadLicense(sec *elf.Section) (string, error) {
|
func loadLicense(sec *elf.Section) (string, error) {
|
||||||
@@ -201,6 +211,18 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
|
|||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isDataSection(name string) bool {
|
||||||
|
return name == ".bss" || strings.HasPrefix(name, ".data") || strings.HasPrefix(name, ".rodata")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isConstantDataSection(name string) bool {
|
||||||
|
return strings.HasPrefix(name, ".rodata")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isKconfigSection(name string) bool {
|
||||||
|
return name == ".kconfig"
|
||||||
|
}
|
||||||
|
|
||||||
type elfSectionKind int
|
type elfSectionKind int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -506,7 +528,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
|
|||||||
|
|
||||||
case elf.STT_OBJECT:
|
case elf.STT_OBJECT:
|
||||||
// LLVM 9 emits OBJECT-LOCAL symbols for anonymous constants.
|
// LLVM 9 emits OBJECT-LOCAL symbols for anonymous constants.
|
||||||
if bind != elf.STB_GLOBAL && bind != elf.STB_LOCAL {
|
if bind != elf.STB_GLOBAL && bind != elf.STB_LOCAL && bind != elf.STB_WEAK {
|
||||||
return fmt.Errorf("direct load: %s: %w: %s", name, errUnsupportedBinding, bind)
|
return fmt.Errorf("direct load: %s: %w: %s", name, errUnsupportedBinding, bind)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,6 +636,8 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
kf := ec.kfuncs[name]
|
kf := ec.kfuncs[name]
|
||||||
|
_, ks := ec.ksyms[name]
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// If a Call / DWordLoad instruction is found and the datasec has a btf.Func with a Name
|
// If a Call / DWordLoad instruction is found and the datasec has a btf.Func with a Name
|
||||||
// that matches the symbol name we mark the instruction as a referencing a kfunc.
|
// that matches the symbol name we mark the instruction as a referencing a kfunc.
|
||||||
@@ -634,6 +658,15 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
|
|||||||
|
|
||||||
ins.Constant = 0
|
ins.Constant = 0
|
||||||
|
|
||||||
|
case ks && ins.OpCode.IsDWordLoad():
|
||||||
|
if bind != elf.STB_GLOBAL && bind != elf.STB_WEAK {
|
||||||
|
return fmt.Errorf("asm relocation: %s: %w: %s", name, errUnsupportedBinding, bind)
|
||||||
|
}
|
||||||
|
ins.Metadata.Set(ksymMetaKey{}, &ksymMeta{
|
||||||
|
Binding: bind,
|
||||||
|
Name: name,
|
||||||
|
})
|
||||||
|
|
||||||
// If no kconfig map is found, this must be a symbol reference from inline
|
// If no kconfig map is found, this must be a symbol reference from inline
|
||||||
// asm (see testdata/loader.c:asm_relocation()) or a call to a forward
|
// asm (see testdata/loader.c:asm_relocation()) or a call to a forward
|
||||||
// function declaration (see testdata/fwd_decl.c). Don't interfere, These
|
// function declaration (see testdata/fwd_decl.c). Don't interfere, These
|
||||||
@@ -980,6 +1013,13 @@ func mapSpecFromBTF(es *elfSection, vs *btf.VarSecinfo, def *btf.Struct, spec *b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some maps don't support value sizes, but annotating their map definitions
|
||||||
|
// with __type macros can still be useful, especially to let bpf2go generate
|
||||||
|
// type definitions for them.
|
||||||
|
if value != nil && !mapType.canHaveValueSize() {
|
||||||
|
valueSize = 0
|
||||||
|
}
|
||||||
|
|
||||||
return &MapSpec{
|
return &MapSpec{
|
||||||
Name: SanitizeName(name, -1),
|
Name: SanitizeName(name, -1),
|
||||||
Type: MapType(mapType),
|
Type: MapType(mapType),
|
||||||
@@ -1092,12 +1132,21 @@ func (ec *elfCode) loadDataSections() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if sec.references == 0 {
|
// If a section has no references, it will be freed as soon as the
|
||||||
// Prune data sections which are not referenced by any
|
// Collection closes, so creating and populating it is wasteful. If it has
|
||||||
// instructions.
|
// no symbols, it is likely an ephemeral section used during compilation
|
||||||
|
// that wasn't sanitized by the bpf linker. (like .rodata.str1.1)
|
||||||
|
//
|
||||||
|
// No symbols means no VariableSpecs can be generated from it, making it
|
||||||
|
// pointless to emit a data section for.
|
||||||
|
if sec.references == 0 && len(sec.symbols) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sec.Size > math.MaxUint32 {
|
||||||
|
return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
|
||||||
|
}
|
||||||
|
|
||||||
mapSpec := &MapSpec{
|
mapSpec := &MapSpec{
|
||||||
Name: SanitizeName(sec.Name, -1),
|
Name: SanitizeName(sec.Name, -1),
|
||||||
Type: Array,
|
Type: Array,
|
||||||
@@ -1106,6 +1155,10 @@ func (ec *elfCode) loadDataSections() error {
|
|||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isConstantDataSection(sec.Name) {
|
||||||
|
mapSpec.Flags = sys.BPF_F_RDONLY_PROG
|
||||||
|
}
|
||||||
|
|
||||||
switch sec.Type {
|
switch sec.Type {
|
||||||
// Only open the section if we know there's actual data to be read.
|
// Only open the section if we know there's actual data to be read.
|
||||||
case elf.SHT_PROGBITS:
|
case elf.SHT_PROGBITS:
|
||||||
@@ -1113,20 +1166,56 @@ func (ec *elfCode) loadDataSections() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
|
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.Contents = []MapKV{{uint32(0), data}}
|
mapSpec.Contents = []MapKV{{uint32(0), data}}
|
||||||
|
|
||||||
case elf.SHT_NOBITS:
|
case elf.SHT_NOBITS:
|
||||||
// NOBITS sections like .bss contain only zeroes, and since data sections
|
// NOBITS sections like .bss contain only zeroes and are not allocated in
|
||||||
// are Arrays, the kernel already preallocates them. Skip reading zeroes
|
// the ELF. Since data sections are Arrays, the kernel can preallocate
|
||||||
// from the ELF.
|
// them. Don't attempt reading zeroes from the ELF, instead allocate the
|
||||||
|
// zeroed memory to support getting and setting VariableSpecs for sections
|
||||||
|
// like .bss.
|
||||||
|
mapSpec.Contents = []MapKV{{uint32(0), make([]byte, sec.Size)}}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("data section %s: unknown section type %s", sec.Name, sec.Type)
|
return fmt.Errorf("data section %s: unknown section type %s", sec.Name, sec.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for off, sym := range sec.symbols {
|
||||||
|
// Skip symbols marked with the 'hidden' attribute.
|
||||||
|
if elf.ST_VISIBILITY(sym.Other) == elf.STV_HIDDEN ||
|
||||||
|
elf.ST_VISIBILITY(sym.Other) == elf.STV_INTERNAL {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only accept symbols with global or weak bindings. The common
|
||||||
|
// alternative is STB_LOCAL, which are either function-scoped or declared
|
||||||
|
// 'static'.
|
||||||
|
if elf.ST_BIND(sym.Info) != elf.STB_GLOBAL &&
|
||||||
|
elf.ST_BIND(sym.Info) != elf.STB_WEAK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if ec.vars[sym.Name] != nil {
|
||||||
|
return fmt.Errorf("data section %s: duplicate variable %s", sec.Name, sym.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip symbols starting with a dot, they are compiler-internal symbols
|
||||||
|
// emitted by clang 11 and earlier and are not cleaned up by the bpf
|
||||||
|
// compiler backend (e.g. symbols named .Lconstinit.1 in sections like
|
||||||
|
// .rodata.cst32). Variables in C cannot start with a dot, so filter these
|
||||||
|
// out.
|
||||||
|
if strings.HasPrefix(sym.Name, ".") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ec.vars[sym.Name] = &VariableSpec{
|
||||||
|
name: sym.Name,
|
||||||
|
offset: off,
|
||||||
|
size: sym.Size,
|
||||||
|
m: mapSpec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// It is possible for a data section to exist without a corresponding BTF Datasec
|
// It is possible for a data section to exist without a corresponding BTF Datasec
|
||||||
// if it only contains anonymous values like macro-defined arrays.
|
// if it only contains anonymous values like macro-defined arrays.
|
||||||
if ec.btf != nil {
|
if ec.btf != nil {
|
||||||
@@ -1135,12 +1224,38 @@ func (ec *elfCode) loadDataSections() error {
|
|||||||
// Assign the spec's key and BTF only if the Datasec lookup was successful.
|
// Assign the spec's key and BTF only if the Datasec lookup was successful.
|
||||||
mapSpec.Key = &btf.Void{}
|
mapSpec.Key = &btf.Void{}
|
||||||
mapSpec.Value = ds
|
mapSpec.Value = ds
|
||||||
}
|
|
||||||
|
// Populate VariableSpecs with type information, if available.
|
||||||
|
for _, v := range ds.Vars {
|
||||||
|
name := v.Type.TypeName()
|
||||||
|
if name == "" {
|
||||||
|
return fmt.Errorf("data section %s: anonymous variable %v", sec.Name, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(sec.Name, ".rodata") {
|
vt, ok := v.Type.(*btf.Var)
|
||||||
mapSpec.Flags = unix.BPF_F_RDONLY_PROG
|
if !ok {
|
||||||
mapSpec.Freeze = true
|
return fmt.Errorf("data section %s: unexpected type %T for variable %s", sec.Name, v.Type, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
ev := ec.vars[name]
|
||||||
|
if ev == nil {
|
||||||
|
// Hidden symbols appear in the BTF Datasec but don't receive a VariableSpec.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(v.Offset) != ev.offset {
|
||||||
|
return fmt.Errorf("data section %s: variable %s datasec offset (%d) doesn't match ELF symbol offset (%d)", sec.Name, name, v.Offset, ev.offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
if uint64(v.Size) != ev.size {
|
||||||
|
return fmt.Errorf("data section %s: variable %s size in datasec (%d) doesn't match ELF symbol size (%d)", sec.Name, name, v.Size, ev.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decouple the Var in the VariableSpec from the underlying DataSec in
|
||||||
|
// the MapSpec to avoid modifications from affecting map loads later on.
|
||||||
|
ev.t = btf.Copy(vt).(*btf.Var)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ec.maps[sec.Name] = mapSpec
|
ec.maps[sec.Name] = mapSpec
|
||||||
@@ -1175,8 +1290,7 @@ func (ec *elfCode) loadKconfigSection() error {
|
|||||||
KeySize: uint32(4),
|
KeySize: uint32(4),
|
||||||
ValueSize: ds.Size,
|
ValueSize: ds.Size,
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
Flags: unix.BPF_F_RDONLY_PROG,
|
Flags: sys.BPF_F_RDONLY_PROG,
|
||||||
Freeze: true,
|
|
||||||
Key: &btf.Int{Size: 4},
|
Key: &btf.Int{Size: 4},
|
||||||
Value: ds,
|
Value: ds,
|
||||||
}
|
}
|
||||||
@@ -1201,8 +1315,14 @@ func (ec *elfCode) loadKsymsSection() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range ds.Vars {
|
for _, v := range ds.Vars {
|
||||||
// we have already checked the .ksyms Datasec to only contain Func Vars.
|
switch t := v.Type.(type) {
|
||||||
ec.kfuncs[v.Type.TypeName()] = v.Type.(*btf.Func)
|
case *btf.Func:
|
||||||
|
ec.kfuncs[t.TypeName()] = t
|
||||||
|
case *btf.Var:
|
||||||
|
ec.ksyms[t.TypeName()] = struct{}{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unexpected variable type in .ksyms: %T", v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -1266,10 +1386,10 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
|
|||||||
|
|
||||||
var flags uint32
|
var flags uint32
|
||||||
if t.flags&_SEC_SLEEPABLE > 0 {
|
if t.flags&_SEC_SLEEPABLE > 0 {
|
||||||
flags |= unix.BPF_F_SLEEPABLE
|
flags |= sys.BPF_F_SLEEPABLE
|
||||||
}
|
}
|
||||||
if t.flags&_SEC_XDP_FRAGS > 0 {
|
if t.flags&_SEC_XDP_FRAGS > 0 {
|
||||||
flags |= unix.BPF_F_XDP_HAS_FRAGS
|
flags |= sys.BPF_F_XDP_HAS_FRAGS
|
||||||
}
|
}
|
||||||
if t.flags&_SEC_EXP_ATTACH_OPT > 0 {
|
if t.flags&_SEC_EXP_ATTACH_OPT > 0 {
|
||||||
if programType == XDP {
|
if programType == XDP {
|
||||||
|
|||||||
352
vendor/github.com/cilium/ebpf/info.go
generated
vendored
352
vendor/github.com/cilium/ebpf/info.go
generated
vendored
@@ -8,10 +8,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
@@ -39,53 +39,83 @@ import (
|
|||||||
|
|
||||||
// MapInfo describes a map.
|
// MapInfo describes a map.
|
||||||
type MapInfo struct {
|
type MapInfo struct {
|
||||||
|
// Type of the map.
|
||||||
Type MapType
|
Type MapType
|
||||||
id MapID
|
// KeySize is the size of the map key in bytes.
|
||||||
KeySize uint32
|
KeySize uint32
|
||||||
|
// ValueSize is the size of the map value in bytes.
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
|
// MaxEntries is the maximum number of entries the map can hold. Its meaning
|
||||||
|
// is map-specific.
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
|
// Flags used during map creation.
|
||||||
Flags uint32
|
Flags uint32
|
||||||
// Name as supplied by user space at load time. Available from 4.15.
|
// Name as supplied by user space at load time. Available from 4.15.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
id MapID
|
||||||
btf btf.ID
|
btf btf.ID
|
||||||
|
mapExtra uint64
|
||||||
|
memlock uint64
|
||||||
|
frozen bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newMapInfoFromFd queries map information about the given fd. [sys.ObjInfo] is
|
||||||
|
// attempted first, supplementing any missing values with information from
|
||||||
|
// /proc/self/fdinfo. Ignores EINVAL from ObjInfo as well as ErrNotSupported
|
||||||
|
// from reading fdinfo (indicating the file exists, but no fields of interest
|
||||||
|
// were found). If both fail, an error is always returned.
|
||||||
func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) {
|
func newMapInfoFromFd(fd *sys.FD) (*MapInfo, error) {
|
||||||
var info sys.MapInfo
|
var info sys.MapInfo
|
||||||
err := sys.ObjInfo(fd, &info)
|
err1 := sys.ObjInfo(fd, &info)
|
||||||
if errors.Is(err, syscall.EINVAL) {
|
// EINVAL means the kernel doesn't support BPF_OBJ_GET_INFO_BY_FD. Continue
|
||||||
return newMapInfoFromProc(fd)
|
// with fdinfo if that's the case.
|
||||||
}
|
if err1 != nil && !errors.Is(err1, unix.EINVAL) {
|
||||||
if err != nil {
|
return nil, fmt.Errorf("getting object info: %w", err1)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &MapInfo{
|
mi := &MapInfo{
|
||||||
MapType(info.Type),
|
MapType(info.Type),
|
||||||
MapID(info.Id),
|
|
||||||
info.KeySize,
|
info.KeySize,
|
||||||
info.ValueSize,
|
info.ValueSize,
|
||||||
info.MaxEntries,
|
info.MaxEntries,
|
||||||
uint32(info.MapFlags),
|
uint32(info.MapFlags),
|
||||||
unix.ByteSliceToString(info.Name[:]),
|
unix.ByteSliceToString(info.Name[:]),
|
||||||
|
MapID(info.Id),
|
||||||
btf.ID(info.BtfId),
|
btf.ID(info.BtfId),
|
||||||
}, nil
|
info.MapExtra,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supplement OBJ_INFO with data from /proc/self/fdinfo. It contains fields
|
||||||
|
// like memlock and frozen that are not present in OBJ_INFO.
|
||||||
|
err2 := readMapInfoFromProc(fd, mi)
|
||||||
|
if err2 != nil && !errors.Is(err2, ErrNotSupported) {
|
||||||
|
return nil, fmt.Errorf("getting map info from fdinfo: %w", err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err1 != nil && err2 != nil {
|
||||||
|
return nil, fmt.Errorf("ObjInfo and fdinfo both failed: objinfo: %w, fdinfo: %w", err1, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapInfoFromProc(fd *sys.FD) (*MapInfo, error) {
|
// readMapInfoFromProc queries map information about the given fd from
|
||||||
var mi MapInfo
|
// /proc/self/fdinfo. It only writes data into fields that have a zero value.
|
||||||
err := scanFdInfo(fd, map[string]interface{}{
|
func readMapInfoFromProc(fd *sys.FD, mi *MapInfo) error {
|
||||||
|
return scanFdInfo(fd, map[string]interface{}{
|
||||||
"map_type": &mi.Type,
|
"map_type": &mi.Type,
|
||||||
|
"map_id": &mi.id,
|
||||||
"key_size": &mi.KeySize,
|
"key_size": &mi.KeySize,
|
||||||
"value_size": &mi.ValueSize,
|
"value_size": &mi.ValueSize,
|
||||||
"max_entries": &mi.MaxEntries,
|
"max_entries": &mi.MaxEntries,
|
||||||
"map_flags": &mi.Flags,
|
"map_flags": &mi.Flags,
|
||||||
|
"map_extra": &mi.mapExtra,
|
||||||
|
"memlock": &mi.memlock,
|
||||||
|
"frozen": &mi.frozen,
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &mi, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID returns the map ID.
|
// ID returns the map ID.
|
||||||
@@ -109,6 +139,35 @@ func (mi *MapInfo) BTFID() (btf.ID, bool) {
|
|||||||
return mi.btf, mi.btf > 0
|
return mi.btf, mi.btf > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MapExtra returns an opaque field whose meaning is map-specific.
|
||||||
|
//
|
||||||
|
// Available from 5.16.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available and
|
||||||
|
// populated, if it was specified during Map creation.
|
||||||
|
func (mi *MapInfo) MapExtra() (uint64, bool) {
|
||||||
|
return mi.mapExtra, mi.mapExtra > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memlock returns an approximate number of bytes allocated to this map.
|
||||||
|
//
|
||||||
|
// Available from 4.10.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (mi *MapInfo) Memlock() (uint64, bool) {
|
||||||
|
return mi.memlock, mi.memlock > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frozen indicates whether [Map.Freeze] was called on this map. If true,
|
||||||
|
// modifications from user space are not allowed.
|
||||||
|
//
|
||||||
|
// Available from 5.2. Requires access to procfs.
|
||||||
|
//
|
||||||
|
// If the kernel doesn't support map freezing, this field will always be false.
|
||||||
|
func (mi *MapInfo) Frozen() bool {
|
||||||
|
return mi.frozen
|
||||||
|
}
|
||||||
|
|
||||||
// programStats holds statistics of a program.
|
// programStats holds statistics of a program.
|
||||||
type programStats struct {
|
type programStats struct {
|
||||||
// Total accumulated runtime of the program ins ns.
|
// Total accumulated runtime of the program ins ns.
|
||||||
@@ -120,6 +179,40 @@ type programStats struct {
|
|||||||
recursionMisses uint64
|
recursionMisses uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// programJitedInfo holds information about JITed info of a program.
|
||||||
|
type programJitedInfo struct {
|
||||||
|
// ksyms holds the ksym addresses of the BPF program, including those of its
|
||||||
|
// subprograms.
|
||||||
|
//
|
||||||
|
// Available from 4.18.
|
||||||
|
ksyms []uintptr
|
||||||
|
numKsyms uint32
|
||||||
|
|
||||||
|
// insns holds the JITed machine native instructions of the program,
|
||||||
|
// including those of its subprograms.
|
||||||
|
//
|
||||||
|
// Available from 4.13.
|
||||||
|
insns []byte
|
||||||
|
numInsns uint32
|
||||||
|
|
||||||
|
// lineInfos holds the JITed line infos, which are kernel addresses.
|
||||||
|
//
|
||||||
|
// Available from 5.0.
|
||||||
|
lineInfos []uint64
|
||||||
|
numLineInfos uint32
|
||||||
|
|
||||||
|
// lineInfoRecSize is the size of a single line info record.
|
||||||
|
//
|
||||||
|
// Available from 5.0.
|
||||||
|
lineInfoRecSize uint32
|
||||||
|
|
||||||
|
// funcLens holds the insns length of each function.
|
||||||
|
//
|
||||||
|
// Available from 4.18.
|
||||||
|
funcLens []uint32
|
||||||
|
numFuncLens uint32
|
||||||
|
}
|
||||||
|
|
||||||
// ProgramInfo describes a program.
|
// ProgramInfo describes a program.
|
||||||
type ProgramInfo struct {
|
type ProgramInfo struct {
|
||||||
Type ProgramType
|
Type ProgramType
|
||||||
@@ -133,9 +226,14 @@ type ProgramInfo struct {
|
|||||||
haveCreatedByUID bool
|
haveCreatedByUID bool
|
||||||
btf btf.ID
|
btf btf.ID
|
||||||
stats *programStats
|
stats *programStats
|
||||||
|
loadTime time.Duration
|
||||||
|
|
||||||
maps []MapID
|
maps []MapID
|
||||||
insns []byte
|
insns []byte
|
||||||
|
jitedSize uint32
|
||||||
|
verifiedInstructions uint32
|
||||||
|
|
||||||
|
jitedInfo programJitedInfo
|
||||||
|
|
||||||
lineInfos []byte
|
lineInfos []byte
|
||||||
numLineInfos uint32
|
numLineInfos uint32
|
||||||
@@ -164,6 +262,9 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
|
|||||||
runCount: info.RunCnt,
|
runCount: info.RunCnt,
|
||||||
recursionMisses: info.RecursionMisses,
|
recursionMisses: info.RecursionMisses,
|
||||||
},
|
},
|
||||||
|
jitedSize: info.JitedProgLen,
|
||||||
|
loadTime: time.Duration(info.LoadTime),
|
||||||
|
verifiedInstructions: info.VerifiedInsns,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start with a clean struct for the second call, otherwise we may get EFAULT.
|
// Start with a clean struct for the second call, otherwise we may get EFAULT.
|
||||||
@@ -174,7 +275,7 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
|
|||||||
if info.NrMapIds > 0 {
|
if info.NrMapIds > 0 {
|
||||||
pi.maps = make([]MapID, info.NrMapIds)
|
pi.maps = make([]MapID, info.NrMapIds)
|
||||||
info2.NrMapIds = info.NrMapIds
|
info2.NrMapIds = info.NrMapIds
|
||||||
info2.MapIds = sys.NewPointer(unsafe.Pointer(&pi.maps[0]))
|
info2.MapIds = sys.NewSlicePointer(pi.maps)
|
||||||
makeSecondCall = true
|
makeSecondCall = true
|
||||||
} else if haveProgramInfoMapIDs() == nil {
|
} else if haveProgramInfoMapIDs() == nil {
|
||||||
// This program really has no associated maps.
|
// This program really has no associated maps.
|
||||||
@@ -215,6 +316,40 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
|
|||||||
makeSecondCall = true
|
makeSecondCall = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pi.jitedInfo.lineInfoRecSize = info.JitedLineInfoRecSize
|
||||||
|
if info.JitedProgLen > 0 {
|
||||||
|
pi.jitedInfo.numInsns = info.JitedProgLen
|
||||||
|
pi.jitedInfo.insns = make([]byte, info.JitedProgLen)
|
||||||
|
info2.JitedProgLen = info.JitedProgLen
|
||||||
|
info2.JitedProgInsns = sys.NewSlicePointer(pi.jitedInfo.insns)
|
||||||
|
makeSecondCall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.NrJitedFuncLens > 0 {
|
||||||
|
pi.jitedInfo.numFuncLens = info.NrJitedFuncLens
|
||||||
|
pi.jitedInfo.funcLens = make([]uint32, info.NrJitedFuncLens)
|
||||||
|
info2.NrJitedFuncLens = info.NrJitedFuncLens
|
||||||
|
info2.JitedFuncLens = sys.NewSlicePointer(pi.jitedInfo.funcLens)
|
||||||
|
makeSecondCall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.NrJitedLineInfo > 0 {
|
||||||
|
pi.jitedInfo.numLineInfos = info.NrJitedLineInfo
|
||||||
|
pi.jitedInfo.lineInfos = make([]uint64, info.NrJitedLineInfo)
|
||||||
|
info2.NrJitedLineInfo = info.NrJitedLineInfo
|
||||||
|
info2.JitedLineInfo = sys.NewSlicePointer(pi.jitedInfo.lineInfos)
|
||||||
|
info2.JitedLineInfoRecSize = info.JitedLineInfoRecSize
|
||||||
|
makeSecondCall = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.NrJitedKsyms > 0 {
|
||||||
|
pi.jitedInfo.numKsyms = info.NrJitedKsyms
|
||||||
|
pi.jitedInfo.ksyms = make([]uintptr, info.NrJitedKsyms)
|
||||||
|
info2.JitedKsyms = sys.NewSlicePointer(pi.jitedInfo.ksyms)
|
||||||
|
info2.NrJitedKsyms = info.NrJitedKsyms
|
||||||
|
makeSecondCall = true
|
||||||
|
}
|
||||||
|
|
||||||
if makeSecondCall {
|
if makeSecondCall {
|
||||||
if err := sys.ObjInfo(fd, &info2); err != nil {
|
if err := sys.ObjInfo(fd, &info2); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -230,7 +365,7 @@ func newProgramInfoFromProc(fd *sys.FD) (*ProgramInfo, error) {
|
|||||||
"prog_type": &info.Type,
|
"prog_type": &info.Type,
|
||||||
"prog_tag": &info.Tag,
|
"prog_tag": &info.Tag,
|
||||||
})
|
})
|
||||||
if errors.Is(err, errMissingFields) {
|
if errors.Is(err, ErrNotSupported) {
|
||||||
return nil, &internal.UnsupportedFeatureError{
|
return nil, &internal.UnsupportedFeatureError{
|
||||||
Name: "reading program info from /proc/self/fdinfo",
|
Name: "reading program info from /proc/self/fdinfo",
|
||||||
MinimumVersion: internal.Version{4, 10, 0},
|
MinimumVersion: internal.Version{4, 10, 0},
|
||||||
@@ -305,6 +440,52 @@ func (pi *ProgramInfo) RecursionMisses() (uint64, bool) {
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// btfSpec returns the BTF spec associated with the program.
|
||||||
|
func (pi *ProgramInfo) btfSpec() (*btf.Spec, error) {
|
||||||
|
id, ok := pi.BTFID()
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("program created without BTF or unsupported kernel: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := btf.NewHandleFromID(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get BTF handle: %w", err)
|
||||||
|
}
|
||||||
|
defer h.Close()
|
||||||
|
|
||||||
|
spec, err := h.Spec(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get BTF spec: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return spec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LineInfos returns the BTF line information of the program.
|
||||||
|
//
|
||||||
|
// Available from 5.0.
|
||||||
|
//
|
||||||
|
// Requires CAP_SYS_ADMIN or equivalent for reading BTF information. Returns
|
||||||
|
// ErrNotSupported if the program was created without BTF or if the kernel
|
||||||
|
// doesn't support the field.
|
||||||
|
func (pi *ProgramInfo) LineInfos() (btf.LineOffsets, error) {
|
||||||
|
if len(pi.lineInfos) == 0 {
|
||||||
|
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := pi.btfSpec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return btf.LoadLineInfos(
|
||||||
|
bytes.NewReader(pi.lineInfos),
|
||||||
|
internal.NativeEndian,
|
||||||
|
pi.numLineInfos,
|
||||||
|
spec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Instructions returns the 'xlated' instruction stream of the program
|
// Instructions returns the 'xlated' instruction stream of the program
|
||||||
// after it has been verified and rewritten by the kernel. These instructions
|
// after it has been verified and rewritten by the kernel. These instructions
|
||||||
// cannot be loaded back into the kernel as-is, this is mainly used for
|
// cannot be loaded back into the kernel as-is, this is mainly used for
|
||||||
@@ -391,6 +572,29 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
|
|||||||
return insns, nil
|
return insns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JitedSize returns the size of the program's JIT-compiled machine code in bytes, which is the
|
||||||
|
// actual code executed on the host's CPU. This field requires the BPF JIT compiler to be enabled.
|
||||||
|
//
|
||||||
|
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
|
||||||
|
func (pi *ProgramInfo) JitedSize() (uint32, error) {
|
||||||
|
if pi.jitedSize == 0 {
|
||||||
|
return 0, fmt.Errorf("insufficient permissions, unsupported kernel, or JIT compiler disabled: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
return pi.jitedSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslatedSize returns the size of the program's translated instructions in bytes, after it has
|
||||||
|
// been verified and rewritten by the kernel.
|
||||||
|
//
|
||||||
|
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
|
||||||
|
func (pi *ProgramInfo) TranslatedSize() (int, error) {
|
||||||
|
insns := len(pi.insns)
|
||||||
|
if insns == 0 {
|
||||||
|
return 0, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
return insns, nil
|
||||||
|
}
|
||||||
|
|
||||||
// MapIDs returns the maps related to the program.
|
// MapIDs returns the maps related to the program.
|
||||||
//
|
//
|
||||||
// Available from 4.15.
|
// Available from 4.15.
|
||||||
@@ -400,6 +604,89 @@ func (pi *ProgramInfo) MapIDs() ([]MapID, bool) {
|
|||||||
return pi.maps, pi.maps != nil
|
return pi.maps, pi.maps != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadTime returns when the program was loaded since boot time.
|
||||||
|
//
|
||||||
|
// Available from 4.15.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) LoadTime() (time.Duration, bool) {
|
||||||
|
// loadTime and NrMapIds were introduced in the same kernel version.
|
||||||
|
return pi.loadTime, pi.loadTime > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifiedInstructions returns the number verified instructions in the program.
|
||||||
|
//
|
||||||
|
// Available from 5.16.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) VerifiedInstructions() (uint32, bool) {
|
||||||
|
return pi.verifiedInstructions, pi.verifiedInstructions > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// JitedKsymAddrs returns the ksym addresses of the BPF program, including its
|
||||||
|
// subprograms. The addresses correspond to their symbols in /proc/kallsyms.
|
||||||
|
//
|
||||||
|
// Available from 4.18. Note that before 5.x, this field can be empty for
|
||||||
|
// programs without subprograms (bpf2bpf calls).
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) JitedKsymAddrs() ([]uintptr, bool) {
|
||||||
|
return pi.jitedInfo.ksyms, len(pi.jitedInfo.ksyms) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// JitedInsns returns the JITed machine native instructions of the program.
|
||||||
|
//
|
||||||
|
// Available from 4.13.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) JitedInsns() ([]byte, bool) {
|
||||||
|
return pi.jitedInfo.insns, len(pi.jitedInfo.insns) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// JitedLineInfos returns the JITed line infos of the program.
|
||||||
|
//
|
||||||
|
// Available from 5.0.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) JitedLineInfos() ([]uint64, bool) {
|
||||||
|
return pi.jitedInfo.lineInfos, len(pi.jitedInfo.lineInfos) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// JitedFuncLens returns the insns length of each function in the JITed program.
|
||||||
|
//
|
||||||
|
// Available from 4.18.
|
||||||
|
//
|
||||||
|
// The bool return value indicates whether this optional field is available.
|
||||||
|
func (pi *ProgramInfo) JitedFuncLens() ([]uint32, bool) {
|
||||||
|
return pi.jitedInfo.funcLens, len(pi.jitedInfo.funcLens) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncInfos returns the offset and function information of all (sub)programs in
|
||||||
|
// a BPF program.
|
||||||
|
//
|
||||||
|
// Available from 5.0.
|
||||||
|
//
|
||||||
|
// Requires CAP_SYS_ADMIN or equivalent for reading BTF information. Returns
|
||||||
|
// ErrNotSupported if the program was created without BTF or if the kernel
|
||||||
|
// doesn't support the field.
|
||||||
|
func (pi *ProgramInfo) FuncInfos() (btf.FuncOffsets, error) {
|
||||||
|
if len(pi.funcInfos) == 0 {
|
||||||
|
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec, err := pi.btfSpec()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return btf.LoadFuncInfos(
|
||||||
|
bytes.NewReader(pi.funcInfos),
|
||||||
|
internal.NativeEndian,
|
||||||
|
pi.numFuncInfos,
|
||||||
|
spec,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
|
func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
|
||||||
fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", fd.Int()))
|
fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", fd.Int()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -413,8 +700,6 @@ func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errMissingFields = errors.New("missing fields")
|
|
||||||
|
|
||||||
func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
|
func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
|
||||||
var (
|
var (
|
||||||
scanner = bufio.NewScanner(r)
|
scanner = bufio.NewScanner(r)
|
||||||
@@ -433,26 +718,37 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If field already contains a non-zero value, don't overwrite it with fdinfo.
|
||||||
|
if zero(field) {
|
||||||
if n, err := fmt.Sscanln(parts[1], field); err != nil || n != 1 {
|
if n, err := fmt.Sscanln(parts[1], field); err != nil || n != 1 {
|
||||||
return fmt.Errorf("can't parse field %s: %v", name, err)
|
return fmt.Errorf("can't parse field %s: %v", name, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
scanned++
|
scanned++
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
return err
|
return fmt.Errorf("scanning fdinfo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(fields) > 0 && scanned == 0 {
|
if len(fields) > 0 && scanned == 0 {
|
||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
if scanned != len(fields) {
|
return nil
|
||||||
return errMissingFields
|
}
|
||||||
|
|
||||||
|
func zero(arg any) bool {
|
||||||
|
v := reflect.ValueOf(arg)
|
||||||
|
|
||||||
|
// Unwrap pointers and interfaces.
|
||||||
|
for v.Kind() == reflect.Pointer ||
|
||||||
|
v.Kind() == reflect.Interface {
|
||||||
|
v = v.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return v.IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableStats starts the measuring of the runtime
|
// EnableStats starts the measuring of the runtime
|
||||||
@@ -471,7 +767,7 @@ func EnableStats(which uint32) (io.Closer, error) {
|
|||||||
return fd, nil
|
return fd, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", "4.15", func() error {
|
var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", func() error {
|
||||||
prog, err := progLoad(asm.Instructions{
|
prog, err := progLoad(asm.Instructions{
|
||||||
asm.LoadImm(asm.R0, 0, asm.DWord),
|
asm.LoadImm(asm.R0, 0, asm.DWord),
|
||||||
asm.Return(),
|
asm.Return(),
|
||||||
@@ -496,4 +792,4 @@ var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", "
|
|||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
}, "4.15")
|
||||||
|
|||||||
6
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
6
vendor/github.com/cilium/ebpf/internal/errors.go
generated
vendored
@@ -23,7 +23,7 @@ func ErrorWithLog(source string, err error, log []byte) *VerifierError {
|
|||||||
|
|
||||||
log = bytes.Trim(log, whitespace)
|
log = bytes.Trim(log, whitespace)
|
||||||
if len(log) == 0 {
|
if len(log) == 0 {
|
||||||
return &VerifierError{source, err, nil, false}
|
return &VerifierError{source, err, nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
logLines := bytes.Split(log, []byte{'\n'})
|
logLines := bytes.Split(log, []byte{'\n'})
|
||||||
@@ -34,7 +34,7 @@ func ErrorWithLog(source string, err error, log []byte) *VerifierError {
|
|||||||
lines = append(lines, string(bytes.TrimRight(line, whitespace)))
|
lines = append(lines, string(bytes.TrimRight(line, whitespace)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &VerifierError{source, err, lines, false}
|
return &VerifierError{source, err, lines}
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifierError includes information from the eBPF verifier.
|
// VerifierError includes information from the eBPF verifier.
|
||||||
@@ -46,8 +46,6 @@ type VerifierError struct {
|
|||||||
Cause error
|
Cause error
|
||||||
// The verifier output split into lines.
|
// The verifier output split into lines.
|
||||||
Log []string
|
Log []string
|
||||||
// Deprecated: the log is never truncated anymore.
|
|
||||||
Truncated bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (le *VerifierError) Unwrap() error {
|
func (le *VerifierError) Unwrap() error {
|
||||||
|
|||||||
51
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
51
vendor/github.com/cilium/ebpf/internal/feature.go
generated
vendored
@@ -3,15 +3,25 @@ package internal
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNotSupported indicates that a feature is not supported by the current kernel.
|
// ErrNotSupported indicates that a feature is not supported.
|
||||||
var ErrNotSupported = errors.New("not supported")
|
var ErrNotSupported = errors.New("not supported")
|
||||||
|
|
||||||
|
// ErrNotSupportedOnOS indicates that a feature is not supported on the current
|
||||||
|
// operating system.
|
||||||
|
var ErrNotSupportedOnOS = fmt.Errorf("%w on %s", ErrNotSupported, runtime.GOOS)
|
||||||
|
|
||||||
// UnsupportedFeatureError is returned by FeatureTest() functions.
|
// UnsupportedFeatureError is returned by FeatureTest() functions.
|
||||||
type UnsupportedFeatureError struct {
|
type UnsupportedFeatureError struct {
|
||||||
// The minimum Linux mainline version required for this feature.
|
// The minimum version required for this feature.
|
||||||
|
//
|
||||||
|
// On Linux this refers to the mainline kernel version, on other platforms
|
||||||
|
// to the version of the runtime.
|
||||||
|
//
|
||||||
// Used for the error string, and for sanity checking during testing.
|
// Used for the error string, and for sanity checking during testing.
|
||||||
MinimumVersion Version
|
MinimumVersion Version
|
||||||
|
|
||||||
@@ -58,13 +68,46 @@ type FeatureTest struct {
|
|||||||
type FeatureTestFn func() error
|
type FeatureTestFn func() error
|
||||||
|
|
||||||
// NewFeatureTest is a convenient way to create a single [FeatureTest].
|
// NewFeatureTest is a convenient way to create a single [FeatureTest].
|
||||||
func NewFeatureTest(name, version string, fn FeatureTestFn) func() error {
|
//
|
||||||
|
// versions specifies in which version of a BPF runtime a feature appeared.
|
||||||
|
// The format is "GOOS:Major.Minor[.Patch]". GOOS may be omitted when targeting
|
||||||
|
// Linux. Returns [ErrNotSupportedOnOS] if there is no version specified for the
|
||||||
|
// current OS.
|
||||||
|
func NewFeatureTest(name string, fn FeatureTestFn, versions ...string) func() error {
|
||||||
|
const nativePrefix = runtime.GOOS + ":"
|
||||||
|
|
||||||
|
if len(versions) == 0 {
|
||||||
|
return func() error {
|
||||||
|
return fmt.Errorf("feature test %q: no versions specified", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ft := &FeatureTest{
|
ft := &FeatureTest{
|
||||||
Name: name,
|
Name: name,
|
||||||
Version: version,
|
|
||||||
Fn: fn,
|
Fn: fn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, version := range versions {
|
||||||
|
if strings.HasPrefix(version, nativePrefix) {
|
||||||
|
ft.Version = strings.TrimPrefix(version, nativePrefix)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime.GOOS == "linux" && !strings.ContainsRune(version, ':') {
|
||||||
|
// Allow version numbers without a GOOS prefix on Linux.
|
||||||
|
ft.Version = version
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ft.Version == "" {
|
||||||
|
return func() error {
|
||||||
|
// We don't return an UnsupportedFeatureError here, since that will
|
||||||
|
// trigger version checks which don't make sense.
|
||||||
|
return fmt.Errorf("%s: %w", name, ErrNotSupportedOnOS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ft.execute
|
return ft.execute
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
vendor/github.com/cilium/ebpf/internal/kallsyms/cache.go
generated
vendored
Normal file
20
vendor/github.com/cilium/ebpf/internal/kallsyms/cache.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package kallsyms
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
|
type cache[K, V comparable] struct {
|
||||||
|
m sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[K, V]) Load(key K) (value V, _ bool) {
|
||||||
|
v, ok := c.m.Load(key)
|
||||||
|
if !ok {
|
||||||
|
return value, false
|
||||||
|
}
|
||||||
|
value = v.(V)
|
||||||
|
return value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cache[K, V]) Store(key K, value V) {
|
||||||
|
c.m.Store(key, value)
|
||||||
|
}
|
||||||
303
vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go
generated
vendored
303
vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go
generated
vendored
@@ -1,74 +1,277 @@
|
|||||||
package kallsyms
|
package kallsyms
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"errors"
|
||||||
"bytes"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var kernelModules struct {
|
var errAmbiguousKsym = errors.New("multiple kernel symbols with the same name")
|
||||||
sync.RWMutex
|
|
||||||
// function to kernel module mapping
|
|
||||||
kmods map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
// KernelModule returns the kernel module, if any, a probe-able function is contained in.
|
var symAddrs cache[string, uint64]
|
||||||
func KernelModule(fn string) (string, error) {
|
var symModules cache[string, string]
|
||||||
kernelModules.RLock()
|
|
||||||
kmods := kernelModules.kmods
|
|
||||||
kernelModules.RUnlock()
|
|
||||||
|
|
||||||
if kmods == nil {
|
// Module returns the kernel module providing the given symbol in the kernel, if
|
||||||
kernelModules.Lock()
|
// any. Returns an empty string and no error if the symbol is not present in the
|
||||||
defer kernelModules.Unlock()
|
// kernel. Only function symbols are considered. Returns an error if multiple
|
||||||
kmods = kernelModules.kmods
|
// symbols with the same name were found.
|
||||||
|
//
|
||||||
|
// Consider [AssignModules] if you need to resolve multiple symbols, as it will
|
||||||
|
// only perform one iteration over /proc/kallsyms.
|
||||||
|
func Module(name string) (string, error) {
|
||||||
|
if name == "" {
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if kmods != nil {
|
if mod, ok := symModules.Load(name); ok {
|
||||||
return kmods[fn], nil
|
return mod, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
request := map[string]string{name: ""}
|
||||||
|
if err := AssignModules(request); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return request[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignModules looks up the kernel module providing each given symbol, if any,
|
||||||
|
// and assigns them to their corresponding values in the symbols map. Only
|
||||||
|
// function symbols are considered. Results of all lookups are cached,
|
||||||
|
// successful or otherwise.
|
||||||
|
//
|
||||||
|
// Any symbols missing in the kernel are ignored. Returns an error if multiple
|
||||||
|
// symbols with a given name were found.
|
||||||
|
func AssignModules(symbols map[string]string) error {
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to fetch symbols from cache.
|
||||||
|
request := make(map[string]string)
|
||||||
|
for name := range symbols {
|
||||||
|
if mod, ok := symModules.Load(name); ok {
|
||||||
|
symbols[name] = mod
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the symbol to be read from /proc/kallsyms.
|
||||||
|
request[name] = ""
|
||||||
|
}
|
||||||
|
if len(request) == 0 {
|
||||||
|
// All symbols satisfied from cache.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open("/proc/kallsyms")
|
f, err := os.Open("/proc/kallsyms")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
kmods, err = loadKernelModuleMapping(f)
|
if err := assignModules(f, request); err != nil {
|
||||||
|
return fmt.Errorf("assigning symbol modules: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the cache with the new symbols. Cache all requested symbols, even if
|
||||||
|
// they're missing or don't belong to a module.
|
||||||
|
for name, mod := range request {
|
||||||
|
symModules.Store(name, mod)
|
||||||
|
symbols[name] = mod
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignModules assigns kernel symbol modules read from f to values requested
|
||||||
|
// by symbols. Always scans the whole input to make sure the user didn't request
|
||||||
|
// an ambiguous symbol.
|
||||||
|
func assignModules(f io.Reader, symbols map[string]string) error {
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
found := make(map[string]struct{})
|
||||||
|
r := newReader(f)
|
||||||
|
for r.Line() {
|
||||||
|
// Only look for function symbols in the kernel's text section (tT).
|
||||||
|
s, err, skip := parseSymbol(r, []rune{'t', 'T'})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return fmt.Errorf("parsing kallsyms line: %w", err)
|
||||||
}
|
}
|
||||||
|
if skip {
|
||||||
kernelModules.kmods = kmods
|
|
||||||
return kmods[fn], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlushKernelModuleCache removes any cached information about function to kernel module mapping.
|
|
||||||
func FlushKernelModuleCache() {
|
|
||||||
kernelModules.Lock()
|
|
||||||
defer kernelModules.Unlock()
|
|
||||||
|
|
||||||
kernelModules.kmods = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadKernelModuleMapping(f io.Reader) (map[string]string, error) {
|
|
||||||
mods := make(map[string]string)
|
|
||||||
scanner := bufio.NewScanner(f)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fields := bytes.Fields(scanner.Bytes())
|
|
||||||
if len(fields) < 4 {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch string(fields[1]) {
|
|
||||||
case "t", "T":
|
if _, requested := symbols[s.name]; !requested {
|
||||||
mods[string(fields[2])] = string(bytes.Trim(fields[3], "[]"))
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := found[s.name]; ok {
|
||||||
|
// We've already seen this symbol. Return an error to avoid silently
|
||||||
|
// attaching to a symbol in the wrong module. libbpf also rejects
|
||||||
|
// referring to ambiguous symbols.
|
||||||
|
//
|
||||||
|
// We can't simply check if we already have a value for the given symbol,
|
||||||
|
// since many won't have an associated kernel module.
|
||||||
|
return fmt.Errorf("symbol %s: duplicate found at address 0x%x (module %q): %w",
|
||||||
|
s.name, s.addr, s.mod, errAmbiguousKsym)
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols[s.name] = s.mod
|
||||||
|
found[s.name] = struct{}{}
|
||||||
|
}
|
||||||
|
if err := r.Err(); err != nil {
|
||||||
|
return fmt.Errorf("reading kallsyms: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Address returns the address of the given symbol in the kernel. Returns 0 and
|
||||||
|
// no error if the symbol is not present. Returns an error if multiple addresses
|
||||||
|
// were found for a symbol.
|
||||||
|
//
|
||||||
|
// Consider [AssignAddresses] if you need to resolve multiple symbols, as it
|
||||||
|
// will only perform one iteration over /proc/kallsyms.
|
||||||
|
func Address(symbol string) (uint64, error) {
|
||||||
|
if symbol == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr, ok := symAddrs.Load(symbol); ok {
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
request := map[string]uint64{symbol: 0}
|
||||||
|
if err := AssignAddresses(request); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return request[symbol], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssignAddresses looks up the addresses of the requested symbols in the kernel
|
||||||
|
// and assigns them to their corresponding values in the symbols map. Results
|
||||||
|
// of all lookups are cached, successful or otherwise.
|
||||||
|
//
|
||||||
|
// Any symbols missing in the kernel are ignored. Returns an error if multiple
|
||||||
|
// addresses were found for a symbol.
|
||||||
|
func AssignAddresses(symbols map[string]uint64) error {
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to fetch symbols from cache.
|
||||||
|
request := make(map[string]uint64)
|
||||||
|
for name := range symbols {
|
||||||
|
if addr, ok := symAddrs.Load(name); ok {
|
||||||
|
symbols[name] = addr
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the symbol to be read from /proc/kallsyms.
|
||||||
|
request[name] = 0
|
||||||
|
}
|
||||||
|
if len(request) == 0 {
|
||||||
|
// All symbols satisfied from cache.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Open("/proc/kallsyms")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := assignAddresses(f, request); err != nil {
|
||||||
|
return fmt.Errorf("loading symbol addresses: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the cache with the new symbols. Cache all requested symbols even if
|
||||||
|
// they weren't found, to avoid repeated lookups.
|
||||||
|
for name, addr := range request {
|
||||||
|
symAddrs.Store(name, addr)
|
||||||
|
symbols[name] = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignAddresses assigns kernel symbol addresses read from f to values
|
||||||
|
// requested by symbols. Always scans the whole input to make sure the user
|
||||||
|
// didn't request an ambiguous symbol.
|
||||||
|
func assignAddresses(f io.Reader, symbols map[string]uint64) error {
|
||||||
|
if len(symbols) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
r := newReader(f)
|
||||||
|
for r.Line() {
|
||||||
|
s, err, skip := parseSymbol(r, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parsing kallsyms line: %w", err)
|
||||||
|
}
|
||||||
|
if skip {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
existing, requested := symbols[s.name]
|
||||||
|
if existing != 0 {
|
||||||
|
// Multiple addresses for a symbol have been found. Return a friendly
|
||||||
|
// error to avoid silently attaching to the wrong symbol. libbpf also
|
||||||
|
// rejects referring to ambiguous symbols.
|
||||||
|
return fmt.Errorf("symbol %s(0x%x): duplicate found at address 0x%x: %w", s.name, existing, s.addr, errAmbiguousKsym)
|
||||||
|
}
|
||||||
|
if requested {
|
||||||
|
symbols[s.name] = s.addr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := r.Err(); err != nil {
|
||||||
|
return fmt.Errorf("reading kallsyms: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ksym struct {
|
||||||
|
addr uint64
|
||||||
|
name string
|
||||||
|
mod string
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseSymbol parses a line from /proc/kallsyms into an address, type, name and
|
||||||
|
// module. Skip will be true if the symbol doesn't match any of the given symbol
|
||||||
|
// types. See `man 1 nm` for all available types.
|
||||||
|
//
|
||||||
|
// Example line: `ffffffffc1682010 T nf_nat_init [nf_nat]`
|
||||||
|
func parseSymbol(r *reader, types []rune) (s ksym, err error, skip bool) {
|
||||||
|
for i := 0; r.Word(); i++ {
|
||||||
|
switch i {
|
||||||
|
// Address of the symbol.
|
||||||
|
case 0:
|
||||||
|
s.addr, err = strconv.ParseUint(r.Text(), 16, 64)
|
||||||
|
if err != nil {
|
||||||
|
return s, fmt.Errorf("parsing address: %w", err), false
|
||||||
|
}
|
||||||
|
// Type of the symbol. Assume the character is ASCII-encoded by converting
|
||||||
|
// it directly to a rune, since it's a fixed field controlled by the kernel.
|
||||||
|
case 1:
|
||||||
|
if len(types) > 0 && !slices.Contains(types, rune(r.Bytes()[0])) {
|
||||||
|
return s, nil, true
|
||||||
|
}
|
||||||
|
// Name of the symbol.
|
||||||
|
case 2:
|
||||||
|
s.name = r.Text()
|
||||||
|
// Kernel module the symbol is provided by.
|
||||||
|
case 3:
|
||||||
|
s.mod = strings.Trim(r.Text(), "[]")
|
||||||
|
// Ignore any future fields.
|
||||||
default:
|
default:
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if scanner.Err() != nil {
|
|
||||||
return nil, scanner.Err()
|
return
|
||||||
}
|
|
||||||
return mods, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
118
vendor/github.com/cilium/ebpf/internal/kallsyms/reader.go
generated
vendored
Normal file
118
vendor/github.com/cilium/ebpf/internal/kallsyms/reader.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package kallsyms
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// reader is a line and word-oriented reader built for reading /proc/kallsyms.
|
||||||
|
// It takes an io.Reader and iterates its contents line by line, then word by
|
||||||
|
// word.
|
||||||
|
//
|
||||||
|
// It's designed to allow partial reading of lines without paying the cost of
|
||||||
|
// allocating objects that will never be accessed, resulting in less work for
|
||||||
|
// the garbage collector.
|
||||||
|
type reader struct {
|
||||||
|
s *bufio.Scanner
|
||||||
|
line []byte
|
||||||
|
word []byte
|
||||||
|
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newReader(r io.Reader) *reader {
|
||||||
|
return &reader{
|
||||||
|
s: bufio.NewScanner(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the current word as a byte slice.
|
||||||
|
func (r *reader) Bytes() []byte {
|
||||||
|
return r.word
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text returns the output of Bytes as a string.
|
||||||
|
func (r *reader) Text() string {
|
||||||
|
return string(r.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line advances the reader to the next line in the input. Calling Line resets
|
||||||
|
// the current word, making [reader.Bytes] and [reader.Text] return empty
|
||||||
|
// values. Follow this up with a call to [reader.Word].
|
||||||
|
//
|
||||||
|
// Like [bufio.Scanner], [reader.Err] needs to be checked after Line returns
|
||||||
|
// false to determine if an error occurred during reading.
|
||||||
|
//
|
||||||
|
// Returns true if Line can be called again. Returns false if all lines in the
|
||||||
|
// input have been read.
|
||||||
|
func (r *reader) Line() bool {
|
||||||
|
for r.s.Scan() {
|
||||||
|
line := r.s.Bytes()
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r.line = line
|
||||||
|
r.word = nil
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err := r.s.Err(); err != nil {
|
||||||
|
r.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word advances the reader to the next word in the current line.
|
||||||
|
//
|
||||||
|
// Returns true if a word is found and Word should be called again. Returns
|
||||||
|
// false when all words on the line have been read.
|
||||||
|
func (r *reader) Word() bool {
|
||||||
|
if len(r.line) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find next word start, skipping leading spaces.
|
||||||
|
start := 0
|
||||||
|
for width := 0; start < len(r.line); start += width {
|
||||||
|
var c rune
|
||||||
|
c, width = utf8.DecodeRune(r.line[start:])
|
||||||
|
if !unicode.IsSpace(c) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whitespace scanning reached the end of the line due to trailing whitespace,
|
||||||
|
// meaning there are no more words to read
|
||||||
|
if start == len(r.line) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find next word end.
|
||||||
|
for width, i := 0, start; i < len(r.line); i += width {
|
||||||
|
var c rune
|
||||||
|
c, width = utf8.DecodeRune(r.line[i:])
|
||||||
|
if unicode.IsSpace(c) {
|
||||||
|
r.word = r.line[start:i]
|
||||||
|
r.line = r.line[i:]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The line contains data, but no end-of-word boundary was found. This is the
|
||||||
|
// last, unterminated word in the line.
|
||||||
|
if len(r.line) > start {
|
||||||
|
r.word = r.line[start:]
|
||||||
|
r.line = nil
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *reader) Err() error {
|
||||||
|
return r.err
|
||||||
|
}
|
||||||
39
vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go
generated
vendored
39
vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go
generated
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
// Package kconfig implements a parser for the format of Linux's .config file.
|
||||||
package kconfig
|
package kconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -7,7 +8,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -15,30 +15,6 @@ import (
|
|||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Find find a kconfig file on the host.
|
|
||||||
// It first reads from /boot/config- of the current running kernel and tries
|
|
||||||
// /proc/config.gz if nothing was found in /boot.
|
|
||||||
// If none of the file provide a kconfig, it returns an error.
|
|
||||||
func Find() (*os.File, error) {
|
|
||||||
kernelRelease, err := internal.KernelRelease()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot get kernel release: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
path := "/boot/config-" + kernelRelease
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err == nil {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err = os.Open("/proc/config.gz")
|
|
||||||
if err == nil {
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("neither %s nor /proc/config.gz provide a kconfig", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses the kconfig file for which a reader is given.
|
// Parse parses the kconfig file for which a reader is given.
|
||||||
// All the CONFIG_* which are in filter and which are set set will be
|
// All the CONFIG_* which are in filter and which are set set will be
|
||||||
// put in the returned map as key with their corresponding value as map value.
|
// put in the returned map as key with their corresponding value as map value.
|
||||||
@@ -127,12 +103,13 @@ func PutValue(data []byte, typ btf.Type, value string) error {
|
|||||||
switch value {
|
switch value {
|
||||||
case "y", "n", "m":
|
case "y", "n", "m":
|
||||||
return putValueTri(data, typ, value)
|
return putValueTri(data, typ, value)
|
||||||
default:
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(value, `"`) {
|
if strings.HasPrefix(value, `"`) {
|
||||||
return putValueString(data, typ, value)
|
return putValueString(data, typ, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return putValueNumber(data, typ, value)
|
return putValueNumber(data, typ, value)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Golang translation of libbpf_tristate enum:
|
// Golang translation of libbpf_tristate enum:
|
||||||
@@ -169,6 +146,10 @@ func putValueTri(data []byte, typ btf.Type, value string) error {
|
|||||||
return fmt.Errorf("cannot use enum %q, only libbpf_tristate is supported", v.Name)
|
return fmt.Errorf("cannot use enum %q, only libbpf_tristate is supported", v.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(data) != 4 {
|
||||||
|
return fmt.Errorf("expected enum value to occupy 4 bytes in datasec, got: %d", len(data))
|
||||||
|
}
|
||||||
|
|
||||||
var tri triState
|
var tri triState
|
||||||
switch value {
|
switch value {
|
||||||
case "y":
|
case "y":
|
||||||
@@ -178,10 +159,10 @@ func putValueTri(data []byte, typ btf.Type, value string) error {
|
|||||||
case "n":
|
case "n":
|
||||||
tri = TriNo
|
tri = TriNo
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("value %q is not support for libbpf_tristate", value)
|
return fmt.Errorf("value %q is not supported for libbpf_tristate", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal.NativeEndian.PutUint64(data, uint64(tri))
|
internal.NativeEndian.PutUint32(data, uint32(tri))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("cannot add number value, expected btf.Int or btf.Enum, got: %T", v)
|
return fmt.Errorf("cannot add number value, expected btf.Int or btf.Enum, got: %T", v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
2
vendor/github.com/cilium/ebpf/internal/linux/doc.go
generated
vendored
Normal file
2
vendor/github.com/cilium/ebpf/internal/linux/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// Package linux contains OS specific wrappers around package unix.
|
||||||
|
package linux
|
||||||
31
vendor/github.com/cilium/ebpf/internal/linux/kconfig.go
generated
vendored
Normal file
31
vendor/github.com/cilium/ebpf/internal/linux/kconfig.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package linux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FindKConfig searches for a kconfig file on the host.
|
||||||
|
//
|
||||||
|
// It first reads from /boot/config- of the current running kernel and tries
|
||||||
|
// /proc/config.gz if nothing was found in /boot.
|
||||||
|
// If none of the file provide a kconfig, it returns an error.
|
||||||
|
func FindKConfig() (*os.File, error) {
|
||||||
|
kernelRelease, err := KernelRelease()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get kernel release: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := "/boot/config-" + kernelRelease
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err == nil {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err = os.Open("/proc/config.gz")
|
||||||
|
if err == nil {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("neither %s nor /proc/config.gz provide a kconfig", path)
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ type elfNoteHeader struct {
|
|||||||
// vdsoLinuxVersionCode returns the LINUX_VERSION_CODE embedded in
|
// vdsoLinuxVersionCode returns the LINUX_VERSION_CODE embedded in
|
||||||
// the ELF notes section of the binary provided by the reader.
|
// the ELF notes section of the binary provided by the reader.
|
||||||
func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
|
func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
|
||||||
hdr, err := NewSafeELFFile(r)
|
hdr, err := internal.NewSafeELFFile(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("reading vDSO ELF: %w", err)
|
return 0, fmt.Errorf("reading vDSO ELF: %w", err)
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
|
|||||||
var name string
|
var name string
|
||||||
if n.NameSize > 0 {
|
if n.NameSize > 0 {
|
||||||
// Read the note name, aligned to 4 bytes.
|
// Read the note name, aligned to 4 bytes.
|
||||||
buf := make([]byte, Align(n.NameSize, 4))
|
buf := make([]byte, internal.Align(n.NameSize, 4))
|
||||||
if err := binary.Read(sr, hdr.ByteOrder, &buf); err != nil {
|
if err := binary.Read(sr, hdr.ByteOrder, &buf); err != nil {
|
||||||
return 0, fmt.Errorf("reading note name: %w", err)
|
return 0, fmt.Errorf("reading note name: %w", err)
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,7 @@ func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Discard the note descriptor if it exists but we're not interested in it.
|
// Discard the note descriptor if it exists but we're not interested in it.
|
||||||
if _, err := io.CopyN(io.Discard, sr, int64(Align(n.DescSize, 4))); err != nil {
|
if _, err := io.CopyN(io.Discard, sr, int64(internal.Align(n.DescSize, 4))); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
34
vendor/github.com/cilium/ebpf/internal/linux/version.go
generated
vendored
Normal file
34
vendor/github.com/cilium/ebpf/internal/linux/version.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package linux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KernelVersion returns the version of the currently running kernel.
|
||||||
|
var KernelVersion = sync.OnceValues(detectKernelVersion)
|
||||||
|
|
||||||
|
// detectKernelVersion returns the version of the running kernel.
|
||||||
|
func detectKernelVersion() (internal.Version, error) {
|
||||||
|
vc, err := vdsoVersion()
|
||||||
|
if err != nil {
|
||||||
|
return internal.Version{}, err
|
||||||
|
}
|
||||||
|
return internal.NewVersionFromCode(vc), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KernelRelease returns the release string of the running kernel.
|
||||||
|
// Its format depends on the Linux distribution and corresponds to directory
|
||||||
|
// names in /lib/modules by convention. Some examples are 5.15.17-1-lts and
|
||||||
|
// 4.19.0-16-amd64.
|
||||||
|
func KernelRelease() (string, error) {
|
||||||
|
var uname unix.Utsname
|
||||||
|
if err := unix.Uname(&uname); err != nil {
|
||||||
|
return "", fmt.Errorf("uname failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return unix.ByteSliceToString(uname.Release[:]), nil
|
||||||
|
}
|
||||||
28
vendor/github.com/cilium/ebpf/internal/math.go
generated
vendored
28
vendor/github.com/cilium/ebpf/internal/math.go
generated
vendored
@@ -1,13 +1,33 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import "golang.org/x/exp/constraints"
|
|
||||||
|
|
||||||
// Align returns 'n' updated to 'alignment' boundary.
|
// Align returns 'n' updated to 'alignment' boundary.
|
||||||
func Align[I constraints.Integer](n, alignment I) I {
|
func Align[I Integer](n, alignment I) I {
|
||||||
return (n + alignment - 1) / alignment * alignment
|
return (n + alignment - 1) / alignment * alignment
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPow returns true if n is a power of two.
|
// IsPow returns true if n is a power of two.
|
||||||
func IsPow[I constraints.Integer](n I) bool {
|
func IsPow[I Integer](n I) bool {
|
||||||
return n != 0 && (n&(n-1)) == 0
|
return n != 0 && (n&(n-1)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Between returns the value clamped between a and b.
|
||||||
|
func Between[I Integer](val, a, b I) I {
|
||||||
|
lower, upper := a, b
|
||||||
|
if lower > upper {
|
||||||
|
upper, lower = a, b
|
||||||
|
}
|
||||||
|
|
||||||
|
val = min(val, upper)
|
||||||
|
return max(val, lower)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integer represents all possible integer types.
|
||||||
|
// Remove when x/exp/constraints is moved to the standard library.
|
||||||
|
type Integer interface {
|
||||||
|
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of integer types known by the Go compiler. Used by TestIntegerConstraint
|
||||||
|
// to warn if a new integer type is introduced. Remove when x/exp/constraints
|
||||||
|
// is moved to the standard library.
|
||||||
|
var integers = []string{"int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr"}
|
||||||
|
|||||||
74
vendor/github.com/cilium/ebpf/internal/sys/fd.go
generated
vendored
74
vendor/github.com/cilium/ebpf/internal/sys/fd.go
generated
vendored
@@ -4,9 +4,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/internal/testutils/fdtrace"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,15 +20,7 @@ type FD struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newFD(value int) *FD {
|
func newFD(value int) *FD {
|
||||||
if onLeakFD != nil {
|
fdtrace.TraceFD(value, 1)
|
||||||
// Attempt to store the caller's stack for the given fd value.
|
|
||||||
// Panic if fds contains an existing stack for the fd.
|
|
||||||
old, exist := fds.LoadOrStore(value, callersFrames())
|
|
||||||
if exist {
|
|
||||||
f := old.(*runtime.Frames)
|
|
||||||
panic(fmt.Sprintf("found existing stack for fd %d:\n%s", value, FormatFrames(f)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fd := &FD{value}
|
fd := &FD{value}
|
||||||
runtime.SetFinalizer(fd, (*FD).finalize)
|
runtime.SetFinalizer(fd, (*FD).finalize)
|
||||||
@@ -39,13 +34,7 @@ func (fd *FD) finalize() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the fd leak callback. Calls LoadAndDelete to guarantee the callback
|
fdtrace.LeakFD(fd.raw)
|
||||||
// is invoked at most once for one sys.FD allocation, runtime.Frames can only
|
|
||||||
// be unwound once.
|
|
||||||
f, ok := fds.LoadAndDelete(fd.Int())
|
|
||||||
if ok && onLeakFD != nil {
|
|
||||||
onLeakFD(f.(*runtime.Frames))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
}
|
}
|
||||||
@@ -92,12 +81,15 @@ func (fd *FD) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return unix.Close(fd.disown())
|
return unix.Close(fd.Disown())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FD) disown() int {
|
// Disown destroys the FD and returns its raw file descriptor without closing
|
||||||
value := int(fd.raw)
|
// it. After this call, the underlying fd is no longer tied to the FD's
|
||||||
fds.Delete(int(value))
|
// lifecycle.
|
||||||
|
func (fd *FD) Disown() int {
|
||||||
|
value := fd.raw
|
||||||
|
fdtrace.ForgetFD(value)
|
||||||
fd.raw = -1
|
fd.raw = -1
|
||||||
|
|
||||||
runtime.SetFinalizer(fd, nil)
|
runtime.SetFinalizer(fd, nil)
|
||||||
@@ -129,5 +121,45 @@ func (fd *FD) File(name string) *os.File {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.NewFile(uintptr(fd.disown()), name)
|
return os.NewFile(uintptr(fd.Disown()), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjGetTyped wraps [ObjGet] with a readlink call to extract the type of the
|
||||||
|
// underlying bpf object.
|
||||||
|
func ObjGetTyped(attr *ObjGetAttr) (*FD, ObjType, error) {
|
||||||
|
fd, err := ObjGet(attr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, err := readType(fd)
|
||||||
|
if err != nil {
|
||||||
|
_ = fd.Close()
|
||||||
|
return nil, 0, fmt.Errorf("reading fd type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd, typ, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readType returns the bpf object type of the file descriptor by calling
|
||||||
|
// readlink(3). Returns an error if the file descriptor does not represent a bpf
|
||||||
|
// object.
|
||||||
|
func readType(fd *FD) (ObjType, error) {
|
||||||
|
s, err := os.Readlink(filepath.Join("/proc/self/fd/", fd.String()))
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("readlink fd %d: %w", fd.Int(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s = strings.TrimPrefix(s, "anon_inode:")
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case "bpf-map":
|
||||||
|
return BPF_TYPE_MAP, nil
|
||||||
|
case "bpf-prog":
|
||||||
|
return BPF_TYPE_PROG, nil
|
||||||
|
case "bpf-link":
|
||||||
|
return BPF_TYPE_LINK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("unknown type %s of fd %d", s, fd.Int())
|
||||||
}
|
}
|
||||||
|
|||||||
93
vendor/github.com/cilium/ebpf/internal/sys/fd_trace.go
generated
vendored
93
vendor/github.com/cilium/ebpf/internal/sys/fd_trace.go
generated
vendored
@@ -1,93 +0,0 @@
|
|||||||
package sys
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OnLeakFD controls tracing [FD] lifetime to detect resources that are not
|
|
||||||
// closed by Close().
|
|
||||||
//
|
|
||||||
// If fn is not nil, tracing is enabled for all FDs created going forward. fn is
|
|
||||||
// invoked for all FDs that are closed by the garbage collector instead of an
|
|
||||||
// explicit Close() by a caller. Calling OnLeakFD twice with a non-nil fn
|
|
||||||
// (without disabling tracing in the meantime) will cause a panic.
|
|
||||||
//
|
|
||||||
// If fn is nil, tracing will be disabled. Any FDs that have not been closed are
|
|
||||||
// considered to be leaked, fn will be invoked for them, and the process will be
|
|
||||||
// terminated.
|
|
||||||
//
|
|
||||||
// fn will be invoked at most once for every unique sys.FD allocation since a
|
|
||||||
// runtime.Frames can only be unwound once.
|
|
||||||
func OnLeakFD(fn func(*runtime.Frames)) {
|
|
||||||
// Enable leak tracing if new fn is provided.
|
|
||||||
if fn != nil {
|
|
||||||
if onLeakFD != nil {
|
|
||||||
panic("OnLeakFD called twice with non-nil fn")
|
|
||||||
}
|
|
||||||
|
|
||||||
onLeakFD = fn
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn is nil past this point.
|
|
||||||
|
|
||||||
if onLeakFD == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call onLeakFD for all open fds.
|
|
||||||
if fs := flushFrames(); len(fs) != 0 {
|
|
||||||
for _, f := range fs {
|
|
||||||
onLeakFD(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onLeakFD = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var onLeakFD func(*runtime.Frames)
|
|
||||||
|
|
||||||
// fds is a registry of all file descriptors wrapped into sys.fds that were
|
|
||||||
// created while an fd tracer was active.
|
|
||||||
var fds sync.Map // map[int]*runtime.Frames
|
|
||||||
|
|
||||||
// flushFrames removes all elements from fds and returns them as a slice. This
|
|
||||||
// deals with the fact that a runtime.Frames can only be unwound once using
|
|
||||||
// Next().
|
|
||||||
func flushFrames() []*runtime.Frames {
|
|
||||||
var frames []*runtime.Frames
|
|
||||||
fds.Range(func(key, value any) bool {
|
|
||||||
frames = append(frames, value.(*runtime.Frames))
|
|
||||||
fds.Delete(key)
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return frames
|
|
||||||
}
|
|
||||||
|
|
||||||
func callersFrames() *runtime.Frames {
|
|
||||||
c := make([]uintptr, 32)
|
|
||||||
|
|
||||||
// Skip runtime.Callers and this function.
|
|
||||||
i := runtime.Callers(2, c)
|
|
||||||
if i == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return runtime.CallersFrames(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FormatFrames formats a runtime.Frames as a human-readable string.
|
|
||||||
func FormatFrames(fs *runtime.Frames) string {
|
|
||||||
var b bytes.Buffer
|
|
||||||
for {
|
|
||||||
f, more := fs.Next()
|
|
||||||
b.WriteString(fmt.Sprintf("\t%s+%#x\n\t\t%s:%d\n", f.Function, f.PC-f.Entry, f.File, f.Line))
|
|
||||||
if !more {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
53
vendor/github.com/cilium/ebpf/internal/sys/mapflags_string.go
generated
vendored
53
vendor/github.com/cilium/ebpf/internal/sys/mapflags_string.go
generated
vendored
@@ -1,53 +0,0 @@
|
|||||||
// Code generated by "stringer -type MapFlags"; DO NOT EDIT.
|
|
||||||
|
|
||||||
package sys
|
|
||||||
|
|
||||||
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_F_NO_PREALLOC-1]
|
|
||||||
_ = x[BPF_F_NO_COMMON_LRU-2]
|
|
||||||
_ = x[BPF_F_NUMA_NODE-4]
|
|
||||||
_ = x[BPF_F_RDONLY-8]
|
|
||||||
_ = x[BPF_F_WRONLY-16]
|
|
||||||
_ = x[BPF_F_STACK_BUILD_ID-32]
|
|
||||||
_ = x[BPF_F_ZERO_SEED-64]
|
|
||||||
_ = x[BPF_F_RDONLY_PROG-128]
|
|
||||||
_ = x[BPF_F_WRONLY_PROG-256]
|
|
||||||
_ = x[BPF_F_CLONE-512]
|
|
||||||
_ = x[BPF_F_MMAPABLE-1024]
|
|
||||||
_ = x[BPF_F_PRESERVE_ELEMS-2048]
|
|
||||||
_ = x[BPF_F_INNER_MAP-4096]
|
|
||||||
_ = x[BPF_F_LINK-8192]
|
|
||||||
_ = x[BPF_F_PATH_FD-16384]
|
|
||||||
}
|
|
||||||
|
|
||||||
const _MapFlags_name = "BPF_F_NO_PREALLOCBPF_F_NO_COMMON_LRUBPF_F_NUMA_NODEBPF_F_RDONLYBPF_F_WRONLYBPF_F_STACK_BUILD_IDBPF_F_ZERO_SEEDBPF_F_RDONLY_PROGBPF_F_WRONLY_PROGBPF_F_CLONEBPF_F_MMAPABLEBPF_F_PRESERVE_ELEMSBPF_F_INNER_MAPBPF_F_LINKBPF_F_PATH_FD"
|
|
||||||
|
|
||||||
var _MapFlags_map = map[MapFlags]string{
|
|
||||||
1: _MapFlags_name[0:17],
|
|
||||||
2: _MapFlags_name[17:36],
|
|
||||||
4: _MapFlags_name[36:51],
|
|
||||||
8: _MapFlags_name[51:63],
|
|
||||||
16: _MapFlags_name[63:75],
|
|
||||||
32: _MapFlags_name[75:95],
|
|
||||||
64: _MapFlags_name[95:110],
|
|
||||||
128: _MapFlags_name[110:127],
|
|
||||||
256: _MapFlags_name[127:144],
|
|
||||||
512: _MapFlags_name[144:155],
|
|
||||||
1024: _MapFlags_name[155:169],
|
|
||||||
2048: _MapFlags_name[169:189],
|
|
||||||
4096: _MapFlags_name[189:204],
|
|
||||||
8192: _MapFlags_name[204:214],
|
|
||||||
16384: _MapFlags_name[214:227],
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i MapFlags) String() string {
|
|
||||||
if str, ok := _MapFlags_map[i]; ok {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
return "MapFlags(" + strconv.FormatInt(int64(i), 10) + ")"
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package internal
|
package sys
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Pin(currentPath, newPath string, fd *sys.FD) error {
|
func Pin(currentPath, newPath string, fd *FD) error {
|
||||||
if newPath == "" {
|
if newPath == "" {
|
||||||
return errors.New("given pinning path cannot be empty")
|
return errors.New("given pinning path cannot be empty")
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@ func Pin(currentPath, newPath string, fd *sys.FD) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fsType, err := FSType(filepath.Dir(newPath))
|
fsType, err := linux.FSType(filepath.Dir(newPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -30,8 +30,8 @@ func Pin(currentPath, newPath string, fd *sys.FD) error {
|
|||||||
defer runtime.KeepAlive(fd)
|
defer runtime.KeepAlive(fd)
|
||||||
|
|
||||||
if currentPath == "" {
|
if currentPath == "" {
|
||||||
return sys.ObjPin(&sys.ObjPinAttr{
|
return ObjPin(&ObjPinAttr{
|
||||||
Pathname: sys.NewStringPointer(newPath),
|
Pathname: NewStringPointer(newPath),
|
||||||
BpfFd: fd.Uint(),
|
BpfFd: fd.Uint(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -47,8 +47,8 @@ func Pin(currentPath, newPath string, fd *sys.FD) error {
|
|||||||
return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, 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.
|
// Internal state not in sync with the file system so let's fix it.
|
||||||
return sys.ObjPin(&sys.ObjPinAttr{
|
return ObjPin(&ObjPinAttr{
|
||||||
Pathname: sys.NewStringPointer(newPath),
|
Pathname: NewStringPointer(newPath),
|
||||||
BpfFd: fd.Uint(),
|
BpfFd: fd.Uint(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
6
vendor/github.com/cilium/ebpf/internal/sys/ptr.go
generated
vendored
6
vendor/github.com/cilium/ebpf/internal/sys/ptr.go
generated
vendored
@@ -11,13 +11,13 @@ func NewPointer(ptr unsafe.Pointer) Pointer {
|
|||||||
return Pointer{ptr: ptr}
|
return Pointer{ptr: ptr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSlicePointer creates a 64-bit pointer from a byte slice.
|
// NewSlicePointer creates a 64-bit pointer from a slice.
|
||||||
func NewSlicePointer(buf []byte) Pointer {
|
func NewSlicePointer[T comparable](buf []T) Pointer {
|
||||||
if len(buf) == 0 {
|
if len(buf) == 0 {
|
||||||
return Pointer{}
|
return Pointer{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pointer{ptr: unsafe.Pointer(&buf[0])}
|
return Pointer{ptr: unsafe.Pointer(unsafe.SliceData(buf))}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSlicePointerLen creates a 64-bit pointer from a byte slice.
|
// NewSlicePointerLen creates a 64-bit pointer from a byte slice.
|
||||||
|
|||||||
37
vendor/github.com/cilium/ebpf/internal/sys/syscall.go
generated
vendored
37
vendor/github.com/cilium/ebpf/internal/sys/syscall.go
generated
vendored
@@ -133,12 +133,12 @@ func ObjInfo(fd *FD, info Info) error {
|
|||||||
|
|
||||||
// BPFObjName is a null-terminated string made up of
|
// BPFObjName is a null-terminated string made up of
|
||||||
// 'A-Za-z0-9_' characters.
|
// 'A-Za-z0-9_' characters.
|
||||||
type ObjName [unix.BPF_OBJ_NAME_LEN]byte
|
type ObjName [BPF_OBJ_NAME_LEN]byte
|
||||||
|
|
||||||
// NewObjName truncates the result if it is too long.
|
// NewObjName truncates the result if it is too long.
|
||||||
func NewObjName(name string) ObjName {
|
func NewObjName(name string) ObjName {
|
||||||
var result ObjName
|
var result ObjName
|
||||||
copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
|
copy(result[:BPF_OBJ_NAME_LEN-1], name)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,29 +160,6 @@ type BTFID uint32
|
|||||||
// TypeID identifies a type in a BTF blob.
|
// TypeID identifies a type in a BTF blob.
|
||||||
type TypeID uint32
|
type TypeID uint32
|
||||||
|
|
||||||
// MapFlags control map behaviour.
|
|
||||||
type MapFlags uint32
|
|
||||||
|
|
||||||
//go:generate go run golang.org/x/tools/cmd/stringer@latest -type MapFlags
|
|
||||||
|
|
||||||
const (
|
|
||||||
BPF_F_NO_PREALLOC MapFlags = 1 << iota
|
|
||||||
BPF_F_NO_COMMON_LRU
|
|
||||||
BPF_F_NUMA_NODE
|
|
||||||
BPF_F_RDONLY
|
|
||||||
BPF_F_WRONLY
|
|
||||||
BPF_F_STACK_BUILD_ID
|
|
||||||
BPF_F_ZERO_SEED
|
|
||||||
BPF_F_RDONLY_PROG
|
|
||||||
BPF_F_WRONLY_PROG
|
|
||||||
BPF_F_CLONE
|
|
||||||
BPF_F_MMAPABLE
|
|
||||||
BPF_F_PRESERVE_ELEMS
|
|
||||||
BPF_F_INNER_MAP
|
|
||||||
BPF_F_LINK
|
|
||||||
BPF_F_PATH_FD
|
|
||||||
)
|
|
||||||
|
|
||||||
// Flags used by bpf_mprog.
|
// Flags used by bpf_mprog.
|
||||||
const (
|
const (
|
||||||
BPF_F_REPLACE = 1 << (iota + 2)
|
BPF_F_REPLACE = 1 << (iota + 2)
|
||||||
@@ -192,6 +169,16 @@ const (
|
|||||||
BPF_F_LINK_MPROG = 1 << 13 // aka BPF_F_LINK
|
BPF_F_LINK_MPROG = 1 << 13 // aka BPF_F_LINK
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Flags used by BPF_PROG_LOAD.
|
||||||
|
const (
|
||||||
|
BPF_F_SLEEPABLE = 1 << 4
|
||||||
|
BPF_F_XDP_HAS_FRAGS = 1 << 5
|
||||||
|
BPF_F_XDP_DEV_BOUND_ONLY = 1 << 6
|
||||||
|
)
|
||||||
|
|
||||||
|
const BPF_TAG_SIZE = 8
|
||||||
|
const BPF_OBJ_NAME_LEN = 16
|
||||||
|
|
||||||
// wrappedErrno wraps syscall.Errno to prevent direct comparisons with
|
// wrappedErrno wraps syscall.Errno to prevent direct comparisons with
|
||||||
// syscall.E* or unix.E* constants.
|
// syscall.E* or unix.E* constants.
|
||||||
//
|
//
|
||||||
|
|||||||
185
vendor/github.com/cilium/ebpf/internal/sys/types.go
vendored
185
vendor/github.com/cilium/ebpf/internal/sys/types.go
vendored
@@ -6,6 +6,170 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BPF_ADJ_ROOM_ENCAP_L2_MASK = 255
|
||||||
|
BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56
|
||||||
|
BPF_ANY = 0
|
||||||
|
BPF_CSUM_LEVEL_DEC = 2
|
||||||
|
BPF_CSUM_LEVEL_INC = 1
|
||||||
|
BPF_CSUM_LEVEL_QUERY = 0
|
||||||
|
BPF_CSUM_LEVEL_RESET = 3
|
||||||
|
BPF_EXIST = 2
|
||||||
|
BPF_FIB_LKUP_RET_BLACKHOLE = 1
|
||||||
|
BPF_FIB_LKUP_RET_FRAG_NEEDED = 8
|
||||||
|
BPF_FIB_LKUP_RET_FWD_DISABLED = 5
|
||||||
|
BPF_FIB_LKUP_RET_NOT_FWDED = 4
|
||||||
|
BPF_FIB_LKUP_RET_NO_NEIGH = 7
|
||||||
|
BPF_FIB_LKUP_RET_NO_SRC_ADDR = 9
|
||||||
|
BPF_FIB_LKUP_RET_PROHIBIT = 3
|
||||||
|
BPF_FIB_LKUP_RET_SUCCESS = 0
|
||||||
|
BPF_FIB_LKUP_RET_UNREACHABLE = 2
|
||||||
|
BPF_FIB_LKUP_RET_UNSUPP_LWT = 6
|
||||||
|
BPF_FIB_LOOKUP_DIRECT = 1
|
||||||
|
BPF_FIB_LOOKUP_OUTPUT = 2
|
||||||
|
BPF_FIB_LOOKUP_SKIP_NEIGH = 4
|
||||||
|
BPF_FIB_LOOKUP_SRC = 16
|
||||||
|
BPF_FIB_LOOKUP_TBID = 8
|
||||||
|
BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = 1
|
||||||
|
BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = 4
|
||||||
|
BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = 2
|
||||||
|
BPF_F_ADJ_ROOM_DECAP_L3_IPV4 = 128
|
||||||
|
BPF_F_ADJ_ROOM_DECAP_L3_IPV6 = 256
|
||||||
|
BPF_F_ADJ_ROOM_ENCAP_L2_ETH = 64
|
||||||
|
BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = 2
|
||||||
|
BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = 4
|
||||||
|
BPF_F_ADJ_ROOM_ENCAP_L4_GRE = 8
|
||||||
|
BPF_F_ADJ_ROOM_ENCAP_L4_UDP = 16
|
||||||
|
BPF_F_ADJ_ROOM_FIXED_GSO = 1
|
||||||
|
BPF_F_ADJ_ROOM_NO_CSUM_RESET = 32
|
||||||
|
BPF_F_BPRM_SECUREEXEC = 1
|
||||||
|
BPF_F_BROADCAST = 8
|
||||||
|
BPF_F_CLONE = 512
|
||||||
|
BPF_F_CTXLEN_MASK = 4503595332403200
|
||||||
|
BPF_F_CURRENT_CPU = 4294967295
|
||||||
|
BPF_F_CURRENT_NETNS = 18446744073709551615
|
||||||
|
BPF_F_DONT_FRAGMENT = 4
|
||||||
|
BPF_F_EXCLUDE_INGRESS = 16
|
||||||
|
BPF_F_FAST_STACK_CMP = 512
|
||||||
|
BPF_F_GET_BRANCH_RECORDS_SIZE = 1
|
||||||
|
BPF_F_HDR_FIELD_MASK = 15
|
||||||
|
BPF_F_INDEX_MASK = 4294967295
|
||||||
|
BPF_F_INGRESS = 1
|
||||||
|
BPF_F_INNER_MAP = 4096
|
||||||
|
BPF_F_INVALIDATE_HASH = 2
|
||||||
|
BPF_F_KPROBE_MULTI_RETURN = 1
|
||||||
|
BPF_F_LINK = 8192
|
||||||
|
BPF_F_LOCK = 4
|
||||||
|
BPF_F_MARK_ENFORCE = 64
|
||||||
|
BPF_F_MARK_MANGLED_0 = 32
|
||||||
|
BPF_F_MMAPABLE = 1024
|
||||||
|
BPF_F_NEIGH = 2
|
||||||
|
BPF_F_NEXTHOP = 8
|
||||||
|
BPF_F_NO_COMMON_LRU = 2
|
||||||
|
BPF_F_NO_PREALLOC = 1
|
||||||
|
BPF_F_NO_TUNNEL_KEY = 16
|
||||||
|
BPF_F_NUMA_NODE = 4
|
||||||
|
BPF_F_PATH_FD = 16384
|
||||||
|
BPF_F_PEER = 4
|
||||||
|
BPF_F_PRESERVE_ELEMS = 2048
|
||||||
|
BPF_F_PSEUDO_HDR = 16
|
||||||
|
BPF_F_RDONLY = 8
|
||||||
|
BPF_F_RDONLY_PROG = 128
|
||||||
|
BPF_F_RECOMPUTE_CSUM = 1
|
||||||
|
BPF_F_REUSE_STACKID = 1024
|
||||||
|
BPF_F_SEQ_NUMBER = 8
|
||||||
|
BPF_F_SKIP_FIELD_MASK = 255
|
||||||
|
BPF_F_STACK_BUILD_ID = 32
|
||||||
|
BPF_F_SYSCTL_BASE_NAME = 1
|
||||||
|
BPF_F_TIMER_ABS = 1
|
||||||
|
BPF_F_TIMER_CPU_PIN = 2
|
||||||
|
BPF_F_TUNINFO_FLAGS = 16
|
||||||
|
BPF_F_TUNINFO_IPV6 = 1
|
||||||
|
BPF_F_UPROBE_MULTI_RETURN = 1
|
||||||
|
BPF_F_USER_BUILD_ID = 2048
|
||||||
|
BPF_F_USER_STACK = 256
|
||||||
|
BPF_F_WRONLY = 16
|
||||||
|
BPF_F_WRONLY_PROG = 256
|
||||||
|
BPF_F_ZERO_CSUM_TX = 2
|
||||||
|
BPF_F_ZERO_SEED = 64
|
||||||
|
BPF_LOAD_HDR_OPT_TCP_SYN = 1
|
||||||
|
BPF_LOCAL_STORAGE_GET_F_CREATE = 1
|
||||||
|
BPF_MAX_LOOPS = 8388608
|
||||||
|
BPF_MAX_TRAMP_LINKS = 38
|
||||||
|
BPF_NOEXIST = 1
|
||||||
|
BPF_RB_AVAIL_DATA = 0
|
||||||
|
BPF_RB_CONS_POS = 2
|
||||||
|
BPF_RB_FORCE_WAKEUP = 2
|
||||||
|
BPF_RB_NO_WAKEUP = 1
|
||||||
|
BPF_RB_PROD_POS = 3
|
||||||
|
BPF_RB_RING_SIZE = 1
|
||||||
|
BPF_REG_0 = 0
|
||||||
|
BPF_REG_1 = 1
|
||||||
|
BPF_REG_10 = 10
|
||||||
|
BPF_REG_2 = 2
|
||||||
|
BPF_REG_3 = 3
|
||||||
|
BPF_REG_4 = 4
|
||||||
|
BPF_REG_5 = 5
|
||||||
|
BPF_REG_6 = 6
|
||||||
|
BPF_REG_7 = 7
|
||||||
|
BPF_REG_8 = 8
|
||||||
|
BPF_REG_9 = 9
|
||||||
|
BPF_RINGBUF_BUSY_BIT = 2147483648
|
||||||
|
BPF_RINGBUF_DISCARD_BIT = 1073741824
|
||||||
|
BPF_RINGBUF_HDR_SZ = 8
|
||||||
|
BPF_SKB_TSTAMP_DELIVERY_MONO = 1
|
||||||
|
BPF_SKB_TSTAMP_UNSPEC = 0
|
||||||
|
BPF_SK_LOOKUP_F_NO_REUSEPORT = 2
|
||||||
|
BPF_SK_LOOKUP_F_REPLACE = 1
|
||||||
|
BPF_SK_STORAGE_GET_F_CREATE = 1
|
||||||
|
BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB = 4
|
||||||
|
BPF_SOCK_OPS_ALL_CB_FLAGS = 127
|
||||||
|
BPF_SOCK_OPS_BASE_RTT = 7
|
||||||
|
BPF_SOCK_OPS_HDR_OPT_LEN_CB = 14
|
||||||
|
BPF_SOCK_OPS_NEEDS_ECN = 6
|
||||||
|
BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = 16
|
||||||
|
BPF_SOCK_OPS_PARSE_HDR_OPT_CB = 13
|
||||||
|
BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = 32
|
||||||
|
BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB = 5
|
||||||
|
BPF_SOCK_OPS_RETRANS_CB = 9
|
||||||
|
BPF_SOCK_OPS_RETRANS_CB_FLAG = 2
|
||||||
|
BPF_SOCK_OPS_RTO_CB = 8
|
||||||
|
BPF_SOCK_OPS_RTO_CB_FLAG = 1
|
||||||
|
BPF_SOCK_OPS_RTT_CB = 12
|
||||||
|
BPF_SOCK_OPS_RTT_CB_FLAG = 8
|
||||||
|
BPF_SOCK_OPS_RWND_INIT = 2
|
||||||
|
BPF_SOCK_OPS_STATE_CB = 10
|
||||||
|
BPF_SOCK_OPS_STATE_CB_FLAG = 4
|
||||||
|
BPF_SOCK_OPS_TCP_CONNECT_CB = 3
|
||||||
|
BPF_SOCK_OPS_TCP_LISTEN_CB = 11
|
||||||
|
BPF_SOCK_OPS_TIMEOUT_INIT = 1
|
||||||
|
BPF_SOCK_OPS_VOID = 0
|
||||||
|
BPF_SOCK_OPS_WRITE_HDR_OPT_CB = 15
|
||||||
|
BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = 64
|
||||||
|
BPF_STRUCT_OPS_TYPE_bpf_dummy_ops = 0
|
||||||
|
BPF_STRUCT_OPS_TYPE_tcp_congestion_ops = 1
|
||||||
|
BPF_TASK_ITER_ALL_PROCS = 0
|
||||||
|
BPF_TASK_ITER_ALL_THREADS = 1
|
||||||
|
BPF_TASK_ITER_PROC_THREADS = 2
|
||||||
|
BPF_TCP_BOUND_INACTIVE = 13
|
||||||
|
BPF_TCP_CLOSE = 7
|
||||||
|
BPF_TCP_CLOSE_WAIT = 8
|
||||||
|
BPF_TCP_CLOSING = 11
|
||||||
|
BPF_TCP_ESTABLISHED = 1
|
||||||
|
BPF_TCP_FIN_WAIT1 = 4
|
||||||
|
BPF_TCP_FIN_WAIT2 = 5
|
||||||
|
BPF_TCP_LAST_ACK = 9
|
||||||
|
BPF_TCP_LISTEN = 10
|
||||||
|
BPF_TCP_MAX_STATES = 14
|
||||||
|
BPF_TCP_NEW_SYN_RECV = 12
|
||||||
|
BPF_TCP_SYN_RECV = 3
|
||||||
|
BPF_TCP_SYN_SENT = 2
|
||||||
|
BPF_TCP_TIME_WAIT = 6
|
||||||
|
BPF_WRITE_HDR_TCP_CURRENT_MSS = 1
|
||||||
|
BPF_WRITE_HDR_TCP_SYNACK_COOKIE = 2
|
||||||
|
BPF_XFRM_STATE_OPTS_SZ = 36
|
||||||
|
)
|
||||||
|
|
||||||
type AdjRoomMode uint32
|
type AdjRoomMode uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -402,6 +566,15 @@ const (
|
|||||||
BPF_MAP_TYPE_CGRP_STORAGE MapType = 32
|
BPF_MAP_TYPE_CGRP_STORAGE MapType = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ObjType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
BPF_TYPE_UNSPEC ObjType = 0
|
||||||
|
BPF_TYPE_PROG ObjType = 1
|
||||||
|
BPF_TYPE_MAP ObjType = 2
|
||||||
|
BPF_TYPE_LINK ObjType = 3
|
||||||
|
)
|
||||||
|
|
||||||
type PerfEventType uint32
|
type PerfEventType uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -537,7 +710,7 @@ type MapInfo struct {
|
|||||||
KeySize uint32
|
KeySize uint32
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
MapFlags MapFlags
|
MapFlags uint32
|
||||||
Name ObjName
|
Name ObjName
|
||||||
Ifindex uint32
|
Ifindex uint32
|
||||||
BtfVmlinuxValueTypeId TypeID
|
BtfVmlinuxValueTypeId TypeID
|
||||||
@@ -556,7 +729,7 @@ type ProgInfo struct {
|
|||||||
Tag [8]uint8
|
Tag [8]uint8
|
||||||
JitedProgLen uint32
|
JitedProgLen uint32
|
||||||
XlatedProgLen uint32
|
XlatedProgLen uint32
|
||||||
JitedProgInsns uint64
|
JitedProgInsns Pointer
|
||||||
XlatedProgInsns Pointer
|
XlatedProgInsns Pointer
|
||||||
LoadTime uint64
|
LoadTime uint64
|
||||||
CreatedByUid uint32
|
CreatedByUid uint32
|
||||||
@@ -569,15 +742,15 @@ type ProgInfo struct {
|
|||||||
NetnsIno uint64
|
NetnsIno uint64
|
||||||
NrJitedKsyms uint32
|
NrJitedKsyms uint32
|
||||||
NrJitedFuncLens uint32
|
NrJitedFuncLens uint32
|
||||||
JitedKsyms uint64
|
JitedKsyms Pointer
|
||||||
JitedFuncLens uint64
|
JitedFuncLens Pointer
|
||||||
BtfId BTFID
|
BtfId BTFID
|
||||||
FuncInfoRecSize uint32
|
FuncInfoRecSize uint32
|
||||||
FuncInfo Pointer
|
FuncInfo Pointer
|
||||||
NrFuncInfo uint32
|
NrFuncInfo uint32
|
||||||
NrLineInfo uint32
|
NrLineInfo uint32
|
||||||
LineInfo Pointer
|
LineInfo Pointer
|
||||||
JitedLineInfo uint64
|
JitedLineInfo Pointer
|
||||||
NrJitedLineInfo uint32
|
NrJitedLineInfo uint32
|
||||||
LineInfoRecSize uint32
|
LineInfoRecSize uint32
|
||||||
JitedLineInfoRecSize uint32
|
JitedLineInfoRecSize uint32
|
||||||
@@ -886,7 +1059,7 @@ type MapCreateAttr struct {
|
|||||||
KeySize uint32
|
KeySize uint32
|
||||||
ValueSize uint32
|
ValueSize uint32
|
||||||
MaxEntries uint32
|
MaxEntries uint32
|
||||||
MapFlags MapFlags
|
MapFlags uint32
|
||||||
InnerMapFd uint32
|
InnerMapFd uint32
|
||||||
NumaNode uint32
|
NumaNode uint32
|
||||||
MapName ObjName
|
MapName ObjName
|
||||||
|
|||||||
10
vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go
generated
vendored
10
vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go
generated
vendored
@@ -51,12 +51,12 @@ func SyscallOutput(dst any, size int) Buffer {
|
|||||||
//
|
//
|
||||||
// Returns the number of copied bytes.
|
// Returns the number of copied bytes.
|
||||||
func (b Buffer) CopyTo(dst []byte) int {
|
func (b Buffer) CopyTo(dst []byte) int {
|
||||||
return copy(dst, b.unsafeBytes())
|
return copy(dst, b.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendTo appends the buffer onto dst.
|
// AppendTo appends the buffer onto dst.
|
||||||
func (b Buffer) AppendTo(dst []byte) []byte {
|
func (b Buffer) AppendTo(dst []byte) []byte {
|
||||||
return append(dst, b.unsafeBytes()...)
|
return append(dst, b.Bytes()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pointer returns the location where a syscall should write.
|
// Pointer returns the location where a syscall should write.
|
||||||
@@ -72,10 +72,12 @@ func (b Buffer) Unmarshal(data any) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return Unmarshal(data, b.unsafeBytes())
|
return Unmarshal(data, b.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b Buffer) unsafeBytes() []byte {
|
// Bytes returns the buffer as a byte slice. Returns nil if the Buffer was
|
||||||
|
// created using UnsafeBuffer or by zero-copy unmarshaling.
|
||||||
|
func (b Buffer) Bytes() []byte {
|
||||||
if b.size == syscallPointerOnly {
|
if b.size == syscallPointerOnly {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
103
vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/fd_trace.go
generated
vendored
Normal file
103
vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/fd_trace.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package fdtrace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// foundLeak is atomic since the GC may collect objects in parallel.
|
||||||
|
var foundLeak atomic.Bool
|
||||||
|
|
||||||
|
func onLeakFD(fs *runtime.Frames) {
|
||||||
|
foundLeak.Store(true)
|
||||||
|
fmt.Fprintln(os.Stderr, "leaked fd created at:")
|
||||||
|
fmt.Fprintln(os.Stderr, formatFrames(fs))
|
||||||
|
}
|
||||||
|
|
||||||
|
// fds is a registry of all file descriptors wrapped into sys.fds that were
|
||||||
|
// created while an fd tracer was active.
|
||||||
|
var fds *sync.Map // map[int]*runtime.Frames
|
||||||
|
|
||||||
|
// TraceFD associates raw with the current execution stack.
|
||||||
|
//
|
||||||
|
// skip controls how many entries of the stack the function should skip.
|
||||||
|
func TraceFD(raw int, skip int) {
|
||||||
|
if fds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to store the caller's stack for the given fd value.
|
||||||
|
// Panic if fds contains an existing stack for the fd.
|
||||||
|
old, exist := fds.LoadOrStore(raw, callersFrames(skip))
|
||||||
|
if exist {
|
||||||
|
f := old.(*runtime.Frames)
|
||||||
|
panic(fmt.Sprintf("found existing stack for fd %d:\n%s", raw, formatFrames(f)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForgetFD removes any existing association for raw.
|
||||||
|
func ForgetFD(raw int) {
|
||||||
|
if fds != nil {
|
||||||
|
fds.Delete(raw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LeakFD indicates that raw was leaked.
|
||||||
|
//
|
||||||
|
// Calling the function with a value that was not passed to [TraceFD] before
|
||||||
|
// is undefined.
|
||||||
|
func LeakFD(raw int) {
|
||||||
|
if fds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke the fd leak callback. Calls LoadAndDelete to guarantee the callback
|
||||||
|
// is invoked at most once for one sys.FD allocation, runtime.Frames can only
|
||||||
|
// be unwound once.
|
||||||
|
f, ok := fds.LoadAndDelete(raw)
|
||||||
|
if ok {
|
||||||
|
onLeakFD(f.(*runtime.Frames))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flushFrames removes all elements from fds and returns them as a slice. This
|
||||||
|
// deals with the fact that a runtime.Frames can only be unwound once using
|
||||||
|
// Next().
|
||||||
|
func flushFrames() []*runtime.Frames {
|
||||||
|
var frames []*runtime.Frames
|
||||||
|
fds.Range(func(key, value any) bool {
|
||||||
|
frames = append(frames, value.(*runtime.Frames))
|
||||||
|
fds.Delete(key)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return frames
|
||||||
|
}
|
||||||
|
|
||||||
|
func callersFrames(skip int) *runtime.Frames {
|
||||||
|
c := make([]uintptr, 32)
|
||||||
|
|
||||||
|
// Skip runtime.Callers and this function.
|
||||||
|
i := runtime.Callers(skip+2, c)
|
||||||
|
if i == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime.CallersFrames(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatFrames formats a runtime.Frames as a human-readable string.
|
||||||
|
func formatFrames(fs *runtime.Frames) string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
for {
|
||||||
|
f, more := fs.Next()
|
||||||
|
b.WriteString(fmt.Sprintf("\t%s+%#x\n\t\t%s:%d\n", f.Function, f.PC-f.Entry, f.File, f.Line))
|
||||||
|
if !more {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
31
vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/main.go
generated
vendored
Normal file
31
vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/main.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package fdtrace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testingM interface {
|
||||||
|
Run() int
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestMain runs m with fd tracing enabled.
|
||||||
|
//
|
||||||
|
// The function calls [os.Exit] and does not return.
|
||||||
|
func TestMain(m testingM) {
|
||||||
|
fds = new(sync.Map)
|
||||||
|
|
||||||
|
ret := m.Run()
|
||||||
|
|
||||||
|
if fs := flushFrames(); len(fs) != 0 {
|
||||||
|
for _, f := range fs {
|
||||||
|
onLeakFD(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if foundLeak.Load() {
|
||||||
|
ret = 99
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
8
vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go
generated
vendored
8
vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go
generated
vendored
@@ -12,6 +12,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ var getTracefsPath = sync.OnceValues(func() (string, error) {
|
|||||||
// RHEL/CentOS
|
// RHEL/CentOS
|
||||||
{"/sys/kernel/debug/tracing", unix.DEBUGFS_MAGIC},
|
{"/sys/kernel/debug/tracing", unix.DEBUGFS_MAGIC},
|
||||||
} {
|
} {
|
||||||
if fsType, err := internal.FSType(p.path); err == nil && fsType == p.fsType {
|
if fsType, err := linux.FSType(p.path); err == nil && fsType == p.fsType {
|
||||||
return p.path, nil
|
return p.path, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +214,10 @@ func NewEvent(args ProbeArgs) (*Event, error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return nil, fmt.Errorf("trace event %s/%s: %w", args.Group, eventName, os.ErrExist)
|
return nil, fmt.Errorf("trace event %s/%s: %w", args.Group, eventName, os.ErrExist)
|
||||||
}
|
}
|
||||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, unix.EINVAL) {
|
||||||
|
return nil, fmt.Errorf("trace event %s/%s: %w (unknown symbol?)", args.Group, eventName, err)
|
||||||
|
}
|
||||||
|
if !errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, fmt.Errorf("checking trace event %s/%s: %w", args.Group, eventName, err)
|
return nil, fmt.Errorf("checking trace event %s/%s: %w", args.Group, eventName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
5
vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
generated
vendored
@@ -81,15 +81,16 @@ const (
|
|||||||
SO_DETACH_BPF = linux.SO_DETACH_BPF
|
SO_DETACH_BPF = linux.SO_DETACH_BPF
|
||||||
SOL_SOCKET = linux.SOL_SOCKET
|
SOL_SOCKET = linux.SOL_SOCKET
|
||||||
SIGPROF = linux.SIGPROF
|
SIGPROF = linux.SIGPROF
|
||||||
|
SIGUSR1 = linux.SIGUSR1
|
||||||
SIG_BLOCK = linux.SIG_BLOCK
|
SIG_BLOCK = linux.SIG_BLOCK
|
||||||
SIG_UNBLOCK = linux.SIG_UNBLOCK
|
SIG_UNBLOCK = linux.SIG_UNBLOCK
|
||||||
EM_NONE = linux.EM_NONE
|
|
||||||
EM_BPF = linux.EM_BPF
|
|
||||||
BPF_FS_MAGIC = linux.BPF_FS_MAGIC
|
BPF_FS_MAGIC = linux.BPF_FS_MAGIC
|
||||||
TRACEFS_MAGIC = linux.TRACEFS_MAGIC
|
TRACEFS_MAGIC = linux.TRACEFS_MAGIC
|
||||||
DEBUGFS_MAGIC = linux.DEBUGFS_MAGIC
|
DEBUGFS_MAGIC = linux.DEBUGFS_MAGIC
|
||||||
BPF_RB_NO_WAKEUP = linux.BPF_RB_NO_WAKEUP
|
BPF_RB_NO_WAKEUP = linux.BPF_RB_NO_WAKEUP
|
||||||
BPF_RB_FORCE_WAKEUP = linux.BPF_RB_FORCE_WAKEUP
|
BPF_RB_FORCE_WAKEUP = linux.BPF_RB_FORCE_WAKEUP
|
||||||
|
AF_UNSPEC = linux.AF_UNSPEC
|
||||||
|
IFF_UP = linux.IFF_UP
|
||||||
)
|
)
|
||||||
|
|
||||||
type Statfs_t = linux.Statfs_t
|
type Statfs_t = linux.Statfs_t
|
||||||
|
|||||||
5
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
5
vendor/github.com/cilium/ebpf/internal/unix/types_other.go
generated
vendored
@@ -84,16 +84,17 @@ const (
|
|||||||
SO_DETACH_BPF
|
SO_DETACH_BPF
|
||||||
SOL_SOCKET
|
SOL_SOCKET
|
||||||
SIGPROF
|
SIGPROF
|
||||||
|
SIGUSR1
|
||||||
SIG_BLOCK
|
SIG_BLOCK
|
||||||
SIG_UNBLOCK
|
SIG_UNBLOCK
|
||||||
EM_NONE
|
|
||||||
EM_BPF
|
|
||||||
BPF_FS_MAGIC
|
BPF_FS_MAGIC
|
||||||
TRACEFS_MAGIC
|
TRACEFS_MAGIC
|
||||||
DEBUGFS_MAGIC
|
DEBUGFS_MAGIC
|
||||||
BPF_RB_NO_WAKEUP
|
BPF_RB_NO_WAKEUP
|
||||||
BPF_RB_FORCE_WAKEUP
|
BPF_RB_FORCE_WAKEUP
|
||||||
BPF_F_LOCK
|
BPF_F_LOCK
|
||||||
|
AF_UNSPEC
|
||||||
|
IFF_UP
|
||||||
)
|
)
|
||||||
|
|
||||||
type Statfs_t struct {
|
type Statfs_t struct {
|
||||||
|
|||||||
30
vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
30
vendor/github.com/cilium/ebpf/internal/version.go
generated
vendored
@@ -2,9 +2,6 @@ package internal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -78,30 +75,3 @@ func (v Version) Kernel() uint32 {
|
|||||||
// each other when overflowing 8 bits.
|
// each other when overflowing 8 bits.
|
||||||
return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
|
return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KernelVersion returns the version of the currently running kernel.
|
|
||||||
var KernelVersion = sync.OnceValues(func() (Version, error) {
|
|
||||||
return detectKernelVersion()
|
|
||||||
})
|
|
||||||
|
|
||||||
// detectKernelVersion returns the version of the running kernel.
|
|
||||||
func detectKernelVersion() (Version, error) {
|
|
||||||
vc, err := vdsoVersion()
|
|
||||||
if err != nil {
|
|
||||||
return Version{}, err
|
|
||||||
}
|
|
||||||
return NewVersionFromCode(vc), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// KernelRelease returns the release string of the running kernel.
|
|
||||||
// Its format depends on the Linux distribution and corresponds to directory
|
|
||||||
// names in /lib/modules by convention. Some examples are 5.15.17-1-lts and
|
|
||||||
// 4.19.0-16-amd64.
|
|
||||||
func KernelRelease() (string, error) {
|
|
||||||
var uname unix.Utsname
|
|
||||||
if err := unix.Uname(&uname); err != nil {
|
|
||||||
return "", fmt.Errorf("uname failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return unix.ByteSliceToString(uname.Release[:]), nil
|
|
||||||
}
|
|
||||||
|
|||||||
12
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
12
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cilium/ebpf"
|
"github.com/cilium/ebpf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/tracefs"
|
"github.com/cilium/ebpf/internal/tracefs"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
@@ -60,6 +61,9 @@ func (ko *KprobeOptions) cookie() uint64 {
|
|||||||
// platform's syscall prefix (e.g. __x64_) to support attaching to syscalls
|
// platform's syscall prefix (e.g. __x64_) to support attaching to syscalls
|
||||||
// in a portable fashion.
|
// in a portable fashion.
|
||||||
//
|
//
|
||||||
|
// On kernels 6.11 and later, setting a kprobe on a nonexistent symbol using
|
||||||
|
// tracefs incorrectly returns [unix.EINVAL] instead of [os.ErrNotExist].
|
||||||
|
//
|
||||||
// The returned Link may implement [PerfEvent].
|
// The returned Link may implement [PerfEvent].
|
||||||
func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
||||||
k, err := kprobe(symbol, prog, opts, false)
|
k, err := kprobe(symbol, prog, opts, false)
|
||||||
@@ -91,7 +95,7 @@ func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error
|
|||||||
// in a portable fashion.
|
// in a portable fashion.
|
||||||
//
|
//
|
||||||
// On kernels 5.10 and earlier, setting a kretprobe on a nonexistent symbol
|
// On kernels 5.10 and earlier, setting a kretprobe on a nonexistent symbol
|
||||||
// incorrectly returns unix.EINVAL instead of os.ErrNotExist.
|
// incorrectly returns [unix.EINVAL] instead of [os.ErrNotExist].
|
||||||
//
|
//
|
||||||
// The returned Link may implement [PerfEvent].
|
// The returned Link may implement [PerfEvent].
|
||||||
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
|
||||||
@@ -169,7 +173,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
|
|||||||
// Use kprobe PMU if the kernel has it available.
|
// Use kprobe PMU if the kernel has it available.
|
||||||
tp, err := pmuProbe(args)
|
tp, err := pmuProbe(args)
|
||||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||||
if prefix := internal.PlatformPrefix(); prefix != "" {
|
if prefix := linux.PlatformPrefix(); prefix != "" {
|
||||||
args.Symbol = prefix + symbol
|
args.Symbol = prefix + symbol
|
||||||
tp, err = pmuProbe(args)
|
tp, err = pmuProbe(args)
|
||||||
}
|
}
|
||||||
@@ -177,7 +181,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return tp, nil
|
return tp, nil
|
||||||
}
|
}
|
||||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
if !errors.Is(err, ErrNotSupported) {
|
||||||
return nil, fmt.Errorf("creating perf_kprobe PMU (arch-specific fallback for %q): %w", symbol, err)
|
return nil, fmt.Errorf("creating perf_kprobe PMU (arch-specific fallback for %q): %w", symbol, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +189,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
|
|||||||
args.Symbol = symbol
|
args.Symbol = symbol
|
||||||
tp, err = tracefsProbe(args)
|
tp, err = tracefsProbe(args)
|
||||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||||
if prefix := internal.PlatformPrefix(); prefix != "" {
|
if prefix := linux.PlatformPrefix(); prefix != "" {
|
||||||
args.Symbol = prefix + symbol
|
args.Symbol = prefix + symbol
|
||||||
tp, err = tracefsProbe(args)
|
tp, err = tracefsProbe(args)
|
||||||
}
|
}
|
||||||
|
|||||||
8
vendor/github.com/cilium/ebpf/link/kprobe_multi.go
generated
vendored
8
vendor/github.com/cilium/ebpf/link/kprobe_multi.go
generated
vendored
@@ -60,7 +60,7 @@ func KprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
|
|||||||
//
|
//
|
||||||
// Requires at least Linux 5.18.
|
// Requires at least Linux 5.18.
|
||||||
func KretprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
|
func KretprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
|
||||||
return kprobeMulti(prog, opts, unix.BPF_F_KPROBE_MULTI_RETURN)
|
return kprobeMulti(prog, opts, sys.BPF_F_KPROBE_MULTI_RETURN)
|
||||||
}
|
}
|
||||||
|
|
||||||
func kprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions, flags uint32) (Link, error) {
|
func kprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions, flags uint32) (Link, error) {
|
||||||
@@ -126,7 +126,7 @@ type kprobeMultiLink struct {
|
|||||||
|
|
||||||
var _ Link = (*kprobeMultiLink)(nil)
|
var _ Link = (*kprobeMultiLink)(nil)
|
||||||
|
|
||||||
func (kml *kprobeMultiLink) Update(prog *ebpf.Program) error {
|
func (kml *kprobeMultiLink) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("update kprobe_multi: %w", ErrNotSupported)
|
return fmt.Errorf("update kprobe_multi: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ func (kml *kprobeMultiLink) Info() (*Info, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5.18", func() error {
|
var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Name: "probe_kpm_link",
|
Name: "probe_kpm_link",
|
||||||
Type: ebpf.Kprobe,
|
Type: ebpf.Kprobe,
|
||||||
@@ -188,4 +188,4 @@ var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5
|
|||||||
fd.Close()
|
fd.Close()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.18")
|
||||||
|
|||||||
15
vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
15
vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
@@ -78,7 +78,9 @@ func NewFromID(id ID) (Link, error) {
|
|||||||
return wrapRawLink(&RawLink{fd, ""})
|
return wrapRawLink(&RawLink{fd, ""})
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPinnedLink loads a link that was persisted into a bpffs.
|
// LoadPinnedLink loads a Link from a pin (file) on the BPF virtual filesystem.
|
||||||
|
//
|
||||||
|
// Requires at least Linux 5.7.
|
||||||
func LoadPinnedLink(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
|
func LoadPinnedLink(fileName string, opts *ebpf.LoadPinOptions) (Link, error) {
|
||||||
raw, err := loadPinnedRawLink(fileName, opts)
|
raw, err := loadPinnedRawLink(fileName, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -350,7 +352,7 @@ func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, error) {
|
func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, error) {
|
||||||
fd, err := sys.ObjGet(&sys.ObjGetAttr{
|
fd, typ, err := sys.ObjGetTyped(&sys.ObjGetAttr{
|
||||||
Pathname: sys.NewStringPointer(fileName),
|
Pathname: sys.NewStringPointer(fileName),
|
||||||
FileFlags: opts.Marshal(),
|
FileFlags: opts.Marshal(),
|
||||||
})
|
})
|
||||||
@@ -358,6 +360,11 @@ func loadPinnedRawLink(fileName string, opts *ebpf.LoadPinOptions) (*RawLink, er
|
|||||||
return nil, fmt.Errorf("load pinned link: %w", err)
|
return nil, fmt.Errorf("load pinned link: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typ != sys.BPF_TYPE_LINK {
|
||||||
|
_ = fd.Close()
|
||||||
|
return nil, fmt.Errorf("%s is not a Link", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
return &RawLink{fd, fileName}, nil
|
return &RawLink{fd, fileName}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +387,7 @@ func (l *RawLink) Close() error {
|
|||||||
// Calling Close on a pinned Link will not break the link
|
// Calling Close on a pinned Link will not break the link
|
||||||
// until the pin is removed.
|
// until the pin is removed.
|
||||||
func (l *RawLink) Pin(fileName string) error {
|
func (l *RawLink) Pin(fileName string) error {
|
||||||
if err := internal.Pin(l.pinnedPath, fileName, l.fd); err != nil {
|
if err := sys.Pin(l.pinnedPath, fileName, l.fd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.pinnedPath = fileName
|
l.pinnedPath = fileName
|
||||||
@@ -389,7 +396,7 @@ func (l *RawLink) Pin(fileName string) error {
|
|||||||
|
|
||||||
// Unpin implements the Link interface.
|
// Unpin implements the Link interface.
|
||||||
func (l *RawLink) Unpin() error {
|
func (l *RawLink) Unpin() error {
|
||||||
if err := internal.Unpin(l.pinnedPath); err != nil {
|
if err := sys.Unpin(l.pinnedPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
l.pinnedPath = ""
|
l.pinnedPath = ""
|
||||||
|
|||||||
2
vendor/github.com/cilium/ebpf/link/netfilter.go
generated
vendored
2
vendor/github.com/cilium/ebpf/link/netfilter.go
generated
vendored
@@ -63,7 +63,7 @@ func AttachNetfilter(opts NetfilterOptions) (Link, error) {
|
|||||||
return &netfilterLink{RawLink{fd, ""}}, nil
|
return &netfilterLink{RawLink{fd, ""}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*netfilterLink) Update(new *ebpf.Program) error {
|
func (*netfilterLink) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("netfilter update: %w", ErrNotSupported)
|
return fmt.Errorf("netfilter update: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
8
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
@@ -115,7 +115,7 @@ func (pl *perfEventLink) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pl *perfEventLink) Update(prog *ebpf.Program) error {
|
func (pl *perfEventLink) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("perf event link update: %w", ErrNotSupported)
|
return fmt.Errorf("perf event link update: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ func (pi *perfEventIoctl) isLink() {}
|
|||||||
//
|
//
|
||||||
// Detaching a program from a perf event is currently not possible, so a
|
// Detaching a program from a perf event is currently not possible, so a
|
||||||
// program replacement mechanism cannot be implemented for perf events.
|
// program replacement mechanism cannot be implemented for perf events.
|
||||||
func (pi *perfEventIoctl) Update(prog *ebpf.Program) error {
|
func (pi *perfEventIoctl) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("perf event ioctl update: %w", ErrNotSupported)
|
return fmt.Errorf("perf event ioctl update: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ func openTracepointPerfEvent(tid uint64, pid int) (*sys.FD, error) {
|
|||||||
//
|
//
|
||||||
// https://elixir.bootlin.com/linux/v5.16.8/source/kernel/bpf/syscall.c#L4307
|
// https://elixir.bootlin.com/linux/v5.16.8/source/kernel/bpf/syscall.c#L4307
|
||||||
// https://github.com/torvalds/linux/commit/b89fbfbb854c9afc3047e8273cc3a694650b802e
|
// https://github.com/torvalds/linux/commit/b89fbfbb854c9afc3047e8273cc3a694650b802e
|
||||||
var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", "5.15", func() error {
|
var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Name: "probe_bpf_perf_link",
|
Name: "probe_bpf_perf_link",
|
||||||
Type: ebpf.Kprobe,
|
Type: ebpf.Kprobe,
|
||||||
@@ -329,4 +329,4 @@ var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", "5.15"
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.15")
|
||||||
|
|||||||
24
vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
24
vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
@@ -30,7 +30,7 @@ const (
|
|||||||
NetkitType = sys.BPF_LINK_TYPE_NETKIT
|
NetkitType = sys.BPF_LINK_TYPE_NETKIT
|
||||||
)
|
)
|
||||||
|
|
||||||
var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
|
var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Type: ebpf.CGroupSKB,
|
Type: ebpf.CGroupSKB,
|
||||||
License: "MIT",
|
License: "MIT",
|
||||||
@@ -48,9 +48,9 @@ var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() e
|
|||||||
// have the syscall.
|
// have the syscall.
|
||||||
prog.Close()
|
prog.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "4.10")
|
||||||
|
|
||||||
var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", "5.5", func() error {
|
var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", func() error {
|
||||||
if err := haveProgAttach(); err != nil {
|
if err := haveProgAttach(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -90,9 +90,9 @@ var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic repl
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.5")
|
||||||
|
|
||||||
var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error {
|
var haveBPFLink = internal.NewFeatureTest("bpf_link", func() error {
|
||||||
attr := sys.LinkCreateAttr{
|
attr := sys.LinkCreateAttr{
|
||||||
// This is a hopefully invalid file descriptor, which triggers EBADF.
|
// This is a hopefully invalid file descriptor, which triggers EBADF.
|
||||||
TargetFd: ^uint32(0),
|
TargetFd: ^uint32(0),
|
||||||
@@ -107,9 +107,9 @@ var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.7")
|
||||||
|
|
||||||
var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() error {
|
var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", func() error {
|
||||||
attr := sys.ProgQueryAttr{
|
attr := sys.ProgQueryAttr{
|
||||||
// We rely on this being checked during the syscall.
|
// We rely on this being checked during the syscall.
|
||||||
// With an otherwise correct payload we expect EBADF here
|
// With an otherwise correct payload we expect EBADF here
|
||||||
@@ -127,9 +127,9 @@ var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() err
|
|||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
return errors.New("syscall succeeded unexpectedly")
|
return errors.New("syscall succeeded unexpectedly")
|
||||||
})
|
}, "4.15")
|
||||||
|
|
||||||
var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error {
|
var haveTCX = internal.NewFeatureTest("tcx", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Type: ebpf.SchedCLS,
|
Type: ebpf.SchedCLS,
|
||||||
License: "MIT",
|
License: "MIT",
|
||||||
@@ -162,9 +162,9 @@ var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error {
|
|||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
return errors.New("syscall succeeded unexpectedly")
|
return errors.New("syscall succeeded unexpectedly")
|
||||||
})
|
}, "6.6")
|
||||||
|
|
||||||
var haveNetkit = internal.NewFeatureTest("netkit", "6.7", func() error {
|
var haveNetkit = internal.NewFeatureTest("netkit", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Type: ebpf.SchedCLS,
|
Type: ebpf.SchedCLS,
|
||||||
License: "MIT",
|
License: "MIT",
|
||||||
@@ -197,4 +197,4 @@ var haveNetkit = internal.NewFeatureTest("netkit", "6.7", func() error {
|
|||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
return errors.New("syscall succeeded unexpectedly")
|
return errors.New("syscall succeeded unexpectedly")
|
||||||
})
|
}, "6.7")
|
||||||
|
|||||||
2
vendor/github.com/cilium/ebpf/link/tracing.go
generated
vendored
2
vendor/github.com/cilium/ebpf/link/tracing.go
generated
vendored
@@ -14,7 +14,7 @@ type tracing struct {
|
|||||||
RawLink
|
RawLink
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *tracing) Update(new *ebpf.Program) error {
|
func (f *tracing) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("tracing update: %w", ErrNotSupported)
|
return fmt.Errorf("tracing update: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
6
vendor/github.com/cilium/ebpf/link/uprobe.go
generated
vendored
@@ -16,7 +16,7 @@ var (
|
|||||||
uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
|
uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
|
||||||
// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
|
// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
|
||||||
uprobeRefCtrOffsetShift = 32
|
uprobeRefCtrOffsetShift = 32
|
||||||
haveRefCtrOffsetPMU = internal.NewFeatureTest("RefCtrOffsetPMU", "4.20", func() error {
|
haveRefCtrOffsetPMU = internal.NewFeatureTest("RefCtrOffsetPMU", func() error {
|
||||||
_, err := os.Stat(uprobeRefCtrOffsetPMUPath)
|
_, err := os.Stat(uprobeRefCtrOffsetPMUPath)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
@@ -25,7 +25,7 @@ var (
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "4.20")
|
||||||
|
|
||||||
// ErrNoSymbol indicates that the given symbol was not found
|
// ErrNoSymbol indicates that the given symbol was not found
|
||||||
// in the ELF symbols table.
|
// in the ELF symbols table.
|
||||||
@@ -321,7 +321,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return tp, nil
|
return tp, nil
|
||||||
}
|
}
|
||||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
if !errors.Is(err, ErrNotSupported) {
|
||||||
return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err)
|
return nil, fmt.Errorf("creating perf_uprobe PMU: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
vendor/github.com/cilium/ebpf/link/uprobe_multi.go
generated
vendored
13
vendor/github.com/cilium/ebpf/link/uprobe_multi.go
generated
vendored
@@ -47,7 +47,7 @@ func (ex *Executable) UretprobeMulti(symbols []string, prog *ebpf.Program, opts
|
|||||||
// The return probe is not limited for symbols entry, so there's no special
|
// The return probe is not limited for symbols entry, so there's no special
|
||||||
// setup for return uprobes (other than the extra flag). The symbols, opts.Offsets
|
// setup for return uprobes (other than the extra flag). The symbols, opts.Offsets
|
||||||
// and opts.Addresses arrays follow the same logic as for entry uprobes.
|
// and opts.Addresses arrays follow the same logic as for entry uprobes.
|
||||||
return ex.uprobeMulti(symbols, prog, opts, unix.BPF_F_UPROBE_MULTI_RETURN)
|
return ex.uprobeMulti(symbols, prog, opts, sys.BPF_F_UPROBE_MULTI_RETURN)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *UprobeMultiOptions, flags uint32) (Link, error) {
|
func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *UprobeMultiOptions, flags uint32) (Link, error) {
|
||||||
@@ -99,8 +99,11 @@ func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *Up
|
|||||||
if errors.Is(err, unix.ESRCH) {
|
if errors.Is(err, unix.ESRCH) {
|
||||||
return nil, fmt.Errorf("%w (specified pid not found?)", os.ErrNotExist)
|
return nil, fmt.Errorf("%w (specified pid not found?)", os.ErrNotExist)
|
||||||
}
|
}
|
||||||
|
// Since Linux commit 46ba0e49b642 ("bpf: fix multi-uprobe PID filtering
|
||||||
|
// logic"), if the provided pid overflows MaxInt32 (turning it negative), the
|
||||||
|
// kernel will return EINVAL instead of ESRCH.
|
||||||
if errors.Is(err, unix.EINVAL) {
|
if errors.Is(err, unix.EINVAL) {
|
||||||
return nil, fmt.Errorf("%w (missing symbol or prog's AttachType not AttachTraceUprobeMulti?)", err)
|
return nil, fmt.Errorf("%w (invalid pid, missing symbol or prog's AttachType not AttachTraceUprobeMulti?)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,11 +171,11 @@ type uprobeMultiLink struct {
|
|||||||
|
|
||||||
var _ Link = (*uprobeMultiLink)(nil)
|
var _ Link = (*uprobeMultiLink)(nil)
|
||||||
|
|
||||||
func (kml *uprobeMultiLink) Update(prog *ebpf.Program) error {
|
func (kml *uprobeMultiLink) Update(_ *ebpf.Program) error {
|
||||||
return fmt.Errorf("update uprobe_multi: %w", ErrNotSupported)
|
return fmt.Errorf("update uprobe_multi: %w", ErrNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6.6", func() error {
|
var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", func() error {
|
||||||
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
|
||||||
Name: "probe_upm_link",
|
Name: "probe_upm_link",
|
||||||
Type: ebpf.Kprobe,
|
Type: ebpf.Kprobe,
|
||||||
@@ -213,4 +216,4 @@ var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6
|
|||||||
// should not happen
|
// should not happen
|
||||||
fd.Close()
|
fd.Close()
|
||||||
return errors.New("successfully attached uprobe_multi to /, kernel bug?")
|
return errors.New("successfully attached uprobe_multi to /, kernel bug?")
|
||||||
})
|
}, "6.6")
|
||||||
|
|||||||
41
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
41
vendor/github.com/cilium/ebpf/linker.go
generated
vendored
@@ -9,10 +9,12 @@ import (
|
|||||||
"io/fs"
|
"io/fs"
|
||||||
"math"
|
"math"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/kallsyms"
|
||||||
)
|
)
|
||||||
|
|
||||||
// handles stores handle objects to avoid gc cleanup
|
// handles stores handle objects to avoid gc cleanup
|
||||||
@@ -457,3 +459,42 @@ func resolveKconfigReferences(insns asm.Instructions) (_ *Map, err error) {
|
|||||||
|
|
||||||
return kconfig, nil
|
return kconfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveKsymReferences(insns asm.Instructions) error {
|
||||||
|
var missing []string
|
||||||
|
|
||||||
|
iter := insns.Iterate()
|
||||||
|
for iter.Next() {
|
||||||
|
ins := iter.Ins
|
||||||
|
meta, _ := ins.Metadata.Get(ksymMetaKey{}).(*ksymMeta)
|
||||||
|
if meta == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := kallsyms.Address(meta.Name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("resolve ksym %s: %w", meta.Name, err)
|
||||||
|
}
|
||||||
|
if addr != 0 {
|
||||||
|
ins.Constant = int64(addr)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if meta.Binding == elf.STB_WEAK {
|
||||||
|
// A weak ksym variable in eBPF C means its resolution is optional.
|
||||||
|
// Set a zero constant explicitly for clarity.
|
||||||
|
ins.Constant = 0
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !slices.Contains(missing, meta.Name) {
|
||||||
|
missing = append(missing, meta.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
return fmt.Errorf("kernel is missing symbol: %s", strings.Join(missing, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
127
vendor/github.com/cilium/ebpf/map.go
generated
vendored
127
vendor/github.com/cilium/ebpf/map.go
generated
vendored
@@ -66,16 +66,13 @@ type MapSpec struct {
|
|||||||
Pinning PinType
|
Pinning PinType
|
||||||
|
|
||||||
// Specify numa node during map creation
|
// Specify numa node during map creation
|
||||||
// (effective only if unix.BPF_F_NUMA_NODE flag is set,
|
// (effective only if sys.BPF_F_NUMA_NODE flag is set,
|
||||||
// which can be imported from golang.org/x/sys/unix)
|
// which can be imported from golang.org/x/sys/unix)
|
||||||
NumaNode uint32
|
NumaNode uint32
|
||||||
|
|
||||||
// The initial contents of the map. May be nil.
|
// The initial contents of the map. May be nil.
|
||||||
Contents []MapKV
|
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 is used as a template for ArrayOfMaps and HashOfMaps
|
||||||
InnerMap *MapSpec
|
InnerMap *MapSpec
|
||||||
|
|
||||||
@@ -161,6 +158,17 @@ func (spec *MapSpec) fixupMagicFields() (*MapSpec, error) {
|
|||||||
// behaviour in the past.
|
// behaviour in the past.
|
||||||
spec.MaxEntries = n
|
spec.MaxEntries = n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CPUMap:
|
||||||
|
n, err := PossibleCPU()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("fixup cpu map: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n := uint32(n); spec.MaxEntries == 0 || spec.MaxEntries > n {
|
||||||
|
// Perform clamping similar to PerfEventArray.
|
||||||
|
spec.MaxEntries = n
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return spec, nil
|
return spec, nil
|
||||||
@@ -190,6 +198,14 @@ func (ms *MapSpec) dataSection() ([]byte, *btf.Datasec, error) {
|
|||||||
return value, ds, nil
|
return value, ds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms *MapSpec) readOnly() bool {
|
||||||
|
return (ms.Flags & sys.BPF_F_RDONLY_PROG) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MapSpec) writeOnly() bool {
|
||||||
|
return (ms.Flags & sys.BPF_F_WRONLY_PROG) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// MapKV is used to initialize the contents of a Map.
|
// MapKV is used to initialize the contents of a Map.
|
||||||
type MapKV struct {
|
type MapKV struct {
|
||||||
Key interface{}
|
Key interface{}
|
||||||
@@ -222,7 +238,7 @@ func (ms *MapSpec) Compatible(m *Map) error {
|
|||||||
|
|
||||||
// BPF_F_RDONLY_PROG is set unconditionally for devmaps. Explicitly allow this
|
// BPF_F_RDONLY_PROG is set unconditionally for devmaps. Explicitly allow this
|
||||||
// mismatch.
|
// mismatch.
|
||||||
if !((ms.Type == DevMap || ms.Type == DevMapHash) && m.flags^ms.Flags == unix.BPF_F_RDONLY_PROG) &&
|
if !((ms.Type == DevMap || ms.Type == DevMapHash) && m.flags^ms.Flags == sys.BPF_F_RDONLY_PROG) &&
|
||||||
m.flags != ms.Flags {
|
m.flags != ms.Flags {
|
||||||
diffs = append(diffs, fmt.Sprintf("Flags: %d changed to %d", m.flags, ms.Flags))
|
diffs = append(diffs, fmt.Sprintf("Flags: %d changed to %d", m.flags, ms.Flags))
|
||||||
}
|
}
|
||||||
@@ -254,6 +270,8 @@ type Map struct {
|
|||||||
pinnedPath string
|
pinnedPath string
|
||||||
// Per CPU maps return values larger than the size in the spec
|
// Per CPU maps return values larger than the size in the spec
|
||||||
fullValueSize int
|
fullValueSize int
|
||||||
|
|
||||||
|
memory *Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMapFromFD creates a map from a raw fd.
|
// NewMapFromFD creates a map from a raw fd.
|
||||||
@@ -359,7 +377,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
|
|||||||
return nil, errors.New("inner maps cannot be pinned")
|
return nil, errors.New("inner maps cannot be pinned")
|
||||||
}
|
}
|
||||||
|
|
||||||
template, err := spec.InnerMap.createMap(nil, opts)
|
template, err := spec.InnerMap.createMap(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("inner map: %w", err)
|
return nil, fmt.Errorf("inner map: %w", err)
|
||||||
}
|
}
|
||||||
@@ -371,7 +389,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
|
|||||||
innerFd = template.fd
|
innerFd = template.fd
|
||||||
}
|
}
|
||||||
|
|
||||||
m, err := spec.createMap(innerFd, opts)
|
m, err := spec.createMap(innerFd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -387,9 +405,54 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
|
|||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memory returns a memory-mapped region for the Map. The Map must have been
|
||||||
|
// created with the BPF_F_MMAPABLE flag. Repeated calls to Memory return the
|
||||||
|
// same mapping. Callers are responsible for coordinating access to Memory.
|
||||||
|
func (m *Map) Memory() (*Memory, error) {
|
||||||
|
if m.memory != nil {
|
||||||
|
return m.memory, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.flags&sys.BPF_F_MMAPABLE == 0 {
|
||||||
|
return nil, fmt.Errorf("Map was not created with the BPF_F_MMAPABLE flag: %w", ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
size, err := m.memorySize()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mm, err := newMemory(m.FD(), size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating new Memory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.memory = mm
|
||||||
|
|
||||||
|
return mm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) memorySize() (int, error) {
|
||||||
|
switch m.Type() {
|
||||||
|
case Array:
|
||||||
|
// In Arrays, values are always laid out on 8-byte boundaries regardless of
|
||||||
|
// architecture. Multiply by MaxEntries and align the result to the host's
|
||||||
|
// page size.
|
||||||
|
size := int(internal.Align(m.ValueSize(), 8) * m.MaxEntries())
|
||||||
|
size = internal.Align(size, os.Getpagesize())
|
||||||
|
return size, nil
|
||||||
|
case Arena:
|
||||||
|
// For Arenas, MaxEntries denotes the maximum number of pages available to
|
||||||
|
// the arena.
|
||||||
|
return int(m.MaxEntries()) * os.Getpagesize(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("determine memory size of map type %s: %w", m.Type(), ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
// createMap validates the spec's properties and creates the map in the kernel
|
// createMap validates the spec's properties and creates the map in the kernel
|
||||||
// using the given opts. It does not populate or freeze the map.
|
// using the given opts. It does not populate or freeze the map.
|
||||||
func (spec *MapSpec) createMap(inner *sys.FD, opts MapOptions) (_ *Map, err error) {
|
func (spec *MapSpec) createMap(inner *sys.FD) (_ *Map, err error) {
|
||||||
closeOnError := func(closer io.Closer) {
|
closeOnError := func(closer io.Closer) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
closer.Close()
|
closer.Close()
|
||||||
@@ -416,7 +479,7 @@ func (spec *MapSpec) createMap(inner *sys.FD, opts MapOptions) (_ *Map, err erro
|
|||||||
KeySize: spec.KeySize,
|
KeySize: spec.KeySize,
|
||||||
ValueSize: spec.ValueSize,
|
ValueSize: spec.ValueSize,
|
||||||
MaxEntries: spec.MaxEntries,
|
MaxEntries: spec.MaxEntries,
|
||||||
MapFlags: sys.MapFlags(spec.Flags),
|
MapFlags: spec.Flags,
|
||||||
NumaNode: spec.NumaNode,
|
NumaNode: spec.NumaNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,32 +537,32 @@ func handleMapCreateError(attr sys.MapCreateAttr, spec *MapSpec, err error) erro
|
|||||||
if errors.Is(err, unix.EINVAL) && spec.Type == UnspecifiedMap {
|
if errors.Is(err, unix.EINVAL) && spec.Type == UnspecifiedMap {
|
||||||
return fmt.Errorf("map create: cannot use type %s", UnspecifiedMap)
|
return fmt.Errorf("map create: cannot use type %s", UnspecifiedMap)
|
||||||
}
|
}
|
||||||
if errors.Is(err, unix.EINVAL) && spec.Flags&unix.BPF_F_NO_PREALLOC > 0 {
|
if errors.Is(err, unix.EINVAL) && spec.Flags&sys.BPF_F_NO_PREALLOC > 0 {
|
||||||
return fmt.Errorf("map create: %w (noPrealloc flag may be incompatible with map type %s)", err, spec.Type)
|
return fmt.Errorf("map create: %w (noPrealloc flag may be incompatible with map type %s)", err, spec.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch spec.Type {
|
if spec.Type.canStoreMap() {
|
||||||
case ArrayOfMaps, HashOfMaps:
|
|
||||||
if haveFeatErr := haveNestedMaps(); haveFeatErr != nil {
|
if haveFeatErr := haveNestedMaps(); haveFeatErr != nil {
|
||||||
return fmt.Errorf("map create: %w", haveFeatErr)
|
return fmt.Errorf("map create: %w", haveFeatErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spec.Flags&(unix.BPF_F_RDONLY_PROG|unix.BPF_F_WRONLY_PROG) > 0 || spec.Freeze {
|
|
||||||
|
if spec.readOnly() || spec.writeOnly() {
|
||||||
if haveFeatErr := haveMapMutabilityModifiers(); haveFeatErr != nil {
|
if haveFeatErr := haveMapMutabilityModifiers(); haveFeatErr != nil {
|
||||||
return fmt.Errorf("map create: %w", haveFeatErr)
|
return fmt.Errorf("map create: %w", haveFeatErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spec.Flags&unix.BPF_F_MMAPABLE > 0 {
|
if spec.Flags&sys.BPF_F_MMAPABLE > 0 {
|
||||||
if haveFeatErr := haveMmapableMaps(); haveFeatErr != nil {
|
if haveFeatErr := haveMmapableMaps(); haveFeatErr != nil {
|
||||||
return fmt.Errorf("map create: %w", haveFeatErr)
|
return fmt.Errorf("map create: %w", haveFeatErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spec.Flags&unix.BPF_F_INNER_MAP > 0 {
|
if spec.Flags&sys.BPF_F_INNER_MAP > 0 {
|
||||||
if haveFeatErr := haveInnerMaps(); haveFeatErr != nil {
|
if haveFeatErr := haveInnerMaps(); haveFeatErr != nil {
|
||||||
return fmt.Errorf("map create: %w", haveFeatErr)
|
return fmt.Errorf("map create: %w", haveFeatErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if spec.Flags&unix.BPF_F_NO_PREALLOC > 0 {
|
if spec.Flags&sys.BPF_F_NO_PREALLOC > 0 {
|
||||||
if haveFeatErr := haveNoPreallocMaps(); haveFeatErr != nil {
|
if haveFeatErr := haveNoPreallocMaps(); haveFeatErr != nil {
|
||||||
return fmt.Errorf("map create: %w", haveFeatErr)
|
return fmt.Errorf("map create: %w", haveFeatErr)
|
||||||
}
|
}
|
||||||
@@ -530,6 +593,7 @@ func newMap(fd *sys.FD, name string, typ MapType, keySize, valueSize, maxEntries
|
|||||||
flags,
|
flags,
|
||||||
"",
|
"",
|
||||||
int(valueSize),
|
int(valueSize),
|
||||||
|
nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !typ.hasPerCPUValue() {
|
if !typ.hasPerCPUValue() {
|
||||||
@@ -577,7 +641,12 @@ func (m *Map) Flags() uint32 {
|
|||||||
return m.flags
|
return m.flags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info returns metadata about the map.
|
// Info returns metadata about the map. This was first introduced in Linux 4.5,
|
||||||
|
// but newer kernels support more MapInfo fields with the introduction of more
|
||||||
|
// features. See [MapInfo] and its methods for more details.
|
||||||
|
//
|
||||||
|
// Returns an error wrapping ErrNotSupported if the kernel supports neither
|
||||||
|
// BPF_OBJ_GET_INFO_BY_FD nor reading map information from /proc/self/fdinfo.
|
||||||
func (m *Map) Info() (*MapInfo, error) {
|
func (m *Map) Info() (*MapInfo, error) {
|
||||||
return newMapInfoFromFd(m.fd)
|
return newMapInfoFromFd(m.fd)
|
||||||
}
|
}
|
||||||
@@ -604,7 +673,7 @@ func (m *Map) Handle() (*btf.Handle, error) {
|
|||||||
type MapLookupFlags uint64
|
type MapLookupFlags uint64
|
||||||
|
|
||||||
// LookupLock look up the value of a spin-locked map.
|
// LookupLock look up the value of a spin-locked map.
|
||||||
const LookupLock MapLookupFlags = unix.BPF_F_LOCK
|
const LookupLock MapLookupFlags = sys.BPF_F_LOCK
|
||||||
|
|
||||||
// Lookup retrieves a value from a Map.
|
// Lookup retrieves a value from a Map.
|
||||||
//
|
//
|
||||||
@@ -1336,6 +1405,7 @@ func (m *Map) Clone() (*Map, error) {
|
|||||||
m.flags,
|
m.flags,
|
||||||
"",
|
"",
|
||||||
m.fullValueSize,
|
m.fullValueSize,
|
||||||
|
nil,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1349,7 +1419,7 @@ func (m *Map) Clone() (*Map, error) {
|
|||||||
// This requires bpffs to be mounted above fileName.
|
// This requires bpffs to be mounted above fileName.
|
||||||
// See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
|
// See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
|
||||||
func (m *Map) Pin(fileName string) error {
|
func (m *Map) Pin(fileName string) error {
|
||||||
if err := internal.Pin(m.pinnedPath, fileName, m.fd); err != nil {
|
if err := sys.Pin(m.pinnedPath, fileName, m.fd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.pinnedPath = fileName
|
m.pinnedPath = fileName
|
||||||
@@ -1362,7 +1432,7 @@ func (m *Map) Pin(fileName string) error {
|
|||||||
//
|
//
|
||||||
// Unpinning an unpinned Map returns nil.
|
// Unpinning an unpinned Map returns nil.
|
||||||
func (m *Map) Unpin() error {
|
func (m *Map) Unpin() error {
|
||||||
if err := internal.Unpin(m.pinnedPath); err != nil {
|
if err := sys.Unpin(m.pinnedPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.pinnedPath = ""
|
m.pinnedPath = ""
|
||||||
@@ -1400,7 +1470,7 @@ func (m *Map) finalize(spec *MapSpec) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if spec.Freeze {
|
if isConstantDataSection(spec.Name) || isKconfigSection(spec.Name) {
|
||||||
if err := m.Freeze(); err != nil {
|
if err := m.Freeze(); err != nil {
|
||||||
return fmt.Errorf("freezing map: %w", err)
|
return fmt.Errorf("freezing map: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1501,9 +1571,11 @@ func (m *Map) unmarshalValue(value any, buf sysenc.Buffer) error {
|
|||||||
return buf.Unmarshal(value)
|
return buf.Unmarshal(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPinnedMap loads a Map from a BPF file.
|
// LoadPinnedMap opens a Map from a pin (file) on the BPF virtual filesystem.
|
||||||
|
//
|
||||||
|
// Requires at least Linux 4.5.
|
||||||
func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) {
|
func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) {
|
||||||
fd, err := sys.ObjGet(&sys.ObjGetAttr{
|
fd, typ, err := sys.ObjGetTyped(&sys.ObjGetAttr{
|
||||||
Pathname: sys.NewStringPointer(fileName),
|
Pathname: sys.NewStringPointer(fileName),
|
||||||
FileFlags: opts.Marshal(),
|
FileFlags: opts.Marshal(),
|
||||||
})
|
})
|
||||||
@@ -1511,6 +1583,11 @@ func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typ != sys.BPF_TYPE_MAP {
|
||||||
|
_ = fd.Close()
|
||||||
|
return nil, fmt.Errorf("%s is not a Map", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
m, err := newMapFromFD(fd)
|
m, err := newMapFromFD(fd)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
m.pinnedPath = fileName
|
m.pinnedPath = fileName
|
||||||
@@ -1530,6 +1607,10 @@ func unmarshalMap(buf sysenc.Buffer) (*Map, error) {
|
|||||||
|
|
||||||
// marshalMap marshals the fd of a map into a buffer in host endianness.
|
// marshalMap marshals the fd of a map into a buffer in host endianness.
|
||||||
func marshalMap(m *Map, length int) ([]byte, error) {
|
func marshalMap(m *Map, length int) ([]byte, error) {
|
||||||
|
if m == nil {
|
||||||
|
return nil, errors.New("can't marshal a nil Map")
|
||||||
|
}
|
||||||
|
|
||||||
if length != 4 {
|
if length != 4 {
|
||||||
return nil, fmt.Errorf("can't marshal map to %d bytes", length)
|
return nil, fmt.Errorf("can't marshal map to %d bytes", length)
|
||||||
}
|
}
|
||||||
|
|||||||
145
vendor/github.com/cilium/ebpf/memory.go
generated
vendored
Normal file
145
vendor/github.com/cilium/ebpf/memory.go
generated
vendored
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package ebpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Memory is the building block for accessing the memory of specific bpf map
|
||||||
|
// types (Array and Arena at the time of writing) without going through the bpf
|
||||||
|
// syscall interface.
|
||||||
|
//
|
||||||
|
// Given the fd of a bpf map created with the BPF_F_MMAPABLE flag, a shared
|
||||||
|
// 'file'-based memory-mapped region can be allocated in the process' address
|
||||||
|
// space, exposing the bpf map's memory by simply accessing a memory location.
|
||||||
|
|
||||||
|
var ErrReadOnly = errors.New("resource is read-only")
|
||||||
|
|
||||||
|
// Memory implements accessing a Map's memory without making any syscalls.
|
||||||
|
// Pay attention to the difference between Go and C struct alignment rules. Use
|
||||||
|
// [structs.HostLayout] on supported Go versions to help with alignment.
|
||||||
|
//
|
||||||
|
// Note on memory coherence: avoid using packed structs in memory shared between
|
||||||
|
// user space and eBPF C programs. This drops a struct's memory alignment to 1,
|
||||||
|
// forcing the compiler to use single-byte loads and stores for field accesses.
|
||||||
|
// This may lead to partially-written data to be observed from user space.
|
||||||
|
//
|
||||||
|
// On most architectures, the memmove implementation used by Go's copy() will
|
||||||
|
// access data in word-sized chunks. If paired with a matching access pattern on
|
||||||
|
// the eBPF C side (and if using default memory alignment), accessing shared
|
||||||
|
// memory without atomics or other synchronization primitives should be sound
|
||||||
|
// for individual values. For accesses beyond a single value, the usual
|
||||||
|
// concurrent programming rules apply.
|
||||||
|
type Memory struct {
|
||||||
|
b []byte
|
||||||
|
ro bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMemory(fd, size int) (*Memory, error) {
|
||||||
|
// Typically, maps created with BPF_F_RDONLY_PROG remain writable from user
|
||||||
|
// space until frozen. As a security precaution, the kernel doesn't allow
|
||||||
|
// mapping bpf map memory as read-write into user space if the bpf map was
|
||||||
|
// frozen, or if it was created using the RDONLY_PROG flag.
|
||||||
|
//
|
||||||
|
// The user would be able to write to the map after freezing (since the kernel
|
||||||
|
// can't change the protection mode of an already-mapped page), while the
|
||||||
|
// verifier assumes the contents to be immutable.
|
||||||
|
b, err := unix.Mmap(fd, 0, size, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
|
||||||
|
|
||||||
|
// If the map is frozen when an rw mapping is requested, expect EPERM. If the
|
||||||
|
// map was created with BPF_F_RDONLY_PROG, expect EACCES.
|
||||||
|
var ro bool
|
||||||
|
if errors.Is(err, unix.EPERM) || errors.Is(err, unix.EACCES) {
|
||||||
|
ro = true
|
||||||
|
b, err = unix.Mmap(fd, 0, size, unix.PROT_READ, unix.MAP_SHARED)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("setting up memory-mapped region: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mm := &Memory{
|
||||||
|
b,
|
||||||
|
ro,
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(mm, (*Memory).close)
|
||||||
|
|
||||||
|
return mm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mm *Memory) close() {
|
||||||
|
if err := unix.Munmap(mm.b); err != nil {
|
||||||
|
panic(fmt.Errorf("unmapping memory: %w", err))
|
||||||
|
}
|
||||||
|
mm.b = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the memory-mapped region in bytes.
|
||||||
|
func (mm *Memory) Size() int {
|
||||||
|
return len(mm.b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadOnly returns true if the memory-mapped region is read-only.
|
||||||
|
func (mm *Memory) ReadOnly() bool {
|
||||||
|
return mm.ro
|
||||||
|
}
|
||||||
|
|
||||||
|
// bounds returns true if an access at off of the given size is within bounds.
|
||||||
|
func (mm *Memory) bounds(off uint64, size uint64) bool {
|
||||||
|
return off+size < uint64(len(mm.b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAt implements [io.ReaderAt]. Useful for creating a new [io.OffsetWriter].
|
||||||
|
//
|
||||||
|
// See [Memory] for details around memory coherence.
|
||||||
|
func (mm *Memory) ReadAt(p []byte, off int64) (int, error) {
|
||||||
|
if mm.b == nil {
|
||||||
|
return 0, fmt.Errorf("memory-mapped region closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if p == nil {
|
||||||
|
return 0, fmt.Errorf("input buffer p is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if off < 0 || off >= int64(len(mm.b)) {
|
||||||
|
return 0, fmt.Errorf("read offset out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
n := copy(p, mm.b[off:])
|
||||||
|
if n < len(p) {
|
||||||
|
return n, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAt implements [io.WriterAt]. Useful for creating a new
|
||||||
|
// [io.SectionReader].
|
||||||
|
//
|
||||||
|
// See [Memory] for details around memory coherence.
|
||||||
|
func (mm *Memory) WriteAt(p []byte, off int64) (int, error) {
|
||||||
|
if mm.b == nil {
|
||||||
|
return 0, fmt.Errorf("memory-mapped region closed")
|
||||||
|
}
|
||||||
|
if mm.ro {
|
||||||
|
return 0, fmt.Errorf("memory-mapped region not writable: %w", ErrReadOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p == nil {
|
||||||
|
return 0, fmt.Errorf("output buffer p is nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if off < 0 || off >= int64(len(mm.b)) {
|
||||||
|
return 0, fmt.Errorf("write offset out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
n := copy(mm.b[off:], p)
|
||||||
|
if n < len(p) {
|
||||||
|
return n, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
102
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
102
vendor/github.com/cilium/ebpf/prog.go
generated
vendored
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/cilium/ebpf/btf"
|
"github.com/cilium/ebpf/btf"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
"github.com/cilium/ebpf/internal/kallsyms"
|
"github.com/cilium/ebpf/internal/kallsyms"
|
||||||
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/sysenc"
|
"github.com/cilium/ebpf/internal/sysenc"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
@@ -46,14 +47,15 @@ const (
|
|||||||
outputPad = 256 + 2
|
outputPad = 256 + 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// Deprecated: the correct log size is now detected automatically and this
|
|
||||||
// constant is unused.
|
|
||||||
const DefaultVerifierLogSize = 64 * 1024
|
|
||||||
|
|
||||||
// minVerifierLogSize is the default number of bytes allocated for the
|
// minVerifierLogSize is the default number of bytes allocated for the
|
||||||
// verifier log.
|
// verifier log.
|
||||||
const minVerifierLogSize = 64 * 1024
|
const minVerifierLogSize = 64 * 1024
|
||||||
|
|
||||||
|
// maxVerifierLogSize is the maximum size of verifier log buffer the kernel
|
||||||
|
// will accept before returning EINVAL. May be increased to MaxUint32 in the
|
||||||
|
// future, but avoid the unnecessary EINVAL for now.
|
||||||
|
const maxVerifierLogSize = math.MaxUint32 >> 2
|
||||||
|
|
||||||
// ProgramOptions control loading a program into the kernel.
|
// ProgramOptions control loading a program into the kernel.
|
||||||
type ProgramOptions struct {
|
type ProgramOptions struct {
|
||||||
// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
|
// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
|
||||||
@@ -73,9 +75,10 @@ type ProgramOptions struct {
|
|||||||
// attempt at loading the program.
|
// attempt at loading the program.
|
||||||
LogLevel LogLevel
|
LogLevel LogLevel
|
||||||
|
|
||||||
// Deprecated: the correct log buffer size is determined automatically
|
// Starting size of the verifier log buffer. If the verifier log is larger
|
||||||
// and this field is ignored.
|
// than this size, the buffer will be grown to fit the entire log. Leave at
|
||||||
LogSize int
|
// its default value unless troubleshooting.
|
||||||
|
LogSizeStart uint32
|
||||||
|
|
||||||
// Disables the verifier log completely, regardless of other options.
|
// Disables the verifier log completely, regardless of other options.
|
||||||
LogDisabled bool
|
LogDisabled bool
|
||||||
@@ -162,26 +165,35 @@ func (ps *ProgramSpec) Tag() (string, error) {
|
|||||||
return ps.Instructions.Tag(internal.NativeEndian)
|
return ps.Instructions.Tag(internal.NativeEndian)
|
||||||
}
|
}
|
||||||
|
|
||||||
// KernelModule returns the kernel module, if any, the AttachTo function is contained in.
|
// kernelModule returns the kernel module providing the symbol in
|
||||||
func (ps *ProgramSpec) KernelModule() (string, error) {
|
// ProgramSpec.AttachTo, if any. Returns an empty string if the symbol is not
|
||||||
if ps.AttachTo == "" {
|
// present or not part of a kernel module.
|
||||||
|
func (ps *ProgramSpec) kernelModule() (string, error) {
|
||||||
|
if ps.AttachTo == "" && ps.targetsKernelModule() {
|
||||||
|
return kallsyms.Module(ps.AttachTo)
|
||||||
|
}
|
||||||
|
|
||||||
return "", nil
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// targetsKernelModule returns true if the program supports being attached to a
|
||||||
|
// symbol provided by a kernel module.
|
||||||
|
func (ps *ProgramSpec) targetsKernelModule() bool {
|
||||||
|
if ps.AttachTo == "" {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ps.Type {
|
switch ps.Type {
|
||||||
default:
|
|
||||||
return "", nil
|
|
||||||
case Tracing:
|
case Tracing:
|
||||||
switch ps.AttachType {
|
switch ps.AttachType {
|
||||||
default:
|
case AttachTraceFEntry, AttachTraceFExit:
|
||||||
return "", nil
|
return true
|
||||||
case AttachTraceFEntry:
|
|
||||||
case AttachTraceFExit:
|
|
||||||
}
|
}
|
||||||
fallthrough
|
|
||||||
case Kprobe:
|
case Kprobe:
|
||||||
return kallsyms.KernelModule(ps.AttachTo)
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifierError is returned by [NewProgram] and [NewProgramWithOptions] if a
|
// VerifierError is returned by [NewProgram] and [NewProgramWithOptions] if a
|
||||||
@@ -261,7 +273,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
// Overwrite Kprobe program version if set to zero or the magic version constant.
|
// Overwrite Kprobe program version if set to zero or the magic version constant.
|
||||||
kv := spec.KernelVersion
|
kv := spec.KernelVersion
|
||||||
if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
|
if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
|
||||||
v, err := internal.KernelVersion()
|
v, err := linux.KernelVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("detecting kernel version: %w", err)
|
return nil, fmt.Errorf("detecting kernel version: %w", err)
|
||||||
}
|
}
|
||||||
@@ -283,7 +295,7 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
insns := make(asm.Instructions, len(spec.Instructions))
|
insns := make(asm.Instructions, len(spec.Instructions))
|
||||||
copy(insns, spec.Instructions)
|
copy(insns, spec.Instructions)
|
||||||
|
|
||||||
kmodName, err := spec.KernelModule()
|
kmodName, err := spec.kernelModule()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("kernel module search: %w", err)
|
return nil, fmt.Errorf("kernel module search: %w", err)
|
||||||
}
|
}
|
||||||
@@ -344,6 +356,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
}
|
}
|
||||||
defer kconfig.Close()
|
defer kconfig.Close()
|
||||||
|
|
||||||
|
if err := resolveKsymReferences(insns); err != nil {
|
||||||
|
return nil, fmt.Errorf("resolve .ksyms: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := fixupAndValidate(insns); err != nil {
|
if err := fixupAndValidate(insns); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -395,9 +411,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
|
|
||||||
// The caller requested a specific verifier log level. Set up the log buffer
|
// The caller requested a specific verifier log level. Set up the log buffer
|
||||||
// so that there is a chance of loading the program in a single shot.
|
// so that there is a chance of loading the program in a single shot.
|
||||||
|
logSize := internal.Between(opts.LogSizeStart, minVerifierLogSize, maxVerifierLogSize)
|
||||||
var logBuf []byte
|
var logBuf []byte
|
||||||
if !opts.LogDisabled && opts.LogLevel != 0 {
|
if !opts.LogDisabled && opts.LogLevel != 0 {
|
||||||
logBuf = make([]byte, minVerifierLogSize)
|
logBuf = make([]byte, logSize)
|
||||||
attr.LogLevel = opts.LogLevel
|
attr.LogLevel = opts.LogLevel
|
||||||
attr.LogSize = uint32(len(logBuf))
|
attr.LogSize = uint32(len(logBuf))
|
||||||
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
attr.LogBuf = sys.NewSlicePointer(logBuf)
|
||||||
@@ -431,12 +448,11 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
attr.LogLevel = LogLevelBranch
|
attr.LogLevel = LogLevelBranch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make an educated guess how large the buffer should be. Start
|
// Make an educated guess how large the buffer should be by multiplying.
|
||||||
// at minVerifierLogSize and then double the size.
|
// Ensure the size doesn't overflow.
|
||||||
logSize := uint32(max(len(logBuf)*2, minVerifierLogSize))
|
const factor = 2
|
||||||
if int(logSize) < len(logBuf) {
|
logSize := internal.Between(logSize, minVerifierLogSize, maxVerifierLogSize/factor)
|
||||||
return nil, errors.New("overflow while probing log buffer size")
|
logSize *= factor
|
||||||
}
|
|
||||||
|
|
||||||
if attr.LogTrueSize != 0 {
|
if attr.LogTrueSize != 0 {
|
||||||
// The kernel has given us a hint how large the log buffer has to be.
|
// The kernel has given us a hint how large the log buffer has to be.
|
||||||
@@ -462,6 +478,12 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
|
|||||||
return nil, fmt.Errorf("load program: %w (MEMLOCK may be too low, consider rlimit.RemoveMemlock)", err)
|
return nil, fmt.Errorf("load program: %w (MEMLOCK may be too low, consider rlimit.RemoveMemlock)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case errors.Is(err, unix.EFAULT):
|
||||||
|
// EFAULT is returned when the kernel hits a verifier bug, and always
|
||||||
|
// overrides ENOSPC, defeating the buffer growth strategy. Warn the user
|
||||||
|
// that they may need to increase the buffer size manually.
|
||||||
|
return nil, fmt.Errorf("load program: %w (hit verifier bug, increase LogSizeStart to fit the log and check dmesg)", err)
|
||||||
|
|
||||||
case errors.Is(err, unix.EINVAL):
|
case errors.Is(err, unix.EINVAL):
|
||||||
if bytes.Contains(tail, coreBadCall) {
|
if bytes.Contains(tail, coreBadCall) {
|
||||||
err = errBadRelocation
|
err = errBadRelocation
|
||||||
@@ -598,7 +620,7 @@ func (p *Program) Clone() (*Program, error) {
|
|||||||
// This requires bpffs to be mounted above fileName.
|
// This requires bpffs to be mounted above fileName.
|
||||||
// See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
|
// See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
|
||||||
func (p *Program) Pin(fileName string) error {
|
func (p *Program) Pin(fileName string) error {
|
||||||
if err := internal.Pin(p.pinnedPath, fileName, p.fd); err != nil {
|
if err := sys.Pin(p.pinnedPath, fileName, p.fd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.pinnedPath = fileName
|
p.pinnedPath = fileName
|
||||||
@@ -611,7 +633,7 @@ func (p *Program) Pin(fileName string) error {
|
|||||||
//
|
//
|
||||||
// Unpinning an unpinned Program returns nil.
|
// Unpinning an unpinned Program returns nil.
|
||||||
func (p *Program) Unpin() error {
|
func (p *Program) Unpin() error {
|
||||||
if err := internal.Unpin(p.pinnedPath); err != nil {
|
if err := sys.Unpin(p.pinnedPath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
p.pinnedPath = ""
|
p.pinnedPath = ""
|
||||||
@@ -699,6 +721,10 @@ func (p *Program) Test(in []byte) (uint32, []byte, error) {
|
|||||||
//
|
//
|
||||||
// Note: the same restrictions from Test apply.
|
// Note: the same restrictions from Test apply.
|
||||||
func (p *Program) Run(opts *RunOptions) (uint32, error) {
|
func (p *Program) Run(opts *RunOptions) (uint32, error) {
|
||||||
|
if opts == nil {
|
||||||
|
opts = &RunOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
ret, _, err := p.run(opts)
|
ret, _, err := p.run(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, fmt.Errorf("run program: %w", err)
|
return ret, fmt.Errorf("run program: %w", err)
|
||||||
@@ -732,7 +758,7 @@ func (p *Program) Benchmark(in []byte, repeat int, reset func()) (uint32, time.D
|
|||||||
return ret, total, nil
|
return ret, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error {
|
var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", func() error {
|
||||||
prog, err := NewProgram(&ProgramSpec{
|
prog, err := NewProgram(&ProgramSpec{
|
||||||
// SocketFilter does not require privileges on newer kernels.
|
// SocketFilter does not require privileges on newer kernels.
|
||||||
Type: SocketFilter,
|
Type: SocketFilter,
|
||||||
@@ -774,7 +800,7 @@ var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
}, "4.12")
|
||||||
|
|
||||||
func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) {
|
func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) {
|
||||||
if uint(len(opts.Data)) > math.MaxUint32 {
|
if uint(len(opts.Data)) > math.MaxUint32 {
|
||||||
@@ -883,6 +909,10 @@ func unmarshalProgram(buf sysenc.Buffer) (*Program, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func marshalProgram(p *Program, length int) ([]byte, error) {
|
func marshalProgram(p *Program, length int) ([]byte, error) {
|
||||||
|
if p == nil {
|
||||||
|
return nil, errors.New("can't marshal a nil Program")
|
||||||
|
}
|
||||||
|
|
||||||
if length != 4 {
|
if length != 4 {
|
||||||
return nil, fmt.Errorf("can't marshal program to %d bytes", length)
|
return nil, fmt.Errorf("can't marshal program to %d bytes", length)
|
||||||
}
|
}
|
||||||
@@ -892,11 +922,12 @@ func marshalProgram(p *Program, length int) ([]byte, error) {
|
|||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadPinnedProgram loads a Program from a BPF file.
|
// LoadPinnedProgram loads a Program from a pin (file) on the BPF virtual
|
||||||
|
// filesystem.
|
||||||
//
|
//
|
||||||
// Requires at least Linux 4.11.
|
// Requires at least Linux 4.11.
|
||||||
func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) {
|
func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error) {
|
||||||
fd, err := sys.ObjGet(&sys.ObjGetAttr{
|
fd, typ, err := sys.ObjGetTyped(&sys.ObjGetAttr{
|
||||||
Pathname: sys.NewStringPointer(fileName),
|
Pathname: sys.NewStringPointer(fileName),
|
||||||
FileFlags: opts.Marshal(),
|
FileFlags: opts.Marshal(),
|
||||||
})
|
})
|
||||||
@@ -904,6 +935,11 @@ func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typ != sys.BPF_TYPE_PROG {
|
||||||
|
_ = fd.Close()
|
||||||
|
return nil, fmt.Errorf("%s is not a Program", fileName)
|
||||||
|
}
|
||||||
|
|
||||||
info, err := newProgramInfoFromFd(fd)
|
info, err := newProgramInfoFromFd(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
|
|||||||
80
vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
80
vendor/github.com/cilium/ebpf/syscalls.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cilium/ebpf/asm"
|
"github.com/cilium/ebpf/asm"
|
||||||
"github.com/cilium/ebpf/internal"
|
"github.com/cilium/ebpf/internal"
|
||||||
|
"github.com/cilium/ebpf/internal/linux"
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/tracefs"
|
"github.com/cilium/ebpf/internal/tracefs"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
"github.com/cilium/ebpf/internal/unix"
|
||||||
@@ -60,7 +61,7 @@ func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveNestedMaps = internal.NewFeatureTest("nested maps", "4.12", func() error {
|
var haveNestedMaps = internal.NewFeatureTest("nested maps", func() error {
|
||||||
_, err := sys.MapCreate(&sys.MapCreateAttr{
|
_, err := sys.MapCreate(&sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(ArrayOfMaps),
|
MapType: sys.MapType(ArrayOfMaps),
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
@@ -76,9 +77,9 @@ var haveNestedMaps = internal.NewFeatureTest("nested maps", "4.12", func() error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
}, "4.12")
|
||||||
|
|
||||||
var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only maps", "5.2", func() error {
|
var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only maps", func() error {
|
||||||
// This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
|
// 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.
|
// BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
|
||||||
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
||||||
@@ -86,39 +87,39 @@ var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only m
|
|||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
ValueSize: 4,
|
ValueSize: 4,
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
MapFlags: unix.BPF_F_RDONLY_PROG,
|
MapFlags: sys.BPF_F_RDONLY_PROG,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
_ = m.Close()
|
_ = m.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.2")
|
||||||
|
|
||||||
var haveMmapableMaps = internal.NewFeatureTest("mmapable maps", "5.5", func() error {
|
var haveMmapableMaps = internal.NewFeatureTest("mmapable maps", func() error {
|
||||||
// This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps.
|
// This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps.
|
||||||
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(Array),
|
MapType: sys.MapType(Array),
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
ValueSize: 4,
|
ValueSize: 4,
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
MapFlags: unix.BPF_F_MMAPABLE,
|
MapFlags: sys.BPF_F_MMAPABLE,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
_ = m.Close()
|
_ = m.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.5")
|
||||||
|
|
||||||
var haveInnerMaps = internal.NewFeatureTest("inner maps", "5.10", func() error {
|
var haveInnerMaps = internal.NewFeatureTest("inner maps", func() error {
|
||||||
// This checks BPF_F_INNER_MAP, which appeared in 5.10.
|
// This checks BPF_F_INNER_MAP, which appeared in 5.10.
|
||||||
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(Array),
|
MapType: sys.MapType(Array),
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
ValueSize: 4,
|
ValueSize: 4,
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
MapFlags: unix.BPF_F_INNER_MAP,
|
MapFlags: sys.BPF_F_INNER_MAP,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -126,16 +127,16 @@ var haveInnerMaps = internal.NewFeatureTest("inner maps", "5.10", func() error {
|
|||||||
}
|
}
|
||||||
_ = m.Close()
|
_ = m.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.10")
|
||||||
|
|
||||||
var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", "4.6", func() error {
|
var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", func() error {
|
||||||
// This checks BPF_F_NO_PREALLOC, which appeared in 4.6.
|
// This checks BPF_F_NO_PREALLOC, which appeared in 4.6.
|
||||||
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
m, err := sys.MapCreate(&sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(Hash),
|
MapType: sys.MapType(Hash),
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
ValueSize: 4,
|
ValueSize: 4,
|
||||||
MaxEntries: 1,
|
MaxEntries: 1,
|
||||||
MapFlags: unix.BPF_F_NO_PREALLOC,
|
MapFlags: sys.BPF_F_NO_PREALLOC,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -143,7 +144,7 @@ var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", "4.6", func()
|
|||||||
}
|
}
|
||||||
_ = m.Close()
|
_ = m.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "4.6")
|
||||||
|
|
||||||
func wrapMapError(err error) error {
|
func wrapMapError(err error) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -169,7 +170,7 @@ func wrapMapError(err error) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error {
|
var haveObjName = internal.NewFeatureTest("object names", func() error {
|
||||||
attr := sys.MapCreateAttr{
|
attr := sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(Array),
|
MapType: sys.MapType(Array),
|
||||||
KeySize: 4,
|
KeySize: 4,
|
||||||
@@ -178,16 +179,24 @@ var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error {
|
|||||||
MapName: sys.NewObjName("feature_test"),
|
MapName: sys.NewObjName("feature_test"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tolerate EPERM as this runs during ELF loading which is potentially
|
||||||
|
// unprivileged. Only EINVAL is conclusive, thrown from CHECK_ATTR.
|
||||||
fd, err := sys.MapCreate(&attr)
|
fd, err := sys.MapCreate(&attr)
|
||||||
if err != nil {
|
if errors.Is(err, unix.EPERM) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "4.15")
|
||||||
|
|
||||||
var objNameAllowsDot = internal.NewFeatureTest("dot in object names", "5.2", func() error {
|
var objNameAllowsDot = internal.NewFeatureTest("dot in object names", func() error {
|
||||||
if err := haveObjName(); err != nil {
|
if err := haveObjName(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -200,16 +209,25 @@ var objNameAllowsDot = internal.NewFeatureTest("dot in object names", "5.2", fun
|
|||||||
MapName: sys.NewObjName(".test"),
|
MapName: sys.NewObjName(".test"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tolerate EPERM, otherwise MapSpec.Name has its dots removed when run by
|
||||||
|
// unprivileged tools. (bpf2go, other code gen). Only EINVAL is conclusive,
|
||||||
|
// thrown from bpf_obj_name_cpy().
|
||||||
fd, err := sys.MapCreate(&attr)
|
fd, err := sys.MapCreate(&attr)
|
||||||
if err != nil {
|
if errors.Is(err, unix.EPERM) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if errors.Is(err, unix.EINVAL) {
|
||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.2")
|
||||||
|
|
||||||
var haveBatchAPI = internal.NewFeatureTest("map batch api", "5.6", func() error {
|
var haveBatchAPI = internal.NewFeatureTest("map batch api", func() error {
|
||||||
var maxEntries uint32 = 2
|
var maxEntries uint32 = 2
|
||||||
attr := sys.MapCreateAttr{
|
attr := sys.MapCreateAttr{
|
||||||
MapType: sys.MapType(Hash),
|
MapType: sys.MapType(Hash),
|
||||||
@@ -239,9 +257,9 @@ var haveBatchAPI = internal.NewFeatureTest("map batch api", "5.6", func() error
|
|||||||
return internal.ErrNotSupported
|
return internal.ErrNotSupported
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.6")
|
||||||
|
|
||||||
var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", "5.5", func() error {
|
var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", func() error {
|
||||||
insns := asm.Instructions{
|
insns := asm.Instructions{
|
||||||
asm.Mov.Reg(asm.R1, asm.R10),
|
asm.Mov.Reg(asm.R1, asm.R10),
|
||||||
asm.Add.Imm(asm.R1, -8),
|
asm.Add.Imm(asm.R1, -8),
|
||||||
@@ -257,9 +275,9 @@ var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", "5.5"
|
|||||||
}
|
}
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "5.5")
|
||||||
|
|
||||||
var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", "4.16", func() error {
|
var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", func() error {
|
||||||
insns := asm.Instructions{
|
insns := asm.Instructions{
|
||||||
asm.Call.Label("prog2").WithSymbol("prog1"),
|
asm.Call.Label("prog2").WithSymbol("prog1"),
|
||||||
asm.Return(),
|
asm.Return(),
|
||||||
@@ -273,10 +291,10 @@ var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", "4.16", func()
|
|||||||
}
|
}
|
||||||
_ = fd.Close()
|
_ = fd.Close()
|
||||||
return nil
|
return nil
|
||||||
})
|
}, "4.16")
|
||||||
|
|
||||||
var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func() error {
|
var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", func() error {
|
||||||
prefix := internal.PlatformPrefix()
|
prefix := linux.PlatformPrefix()
|
||||||
if prefix == "" {
|
if prefix == "" {
|
||||||
return fmt.Errorf("unable to find the platform prefix for (%s)", runtime.GOARCH)
|
return fmt.Errorf("unable to find the platform prefix for (%s)", runtime.GOARCH)
|
||||||
}
|
}
|
||||||
@@ -302,9 +320,9 @@ var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func
|
|||||||
}
|
}
|
||||||
|
|
||||||
return evt.Close()
|
return evt.Close()
|
||||||
})
|
}, "4.17")
|
||||||
|
|
||||||
var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", func() error {
|
var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", func() error {
|
||||||
insns := asm.Instructions{
|
insns := asm.Instructions{
|
||||||
asm.Mov.Imm(asm.R0, 0),
|
asm.Mov.Imm(asm.R0, 0),
|
||||||
asm.Return(),
|
asm.Return(),
|
||||||
@@ -334,4 +352,4 @@ var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
}, "5.0")
|
||||||
|
|||||||
28
vendor/github.com/cilium/ebpf/types.go
generated
vendored
28
vendor/github.com/cilium/ebpf/types.go
generated
vendored
@@ -2,7 +2,6 @@ package ebpf
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cilium/ebpf/internal/sys"
|
"github.com/cilium/ebpf/internal/sys"
|
||||||
"github.com/cilium/ebpf/internal/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run golang.org/x/tools/cmd/stringer@latest -output types_string.go -type=MapType,ProgramType,PinType
|
//go:generate go run golang.org/x/tools/cmd/stringer@latest -output types_string.go -type=MapType,ProgramType,PinType
|
||||||
@@ -95,6 +94,14 @@ const (
|
|||||||
InodeStorage
|
InodeStorage
|
||||||
// TaskStorage - Specialized local storage map for task_struct.
|
// TaskStorage - Specialized local storage map for task_struct.
|
||||||
TaskStorage
|
TaskStorage
|
||||||
|
// BloomFilter - Space-efficient data structure to quickly test whether an element exists in a set.
|
||||||
|
BloomFilter
|
||||||
|
// UserRingbuf - The reverse of RingBuf, used to send messages from user space to BPF programs.
|
||||||
|
UserRingbuf
|
||||||
|
// CgroupStorage - Store data keyed on a cgroup. If the cgroup disappears, the key is automatically removed.
|
||||||
|
CgroupStorage
|
||||||
|
// Arena - Sparse shared memory region between a BPF program and user space.
|
||||||
|
Arena
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasPerCPUValue returns true if the Map stores a value per CPU.
|
// hasPerCPUValue returns true if the Map stores a value per CPU.
|
||||||
@@ -120,6 +127,21 @@ func (mt MapType) canStoreProgram() bool {
|
|||||||
return mt == ProgramArray
|
return mt == ProgramArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// canHaveValueSize returns true if the map type supports setting a value size.
|
||||||
|
func (mt MapType) canHaveValueSize() bool {
|
||||||
|
switch mt {
|
||||||
|
case RingBuf, Arena:
|
||||||
|
return false
|
||||||
|
|
||||||
|
// Special-case perf events since they require a value size of either 0 or 4
|
||||||
|
// for historical reasons. Let the library fix this up later.
|
||||||
|
case PerfEventArray:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// ProgramType of the eBPF program
|
// ProgramType of the eBPF program
|
||||||
type ProgramType uint32
|
type ProgramType uint32
|
||||||
|
|
||||||
@@ -263,10 +285,10 @@ func (lpo *LoadPinOptions) Marshal() uint32 {
|
|||||||
|
|
||||||
flags := lpo.Flags
|
flags := lpo.Flags
|
||||||
if lpo.ReadOnly {
|
if lpo.ReadOnly {
|
||||||
flags |= unix.BPF_F_RDONLY
|
flags |= sys.BPF_F_RDONLY
|
||||||
}
|
}
|
||||||
if lpo.WriteOnly {
|
if lpo.WriteOnly {
|
||||||
flags |= unix.BPF_F_WRONLY
|
flags |= sys.BPF_F_WRONLY
|
||||||
}
|
}
|
||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|||||||
8
vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
8
vendor/github.com/cilium/ebpf/types_string.go
generated
vendored
@@ -38,11 +38,15 @@ func _() {
|
|||||||
_ = x[RingBuf-27]
|
_ = x[RingBuf-27]
|
||||||
_ = x[InodeStorage-28]
|
_ = x[InodeStorage-28]
|
||||||
_ = x[TaskStorage-29]
|
_ = x[TaskStorage-29]
|
||||||
|
_ = x[BloomFilter-30]
|
||||||
|
_ = x[UserRingbuf-31]
|
||||||
|
_ = x[CgroupStorage-32]
|
||||||
|
_ = x[Arena-33]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOpsMapRingBufInodeStorageTaskStorage"
|
const _MapType_name = "UnspecifiedMapHashArrayProgramArrayPerfEventArrayPerCPUHashPerCPUArrayStackTraceCGroupArrayLRUHashLRUCPUHashLPMTrieArrayOfMapsHashOfMapsDevMapSockMapCPUMapXSKMapSockHashCGroupStorageReusePortSockArrayPerCPUCGroupStorageQueueStackSkStorageDevMapHashStructOpsMapRingBufInodeStorageTaskStorageBloomFilterUserRingbufCgroupStorageArena"
|
||||||
|
|
||||||
var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 260, 267, 279, 290}
|
var _MapType_index = [...]uint16{0, 14, 18, 23, 35, 49, 59, 70, 80, 91, 98, 108, 115, 126, 136, 142, 149, 155, 161, 169, 182, 200, 219, 224, 229, 238, 248, 260, 267, 279, 290, 301, 312, 325, 330}
|
||||||
|
|
||||||
func (i MapType) String() string {
|
func (i MapType) String() string {
|
||||||
if i >= MapType(len(_MapType_index)-1) {
|
if i >= MapType(len(_MapType_index)-1) {
|
||||||
|
|||||||
230
vendor/github.com/cilium/ebpf/variable.go
generated
vendored
Normal file
230
vendor/github.com/cilium/ebpf/variable.go
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
package ebpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/cilium/ebpf/btf"
|
||||||
|
"github.com/cilium/ebpf/internal/sysenc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VariableSpec is a convenience wrapper for modifying global variables of a
|
||||||
|
// CollectionSpec before loading it into the kernel.
|
||||||
|
//
|
||||||
|
// All operations on a VariableSpec's underlying MapSpec are performed in the
|
||||||
|
// host's native endianness.
|
||||||
|
type VariableSpec struct {
|
||||||
|
name string
|
||||||
|
offset uint64
|
||||||
|
size uint64
|
||||||
|
|
||||||
|
m *MapSpec
|
||||||
|
t *btf.Var
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the value of the VariableSpec to the provided input using the host's
|
||||||
|
// native endianness.
|
||||||
|
func (s *VariableSpec) Set(in any) error {
|
||||||
|
buf, err := sysenc.Marshal(in, int(s.size))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshaling value %s: %w", s.name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, _, err := s.m.dataSection()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting data section of map %s: %w", s.m.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if int(s.offset+s.size) > len(b) {
|
||||||
|
return fmt.Errorf("offset %d(+%d) for variable %s is out of bounds", s.offset, s.size, s.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapSpec.Copy() performs a shallow copy. Fully copy the byte slice
|
||||||
|
// to avoid any changes affecting other copies of the MapSpec.
|
||||||
|
cpy := make([]byte, len(b))
|
||||||
|
copy(cpy, b)
|
||||||
|
|
||||||
|
buf.CopyTo(cpy[s.offset : s.offset+s.size])
|
||||||
|
|
||||||
|
s.m.Contents[0] = MapKV{Key: uint32(0), Value: cpy}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get writes the value of the VariableSpec to the provided output using the
|
||||||
|
// host's native endianness.
|
||||||
|
func (s *VariableSpec) Get(out any) error {
|
||||||
|
b, _, err := s.m.dataSection()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getting data section of map %s: %w", s.m.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if int(s.offset+s.size) > len(b) {
|
||||||
|
return fmt.Errorf("offset %d(+%d) for variable %s is out of bounds", s.offset, s.size, s.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sysenc.Unmarshal(out, b[s.offset:s.offset+s.size]); err != nil {
|
||||||
|
return fmt.Errorf("unmarshaling value: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the variable in bytes.
|
||||||
|
func (s *VariableSpec) Size() uint64 {
|
||||||
|
return s.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapName returns the name of the underlying MapSpec.
|
||||||
|
func (s *VariableSpec) MapName() string {
|
||||||
|
return s.m.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset returns the offset of the variable in the underlying MapSpec.
|
||||||
|
func (s *VariableSpec) Offset() uint64 {
|
||||||
|
return s.offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant returns true if the VariableSpec represents a variable that is
|
||||||
|
// read-only from the perspective of the BPF program.
|
||||||
|
func (s *VariableSpec) Constant() bool {
|
||||||
|
return s.m.readOnly()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns the [btf.Var] representing the variable in its data section.
|
||||||
|
// This is useful for inspecting the variable's decl tags and the type
|
||||||
|
// information of the inner type.
|
||||||
|
//
|
||||||
|
// Returns nil if the original ELF object did not contain BTF information.
|
||||||
|
func (s *VariableSpec) Type() *btf.Var {
|
||||||
|
return s.t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *VariableSpec) String() string {
|
||||||
|
return fmt.Sprintf("%s (type=%v, map=%s, offset=%d, size=%d)", s.name, s.t, s.m.Name, s.offset, s.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy returns a new VariableSpec with the same values as the original,
|
||||||
|
// but with a different underlying MapSpec. This is useful when copying a
|
||||||
|
// CollectionSpec. Returns nil if a MapSpec with the same name is not found.
|
||||||
|
func (s *VariableSpec) copy(cpy *CollectionSpec) *VariableSpec {
|
||||||
|
out := &VariableSpec{
|
||||||
|
name: s.name,
|
||||||
|
offset: s.offset,
|
||||||
|
size: s.size,
|
||||||
|
}
|
||||||
|
if s.t != nil {
|
||||||
|
out.t = btf.Copy(s.t).(*btf.Var)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to find a MapSpec with the same name in the copied CollectionSpec.
|
||||||
|
for _, m := range cpy.Maps {
|
||||||
|
if m.Name == s.m.Name {
|
||||||
|
out.m = m
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable is a convenience wrapper for modifying global variables of a
|
||||||
|
// Collection after loading it into the kernel. Operations on a Variable are
|
||||||
|
// performed using direct memory access, bypassing the BPF map syscall API.
|
||||||
|
//
|
||||||
|
// On kernels older than 5.5, most interactions with Variable return
|
||||||
|
// [ErrNotSupported].
|
||||||
|
type Variable struct {
|
||||||
|
name string
|
||||||
|
offset uint64
|
||||||
|
size uint64
|
||||||
|
t *btf.Var
|
||||||
|
|
||||||
|
mm *Memory
|
||||||
|
}
|
||||||
|
|
||||||
|
func newVariable(name string, offset, size uint64, t *btf.Var, mm *Memory) (*Variable, error) {
|
||||||
|
if mm != nil {
|
||||||
|
if int(offset+size) > mm.Size() {
|
||||||
|
return nil, fmt.Errorf("offset %d(+%d) is out of bounds", offset, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Variable{
|
||||||
|
name: name,
|
||||||
|
offset: offset,
|
||||||
|
size: size,
|
||||||
|
t: t,
|
||||||
|
mm: mm,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of the variable.
|
||||||
|
func (v *Variable) Size() uint64 {
|
||||||
|
return v.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadOnly returns true if the Variable represents a variable that is read-only
|
||||||
|
// after loading the Collection into the kernel.
|
||||||
|
//
|
||||||
|
// On systems without BPF_F_MMAPABLE support, ReadOnly always returns true.
|
||||||
|
func (v *Variable) ReadOnly() bool {
|
||||||
|
if v.mm == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return v.mm.ReadOnly()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns the [btf.Var] representing the variable in its data section.
|
||||||
|
// This is useful for inspecting the variable's decl tags and the type
|
||||||
|
// information of the inner type.
|
||||||
|
//
|
||||||
|
// Returns nil if the original ELF object did not contain BTF information.
|
||||||
|
func (v *Variable) Type() *btf.Var {
|
||||||
|
return v.t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variable) String() string {
|
||||||
|
return fmt.Sprintf("%s (type=%v)", v.name, v.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the value of the Variable to the provided input. The input must marshal
|
||||||
|
// to the same length as the size of the Variable.
|
||||||
|
func (v *Variable) Set(in any) error {
|
||||||
|
if v.mm == nil {
|
||||||
|
return fmt.Errorf("variable %s: direct access requires Linux 5.5 or later: %w", v.name, ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.ReadOnly() {
|
||||||
|
return fmt.Errorf("variable %s: %w", v.name, ErrReadOnly)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := sysenc.Marshal(in, int(v.size))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("marshaling value %s: %w", v.name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := v.mm.WriteAt(buf.Bytes(), int64(v.offset)); err != nil {
|
||||||
|
return fmt.Errorf("writing value to %s: %w", v.name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get writes the value of the Variable to the provided output. The output must
|
||||||
|
// be a pointer to a value whose size matches the Variable.
|
||||||
|
func (v *Variable) Get(out any) error {
|
||||||
|
if v.mm == nil {
|
||||||
|
return fmt.Errorf("variable %s: direct access requires Linux 5.5 or later: %w", v.name, ErrNotSupported)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.mm.bounds(v.offset, v.size) {
|
||||||
|
return fmt.Errorf("variable %s: access out of bounds: %w", v.name, io.EOF)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sysenc.Unmarshal(out, v.mm.b[v.offset:v.offset+v.size]); err != nil {
|
||||||
|
return fmt.Errorf("unmarshaling value %s: %w", v.name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
27
vendor/golang.org/x/exp/LICENSE
generated
vendored
27
vendor/golang.org/x/exp/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
22
vendor/golang.org/x/exp/PATENTS
generated
vendored
22
vendor/golang.org/x/exp/PATENTS
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
Additional IP Rights Grant (Patents)
|
|
||||||
|
|
||||||
"This implementation" means the copyrightable works distributed by
|
|
||||||
Google as part of the Go project.
|
|
||||||
|
|
||||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
|
||||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
|
||||||
patent license to make, have made, use, offer to sell, sell, import,
|
|
||||||
transfer and otherwise run, modify and propagate the contents of this
|
|
||||||
implementation of Go, where such license applies only to those patent
|
|
||||||
claims, both currently owned or controlled by Google and acquired in
|
|
||||||
the future, licensable by Google that are necessarily infringed by this
|
|
||||||
implementation of Go. This grant does not include claims that would be
|
|
||||||
infringed only as a consequence of further modification of this
|
|
||||||
implementation. If you or your agent or exclusive licensee institute or
|
|
||||||
order or agree to the institution of patent litigation against any
|
|
||||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
|
||||||
that this implementation of Go or any code incorporated within this
|
|
||||||
implementation of Go constitutes direct or contributory patent
|
|
||||||
infringement, or inducement of patent infringement, then any patent
|
|
||||||
rights granted to you under this License for this implementation of Go
|
|
||||||
shall terminate as of the date such litigation is filed.
|
|
||||||
50
vendor/golang.org/x/exp/constraints/constraints.go
generated
vendored
50
vendor/golang.org/x/exp/constraints/constraints.go
generated
vendored
@@ -1,50 +0,0 @@
|
|||||||
// Copyright 2021 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Package constraints defines a set of useful constraints to be used
|
|
||||||
// with type parameters.
|
|
||||||
package constraints
|
|
||||||
|
|
||||||
// Signed is a constraint that permits any signed integer type.
|
|
||||||
// If future releases of Go add new predeclared signed integer types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Signed interface {
|
|
||||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unsigned is a constraint that permits any unsigned integer type.
|
|
||||||
// If future releases of Go add new predeclared unsigned integer types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Unsigned interface {
|
|
||||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Integer is a constraint that permits any integer type.
|
|
||||||
// If future releases of Go add new predeclared integer types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Integer interface {
|
|
||||||
Signed | Unsigned
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float is a constraint that permits any floating-point type.
|
|
||||||
// If future releases of Go add new predeclared floating-point types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Float interface {
|
|
||||||
~float32 | ~float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complex is a constraint that permits any complex numeric type.
|
|
||||||
// If future releases of Go add new predeclared complex numeric types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Complex interface {
|
|
||||||
~complex64 | ~complex128
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ordered is a constraint that permits any ordered type: any type
|
|
||||||
// that supports the operators < <= >= >.
|
|
||||||
// If future releases of Go add new ordered types,
|
|
||||||
// this constraint will be modified to include them.
|
|
||||||
type Ordered interface {
|
|
||||||
Integer | Float | ~string
|
|
||||||
}
|
|
||||||
9
vendor/modules.txt
vendored
9
vendor/modules.txt
vendored
@@ -2,16 +2,18 @@
|
|||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
github.com/checkpoint-restore/go-criu/v6
|
github.com/checkpoint-restore/go-criu/v6
|
||||||
github.com/checkpoint-restore/go-criu/v6/rpc
|
github.com/checkpoint-restore/go-criu/v6/rpc
|
||||||
# github.com/cilium/ebpf v0.16.0
|
# github.com/cilium/ebpf v0.17.0
|
||||||
## explicit; go 1.21
|
## explicit; go 1.22
|
||||||
github.com/cilium/ebpf
|
github.com/cilium/ebpf
|
||||||
github.com/cilium/ebpf/asm
|
github.com/cilium/ebpf/asm
|
||||||
github.com/cilium/ebpf/btf
|
github.com/cilium/ebpf/btf
|
||||||
github.com/cilium/ebpf/internal
|
github.com/cilium/ebpf/internal
|
||||||
github.com/cilium/ebpf/internal/kallsyms
|
github.com/cilium/ebpf/internal/kallsyms
|
||||||
github.com/cilium/ebpf/internal/kconfig
|
github.com/cilium/ebpf/internal/kconfig
|
||||||
|
github.com/cilium/ebpf/internal/linux
|
||||||
github.com/cilium/ebpf/internal/sys
|
github.com/cilium/ebpf/internal/sys
|
||||||
github.com/cilium/ebpf/internal/sysenc
|
github.com/cilium/ebpf/internal/sysenc
|
||||||
|
github.com/cilium/ebpf/internal/testutils/fdtrace
|
||||||
github.com/cilium/ebpf/internal/tracefs
|
github.com/cilium/ebpf/internal/tracefs
|
||||||
github.com/cilium/ebpf/internal/unix
|
github.com/cilium/ebpf/internal/unix
|
||||||
github.com/cilium/ebpf/link
|
github.com/cilium/ebpf/link
|
||||||
@@ -78,9 +80,6 @@ github.com/vishvananda/netlink/nl
|
|||||||
# github.com/vishvananda/netns v0.0.4
|
# github.com/vishvananda/netns v0.0.4
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/vishvananda/netns
|
github.com/vishvananda/netns
|
||||||
# golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2
|
|
||||||
## explicit; go 1.18
|
|
||||||
golang.org/x/exp/constraints
|
|
||||||
# golang.org/x/net v0.33.0
|
# golang.org/x/net v0.33.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
golang.org/x/net/bpf
|
golang.org/x/net/bpf
|
||||||
|
|||||||
Reference in New Issue
Block a user