Files
runc/vendor/github.com/cilium/ebpf/btf/kernel.go
dependabot[bot] e809db842f 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>
2024-12-20 00:07:03 +00:00

158 lines
3.5 KiB
Go

package btf
import (
"errors"
"fmt"
"os"
"path/filepath"
"sync"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/linux"
)
var kernelBTF = struct {
sync.RWMutex
kernel *Spec
modules map[string]*Spec
}{
modules: make(map[string]*Spec),
}
// FlushKernelSpec removes any cached kernel type information.
func FlushKernelSpec() {
kernelBTF.Lock()
defer kernelBTF.Unlock()
kernelBTF.kernel = nil
kernelBTF.modules = make(map[string]*Spec)
}
// LoadKernelSpec returns the current kernel's BTF information.
//
// Defaults to /sys/kernel/btf/vmlinux and falls back to scanning the file system
// for vmlinux ELFs. Returns an error wrapping ErrNotSupported if BTF is not enabled.
func LoadKernelSpec() (*Spec, error) {
kernelBTF.RLock()
spec := kernelBTF.kernel
kernelBTF.RUnlock()
if spec == nil {
kernelBTF.Lock()
defer kernelBTF.Unlock()
spec = kernelBTF.kernel
}
if spec != nil {
return spec.Copy(), nil
}
spec, _, err := loadKernelSpec()
if err != nil {
return nil, err
}
kernelBTF.kernel = spec
return spec.Copy(), nil
}
// LoadKernelModuleSpec returns the BTF information for the named kernel module.
//
// Defaults to /sys/kernel/btf/<module>.
// Returns an error wrapping ErrNotSupported if BTF is not enabled.
// Returns an error wrapping fs.ErrNotExist if BTF for the specific module doesn't exist.
func LoadKernelModuleSpec(module string) (*Spec, error) {
kernelBTF.RLock()
spec := kernelBTF.modules[module]
kernelBTF.RUnlock()
if spec != nil {
return spec.Copy(), nil
}
base, err := LoadKernelSpec()
if err != nil {
return nil, fmt.Errorf("load kernel spec: %w", err)
}
kernelBTF.Lock()
defer kernelBTF.Unlock()
if spec = kernelBTF.modules[module]; spec != nil {
return spec.Copy(), nil
}
spec, err = loadKernelModuleSpec(module, base)
if err != nil {
return nil, err
}
kernelBTF.modules[module] = spec
return spec.Copy(), nil
}
func loadKernelSpec() (_ *Spec, fallback bool, _ error) {
fh, err := os.Open("/sys/kernel/btf/vmlinux")
if err == nil {
defer fh.Close()
spec, err := loadRawSpec(fh, internal.NativeEndian, nil)
return spec, false, err
}
file, err := findVMLinux()
if err != nil {
return nil, false, err
}
defer file.Close()
spec, err := LoadSpecFromReader(file)
return spec, true, err
}
func loadKernelModuleSpec(module string, base *Spec) (*Spec, error) {
dir, file := filepath.Split(module)
if dir != "" || filepath.Ext(file) != "" {
return nil, fmt.Errorf("invalid module name %q", module)
}
fh, err := os.Open(filepath.Join("/sys/kernel/btf", module))
if err != nil {
return nil, err
}
defer fh.Close()
return loadRawSpec(fh, internal.NativeEndian, base)
}
// findVMLinux scans multiple well-known paths for vmlinux kernel images.
func findVMLinux() (*os.File, error) {
release, err := linux.KernelRelease()
if err != nil {
return nil, err
}
// use same list of locations as libbpf
// https://github.com/libbpf/libbpf/blob/9a3a42608dbe3731256a5682a125ac1e23bced8f/src/btf.c#L3114-L3122
locations := []string{
"/boot/vmlinux-%s",
"/lib/modules/%s/vmlinux-%[1]s",
"/lib/modules/%s/build/vmlinux",
"/usr/lib/modules/%s/kernel/vmlinux",
"/usr/lib/debug/boot/vmlinux-%s",
"/usr/lib/debug/boot/vmlinux-%s.debug",
"/usr/lib/debug/lib/modules/%s/vmlinux",
}
for _, loc := range locations {
file, err := os.Open(fmt.Sprintf(loc, release))
if errors.Is(err, os.ErrNotExist) {
continue
}
return file, err
}
return nil, fmt.Errorf("no BTF found for kernel version %s: %w", release, internal.ErrNotSupported)
}