diff --git a/go.mod b/go.mod
index 160f084088def5f98b316a3f52067c04258a6c29..c4971c49e7e7da0f784e4222b2fecf0d1c15bbfc 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ toolchain go1.23.5
 
 require (
 	github.com/caarlos0/env/v6 v6.10.1
-	github.com/cilium/ebpf v0.16.0
+	github.com/cilium/ebpf v0.17.1
 	github.com/fsnotify/fsnotify v1.8.0
 	github.com/gavv/monotime v0.0.0-20190418164738-30dba4353424
 	github.com/gopacket/gopacket v1.3.1
@@ -129,7 +129,6 @@ require (
 	go.opentelemetry.io/proto/otlp v1.3.1 // indirect
 	go.uber.org/atomic v1.9.0 // indirect
 	golang.org/x/crypto v0.31.0 // indirect
-	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
 	golang.org/x/net v0.33.0 // indirect
 	golang.org/x/oauth2 v0.23.0 // indirect
 	golang.org/x/term v0.27.0 // indirect
diff --git a/go.sum b/go.sum
index 5a80c94cc9fd334359fe83132c561e8de779a781..bfe8bc712c90f8f30535cf2079f860192f59443f 100644
--- a/go.sum
+++ b/go.sum
@@ -142,8 +142,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok=
-github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE=
+github.com/cilium/ebpf v0.17.1 h1:G8mzU81R2JA1nE5/8SRubzqvBMmAmri2VL8BIZPWvV0=
+github.com/cilium/ebpf v0.17.1/go.mod h1:vay2FaYSmIlv3r8dNACd4mW/OCaZLJKJOo+IHBvCIO8=
 github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
diff --git a/vendor/github.com/cilium/ebpf/.golangci.yaml b/vendor/github.com/cilium/ebpf/.golangci.yaml
index 65f91b910bf6678471bc5de97dabdfdc81e1e5d5..366d4893f204b676e67885f15422d12bf451cc7b 100644
--- a/vendor/github.com/cilium/ebpf/.golangci.yaml
+++ b/vendor/github.com/cilium/ebpf/.golangci.yaml
@@ -11,3 +11,9 @@ linters:
     - typecheck
     - unused
     - 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
diff --git a/vendor/github.com/cilium/ebpf/CODEOWNERS b/vendor/github.com/cilium/ebpf/CODEOWNERS
index ca65d23c09d294775d3a3f6f47dd90c539bb0865..0f76dce85c8ee371900b0155acd2eae8439ecaa9 100644
--- a/vendor/github.com/cilium/ebpf/CODEOWNERS
+++ b/vendor/github.com/cilium/ebpf/CODEOWNERS
@@ -9,3 +9,5 @@ ringbuf/ @florianl
 btf/ @dylandreimerink
 
 cmd/bpf2go/ @mejedi
+
+docs/ @ti-mo
diff --git a/vendor/github.com/cilium/ebpf/Makefile b/vendor/github.com/cilium/ebpf/Makefile
index d355eea71caed0dd31c26ad44043b3ad1457e8df..e0fe974920602c3f61938e427265366725528157 100644
--- a/vendor/github.com/cilium/ebpf/Makefile
+++ b/vendor/github.com/cilium/ebpf/Makefile
@@ -39,16 +39,18 @@ TARGETS := \
 	testdata/subprog_reloc \
 	testdata/fwd_decl \
 	testdata/kconfig \
-	testdata/kconfig_config \
+	testdata/ksym \
 	testdata/kfunc \
 	testdata/invalid-kfunc \
 	testdata/kfunc-kmod \
 	testdata/constants \
 	testdata/errors \
+	testdata/variables \
 	btf/testdata/relocs \
 	btf/testdata/relocs_read \
 	btf/testdata/relocs_read_tgt \
 	btf/testdata/relocs_enum \
+	btf/testdata/tags \
 	cmd/bpf2go/testdata/minimal
 
 .PHONY: all clean container-all container-shell generate
@@ -57,7 +59,7 @@ TARGETS := \
 
 # Build all ELF binaries using a containerized LLVM toolchain.
 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 \
 		--env HOME="/tmp" \
 		--env BPF2GO_CC="$(CLANG)" \
diff --git a/vendor/github.com/cilium/ebpf/README.md b/vendor/github.com/cilium/ebpf/README.md
index 85871db1ae39b13b4a2ba7b9f71aa89ee964aa6e..8238256c8ed13e42238566d40927088b7e65216a 100644
--- a/vendor/github.com/cilium/ebpf/README.md
+++ b/vendor/github.com/cilium/ebpf/README.md
@@ -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
   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.
+* [pin](https://pkg.go.dev/github.com/cilium/ebpf/pin) provides APIs for working with pinned objects on bpffs.
 
 ## Requirements
 
diff --git a/vendor/github.com/cilium/ebpf/asm/instruction.go b/vendor/github.com/cilium/ebpf/asm/instruction.go
index 67cd39d6f672fe8999f046b2b5faaaa7a888555e..86b384c02a99844684fad5548f7852a32964d0af 100644
--- a/vendor/github.com/cilium/ebpf/asm/instruction.go
+++ b/vendor/github.com/cilium/ebpf/asm/instruction.go
@@ -12,7 +12,6 @@ import (
 	"strings"
 
 	"github.com/cilium/ebpf/internal/sys"
-	"github.com/cilium/ebpf/internal/unix"
 )
 
 // 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 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
diff --git a/vendor/github.com/cilium/ebpf/btf/btf.go b/vendor/github.com/cilium/ebpf/btf/btf.go
index 671f680b2af2a3127729e491d68a6d5cf8c5e412..880c5ade0c16a8a6d2017043013d3c8ab7cfd112 100644
--- a/vendor/github.com/cilium/ebpf/btf/btf.go
+++ b/vendor/github.com/cilium/ebpf/btf/btf.go
@@ -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.
 		switch name {
 		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.
 			for _, vsi := range ds.Vars {
-				_, ok := vsi.Type.(*Func)
-				if !ok {
-					// Only Funcs are supported in the .ksyms Datasec.
-					return fmt.Errorf("data section %s: expected *btf.Func, not %T: %w", name, vsi.Type, ErrNotSupported)
+				switch t := vsi.Type.(type) {
+				case *Func:
+					continue
+				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.id++
 	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
 }
diff --git a/vendor/github.com/cilium/ebpf/btf/btf_types.go b/vendor/github.com/cilium/ebpf/btf/btf_types.go
index f0e327abc0e6409122fca8d5c2f0186091c8fa70..320311b332068136e84d9a9f3aa415bb64e909d0 100644
--- a/vendor/github.com/cilium/ebpf/btf/btf_types.go
+++ b/vendor/github.com/cilium/ebpf/btf/btf_types.go
@@ -39,6 +39,7 @@ const (
 	kindFloat // Float
 	// Added 5.16
 	kindDeclTag // DeclTag
+	// Added 5.17
 	kindTypeTag // TypeTag
 	// Added 6.0
 	kindEnum64 // Enum64
diff --git a/vendor/github.com/cilium/ebpf/btf/ext_info.go b/vendor/github.com/cilium/ebpf/btf/ext_info.go
index eb9044badf2381c520d1d24f0b1df7fbe92199c4..2c684fe2a79a7c3a8c54a72a788433504dce6bf9 100644
--- a/vendor/github.com/cilium/ebpf/btf/ext_info.go
+++ b/vendor/github.com/cilium/ebpf/btf/ext_info.go
@@ -16,8 +16,8 @@ import (
 // ExtInfos contains ELF section metadata.
 type ExtInfos struct {
 	// The slices are sorted by offset in ascending order.
-	funcInfos       map[string]FuncInfos
-	lineInfos       map[string]LineInfos
+	funcInfos       map[string]FuncOffsets
+	lineInfos       map[string]LineOffsets
 	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)
 	}
 
-	funcInfos := make(map[string]FuncInfos, len(btfFuncInfos))
+	funcInfos := make(map[string]FuncOffsets, len(btfFuncInfos))
 	for section, bfis := range btfFuncInfos {
-		funcInfos[section], err = newFuncInfos(bfis, spec)
+		funcInfos[section], err = newFuncOffsets(bfis, spec)
 		if err != nil {
 			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)
 	}
 
-	lineInfos := make(map[string]LineInfos, len(btfLineInfos))
+	lineInfos := make(map[string]LineOffsets, len(btfLineInfos))
 	for section, blis := range btfLineInfos {
 		lineInfos[section], err = newLineInfos(blis, spec.strings)
 		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
 }
 
-type funcInfoMeta struct{}
-type coreRelocationMeta struct{}
+type (
+	funcInfoMeta       struct{}
+	coreRelocationMeta struct{}
+)
 
 // Assign per-section metadata from BTF to a section's instructions.
 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.
 func AssignMetadataToInstructions(
 	insns asm.Instructions,
-	funcInfos FuncInfos,
-	lineInfos LineInfos,
+	funcInfos FuncOffsets,
+	lineInfos LineOffsets,
 	reloInfos CORERelocationInfos,
 ) {
 	iter := insns.Iterate()
 	for iter.Next() {
-		if len(funcInfos.infos) > 0 && funcInfos.infos[0].offset == iter.Offset {
-			*iter.Ins = WithFuncMetadata(*iter.Ins, funcInfos.infos[0].fn)
-			funcInfos.infos = funcInfos.infos[1:]
+		if len(funcInfos) > 0 && funcInfos[0].Offset == iter.Offset {
+			*iter.Ins = WithFuncMetadata(*iter.Ins, funcInfos[0].Func)
+			funcInfos = funcInfos[1:]
 		}
 
-		if len(lineInfos.infos) > 0 && lineInfos.infos[0].offset == iter.Offset {
-			*iter.Ins = iter.Ins.WithSource(lineInfos.infos[0].line)
-			lineInfos.infos = lineInfos.infos[1:]
+		if len(lineInfos) > 0 && lineInfos[0].Offset == iter.Offset {
+			*iter.Ins = iter.Ins.WithSource(lineInfos[0].Line)
+			lineInfos = lineInfos[1:]
 		}
 
 		if len(reloInfos.infos) > 0 && reloInfos.infos[0].offset == iter.Offset {
@@ -159,9 +161,9 @@ marshal:
 	var fiBuf, liBuf bytes.Buffer
 	for {
 		if fn := FuncMetadata(iter.Ins); fn != nil {
-			fi := &funcInfo{
-				fn:     fn,
-				offset: iter.Offset,
+			fi := &FuncOffset{
+				Func:   fn,
+				Offset: iter.Offset,
 			}
 			if err := fi.marshal(&fiBuf, b); err != nil {
 				return nil, nil, fmt.Errorf("write func info: %w", err)
@@ -178,9 +180,9 @@ marshal:
 				}
 			}
 
-			li := &lineInfo{
-				line:   line,
-				offset: iter.Offset,
+			li := &LineOffset{
+				Offset: iter.Offset,
+				Line:   line,
 			}
 			if err := li.marshal(&liBuf, b); err != nil {
 				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
 }
 
-// FuncInfos contains a sorted list of func infos.
-type FuncInfos struct {
-	infos []funcInfo
-}
+// FuncOffsets is a sorted slice of FuncOffset.
+type FuncOffsets []FuncOffset
 
 // The size of a FuncInfo in BTF wire format.
 var FuncInfoSize = uint32(binary.Size(bpfFuncInfo{}))
 
-type funcInfo struct {
-	fn     *Func
-	offset asm.RawInstructionOffset
+// FuncOffset represents a [btf.Func] and its raw instruction offset within a
+// BPF program.
+type FuncOffset struct {
+	Offset asm.RawInstructionOffset
+	Func   *Func
 }
 
 type bpfFuncInfo struct {
@@ -352,7 +354,7 @@ type bpfFuncInfo struct {
 	TypeID  TypeID
 }
 
-func newFuncInfo(fi bpfFuncInfo, spec *Spec) (*funcInfo, error) {
+func newFuncOffset(fi bpfFuncInfo, spec *Spec) (*FuncOffset, error) {
 	typ, err := spec.TypeByID(fi.TypeID)
 	if err != nil {
 		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 &funcInfo{
-		fn,
+	return &FuncOffset{
 		asm.RawInstructionOffset(fi.InsnOff),
+		fn,
 	}, nil
 }
 
-func newFuncInfos(bfis []bpfFuncInfo, spec *Spec) (FuncInfos, error) {
-	fis := FuncInfos{
-		infos: make([]funcInfo, 0, len(bfis)),
-	}
+func newFuncOffsets(bfis []bpfFuncInfo, spec *Spec) (FuncOffsets, error) {
+	fos := make(FuncOffsets, 0, len(bfis))
+
 	for _, bfi := range bfis {
-		fi, err := newFuncInfo(bfi, spec)
+		fi, err := newFuncOffset(bfi, spec)
 		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 {
-		return fis.infos[i].offset <= fis.infos[j].offset
+	sort.Slice(fos, func(i, j int) bool {
+		return fos[i].Offset <= fos[j].Offset
 	})
-	return fis, nil
+	return fos, nil
 }
 
-// LoadFuncInfos parses BTF func info in kernel wire format.
-func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec *Spec) (FuncInfos, error) {
+// LoadFuncInfos parses BTF func info from kernel wire format into a
+// [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(
 		reader,
 		bo,
@@ -401,20 +404,20 @@ func LoadFuncInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec
 		false,
 	)
 	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.
-func (fi *funcInfo) marshal(w *bytes.Buffer, b *Builder) error {
-	id, err := b.Add(fi.fn)
+func (fi *FuncOffset) marshal(w *bytes.Buffer, b *Builder) error {
+	id, err := b.Add(fi.Func)
 	if err != nil {
 		return err
 	}
 	bfi := bpfFuncInfo{
-		InsnOff: uint32(fi.offset),
+		InsnOff: uint32(fi.Offset),
 		TypeID:  id,
 	}
 	buf := make([]byte, FuncInfoSize)
@@ -515,14 +518,13 @@ func (li *Line) String() string {
 	return li.line
 }
 
-// LineInfos contains a sorted list of line infos.
-type LineInfos struct {
-	infos []lineInfo
-}
+// LineOffsets contains a sorted list of line infos.
+type LineOffsets []LineOffset
 
-type lineInfo struct {
-	line   *Line
-	offset asm.RawInstructionOffset
+// LineOffset represents a line info and its raw instruction offset.
+type LineOffset struct {
+	Offset asm.RawInstructionOffset
+	Line   *Line
 }
 
 // Constants for the format of bpfLineInfo.LineCol.
@@ -541,7 +543,7 @@ type bpfLineInfo struct {
 }
 
 // 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(
 		reader,
 		bo,
@@ -550,57 +552,55 @@ func LoadLineInfos(reader io.Reader, bo binary.ByteOrder, recordNum uint32, spec
 		false,
 	)
 	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)
 }
 
-func newLineInfo(li bpfLineInfo, strings *stringTable) (lineInfo, error) {
+func newLineInfo(li bpfLineInfo, strings *stringTable) (LineOffset, error) {
 	line, err := strings.Lookup(li.LineOff)
 	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)
 	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
 	lineColumn := li.LineCol & bpfColumnMax
 
-	return lineInfo{
+	return LineOffset{
+		asm.RawInstructionOffset(li.InsnOff),
 		&Line{
 			fileName,
 			line,
 			lineNumber,
 			lineColumn,
 		},
-		asm.RawInstructionOffset(li.InsnOff),
 	}, nil
 }
 
-func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineInfos, error) {
-	lis := LineInfos{
-		infos: make([]lineInfo, 0, len(blis)),
-	}
+func newLineInfos(blis []bpfLineInfo, strings *stringTable) (LineOffsets, error) {
+	lis := make([]LineOffset, 0, len(blis))
 	for _, bli := range blis {
 		li, err := newLineInfo(bli, strings)
 		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 {
-		return lis.infos[i].offset <= lis.infos[j].offset
+	sort.Slice(lis, func(i, j int) bool {
+		return lis[i].Offset <= lis[j].Offset
 	})
 	return lis, nil
 }
 
 // marshal writes the binary representation of the LineInfo to w.
-func (li *lineInfo) marshal(w *bytes.Buffer, b *Builder) error {
-	line := li.line
+func (li *LineOffset) marshal(w *bytes.Buffer, b *Builder) error {
+	line := li.Line
 	if 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{
-		uint32(li.offset),
+		uint32(li.Offset),
 		fileNameOff,
 		lineOff,
 		(line.lineNumber << bpfLineShift) | line.lineColumn,
@@ -799,7 +799,7 @@ func parseCORERelos(r io.Reader, bo binary.ByteOrder, strings *stringTable) (map
 			return nil, err
 		}
 
-		records, err := parseCOREReloRecords(r, bo, recordSize, infoHeader.NumInfo)
+		records, err := parseCOREReloRecords(r, bo, infoHeader.NumInfo)
 		if err != nil {
 			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
 // coreRelos. These records appear after a btf_ext_info_sec header in the
 // 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 relo bpfCORERelo
diff --git a/vendor/github.com/cilium/ebpf/btf/feature.go b/vendor/github.com/cilium/ebpf/btf/feature.go
index 6feb08dfbb0f3a3bbfb51ca11557edbdedec9e43..e71c707fe4db9cd35c9260cde19fa595840870bf 100644
--- a/vendor/github.com/cilium/ebpf/btf/feature.go
+++ b/vendor/github.com/cilium/ebpf/btf/feature.go
@@ -11,19 +11,19 @@ import (
 
 // haveBTF attempts to load a BTF blob containing an Int. It should pass on any
 // 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
 	err := probeBTF(&Int{})
 	if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
 		return internal.ErrNotSupported
 	}
 	return err
-})
+}, "4.18")
 
 // 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
 // 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 {
 		return err
 	}
@@ -40,12 +40,12 @@ var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func()
 		return internal.ErrNotSupported
 	}
 	return err
-})
+}, "5.2")
 
 // 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
 // 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 {
 		return err
 	}
@@ -60,9 +60,9 @@ var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0",
 		return internal.ErrNotSupported
 	}
 	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 {
 		return err
 	}
@@ -78,9 +78,44 @@ var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func()
 		return internal.ErrNotSupported
 	}
 	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 {
 		return err
 	}
@@ -97,7 +132,7 @@ var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error {
 		return internal.ErrNotSupported
 	}
 	return err
-})
+}, "6.0")
 
 func probeBTF(typ Type) error {
 	b, err := NewBuilder([]Type{typ})
diff --git a/vendor/github.com/cilium/ebpf/btf/format.go b/vendor/github.com/cilium/ebpf/btf/format.go
index 5e581b4a851848844d406202cbe5c2c486df10ac..3e0dedaa2bdd1c9ee2ec8303478e2e63366fb60e 100644
--- a/vendor/github.com/cilium/ebpf/btf/format.go
+++ b/vendor/github.com/cilium/ebpf/btf/format.go
@@ -161,6 +161,9 @@ func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
 	case *Datasec:
 		err = gf.writeDatasecLit(v, depth)
 
+	case *Var:
+		err = gf.writeTypeLit(v.Type, depth)
+
 	default:
 		return fmt.Errorf("type %T: %w", v, ErrNotSupported)
 	}
diff --git a/vendor/github.com/cilium/ebpf/btf/kernel.go b/vendor/github.com/cilium/ebpf/btf/kernel.go
index 8584ebcb932a1b280b39c4870832a456d5e56215..1a9321f054c7c5bbd38f003bd6cb3c0562c3dad5 100644
--- a/vendor/github.com/cilium/ebpf/btf/kernel.go
+++ b/vendor/github.com/cilium/ebpf/btf/kernel.go
@@ -8,7 +8,7 @@ import (
 	"sync"
 
 	"github.com/cilium/ebpf/internal"
-	"github.com/cilium/ebpf/internal/kallsyms"
+	"github.com/cilium/ebpf/internal/linux"
 )
 
 var kernelBTF = struct {
@@ -21,8 +21,6 @@ var kernelBTF = struct {
 
 // FlushKernelSpec removes any cached kernel type information.
 func FlushKernelSpec() {
-	kallsyms.FlushKernelModuleCache()
-
 	kernelBTF.Lock()
 	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.
 func findVMLinux() (*os.File, error) {
-	release, err := internal.KernelRelease()
+	release, err := linux.KernelRelease()
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/cilium/ebpf/btf/marshal.go b/vendor/github.com/cilium/ebpf/btf/marshal.go
index f14cfa6e9735e793605a03d75590a9ce8287067f..d7204e62476be82094457f07f4a180e935a638d6 100644
--- a/vendor/github.com/cilium/ebpf/btf/marshal.go
+++ b/vendor/github.com/cilium/ebpf/btf/marshal.go
@@ -18,6 +18,10 @@ type MarshalOptions struct {
 	Order binary.ByteOrder
 	// Remove function linkage information for compatibility with <5.6 kernels.
 	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.
 	ReplaceEnum64 bool
 	// Prevent the "No type found" error when loading BTF without any types.
@@ -29,6 +33,8 @@ func KernelMarshalOptions() *MarshalOptions {
 	return &MarshalOptions{
 		Order:              internal.NativeEndian,
 		StripFuncLinkage:   haveFuncLinkage() != nil,
+		ReplaceDeclTags:    haveDeclTags() != nil,
+		ReplaceTypeTags:    haveTypeTags() != nil,
 		ReplaceEnum64:      haveEnum64() != nil,
 		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")
 
 	case *Int:
-		raw.SetKind(kindInt)
-		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
+		e.deflateInt(&raw, v)
 
 	case *Pointer:
 		raw.SetKind(kindPointer)
@@ -368,8 +366,7 @@ func (e *encoder) deflateType(typ Type) (err error) {
 		raw.SetType(e.id(v.Type))
 
 	case *Const:
-		raw.SetKind(kindConst)
-		raw.SetType(e.id(v.Type))
+		e.deflateConst(&raw, v)
 
 	case *Restrict:
 		raw.SetKind(kindRestrict)
@@ -404,15 +401,10 @@ func (e *encoder) deflateType(typ Type) (err error) {
 		raw.SetSize(v.Size)
 
 	case *declTag:
-		raw.SetKind(kindDeclTag)
-		raw.SetType(e.id(v.Type))
-		raw.data = &btfDeclTag{uint32(v.Index)}
-		raw.NameOff, err = e.strings.Add(v.Value)
+		err = e.deflateDeclTag(&raw, v)
 
-	case *typeTag:
-		raw.SetKind(kindTypeTag)
-		raw.SetType(e.id(v.Type))
-		raw.NameOff, err = e.strings.Add(v.Value)
+	case *TypeTag:
+		err = e.deflateTypeTag(&raw, v)
 
 	default:
 		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)
 }
 
+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) {
 	raw.SetKind(kindUnion)
 	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)
diff --git a/vendor/github.com/cilium/ebpf/btf/traversal.go b/vendor/github.com/cilium/ebpf/btf/traversal.go
index c39dc66e46ce14857daa60a274f282dbde4ee5d7..13647d931ffc6ef042fe8172239df53f49833806 100644
--- a/vendor/github.com/cilium/ebpf/btf/traversal.go
+++ b/vendor/github.com/cilium/ebpf/btf/traversal.go
@@ -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
 	// do its work. This avoids allocating intermediate slices from walk() on
 	// the heap.
+	var tags []string
 	switch v := typ.(type) {
-	case *Void, *Int, *Enum, *Fwd, *Float:
+	case *Void, *Int, *Enum, *Fwd, *Float, *declTag:
 		// 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:
 		if !yield(&v.Target) {
 			return false
@@ -59,17 +62,32 @@ func children(typ Type, yield func(child *Type) bool) bool {
 			if !yield(&v.Members[i].Type) {
 				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:
 		for i := range v.Members {
 			if !yield(&v.Members[i].Type) {
 				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:
 		if !yield(&v.Type) {
 			return false
 		}
+		tags = v.Tags
 	case *Volatile:
 		if !yield(&v.Type) {
 			return false
@@ -86,6 +104,20 @@ func children(typ Type, yield func(child *Type) bool) bool {
 		if !yield(&v.Type) {
 			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:
 		if !yield(&v.Return) {
 			return false
@@ -99,17 +131,14 @@ func children(typ Type, yield func(child *Type) bool) bool {
 		if !yield(&v.Type) {
 			return false
 		}
+		tags = v.Tags
 	case *Datasec:
 		for i := range v.Vars {
 			if !yield(&v.Vars[i].Type) {
 				return false
 			}
 		}
-	case *declTag:
-		if !yield(&v.Type) {
-			return false
-		}
-	case *typeTag:
+	case *TypeTag:
 		if !yield(&v.Type) {
 			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))
 	}
 
+	for _, t := range tags {
+		var tag Type = &declTag{typ, t, -1}
+		if !yield(&tag) {
+			return false
+		}
+	}
+
 	return true
 }
diff --git a/vendor/github.com/cilium/ebpf/btf/types.go b/vendor/github.com/cilium/ebpf/btf/types.go
index a3397460b9d50f99861c1f709821307f7ab2a416..dbcdf9dd7aac1fa1ece0cecc511367128061635e 100644
--- a/vendor/github.com/cilium/ebpf/btf/types.go
+++ b/vendor/github.com/cilium/ebpf/btf/types.go
@@ -67,7 +67,7 @@ var (
 	_ Type = (*Datasec)(nil)
 	_ Type = (*Float)(nil)
 	_ Type = (*declTag)(nil)
-	_ Type = (*typeTag)(nil)
+	_ Type = (*TypeTag)(nil)
 	_ Type = (*cycle)(nil)
 )
 
@@ -169,6 +169,7 @@ type Struct struct {
 	// The size of the struct including padding, in bytes
 	Size    uint32
 	Members []Member
+	Tags    []string
 }
 
 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 {
 	cpy := *s
 	cpy.Members = copyMembers(s.Members)
+	cpy.Tags = copyTags(cpy.Tags)
 	return &cpy
 }
 
@@ -195,6 +197,7 @@ type Union struct {
 	// The size of the union including padding, in bytes.
 	Size    uint32
 	Members []Member
+	Tags    []string
 }
 
 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 {
 	cpy := *u
 	cpy.Members = copyMembers(u.Members)
+	cpy.Tags = copyTags(cpy.Tags)
 	return &cpy
 }
 
@@ -218,6 +222,18 @@ func (u *Union) members() []Member {
 func copyMembers(orig []Member) []Member {
 	cpy := make([]Member, len(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
 }
 
@@ -247,6 +263,7 @@ type Member struct {
 	Type         Type
 	Offset       Bits
 	BitfieldSize Bits
+	Tags         []string
 }
 
 // Enum lists possible values.
@@ -334,6 +351,7 @@ func (f *Fwd) matches(typ Type) bool {
 type Typedef struct {
 	Name string
 	Type Type
+	Tags []string
 }
 
 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 {
 	cpy := *td
+	cpy.Tags = copyTags(td.Tags)
 	return &cpy
 }
 
@@ -403,6 +422,12 @@ type Func struct {
 	Name    string
 	Type    Type
 	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 {
@@ -424,6 +449,14 @@ func (f *Func) TypeName() string { return f.Name }
 
 func (f *Func) copy() Type {
 	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
 }
 
@@ -456,6 +489,7 @@ type Var struct {
 	Name    string
 	Type    Type
 	Linkage VarLinkage
+	Tags    []string
 }
 
 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 {
 	cpy := *v
+	cpy.Tags = copyTags(v.Tags)
 	return &cpy
 }
 
@@ -540,19 +575,25 @@ func (dt *declTag) copy() Type {
 	return &cpy
 }
 
-// typeTag associates metadata with a type.
-type typeTag struct {
+// TypeTag associates metadata with a pointer type. Tag types act as a custom
+// 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
 	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)
 }
 
-func (tt *typeTag) TypeName() string { return "" }
-func (tt *typeTag) qualify() Type    { return tt.Type }
-func (tt *typeTag) copy() Type {
+func (tt *TypeTag) TypeName() string { return "" }
+func (tt *TypeTag) qualify() Type    { return tt.Type }
+func (tt *TypeTag) copy() Type {
 	cpy := *tt
 	return &cpy
 }
@@ -591,7 +632,7 @@ var (
 	_ qualifier = (*Const)(nil)
 	_ qualifier = (*Restrict)(nil)
 	_ qualifier = (*Volatile)(nil)
-	_ qualifier = (*typeTag)(nil)
+	_ qualifier = (*TypeTag)(nil)
 )
 
 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 {
 				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:
 			vlen := header.Vlen()
@@ -935,7 +976,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
 			if err != nil {
 				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:
 			vlen := header.Vlen()
@@ -968,7 +1009,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
 			typ = &Fwd{name, header.FwdKind()}
 
 		case kindTypedef:
-			typedef := &Typedef{name, nil}
+			typedef := &Typedef{name, nil, nil}
 			fixup(header.Type(), &typedef.Type)
 			typ = typedef
 
@@ -988,7 +1029,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
 			typ = restrict
 
 		case kindFunc:
-			fn := &Func{name, nil, header.Linkage()}
+			fn := &Func{name, nil, header.Linkage(), nil, nil}
 			fixup(header.Type(), &fn.Type)
 			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)
 			}
 
-			v := &Var{name, nil, VarLinkage(bVariable.Linkage)}
+			v := &Var{name, nil, VarLinkage(bVariable.Linkage), nil}
 			fixup(header.Type(), &v.Type)
 			typ = v
 
@@ -1081,7 +1122,7 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
 			declTags = append(declTags, dt)
 
 		case kindTypeTag:
-			tt := &typeTag{nil, name}
+			tt := &TypeTag{nil, name}
 			fixup(header.Type(), &tt.Type)
 			typ = tt
 
@@ -1142,26 +1183,69 @@ func readAndInflateTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32, rawSt
 
 	for _, dt := range declTags {
 		switch t := dt.Type.(type) {
-		case *Var, *Typedef:
+		case *Var:
+			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 *Typedef:
 			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 composite:
-			if dt.Index >= len(t.members()) {
-				return nil, fmt.Errorf("type %s: index %d exceeds members of %s", dt, dt.Index, t)
+			if dt.Index >= 0 {
+				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:
 			fp, ok := t.Type.(*FuncProto)
 			if !ok {
 				return nil, fmt.Errorf("type %s: %s is not a FuncProto", dt, t.Type)
 			}
 
-			if dt.Index >= len(fp.Params) {
-				return nil, fmt.Errorf("type %s: index %d exceeds params of %s", dt, dt.Index, t)
+			// Ensure the number of argument tag lists equals the number of arguments
+			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:
 			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}
 }
 
+// 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
 // until it finds a T.
 //
diff --git a/vendor/github.com/cilium/ebpf/btf/workarounds.go b/vendor/github.com/cilium/ebpf/btf/workarounds.go
index 12a89b87eedb144c1f6ce46cbd2dfb95a9b044c1..eb09047fb30f114a3bba14f495efe61ee40fc8b7 100644
--- a/vendor/github.com/cilium/ebpf/btf/workarounds.go
+++ b/vendor/github.com/cilium/ebpf/btf/workarounds.go
@@ -12,7 +12,7 @@ func datasecResolveWorkaround(b *Builder, ds *Datasec) error {
 		}
 
 		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
 			// infinite recursion.
 			_, err := b.Add(v.Type)
diff --git a/vendor/github.com/cilium/ebpf/collection.go b/vendor/github.com/cilium/ebpf/collection.go
index b2cb214adce0e1657bf9423952a0da8a7d9119f6..1bda110a4014ede8cab43532db4ee3761bfa3f28 100644
--- a/vendor/github.com/cilium/ebpf/collection.go
+++ b/vendor/github.com/cilium/ebpf/collection.go
@@ -10,8 +10,10 @@ import (
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/kallsyms"
 	"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.
@@ -38,6 +40,11 @@ type CollectionSpec struct {
 	Maps     map[string]*MapSpec
 	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.
 	// Modifications to Types are currently undefined behaviour.
 	Types *btf.Spec
@@ -56,6 +63,7 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
 	cpy := CollectionSpec{
 		Maps:      make(map[string]*MapSpec, len(cs.Maps)),
 		Programs:  make(map[string]*ProgramSpec, len(cs.Programs)),
+		Variables: make(map[string]*VariableSpec, len(cs.Variables)),
 		ByteOrder: cs.ByteOrder,
 		Types:     cs.Types.Copy(),
 	}
@@ -68,6 +76,10 @@ func (cs *CollectionSpec) Copy() *CollectionSpec {
 		cpy.Programs[name] = spec.Copy()
 	}
 
+	for name, spec := range cs.Variables {
+		cpy.Variables[name] = spec.copy(&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.
 //
 // 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 {
-	replaced := make(map[string]bool)
-
-	for name, spec := range cs.Maps {
-		if !strings.HasPrefix(name, ".rodata") {
+	var missing []string
+	for n, c := range consts {
+		v, ok := cs.Variables[n]
+		if !ok {
+			missing = append(missing, n)
 			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)
+		if !v.Constant() {
+			return fmt.Errorf("variable %s is not a constant", n)
 		}
 
-		// 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
-	for c := range consts {
-		if !replaced[c] {
-			missing = append(missing, c)
+		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.
 //
 // 'to' must be a pointer to a struct. A field of the
-// struct is updated with values from Programs or Maps if it
-// has an `ebpf` tag and its type is *ProgramSpec or *MapSpec.
+// struct is updated with values from Programs, Maps or Variables if it
+// 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
 // found in the CollectionSpec.
 //
 //	struct {
-//	    Foo     *ebpf.ProgramSpec `ebpf:"xdp_foo"`
-//	    Bar     *ebpf.MapSpec     `ebpf:"bar_map"`
+//	    Foo     *ebpf.ProgramSpec  `ebpf:"xdp_foo"`
+//	    Bar     *ebpf.MapSpec      `ebpf:"bar_map"`
+//	    Var     *ebpf.VariableSpec `ebpf:"some_var"`
 //	    Ignored int
 //	}
 //
 // 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 {
-	// 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) {
 		switch typ {
-
 		case reflect.TypeOf((*ProgramSpec)(nil)):
 			if p := cs.Programs[name]; p != nil {
 				return p, nil
@@ -241,6 +210,12 @@ func (cs *CollectionSpec) Assign(to interface{}) error {
 			}
 			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:
 			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.
 	assignedMaps := make(map[string]bool)
 	assignedProgs := make(map[string]bool)
+	assignedVars := make(map[string]bool)
 
 	getValue := func(typ reflect.Type, name string) (interface{}, error) {
 		switch typ {
@@ -298,6 +274,10 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
 			assignedMaps[name] = true
 			return loader.loadMap(name)
 
+		case reflect.TypeOf((*Variable)(nil)):
+			assignedVars[name] = true
+			return loader.loadVariable(name)
+
 		default:
 			return nil, fmt.Errorf("unsupported type %s", typ)
 		}
@@ -338,15 +318,22 @@ func (cs *CollectionSpec) LoadAndAssign(to interface{}, opts *CollectionOptions)
 	for p := range assignedProgs {
 		delete(loader.programs, p)
 	}
+	for p := range assignedVars {
+		delete(loader.vars, p)
+	}
 
 	return nil
 }
 
-// Collection is a collection of Programs and Maps associated
-// with their symbols
+// Collection is a collection of live BPF resources present in the kernel.
 type Collection struct {
 	Programs map[string]*Program
 	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
@@ -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
 	// all Maps and Programs have been successfully loaded.
 	if err := loader.populateDeferredMaps(); err != nil {
 		return nil, err
 	}
 
-	// Prevent loader.cleanup from closing maps and programs.
-	maps, progs := loader.maps, loader.programs
-	loader.maps, loader.programs = nil, nil
+	// Prevent loader.cleanup from closing maps, programs and vars.
+	maps, progs, vars := loader.maps, loader.programs, loader.vars
+	loader.maps, loader.programs, loader.vars = nil, nil, nil
 
 	return &Collection{
 		progs,
 		maps,
+		vars,
 	}, nil
 }
 
@@ -408,6 +402,7 @@ type collectionLoader struct {
 	opts     *CollectionOptions
 	maps     map[string]*Map
 	programs map[string]*Program
+	vars     map[string]*Variable
 }
 
 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{
 		coll,
 		opts,
 		make(map[string]*Map),
 		make(map[string]*Program),
+		make(map[string]*Variable),
 	}, 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.
 func (cl *collectionLoader) close() {
 	for _, m := range cl.maps {
@@ -466,6 +505,13 @@ func (cl *collectionLoader) loadMap(mapName string) (*Map, error) {
 		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)
 	if err != nil {
 		return nil, fmt.Errorf("map %s: %w", mapName, err)
@@ -537,6 +583,58 @@ func (cl *collectionLoader) loadProgram(progName string) (*Program, error) {
 	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
 // any dependencies. Populates all maps in cl and freezes them if specified.
 func (cl *collectionLoader) populateDeferredMaps() error {
@@ -603,6 +701,7 @@ func resolveKconfig(m *MapSpec) error {
 
 	type configInfo struct {
 		offset uint32
+		size   uint32
 		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)
 			}
 
-			kv, err := internal.KernelVersion()
+			kv, err := linux.KernelVersion()
 			if err != nil {
 				return fmt.Errorf("getting kernel version: %w", err)
 			}
@@ -644,6 +743,7 @@ func resolveKconfig(m *MapSpec) error {
 		default: // Catch CONFIG_*.
 			configs[n] = configInfo{
 				offset: vsi.Offset,
+				size:   vsi.Size,
 				typ:    v.Type,
 			}
 		}
@@ -651,7 +751,7 @@ func resolveKconfig(m *MapSpec) error {
 
 	// We only parse kconfig file if a CONFIG_* variable was found.
 	if len(configs) > 0 {
-		f, err := kconfig.Find()
+		f, err := linux.FindKConfig()
 		if err != nil {
 			return fmt.Errorf("cannot find a kconfig file: %w", err)
 		}
@@ -670,10 +770,10 @@ func resolveKconfig(m *MapSpec) error {
 		for n, info := range configs {
 			value, ok := kernelConfig[n]
 			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 {
 				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 {
 	assignedMaps := make(map[string]bool)
 	assignedProgs := make(map[string]bool)
+	assignedVars := make(map[string]bool)
 
 	// Assign() only transfers already-loaded Maps and Programs. No extra
 	// loading is done.
@@ -743,6 +844,13 @@ func (coll *Collection) Assign(to interface{}) error {
 			}
 			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:
 			return nil, fmt.Errorf("unsupported type %s", typ)
 		}
@@ -759,6 +867,9 @@ func (coll *Collection) Assign(to interface{}) error {
 	for m := range assignedMaps {
 		delete(coll.Maps, m)
 	}
+	for s := range assignedVars {
+		delete(coll.Variables, s)
+	}
 
 	return nil
 }
diff --git a/vendor/github.com/cilium/ebpf/elf_reader.go b/vendor/github.com/cilium/ebpf/elf_reader.go
index 620037d80a8a7f7574895471b0632ba4007777cb..9e8dbc7ae5a9094e0a78ff5c308c235e85ea5243 100644
--- a/vendor/github.com/cilium/ebpf/elf_reader.go
+++ b/vendor/github.com/cilium/ebpf/elf_reader.go
@@ -16,7 +16,6 @@ import (
 	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/sys"
-	"github.com/cilium/ebpf/internal/unix"
 )
 
 type kconfigMetaKey struct{}
@@ -33,6 +32,13 @@ type kfuncMeta struct {
 	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
 // be passed around explicitly. You should treat its contents as immutable.
 type elfCode struct {
@@ -43,7 +49,9 @@ type elfCode struct {
 	btf      *btf.Spec
 	extInfo  *btf.ExtInfos
 	maps     map[string]*MapSpec
+	vars     map[string]*VariableSpec
 	kfuncs   map[string]*btf.Func
+	ksyms    map[string]struct{}
 	kconfig  *MapSpec
 }
 
@@ -71,7 +79,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 
 	// Checks if the ELF file is for BPF data.
 	// 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)
 	}
 
@@ -101,7 +109,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 			sections[idx] = newElfSection(sec, mapSection)
 		case sec.Name == ".maps":
 			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)
 		case sec.Type == elf.SHT_REL:
 			// Store relocations under the section index of the target
@@ -134,7 +142,9 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 		btf:         btfSpec,
 		extInfo:     btfExtInfo,
 		maps:        make(map[string]*MapSpec),
+		vars:        make(map[string]*VariableSpec),
 		kfuncs:      make(map[string]*btf.Func),
+		ksyms:       make(map[string]struct{}),
 	}
 
 	symbols, err := f.Symbols()
@@ -174,7 +184,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
 		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) {
@@ -201,6 +211,18 @@ func loadVersion(sec *elf.Section, bo binary.ByteOrder) (uint32, error) {
 	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
 
 const (
@@ -506,7 +528,7 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
 
 		case elf.STT_OBJECT:
 			// 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)
 			}
 
@@ -614,6 +636,8 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
 		}
 
 		kf := ec.kfuncs[name]
+		_, ks := ec.ksyms[name]
+
 		switch {
 		// 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.
@@ -634,6 +658,15 @@ func (ec *elfCode) relocateInstruction(ins *asm.Instruction, rel elf.Symbol) err
 
 			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
 		// asm (see testdata/loader.c:asm_relocation()) or a call to a forward
 		// 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{
 		Name:       SanitizeName(name, -1),
 		Type:       MapType(mapType),
@@ -1092,12 +1132,21 @@ func (ec *elfCode) loadDataSections() error {
 			continue
 		}
 
-		if sec.references == 0 {
-			// Prune data sections which are not referenced by any
-			// instructions.
+		// If a section has no references, it will be freed as soon as the
+		// Collection closes, so creating and populating it is wasteful. If it has
+		// 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
 		}
 
+		if sec.Size > math.MaxUint32 {
+			return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
+		}
+
 		mapSpec := &MapSpec{
 			Name:       SanitizeName(sec.Name, -1),
 			Type:       Array,
@@ -1106,6 +1155,10 @@ func (ec *elfCode) loadDataSections() error {
 			MaxEntries: 1,
 		}
 
+		if isConstantDataSection(sec.Name) {
+			mapSpec.Flags = sys.BPF_F_RDONLY_PROG
+		}
+
 		switch sec.Type {
 		// Only open the section if we know there's actual data to be read.
 		case elf.SHT_PROGBITS:
@@ -1113,20 +1166,56 @@ func (ec *elfCode) loadDataSections() error {
 			if err != nil {
 				return fmt.Errorf("data section %s: can't get contents: %w", sec.Name, err)
 			}
-
-			if uint64(len(data)) > math.MaxUint32 {
-				return fmt.Errorf("data section %s: contents exceed maximum size", sec.Name)
-			}
 			mapSpec.Contents = []MapKV{{uint32(0), data}}
 
 		case elf.SHT_NOBITS:
-			// NOBITS sections like .bss contain only zeroes, and since data sections
-			// are Arrays, the kernel already preallocates them. Skip reading zeroes
-			// from the ELF.
+			// NOBITS sections like .bss contain only zeroes and are not allocated in
+			// the ELF. Since data sections are Arrays, the kernel can preallocate
+			// 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:
 			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
 		// if it only contains anonymous values like macro-defined arrays.
 		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.
 				mapSpec.Key = &btf.Void{}
 				mapSpec.Value = ds
-			}
-		}
 
-		if strings.HasPrefix(sec.Name, ".rodata") {
-			mapSpec.Flags = unix.BPF_F_RDONLY_PROG
-			mapSpec.Freeze = true
+				// 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)
+					}
+
+					vt, ok := v.Type.(*btf.Var)
+					if !ok {
+						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
@@ -1175,8 +1290,7 @@ func (ec *elfCode) loadKconfigSection() error {
 		KeySize:    uint32(4),
 		ValueSize:  ds.Size,
 		MaxEntries: 1,
-		Flags:      unix.BPF_F_RDONLY_PROG,
-		Freeze:     true,
+		Flags:      sys.BPF_F_RDONLY_PROG,
 		Key:        &btf.Int{Size: 4},
 		Value:      ds,
 	}
@@ -1201,8 +1315,14 @@ func (ec *elfCode) loadKsymsSection() error {
 	}
 
 	for _, v := range ds.Vars {
-		// we have already checked the .ksyms Datasec to only contain Func Vars.
-		ec.kfuncs[v.Type.TypeName()] = v.Type.(*btf.Func)
+		switch t := v.Type.(type) {
+		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
@@ -1266,10 +1386,10 @@ func getProgType(sectionName string) (ProgramType, AttachType, uint32, string) {
 
 		var flags uint32
 		if t.flags&_SEC_SLEEPABLE > 0 {
-			flags |= unix.BPF_F_SLEEPABLE
+			flags |= sys.BPF_F_SLEEPABLE
 		}
 		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 programType == XDP {
diff --git a/vendor/github.com/cilium/ebpf/info.go b/vendor/github.com/cilium/ebpf/info.go
index 04c60c64b893724452abcbd13791862b2f80b019..56a1f1e9a318680d3ec3950bcb971f5ef3a2df5c 100644
--- a/vendor/github.com/cilium/ebpf/info.go
+++ b/vendor/github.com/cilium/ebpf/info.go
@@ -8,10 +8,10 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"reflect"
 	"strings"
 	"syscall"
 	"time"
-	"unsafe"
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/btf"
@@ -39,53 +39,83 @@ import (
 
 // MapInfo describes a map.
 type MapInfo struct {
-	Type       MapType
-	id         MapID
-	KeySize    uint32
-	ValueSize  uint32
+	// Type of the map.
+	Type MapType
+	// KeySize is the size of the map key in bytes.
+	KeySize uint32
+	// ValueSize is the size of the map value in bytes.
+	ValueSize uint32
+	// MaxEntries is the maximum number of entries the map can hold. Its meaning
+	// is map-specific.
 	MaxEntries uint32
-	Flags      uint32
+	// Flags used during map creation.
+	Flags uint32
 	// Name as supplied by user space at load time. Available from 4.15.
 	Name string
 
-	btf btf.ID
+	id       MapID
+	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) {
 	var info sys.MapInfo
-	err := sys.ObjInfo(fd, &info)
-	if errors.Is(err, syscall.EINVAL) {
-		return newMapInfoFromProc(fd)
-	}
-	if err != nil {
-		return nil, err
+	err1 := sys.ObjInfo(fd, &info)
+	// EINVAL means the kernel doesn't support BPF_OBJ_GET_INFO_BY_FD. Continue
+	// with fdinfo if that's the case.
+	if err1 != nil && !errors.Is(err1, unix.EINVAL) {
+		return nil, fmt.Errorf("getting object info: %w", err1)
 	}
 
-	return &MapInfo{
+	mi := &MapInfo{
 		MapType(info.Type),
-		MapID(info.Id),
 		info.KeySize,
 		info.ValueSize,
 		info.MaxEntries,
 		uint32(info.MapFlags),
 		unix.ByteSliceToString(info.Name[:]),
+		MapID(info.Id),
 		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) {
-	var mi MapInfo
-	err := scanFdInfo(fd, map[string]interface{}{
+// readMapInfoFromProc queries map information about the given fd from
+// /proc/self/fdinfo. It only writes data into fields that have a zero value.
+func readMapInfoFromProc(fd *sys.FD, mi *MapInfo) error {
+	return scanFdInfo(fd, map[string]interface{}{
 		"map_type":    &mi.Type,
+		"map_id":      &mi.id,
 		"key_size":    &mi.KeySize,
 		"value_size":  &mi.ValueSize,
 		"max_entries": &mi.MaxEntries,
 		"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.
@@ -109,6 +139,35 @@ func (mi *MapInfo) BTFID() (btf.ID, bool) {
 	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.
 type programStats struct {
 	// Total accumulated runtime of the program ins ns.
@@ -120,6 +179,40 @@ type programStats struct {
 	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.
 type ProgramInfo struct {
 	Type ProgramType
@@ -133,9 +226,14 @@ type ProgramInfo struct {
 	haveCreatedByUID bool
 	btf              btf.ID
 	stats            *programStats
+	loadTime         time.Duration
+
+	maps                 []MapID
+	insns                []byte
+	jitedSize            uint32
+	verifiedInstructions uint32
 
-	maps  []MapID
-	insns []byte
+	jitedInfo programJitedInfo
 
 	lineInfos    []byte
 	numLineInfos uint32
@@ -164,6 +262,9 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
 			runCount:        info.RunCnt,
 			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.
@@ -174,7 +275,7 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
 	if info.NrMapIds > 0 {
 		pi.maps = make([]MapID, info.NrMapIds)
 		info2.NrMapIds = info.NrMapIds
-		info2.MapIds = sys.NewPointer(unsafe.Pointer(&pi.maps[0]))
+		info2.MapIds = sys.NewSlicePointer(pi.maps)
 		makeSecondCall = true
 	} else if haveProgramInfoMapIDs() == nil {
 		// This program really has no associated maps.
@@ -215,6 +316,40 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
 		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 err := sys.ObjInfo(fd, &info2); err != nil {
 			return nil, err
@@ -230,7 +365,7 @@ func newProgramInfoFromProc(fd *sys.FD) (*ProgramInfo, error) {
 		"prog_type": &info.Type,
 		"prog_tag":  &info.Tag,
 	})
-	if errors.Is(err, errMissingFields) {
+	if errors.Is(err, ErrNotSupported) {
 		return nil, &internal.UnsupportedFeatureError{
 			Name:           "reading program info from /proc/self/fdinfo",
 			MinimumVersion: internal.Version{4, 10, 0},
@@ -305,6 +440,52 @@ func (pi *ProgramInfo) RecursionMisses() (uint64, bool) {
 	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
 // 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
@@ -391,6 +572,29 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
 	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.
 //
 // Available from 4.15.
@@ -400,6 +604,89 @@ func (pi *ProgramInfo) MapIDs() ([]MapID, bool) {
 	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 {
 	fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", fd.Int()))
 	if err != nil {
@@ -413,8 +700,6 @@ func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
 	return nil
 }
 
-var errMissingFields = errors.New("missing fields")
-
 func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
 	var (
 		scanner = bufio.NewScanner(r)
@@ -433,26 +718,37 @@ func scanFdInfoReader(r io.Reader, fields map[string]interface{}) error {
 			continue
 		}
 
-		if n, err := fmt.Sscanln(parts[1], field); err != nil || n != 1 {
-			return fmt.Errorf("can't parse field %s: %v", name, err)
+		// 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 {
+				return fmt.Errorf("can't parse field %s: %v", name, err)
+			}
 		}
 
 		scanned++
 	}
 
 	if err := scanner.Err(); err != nil {
-		return err
+		return fmt.Errorf("scanning fdinfo: %w", err)
 	}
 
 	if len(fields) > 0 && scanned == 0 {
 		return ErrNotSupported
 	}
 
-	if scanned != len(fields) {
-		return errMissingFields
+	return nil
+}
+
+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
@@ -471,7 +767,7 @@ func EnableStats(which uint32) (io.Closer, error) {
 	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{
 		asm.LoadImm(asm.R0, 0, asm.DWord),
 		asm.Return(),
@@ -496,4 +792,4 @@ var haveProgramInfoMapIDs = internal.NewFeatureTest("map IDs in program info", "
 	}
 
 	return err
-})
+}, "4.15")
diff --git a/vendor/github.com/cilium/ebpf/internal/epoll/poller.go b/vendor/github.com/cilium/ebpf/internal/epoll/poller.go
index ed1c3a3c8f4cff98d5699ecd6338d5facabcdff3..733e839be7b97fc4645a9b86d906a6ffb168b7c8 100644
--- a/vendor/github.com/cilium/ebpf/internal/epoll/poller.go
+++ b/vendor/github.com/cilium/ebpf/internal/epoll/poller.go
@@ -14,7 +14,11 @@ import (
 	"github.com/cilium/ebpf/internal/unix"
 )
 
-var ErrFlushed = errors.New("data was flushed")
+var (
+	ErrFlushed                   = errors.New("data was flushed")
+	errEpollWaitDeadlineExceeded = fmt.Errorf("epoll wait: %w", os.ErrDeadlineExceeded)
+	errEpollWaitClosed           = fmt.Errorf("epoll wait: %w", os.ErrClosed)
+)
 
 // Poller waits for readiness notifications from multiple file descriptors.
 //
@@ -44,7 +48,7 @@ func New() (_ *Poller, err error) {
 
 	epollFd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
 	if err != nil {
-		return nil, fmt.Errorf("create epoll fd: %v", err)
+		return nil, fmt.Errorf("create epoll fd: %w", err)
 	}
 	defer closeFDOnError(epollFd)
 
@@ -158,19 +162,14 @@ func (p *Poller) Wait(events []unix.EpollEvent, deadline time.Time) (int, error)
 	defer p.epollMu.Unlock()
 
 	if p.epollFd == -1 {
-		return 0, fmt.Errorf("epoll wait: %w", os.ErrClosed)
+		return 0, errEpollWaitClosed
 	}
 
 	for {
 		timeout := int(-1)
 		if !deadline.IsZero() {
-			msec := time.Until(deadline).Milliseconds()
-			// Deadline is in the past, don't block.
-			msec = max(msec, 0)
-			// Deadline is too far in the future.
-			msec = min(msec, math.MaxInt)
-
-			timeout = int(msec)
+			// Ensure deadline is not in the past and not too far into the future.
+			timeout = int(internal.Between(time.Until(deadline).Milliseconds(), 0, math.MaxInt))
 		}
 
 		n, err := unix.EpollWait(p.epollFd, events, timeout)
@@ -184,7 +183,7 @@ func (p *Poller) Wait(events []unix.EpollEvent, deadline time.Time) (int, error)
 		}
 
 		if n == 0 {
-			return 0, fmt.Errorf("epoll wait: %w", os.ErrDeadlineExceeded)
+			return 0, errEpollWaitDeadlineExceeded
 		}
 
 		for i := 0; i < n; {
@@ -193,7 +192,7 @@ func (p *Poller) Wait(events []unix.EpollEvent, deadline time.Time) (int, error)
 				// Since we don't read p.closeEvent the event is never cleared and
 				// we'll keep getting this wakeup until Close() acquires the
 				// lock and sets p.epollFd = -1.
-				return 0, fmt.Errorf("epoll wait: %w", os.ErrClosed)
+				return 0, errEpollWaitClosed
 			}
 			if int(event.Fd) == p.flushEvent.raw {
 				// read event to prevent it from continuing to wake
diff --git a/vendor/github.com/cilium/ebpf/internal/errors.go b/vendor/github.com/cilium/ebpf/internal/errors.go
index 83a371ad35d614cbfeb687f5d4c1eecaf1e89e73..19d5294ca04262f5ab5013aa35465ef7c6d9565f 100644
--- a/vendor/github.com/cilium/ebpf/internal/errors.go
+++ b/vendor/github.com/cilium/ebpf/internal/errors.go
@@ -23,7 +23,7 @@ func ErrorWithLog(source string, err error, log []byte) *VerifierError {
 
 	log = bytes.Trim(log, whitespace)
 	if len(log) == 0 {
-		return &VerifierError{source, err, nil, false}
+		return &VerifierError{source, err, nil}
 	}
 
 	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)))
 	}
 
-	return &VerifierError{source, err, lines, false}
+	return &VerifierError{source, err, lines}
 }
 
 // VerifierError includes information from the eBPF verifier.
@@ -46,8 +46,6 @@ type VerifierError struct {
 	Cause error
 	// The verifier output split into lines.
 	Log []string
-	// Deprecated: the log is never truncated anymore.
-	Truncated bool
 }
 
 func (le *VerifierError) Unwrap() error {
diff --git a/vendor/github.com/cilium/ebpf/internal/feature.go b/vendor/github.com/cilium/ebpf/internal/feature.go
index 2b856c735e7f3b20022a2eed9efe262d1c0dd263..6399be08514bb4a0e7c901305f62bb41b40d94c3 100644
--- a/vendor/github.com/cilium/ebpf/internal/feature.go
+++ b/vendor/github.com/cilium/ebpf/internal/feature.go
@@ -3,15 +3,25 @@ package internal
 import (
 	"errors"
 	"fmt"
+	"runtime"
+	"strings"
 	"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")
 
+// 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.
 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.
 	MinimumVersion Version
 
@@ -58,11 +68,44 @@ type FeatureTest struct {
 type FeatureTestFn func() error
 
 // 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{
-		Name:    name,
-		Version: version,
-		Fn:      fn,
+		Name: name,
+		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
diff --git a/vendor/github.com/cilium/ebpf/internal/kallsyms/cache.go b/vendor/github.com/cilium/ebpf/internal/kallsyms/cache.go
new file mode 100644
index 0000000000000000000000000000000000000000..b7f3e0b7819820694629fd2e23f60a0a11765941
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/kallsyms/cache.go
@@ -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)
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go b/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go
index 776c7a10a28e68137482184c8d28e94c8ee3590a..f93d785849c54c17adc5b58d536390e1343ed62a 100644
--- a/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go
+++ b/vendor/github.com/cilium/ebpf/internal/kallsyms/kallsyms.go
@@ -1,74 +1,277 @@
 package kallsyms
 
 import (
-	"bufio"
-	"bytes"
+	"errors"
+	"fmt"
 	"io"
 	"os"
-	"sync"
+	"slices"
+	"strconv"
+	"strings"
 )
 
-var kernelModules struct {
-	sync.RWMutex
-	// function to kernel module mapping
-	kmods map[string]string
-}
+var errAmbiguousKsym = errors.New("multiple kernel symbols with the same name")
 
-// KernelModule returns the kernel module, if any, a probe-able function is contained in.
-func KernelModule(fn string) (string, error) {
-	kernelModules.RLock()
-	kmods := kernelModules.kmods
-	kernelModules.RUnlock()
+var symAddrs cache[string, uint64]
+var symModules cache[string, string]
 
-	if kmods == nil {
-		kernelModules.Lock()
-		defer kernelModules.Unlock()
-		kmods = kernelModules.kmods
+// Module returns the kernel module providing the given symbol in the kernel, if
+// any. Returns an empty string and no error if the symbol is not present in the
+// kernel. Only function symbols are considered. Returns an error if multiple
+// 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 {
-		return kmods[fn], nil
+	if mod, ok := symModules.Load(name); ok {
+		return mod, nil
 	}
 
-	f, err := os.Open("/proc/kallsyms")
-	if err != nil {
+	request := map[string]string{name: ""}
+	if err := AssignModules(request); err != nil {
 		return "", err
 	}
-	defer f.Close()
-	kmods, err = loadKernelModuleMapping(f)
+
+	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")
 	if err != nil {
-		return "", err
+		return err
+	}
+
+	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 {
+			return fmt.Errorf("parsing kallsyms line: %w", err)
+		}
+		if skip {
+			continue
+		}
+
+		if _, requested := symbols[s.name]; !requested {
+			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)
 	}
 
-	kernelModules.kmods = kmods
-	return kmods[fn], nil
+	return nil
 }
 
-// FlushKernelModuleCache removes any cached information about function to kernel module mapping.
-func FlushKernelModuleCache() {
-	kernelModules.Lock()
-	defer kernelModules.Unlock()
+// 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
+	}
 
-	kernelModules.kmods = nil
+	return request[symbol], 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 {
+// 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
 		}
-		switch string(fields[1]) {
-		case "t", "T":
-			mods[string(fields[2])] = string(bytes.Trim(fields[3], "[]"))
-		default:
+
+		// 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 scanner.Err() != nil {
-		return nil, scanner.Err()
+	if err := r.Err(); err != nil {
+		return fmt.Errorf("reading kallsyms: %w", err)
 	}
-	return mods, nil
+
+	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:
+			break
+		}
+	}
+
+	return
 }
diff --git a/vendor/github.com/cilium/ebpf/internal/kallsyms/reader.go b/vendor/github.com/cilium/ebpf/internal/kallsyms/reader.go
new file mode 100644
index 0000000000000000000000000000000000000000..2bd4f8eafcbbe9b3a7d9586cdb421e9971c2e4c9
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/kallsyms/reader.go
@@ -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
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go b/vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go
index 1921e4f15ad74523647cba64119f36e98f4abd78..29c62b6266edbe18c901783d59a6df9ac6ce6012 100644
--- a/vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go
+++ b/vendor/github.com/cilium/ebpf/internal/kconfig/kconfig.go
@@ -1,3 +1,4 @@
+// Package kconfig implements a parser for the format of Linux's .config file.
 package kconfig
 
 import (
@@ -7,7 +8,6 @@ import (
 	"fmt"
 	"io"
 	"math"
-	"os"
 	"strconv"
 	"strings"
 
@@ -15,30 +15,6 @@ import (
 	"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.
 // 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.
@@ -127,12 +103,13 @@ func PutValue(data []byte, typ btf.Type, value string) error {
 	switch value {
 	case "y", "n", "m":
 		return putValueTri(data, typ, value)
-	default:
-		if strings.HasPrefix(value, `"`) {
-			return putValueString(data, typ, value)
-		}
-		return putValueNumber(data, typ, value)
 	}
+
+	if strings.HasPrefix(value, `"`) {
+		return putValueString(data, typ, value)
+	}
+
+	return putValueNumber(data, typ, value)
 }
 
 // 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)
 		}
 
+		if len(data) != 4 {
+			return fmt.Errorf("expected enum value to occupy 4 bytes in datasec, got: %d", len(data))
+		}
+
 		var tri triState
 		switch value {
 		case "y":
@@ -178,10 +159,10 @@ func putValueTri(data []byte, typ btf.Type, value string) error {
 		case "n":
 			tri = TriNo
 		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:
 		return fmt.Errorf("cannot add number value, expected btf.Int or btf.Enum, got: %T", v)
 	}
diff --git a/vendor/github.com/cilium/ebpf/internal/auxv.go b/vendor/github.com/cilium/ebpf/internal/linux/auxv.go
similarity index 98%
rename from vendor/github.com/cilium/ebpf/internal/auxv.go
rename to vendor/github.com/cilium/ebpf/internal/linux/auxv.go
index 45fd0d37f132177e1f88e8186791a4e4d3c77273..98bb5d83cade52cd21a16578126b00c9ce485fd2 100644
--- a/vendor/github.com/cilium/ebpf/internal/auxv.go
+++ b/vendor/github.com/cilium/ebpf/internal/linux/auxv.go
@@ -1,4 +1,4 @@
-package internal
+package linux
 
 import (
 	"errors"
diff --git a/vendor/github.com/cilium/ebpf/internal/linux/doc.go b/vendor/github.com/cilium/ebpf/internal/linux/doc.go
new file mode 100644
index 0000000000000000000000000000000000000000..064e75437d83d57f2fbde7882fb237bb9e4b28f9
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/linux/doc.go
@@ -0,0 +1,2 @@
+// Package linux contains OS specific wrappers around package unix.
+package linux
diff --git a/vendor/github.com/cilium/ebpf/internal/linux/kconfig.go b/vendor/github.com/cilium/ebpf/internal/linux/kconfig.go
new file mode 100644
index 0000000000000000000000000000000000000000..1488ecb35c36a6c5e14643166cabc3144cf214fc
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/linux/kconfig.go
@@ -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)
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/platform.go b/vendor/github.com/cilium/ebpf/internal/linux/platform.go
similarity index 97%
rename from vendor/github.com/cilium/ebpf/internal/platform.go
rename to vendor/github.com/cilium/ebpf/internal/linux/platform.go
index 6e90f2ef7148833ba817434cbb3d1c5f909664b6..39bdcc51f9a3bf30e8ce2f3ddedbc074b50f7c94 100644
--- a/vendor/github.com/cilium/ebpf/internal/platform.go
+++ b/vendor/github.com/cilium/ebpf/internal/linux/platform.go
@@ -1,4 +1,4 @@
-package internal
+package linux
 
 import (
 	"runtime"
diff --git a/vendor/github.com/cilium/ebpf/internal/statfs.go b/vendor/github.com/cilium/ebpf/internal/linux/statfs.go
similarity index 96%
rename from vendor/github.com/cilium/ebpf/internal/statfs.go
rename to vendor/github.com/cilium/ebpf/internal/linux/statfs.go
index 44c02d676e6d5460d14d0f9acd9c08cc9ebe2fab..e268c06fab6c5608bf3d4fa111dcf44f65e97501 100644
--- a/vendor/github.com/cilium/ebpf/internal/statfs.go
+++ b/vendor/github.com/cilium/ebpf/internal/linux/statfs.go
@@ -1,4 +1,4 @@
-package internal
+package linux
 
 import (
 	"unsafe"
diff --git a/vendor/github.com/cilium/ebpf/internal/vdso.go b/vendor/github.com/cilium/ebpf/internal/linux/vdso.go
similarity index 93%
rename from vendor/github.com/cilium/ebpf/internal/vdso.go
rename to vendor/github.com/cilium/ebpf/internal/linux/vdso.go
index 1049278554e04c07c96b44f50e4af78f8d2649cc..1d8d0ef6b1105759f2ced4f6cbea35fbb5683c96 100644
--- a/vendor/github.com/cilium/ebpf/internal/vdso.go
+++ b/vendor/github.com/cilium/ebpf/internal/linux/vdso.go
@@ -1,4 +1,4 @@
-package internal
+package linux
 
 import (
 	"debug/elf"
@@ -9,6 +9,7 @@ import (
 	"math"
 	"os"
 
+	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -82,7 +83,7 @@ type elfNoteHeader struct {
 // vdsoLinuxVersionCode returns the LINUX_VERSION_CODE embedded in
 // the ELF notes section of the binary provided by the reader.
 func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
-	hdr, err := NewSafeELFFile(r)
+	hdr, err := internal.NewSafeELFFile(r)
 	if err != nil {
 		return 0, fmt.Errorf("reading vDSO ELF: %w", err)
 	}
@@ -110,7 +111,7 @@ func vdsoLinuxVersionCode(r io.ReaderAt) (uint32, error) {
 			var name string
 			if n.NameSize > 0 {
 				// 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 {
 					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.
-				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
 				}
 			}
diff --git a/vendor/github.com/cilium/ebpf/internal/linux/version.go b/vendor/github.com/cilium/ebpf/internal/linux/version.go
new file mode 100644
index 0000000000000000000000000000000000000000..798dd3fed02db90500ce02139fbdc561fbf30a74
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/linux/version.go
@@ -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
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/math.go b/vendor/github.com/cilium/ebpf/internal/math.go
index e95c8efde51a0d418ffac8f884597417bc3987d2..10cde66860d68f7f9cedf9e2185b5656d01f5bc4 100644
--- a/vendor/github.com/cilium/ebpf/internal/math.go
+++ b/vendor/github.com/cilium/ebpf/internal/math.go
@@ -1,13 +1,33 @@
 package internal
 
-import "golang.org/x/exp/constraints"
-
 // 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
 }
 
 // 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
 }
+
+// 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"}
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/fd.go b/vendor/github.com/cilium/ebpf/internal/sys/fd.go
index 941a56fb91b177fc791f68c8682f4d9c9bc2d21c..e2ba43fd3b3e043b1da90b8188bae1d30776bdcb 100644
--- a/vendor/github.com/cilium/ebpf/internal/sys/fd.go
+++ b/vendor/github.com/cilium/ebpf/internal/sys/fd.go
@@ -4,9 +4,12 @@ import (
 	"fmt"
 	"math"
 	"os"
+	"path/filepath"
 	"runtime"
 	"strconv"
+	"strings"
 
+	"github.com/cilium/ebpf/internal/testutils/fdtrace"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -17,15 +20,7 @@ type FD struct {
 }
 
 func newFD(value int) *FD {
-	if onLeakFD != nil {
-		// 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)))
-		}
-	}
+	fdtrace.TraceFD(value, 1)
 
 	fd := &FD{value}
 	runtime.SetFinalizer(fd, (*FD).finalize)
@@ -39,13 +34,7 @@ func (fd *FD) finalize() {
 		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(fd.Int())
-	if ok && onLeakFD != nil {
-		onLeakFD(f.(*runtime.Frames))
-	}
+	fdtrace.LeakFD(fd.raw)
 
 	_ = fd.Close()
 }
@@ -92,12 +81,15 @@ func (fd *FD) Close() error {
 		return nil
 	}
 
-	return unix.Close(fd.disown())
+	return unix.Close(fd.Disown())
 }
 
-func (fd *FD) disown() int {
-	value := int(fd.raw)
-	fds.Delete(int(value))
+// Disown destroys the FD and returns its raw file descriptor without closing
+// it. After this call, the underlying fd is no longer tied to the FD's
+// lifecycle.
+func (fd *FD) Disown() int {
+	value := fd.raw
+	fdtrace.ForgetFD(value)
 	fd.raw = -1
 
 	runtime.SetFinalizer(fd, nil)
@@ -129,5 +121,45 @@ func (fd *FD) File(name string) *os.File {
 		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())
 }
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/fd_trace.go b/vendor/github.com/cilium/ebpf/internal/sys/fd_trace.go
deleted file mode 100644
index cd50dd1f64285051ce641d3d057c219652a15886..0000000000000000000000000000000000000000
--- a/vendor/github.com/cilium/ebpf/internal/sys/fd_trace.go
+++ /dev/null
@@ -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()
-}
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/mapflags_string.go b/vendor/github.com/cilium/ebpf/internal/sys/mapflags_string.go
deleted file mode 100644
index d9fe217222bfb0300f75538581507c8899bcfeb8..0000000000000000000000000000000000000000
--- a/vendor/github.com/cilium/ebpf/internal/sys/mapflags_string.go
+++ /dev/null
@@ -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) + ")"
-}
diff --git a/vendor/github.com/cilium/ebpf/internal/pinning.go b/vendor/github.com/cilium/ebpf/internal/sys/pinning.go
similarity index 77%
rename from vendor/github.com/cilium/ebpf/internal/pinning.go
rename to vendor/github.com/cilium/ebpf/internal/sys/pinning.go
index 01d892f93444d3b60acca9872afc351023009f1d..9a4c6c7a15381fd34fbe157a7e2e6d29ce64aa2e 100644
--- a/vendor/github.com/cilium/ebpf/internal/pinning.go
+++ b/vendor/github.com/cilium/ebpf/internal/sys/pinning.go
@@ -1,4 +1,4 @@
-package internal
+package sys
 
 import (
 	"errors"
@@ -7,11 +7,11 @@ import (
 	"path/filepath"
 	"runtime"
 
-	"github.com/cilium/ebpf/internal/sys"
+	"github.com/cilium/ebpf/internal/linux"
 	"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 == "" {
 		return errors.New("given pinning path cannot be empty")
 	}
@@ -19,7 +19,7 @@ func Pin(currentPath, newPath string, fd *sys.FD) error {
 		return nil
 	}
 
-	fsType, err := FSType(filepath.Dir(newPath))
+	fsType, err := linux.FSType(filepath.Dir(newPath))
 	if err != nil {
 		return err
 	}
@@ -30,8 +30,8 @@ func Pin(currentPath, newPath string, fd *sys.FD) error {
 	defer runtime.KeepAlive(fd)
 
 	if currentPath == "" {
-		return sys.ObjPin(&sys.ObjPinAttr{
-			Pathname: sys.NewStringPointer(newPath),
+		return ObjPin(&ObjPinAttr{
+			Pathname: NewStringPointer(newPath),
 			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)
 	}
 	// Internal state not in sync with the file system so let's fix it.
-	return sys.ObjPin(&sys.ObjPinAttr{
-		Pathname: sys.NewStringPointer(newPath),
+	return ObjPin(&ObjPinAttr{
+		Pathname: NewStringPointer(newPath),
 		BpfFd:    fd.Uint(),
 	})
 }
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/ptr.go b/vendor/github.com/cilium/ebpf/internal/sys/ptr.go
index e9bb590597309a8c1d27cf490dc4b02fc43c366f..af0c014e3b973d13c6368cdc0a0d64e1174f4092 100644
--- a/vendor/github.com/cilium/ebpf/internal/sys/ptr.go
+++ b/vendor/github.com/cilium/ebpf/internal/sys/ptr.go
@@ -11,13 +11,13 @@ func NewPointer(ptr unsafe.Pointer) Pointer {
 	return Pointer{ptr: ptr}
 }
 
-// NewSlicePointer creates a 64-bit pointer from a byte slice.
-func NewSlicePointer(buf []byte) Pointer {
+// NewSlicePointer creates a 64-bit pointer from a slice.
+func NewSlicePointer[T comparable](buf []T) Pointer {
 	if len(buf) == 0 {
 		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.
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/syscall.go b/vendor/github.com/cilium/ebpf/internal/sys/syscall.go
index f6b6e93458020362d5739a950ce0f2689bb5b8f2..e37f4cf671094bd81600e831dfb9b9e1a553130a 100644
--- a/vendor/github.com/cilium/ebpf/internal/sys/syscall.go
+++ b/vendor/github.com/cilium/ebpf/internal/sys/syscall.go
@@ -133,12 +133,12 @@ func ObjInfo(fd *FD, info Info) error {
 
 // BPFObjName is a null-terminated string made up of
 // '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.
 func NewObjName(name string) ObjName {
 	var result ObjName
-	copy(result[:unix.BPF_OBJ_NAME_LEN-1], name)
+	copy(result[:BPF_OBJ_NAME_LEN-1], name)
 	return result
 }
 
@@ -160,29 +160,6 @@ type BTFID uint32
 // TypeID identifies a type in a BTF blob.
 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.
 const (
 	BPF_F_REPLACE = 1 << (iota + 2)
@@ -192,6 +169,16 @@ const (
 	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
 // syscall.E* or unix.E* constants.
 //
diff --git a/vendor/github.com/cilium/ebpf/internal/sys/types.go b/vendor/github.com/cilium/ebpf/internal/sys/types.go
index 70e754de71d4f3088322cc4bf6046f5175ad8142..88001c319eb98365d5b11b9088266aae782fd17a 100644
--- a/vendor/github.com/cilium/ebpf/internal/sys/types.go
+++ b/vendor/github.com/cilium/ebpf/internal/sys/types.go
@@ -6,6 +6,170 @@ import (
 	"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
 
 const (
@@ -402,6 +566,15 @@ const (
 	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
 
 const (
@@ -537,7 +710,7 @@ type MapInfo struct {
 	KeySize               uint32
 	ValueSize             uint32
 	MaxEntries            uint32
-	MapFlags              MapFlags
+	MapFlags              uint32
 	Name                  ObjName
 	Ifindex               uint32
 	BtfVmlinuxValueTypeId TypeID
@@ -556,7 +729,7 @@ type ProgInfo struct {
 	Tag                  [8]uint8
 	JitedProgLen         uint32
 	XlatedProgLen        uint32
-	JitedProgInsns       uint64
+	JitedProgInsns       Pointer
 	XlatedProgInsns      Pointer
 	LoadTime             uint64
 	CreatedByUid         uint32
@@ -569,15 +742,15 @@ type ProgInfo struct {
 	NetnsIno             uint64
 	NrJitedKsyms         uint32
 	NrJitedFuncLens      uint32
-	JitedKsyms           uint64
-	JitedFuncLens        uint64
+	JitedKsyms           Pointer
+	JitedFuncLens        Pointer
 	BtfId                BTFID
 	FuncInfoRecSize      uint32
 	FuncInfo             Pointer
 	NrFuncInfo           uint32
 	NrLineInfo           uint32
 	LineInfo             Pointer
-	JitedLineInfo        uint64
+	JitedLineInfo        Pointer
 	NrJitedLineInfo      uint32
 	LineInfoRecSize      uint32
 	JitedLineInfoRecSize uint32
@@ -886,7 +1059,7 @@ type MapCreateAttr struct {
 	KeySize               uint32
 	ValueSize             uint32
 	MaxEntries            uint32
-	MapFlags              MapFlags
+	MapFlags              uint32
 	InnerMapFd            uint32
 	NumaNode              uint32
 	MapName               ObjName
diff --git a/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go b/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go
index d184ea196aebc1db4ad4644a86df96c41ba45105..1b4f052ee2b8203f9b9ce2e0efdcfbe3376a4a66 100644
--- a/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go
+++ b/vendor/github.com/cilium/ebpf/internal/sysenc/buffer.go
@@ -51,12 +51,12 @@ func SyscallOutput(dst any, size int) Buffer {
 //
 // Returns the number of copied bytes.
 func (b Buffer) CopyTo(dst []byte) int {
-	return copy(dst, b.unsafeBytes())
+	return copy(dst, b.Bytes())
 }
 
 // AppendTo appends the buffer onto dst.
 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.
@@ -72,10 +72,12 @@ func (b Buffer) Unmarshal(data any) error {
 		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 {
 		return nil
 	}
diff --git a/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/fd_trace.go b/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/fd_trace.go
new file mode 100644
index 0000000000000000000000000000000000000000..562df2cc0c225edf6b25db520832c836bf21a82f
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/fd_trace.go
@@ -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()
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/main.go b/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..c1f7b42d91d3ef44af5a16adea5f33de0ac0110a
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/internal/testutils/fdtrace/main.go
@@ -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)
+}
diff --git a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go
index 897740fec0cb6110a053782da383799f63ed63c6..062bef9ec37fb8d6fc609cc6749db70bc46dce44 100644
--- a/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go
+++ b/vendor/github.com/cilium/ebpf/internal/tracefs/kprobe.go
@@ -12,6 +12,7 @@ import (
 	"syscall"
 
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/linux"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -121,7 +122,7 @@ var getTracefsPath = sync.OnceValues(func() (string, error) {
 		// RHEL/CentOS
 		{"/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
 		}
 	}
@@ -213,7 +214,10 @@ func NewEvent(args ProbeArgs) (*Event, error) {
 	if err == nil {
 		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)
 	}
 
diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
index d725cfaa3941dd521afbce11ea30b42b88442b80..144e608d1c79ec92e9e31f661afb136d4f5fccb8 100644
--- a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
+++ b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
@@ -81,15 +81,16 @@ const (
 	SO_DETACH_BPF             = linux.SO_DETACH_BPF
 	SOL_SOCKET                = linux.SOL_SOCKET
 	SIGPROF                   = linux.SIGPROF
+	SIGUSR1                   = linux.SIGUSR1
 	SIG_BLOCK                 = linux.SIG_BLOCK
 	SIG_UNBLOCK               = linux.SIG_UNBLOCK
-	EM_NONE                   = linux.EM_NONE
-	EM_BPF                    = linux.EM_BPF
 	BPF_FS_MAGIC              = linux.BPF_FS_MAGIC
 	TRACEFS_MAGIC             = linux.TRACEFS_MAGIC
 	DEBUGFS_MAGIC             = linux.DEBUGFS_MAGIC
 	BPF_RB_NO_WAKEUP          = linux.BPF_RB_NO_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
diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
index 3ff8962716a29d5a411c23d6421d746681a55979..06cc3a096630081dc74203258e7328c883000425 100644
--- a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
+++ b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
@@ -84,16 +84,17 @@ const (
 	SO_DETACH_BPF
 	SOL_SOCKET
 	SIGPROF
+	SIGUSR1
 	SIG_BLOCK
 	SIG_UNBLOCK
-	EM_NONE
-	EM_BPF
 	BPF_FS_MAGIC
 	TRACEFS_MAGIC
 	DEBUGFS_MAGIC
 	BPF_RB_NO_WAKEUP
 	BPF_RB_FORCE_WAKEUP
 	BPF_F_LOCK
+	AF_UNSPEC
+	IFF_UP
 )
 
 type Statfs_t struct {
diff --git a/vendor/github.com/cilium/ebpf/internal/version.go b/vendor/github.com/cilium/ebpf/internal/version.go
index acd4650af732067954bf10607b574cf050e5ca4c..a230830b013a6f937e7382b1ea5aee02953ea7a3 100644
--- a/vendor/github.com/cilium/ebpf/internal/version.go
+++ b/vendor/github.com/cilium/ebpf/internal/version.go
@@ -2,9 +2,6 @@ package internal
 
 import (
 	"fmt"
-	"sync"
-
-	"github.com/cilium/ebpf/internal/unix"
 )
 
 const (
@@ -78,30 +75,3 @@ func (v Version) Kernel() uint32 {
 	// each other when overflowing 8 bits.
 	return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
 }
-
-// KernelVersion returns the version of the currently running kernel.
-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
-}
diff --git a/vendor/github.com/cilium/ebpf/link/kprobe.go b/vendor/github.com/cilium/ebpf/link/kprobe.go
index fe3f17c371744b4123d23887aaf2676932c58a15..6f93a27a254c8b611e0ea6e6291fdab0d354b9d7 100644
--- a/vendor/github.com/cilium/ebpf/link/kprobe.go
+++ b/vendor/github.com/cilium/ebpf/link/kprobe.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/linux"
 	"github.com/cilium/ebpf/internal/sys"
 	"github.com/cilium/ebpf/internal/tracefs"
 	"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
 // 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].
 func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
 	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.
 //
 // 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].
 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.
 	tp, err := pmuProbe(args)
 	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
 			tp, err = pmuProbe(args)
 		}
@@ -177,7 +181,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
 	if err == 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)
 	}
 
@@ -185,7 +189,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*
 	args.Symbol = symbol
 	tp, err = tracefsProbe(args)
 	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
 			tp, err = tracefsProbe(args)
 		}
diff --git a/vendor/github.com/cilium/ebpf/link/kprobe_multi.go b/vendor/github.com/cilium/ebpf/link/kprobe_multi.go
index f7a8291f945301cd1e1c4962880d6fc434a9eb5d..094cb0538cb992ad6a3604dbcb21452346a1cd6a 100644
--- a/vendor/github.com/cilium/ebpf/link/kprobe_multi.go
+++ b/vendor/github.com/cilium/ebpf/link/kprobe_multi.go
@@ -60,7 +60,7 @@ func KprobeMulti(prog *ebpf.Program, opts KprobeMultiOptions) (Link, error) {
 //
 // Requires at least Linux 5.18.
 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) {
@@ -126,7 +126,7 @@ type kprobeMultiLink struct {
 
 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)
 }
 
@@ -149,7 +149,7 @@ func (kml *kprobeMultiLink) Info() (*Info, error) {
 	}, 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{
 		Name: "probe_kpm_link",
 		Type: ebpf.Kprobe,
@@ -188,4 +188,4 @@ var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5
 	fd.Close()
 
 	return nil
-})
+}, "5.18")
diff --git a/vendor/github.com/cilium/ebpf/link/link.go b/vendor/github.com/cilium/ebpf/link/link.go
index 9c34616c9a9a47df79654355c570ad36ded8206e..796769f8ea462954870df0d7f1c3d88895d6e94a 100644
--- a/vendor/github.com/cilium/ebpf/link/link.go
+++ b/vendor/github.com/cilium/ebpf/link/link.go
@@ -78,7 +78,9 @@ func NewFromID(id ID) (Link, error) {
 	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) {
 	raw, err := loadPinnedRawLink(fileName, opts)
 	if err != nil {
@@ -350,7 +352,7 @@ func AttachRawLink(opts RawLinkOptions) (*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),
 		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)
 	}
 
+	if typ != sys.BPF_TYPE_LINK {
+		_ = fd.Close()
+		return nil, fmt.Errorf("%s is not a Link", fileName)
+	}
+
 	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
 // until the pin is removed.
 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
 	}
 	l.pinnedPath = fileName
@@ -389,7 +396,7 @@ func (l *RawLink) Pin(fileName string) error {
 
 // Unpin implements the Link interface.
 func (l *RawLink) Unpin() error {
-	if err := internal.Unpin(l.pinnedPath); err != nil {
+	if err := sys.Unpin(l.pinnedPath); err != nil {
 		return err
 	}
 	l.pinnedPath = ""
diff --git a/vendor/github.com/cilium/ebpf/link/netfilter.go b/vendor/github.com/cilium/ebpf/link/netfilter.go
index 34be390859764269f6eee9c1e098c5042b3c5b58..9436d11df93ea427574bbf5c86852dc9269693e2 100644
--- a/vendor/github.com/cilium/ebpf/link/netfilter.go
+++ b/vendor/github.com/cilium/ebpf/link/netfilter.go
@@ -63,7 +63,7 @@ func AttachNetfilter(opts NetfilterOptions) (Link, error) {
 	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)
 }
 
diff --git a/vendor/github.com/cilium/ebpf/link/perf_event.go b/vendor/github.com/cilium/ebpf/link/perf_event.go
index 1d8feb58c1c09c634f9edb39fffb3667236c08e0..7440e8b292abacf9aa6737615f301510a173139a 100644
--- a/vendor/github.com/cilium/ebpf/link/perf_event.go
+++ b/vendor/github.com/cilium/ebpf/link/perf_event.go
@@ -115,7 +115,7 @@ func (pl *perfEventLink) Close() error {
 	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)
 }
 
@@ -185,7 +185,7 @@ func (pi *perfEventIoctl) isLink() {}
 //
 // Detaching a program from a perf event is currently not possible, so a
 // 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)
 }
 
@@ -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://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{
 		Name: "probe_bpf_perf_link",
 		Type: ebpf.Kprobe,
@@ -329,4 +329,4 @@ var haveBPFLinkPerfEvent = internal.NewFeatureTest("bpf_link_perf_event", "5.15"
 		return nil
 	}
 	return err
-})
+}, "5.15")
diff --git a/vendor/github.com/cilium/ebpf/link/syscalls.go b/vendor/github.com/cilium/ebpf/link/syscalls.go
index d09b5acb0f3517357494f1edf1c0a4b895fe9c58..25951b017dd20528bc190621540a8f8b4f484948 100644
--- a/vendor/github.com/cilium/ebpf/link/syscalls.go
+++ b/vendor/github.com/cilium/ebpf/link/syscalls.go
@@ -30,7 +30,7 @@ const (
 	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{
 		Type:    ebpf.CGroupSKB,
 		License: "MIT",
@@ -48,9 +48,9 @@ var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() e
 	// have the syscall.
 	prog.Close()
 	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 {
 		return err
 	}
@@ -90,9 +90,9 @@ var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic repl
 		return nil
 	}
 	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{
 		// This is a hopefully invalid file descriptor, which triggers EBADF.
 		TargetFd:   ^uint32(0),
@@ -107,9 +107,9 @@ var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error {
 		return nil
 	}
 	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{
 		// We rely on this being checked during the syscall.
 		// 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 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{
 		Type:    ebpf.SchedCLS,
 		License: "MIT",
@@ -162,9 +162,9 @@ var haveTCX = internal.NewFeatureTest("tcx", "6.6", func() error {
 		return ErrNotSupported
 	}
 	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{
 		Type:    ebpf.SchedCLS,
 		License: "MIT",
@@ -197,4 +197,4 @@ var haveNetkit = internal.NewFeatureTest("netkit", "6.7", func() error {
 		return ErrNotSupported
 	}
 	return errors.New("syscall succeeded unexpectedly")
-})
+}, "6.7")
diff --git a/vendor/github.com/cilium/ebpf/link/tracing.go b/vendor/github.com/cilium/ebpf/link/tracing.go
index 9e570afc96a829387edd1bd610668e21ae7a973e..a461007f9f510c7a088025dbabc2a9deaeeea997 100644
--- a/vendor/github.com/cilium/ebpf/link/tracing.go
+++ b/vendor/github.com/cilium/ebpf/link/tracing.go
@@ -14,7 +14,7 @@ type tracing struct {
 	RawLink
 }
 
-func (f *tracing) Update(new *ebpf.Program) error {
+func (f *tracing) Update(_ *ebpf.Program) error {
 	return fmt.Errorf("tracing update: %w", ErrNotSupported)
 }
 
diff --git a/vendor/github.com/cilium/ebpf/link/uprobe.go b/vendor/github.com/cilium/ebpf/link/uprobe.go
index 194d1d319a7b88fd50a972906dfb0ce960ffb27f..1852a3fadd27eb147eed7de547ab913c41324125 100644
--- a/vendor/github.com/cilium/ebpf/link/uprobe.go
+++ b/vendor/github.com/cilium/ebpf/link/uprobe.go
@@ -16,7 +16,7 @@ var (
 	uprobeRefCtrOffsetPMUPath = "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset"
 	// elixir.bootlin.com/linux/v5.15-rc7/source/kernel/events/core.c#L9799
 	uprobeRefCtrOffsetShift = 32
-	haveRefCtrOffsetPMU     = internal.NewFeatureTest("RefCtrOffsetPMU", "4.20", func() error {
+	haveRefCtrOffsetPMU     = internal.NewFeatureTest("RefCtrOffsetPMU", func() error {
 		_, err := os.Stat(uprobeRefCtrOffsetPMUPath)
 		if errors.Is(err, os.ErrNotExist) {
 			return internal.ErrNotSupported
@@ -25,7 +25,7 @@ var (
 			return err
 		}
 		return nil
-	})
+	}, "4.20")
 
 	// ErrNoSymbol indicates that the given symbol was not found
 	// in the ELF symbols table.
@@ -321,7 +321,7 @@ func (ex *Executable) uprobe(symbol string, prog *ebpf.Program, opts *UprobeOpti
 	if err == 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)
 	}
 
diff --git a/vendor/github.com/cilium/ebpf/link/uprobe_multi.go b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go
index aea807b329ae52eedab602f22a2603819358fc46..49dc18b44924eb57158607bcd11baa236d6eea24 100644
--- a/vendor/github.com/cilium/ebpf/link/uprobe_multi.go
+++ b/vendor/github.com/cilium/ebpf/link/uprobe_multi.go
@@ -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
 	// 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.
-	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) {
@@ -99,8 +99,11 @@ func (ex *Executable) uprobeMulti(symbols []string, prog *ebpf.Program, opts *Up
 	if errors.Is(err, unix.ESRCH) {
 		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) {
-		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 {
@@ -168,11 +171,11 @@ type uprobeMultiLink struct {
 
 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)
 }
 
-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{
 		Name: "probe_upm_link",
 		Type: ebpf.Kprobe,
@@ -213,4 +216,4 @@ var haveBPFLinkUprobeMulti = internal.NewFeatureTest("bpf_link_uprobe_multi", "6
 	// should not happen
 	fd.Close()
 	return errors.New("successfully attached uprobe_multi to /, kernel bug?")
-})
+}, "6.6")
diff --git a/vendor/github.com/cilium/ebpf/linker.go b/vendor/github.com/cilium/ebpf/linker.go
index 788f21b7b6fc2f72f5eb25ae44dd0d9772b2f07d..6f97af27840c5b1761fe6eaa50de905b780d71c4 100644
--- a/vendor/github.com/cilium/ebpf/linker.go
+++ b/vendor/github.com/cilium/ebpf/linker.go
@@ -9,10 +9,12 @@ import (
 	"io/fs"
 	"math"
 	"slices"
+	"strings"
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/kallsyms"
 )
 
 // handles stores handle objects to avoid gc cleanup
@@ -457,3 +459,42 @@ func resolveKconfigReferences(insns asm.Instructions) (_ *Map, err error) {
 
 	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
+}
diff --git a/vendor/github.com/cilium/ebpf/map.go b/vendor/github.com/cilium/ebpf/map.go
index 0b62101c3cb0fa86d6123d321dcf25f2db87d722..e5d8bd78095030c8aafc235e809b259c4cc70cef 100644
--- a/vendor/github.com/cilium/ebpf/map.go
+++ b/vendor/github.com/cilium/ebpf/map.go
@@ -66,16 +66,13 @@ type MapSpec struct {
 	Pinning PinType
 
 	// 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)
 	NumaNode uint32
 
 	// The initial contents of the map. May be nil.
 	Contents []MapKV
 
-	// Whether to freeze a map after setting its initial contents.
-	Freeze bool
-
 	// InnerMap is used as a template for ArrayOfMaps and HashOfMaps
 	InnerMap *MapSpec
 
@@ -161,6 +158,17 @@ func (spec *MapSpec) fixupMagicFields() (*MapSpec, error) {
 			// behaviour in the past.
 			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
@@ -190,6 +198,14 @@ func (ms *MapSpec) dataSection() ([]byte, *btf.Datasec, error) {
 	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.
 type MapKV struct {
 	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
 	// 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 {
 		diffs = append(diffs, fmt.Sprintf("Flags: %d changed to %d", m.flags, ms.Flags))
 	}
@@ -254,6 +270,8 @@ type Map struct {
 	pinnedPath string
 	// Per CPU maps return values larger than the size in the spec
 	fullValueSize int
+
+	memory *Memory
 }
 
 // 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")
 		}
 
-		template, err := spec.InnerMap.createMap(nil, opts)
+		template, err := spec.InnerMap.createMap(nil)
 		if err != nil {
 			return nil, fmt.Errorf("inner map: %w", err)
 		}
@@ -371,7 +389,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
 		innerFd = template.fd
 	}
 
-	m, err := spec.createMap(innerFd, opts)
+	m, err := spec.createMap(innerFd)
 	if err != nil {
 		return nil, err
 	}
@@ -387,9 +405,54 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions) (_ *Map, err error) {
 	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
 // 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) {
 		if err != nil {
 			closer.Close()
@@ -416,7 +479,7 @@ func (spec *MapSpec) createMap(inner *sys.FD, opts MapOptions) (_ *Map, err erro
 		KeySize:    spec.KeySize,
 		ValueSize:  spec.ValueSize,
 		MaxEntries: spec.MaxEntries,
-		MapFlags:   sys.MapFlags(spec.Flags),
+		MapFlags:   spec.Flags,
 		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 {
 		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)
 	}
 
-	switch spec.Type {
-	case ArrayOfMaps, HashOfMaps:
+	if spec.Type.canStoreMap() {
 		if haveFeatErr := haveNestedMaps(); haveFeatErr != nil {
 			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 {
 			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 {
 			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 {
 			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 {
 			return fmt.Errorf("map create: %w", haveFeatErr)
 		}
@@ -530,6 +593,7 @@ func newMap(fd *sys.FD, name string, typ MapType, keySize, valueSize, maxEntries
 		flags,
 		"",
 		int(valueSize),
+		nil,
 	}
 
 	if !typ.hasPerCPUValue() {
@@ -577,7 +641,12 @@ func (m *Map) Flags() uint32 {
 	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) {
 	return newMapInfoFromFd(m.fd)
 }
@@ -604,7 +673,7 @@ func (m *Map) Handle() (*btf.Handle, error) {
 type MapLookupFlags uint64
 
 // 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.
 //
@@ -1336,6 +1405,7 @@ func (m *Map) Clone() (*Map, error) {
 		m.flags,
 		"",
 		m.fullValueSize,
+		nil,
 	}, nil
 }
 
@@ -1349,7 +1419,7 @@ func (m *Map) Clone() (*Map, error) {
 // This requires bpffs to be mounted above fileName.
 // See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
 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
 	}
 	m.pinnedPath = fileName
@@ -1362,7 +1432,7 @@ func (m *Map) Pin(fileName string) error {
 //
 // Unpinning an unpinned Map returns nil.
 func (m *Map) Unpin() error {
-	if err := internal.Unpin(m.pinnedPath); err != nil {
+	if err := sys.Unpin(m.pinnedPath); err != nil {
 		return err
 	}
 	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 {
 			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)
 }
 
-// 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) {
-	fd, err := sys.ObjGet(&sys.ObjGetAttr{
+	fd, typ, err := sys.ObjGetTyped(&sys.ObjGetAttr{
 		Pathname:  sys.NewStringPointer(fileName),
 		FileFlags: opts.Marshal(),
 	})
@@ -1511,6 +1583,11 @@ func LoadPinnedMap(fileName string, opts *LoadPinOptions) (*Map, error) {
 		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)
 	if err == nil {
 		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.
 func marshalMap(m *Map, length int) ([]byte, error) {
+	if m == nil {
+		return nil, errors.New("can't marshal a nil Map")
+	}
+
 	if length != 4 {
 		return nil, fmt.Errorf("can't marshal map to %d bytes", length)
 	}
diff --git a/vendor/github.com/cilium/ebpf/memory.go b/vendor/github.com/cilium/ebpf/memory.go
new file mode 100644
index 0000000000000000000000000000000000000000..312c967131a37906b553f91ccb08abf16ce800d2
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/memory.go
@@ -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
+}
diff --git a/vendor/github.com/cilium/ebpf/prog.go b/vendor/github.com/cilium/ebpf/prog.go
index 9bc6325f8879d25cc623d9bf1fa8c2dc5ed2130c..4f3ce43bfae2c89ed04ccbad7fae738e162a29ce 100644
--- a/vendor/github.com/cilium/ebpf/prog.go
+++ b/vendor/github.com/cilium/ebpf/prog.go
@@ -16,6 +16,7 @@ import (
 	"github.com/cilium/ebpf/btf"
 	"github.com/cilium/ebpf/internal"
 	"github.com/cilium/ebpf/internal/kallsyms"
+	"github.com/cilium/ebpf/internal/linux"
 	"github.com/cilium/ebpf/internal/sys"
 	"github.com/cilium/ebpf/internal/sysenc"
 	"github.com/cilium/ebpf/internal/unix"
@@ -46,14 +47,15 @@ const (
 	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
 // verifier log.
 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.
 type ProgramOptions struct {
 	// Bitmap controlling the detail emitted by the kernel's eBPF verifier log.
@@ -73,9 +75,10 @@ type ProgramOptions struct {
 	// attempt at loading the program.
 	LogLevel LogLevel
 
-	// Deprecated: the correct log buffer size is determined automatically
-	// and this field is ignored.
-	LogSize int
+	// Starting size of the verifier log buffer. If the verifier log is larger
+	// than this size, the buffer will be grown to fit the entire log. Leave at
+	// its default value unless troubleshooting.
+	LogSizeStart uint32
 
 	// Disables the verifier log completely, regardless of other options.
 	LogDisabled bool
@@ -162,26 +165,35 @@ func (ps *ProgramSpec) Tag() (string, error) {
 	return ps.Instructions.Tag(internal.NativeEndian)
 }
 
-// KernelModule returns the kernel module, if any, the AttachTo function is contained in.
-func (ps *ProgramSpec) KernelModule() (string, error) {
+// kernelModule returns the kernel module providing the symbol in
+// ProgramSpec.AttachTo, if any. Returns an empty string if the symbol is not
+// 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
+}
+
+// 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 "", nil
+		return false
 	}
 
 	switch ps.Type {
-	default:
-		return "", nil
 	case Tracing:
 		switch ps.AttachType {
-		default:
-			return "", nil
-		case AttachTraceFEntry:
-		case AttachTraceFExit:
+		case AttachTraceFEntry, AttachTraceFExit:
+			return true
 		}
-		fallthrough
 	case Kprobe:
-		return kallsyms.KernelModule(ps.AttachTo)
+		return true
 	}
+
+	return false
 }
 
 // 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.
 	kv := spec.KernelVersion
 	if spec.Type == Kprobe && (kv == 0 || kv == internal.MagicKernelVersion) {
-		v, err := internal.KernelVersion()
+		v, err := linux.KernelVersion()
 		if err != nil {
 			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))
 	copy(insns, spec.Instructions)
 
-	kmodName, err := spec.KernelModule()
+	kmodName, err := spec.kernelModule()
 	if err != nil {
 		return nil, fmt.Errorf("kernel module search: %w", err)
 	}
@@ -344,6 +356,10 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
 	}
 	defer kconfig.Close()
 
+	if err := resolveKsymReferences(insns); err != nil {
+		return nil, fmt.Errorf("resolve .ksyms: %w", err)
+	}
+
 	if err := fixupAndValidate(insns); err != nil {
 		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
 	// so that there is a chance of loading the program in a single shot.
+	logSize := internal.Between(opts.LogSizeStart, minVerifierLogSize, maxVerifierLogSize)
 	var logBuf []byte
 	if !opts.LogDisabled && opts.LogLevel != 0 {
-		logBuf = make([]byte, minVerifierLogSize)
+		logBuf = make([]byte, logSize)
 		attr.LogLevel = opts.LogLevel
 		attr.LogSize = uint32(len(logBuf))
 		attr.LogBuf = sys.NewSlicePointer(logBuf)
@@ -431,12 +448,11 @@ func newProgramWithOptions(spec *ProgramSpec, opts ProgramOptions) (*Program, er
 			attr.LogLevel = LogLevelBranch
 		}
 
-		// Make an educated guess how large the buffer should be. Start
-		// at minVerifierLogSize and then double the size.
-		logSize := uint32(max(len(logBuf)*2, minVerifierLogSize))
-		if int(logSize) < len(logBuf) {
-			return nil, errors.New("overflow while probing log buffer size")
-		}
+		// Make an educated guess how large the buffer should be by multiplying.
+		// Ensure the size doesn't overflow.
+		const factor = 2
+		logSize = internal.Between(logSize, minVerifierLogSize, maxVerifierLogSize/factor)
+		logSize *= factor
 
 		if attr.LogTrueSize != 0 {
 			// 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)
 		}
 
+	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):
 		if bytes.Contains(tail, coreBadCall) {
 			err = errBadRelocation
@@ -598,7 +620,7 @@ func (p *Program) Clone() (*Program, error) {
 // This requires bpffs to be mounted above fileName.
 // See https://docs.cilium.io/en/stable/network/kubernetes/configuration/#mounting-bpffs-with-systemd
 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
 	}
 	p.pinnedPath = fileName
@@ -611,7 +633,7 @@ func (p *Program) Pin(fileName string) error {
 //
 // Unpinning an unpinned Program returns nil.
 func (p *Program) Unpin() error {
-	if err := internal.Unpin(p.pinnedPath); err != nil {
+	if err := sys.Unpin(p.pinnedPath); err != nil {
 		return err
 	}
 	p.pinnedPath = ""
@@ -699,6 +721,10 @@ func (p *Program) Test(in []byte) (uint32, []byte, error) {
 //
 // Note: the same restrictions from Test apply.
 func (p *Program) Run(opts *RunOptions) (uint32, error) {
+	if opts == nil {
+		opts = &RunOptions{}
+	}
+
 	ret, _, err := p.run(opts)
 	if err != nil {
 		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
 }
 
-var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error {
+var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", func() error {
 	prog, err := NewProgram(&ProgramSpec{
 		// SocketFilter does not require privileges on newer kernels.
 		Type: SocketFilter,
@@ -774,7 +800,7 @@ var haveProgRun = internal.NewFeatureTest("BPF_PROG_RUN", "4.12", func() error {
 	}
 
 	return err
-})
+}, "4.12")
 
 func (p *Program) run(opts *RunOptions) (uint32, time.Duration, error) {
 	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) {
+	if p == nil {
+		return nil, errors.New("can't marshal a nil Program")
+	}
+
 	if length != 4 {
 		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
 }
 
-// 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.
 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),
 		FileFlags: opts.Marshal(),
 	})
@@ -904,6 +935,11 @@ func LoadPinnedProgram(fileName string, opts *LoadPinOptions) (*Program, error)
 		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)
 	if err != nil {
 		_ = fd.Close()
diff --git a/vendor/github.com/cilium/ebpf/ringbuf/reader.go b/vendor/github.com/cilium/ebpf/ringbuf/reader.go
index 3d3ba0ecfa755e378f1bb49c1c75245b3aa7c3e7..11ef93b40b7ab896c46903d76cf0801a235a74a9 100644
--- a/vendor/github.com/cilium/ebpf/ringbuf/reader.go
+++ b/vendor/github.com/cilium/ebpf/ringbuf/reader.go
@@ -6,9 +6,11 @@ import (
 	"os"
 	"sync"
 	"time"
+	"unsafe"
 
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/internal/epoll"
+	"github.com/cilium/ebpf/internal/sys"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -25,16 +27,18 @@ type ringbufHeader struct {
 	_   uint32 // pg_off, only used by kernel internals
 }
 
+const ringbufHeaderSize = int(unsafe.Sizeof(ringbufHeader{}))
+
 func (rh *ringbufHeader) isBusy() bool {
-	return rh.Len&unix.BPF_RINGBUF_BUSY_BIT != 0
+	return rh.Len&sys.BPF_RINGBUF_BUSY_BIT != 0
 }
 
 func (rh *ringbufHeader) isDiscard() bool {
-	return rh.Len&unix.BPF_RINGBUF_DISCARD_BIT != 0
+	return rh.Len&sys.BPF_RINGBUF_DISCARD_BIT != 0
 }
 
 func (rh *ringbufHeader) dataLen() int {
-	return int(rh.Len & ^uint32(unix.BPF_RINGBUF_BUSY_BIT|unix.BPF_RINGBUF_DISCARD_BIT))
+	return int(rh.Len & ^uint32(sys.BPF_RINGBUF_BUSY_BIT|sys.BPF_RINGBUF_DISCARD_BIT))
 }
 
 type Record struct {
@@ -195,3 +199,10 @@ func (r *Reader) BufferSize() int {
 func (r *Reader) Flush() error {
 	return r.poller.Flush()
 }
+
+// AvailableBytes returns the amount of data available to read in the ring buffer in bytes.
+func (r *Reader) AvailableBytes() int {
+	// Don't need to acquire the lock here since the implementation of AvailableBytes
+	// performs atomic loads on the producer and consumer positions.
+	return int(r.ring.AvailableBytes())
+}
diff --git a/vendor/github.com/cilium/ebpf/ringbuf/ring.go b/vendor/github.com/cilium/ebpf/ringbuf/ring.go
index 8f8f4bce363403c2352822b5ab222c523d193bcb..8f75bba89508bf4e66aa2645db47249bb1221033 100644
--- a/vendor/github.com/cilium/ebpf/ringbuf/ring.go
+++ b/vendor/github.com/cilium/ebpf/ringbuf/ring.go
@@ -9,6 +9,7 @@ import (
 	"unsafe"
 
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/sys"
 	"github.com/cilium/ebpf/internal/unix"
 )
 
@@ -77,6 +78,13 @@ func (rr *ringReader) size() int {
 	return cap(rr.ring) / 2
 }
 
+// The amount of data available to read in the ring buffer.
+func (rr *ringReader) AvailableBytes() uint64 {
+	prod := atomic.LoadUint64(rr.prod_pos)
+	cons := atomic.LoadUint64(rr.cons_pos)
+	return prod - cons
+}
+
 // Read a record from an event ring.
 func (rr *ringReader) readRecord(rec *Record) error {
 	prod := atomic.LoadUint64(rr.prod_pos)
@@ -85,7 +93,7 @@ func (rr *ringReader) readRecord(rec *Record) error {
 	for {
 		if remaining := prod - cons; remaining == 0 {
 			return errEOR
-		} else if remaining < unix.BPF_RINGBUF_HDR_SZ {
+		} else if remaining < sys.BPF_RINGBUF_HDR_SZ {
 			return fmt.Errorf("read record header: %w", io.ErrUnexpectedEOF)
 		}
 
@@ -104,7 +112,7 @@ func (rr *ringReader) readRecord(rec *Record) error {
 			return errBusy
 		}
 
-		cons += unix.BPF_RINGBUF_HDR_SZ
+		cons += sys.BPF_RINGBUF_HDR_SZ
 
 		// Data is always padded to 8 byte alignment.
 		dataLenAligned := uint64(internal.Align(header.dataLen(), 8))
diff --git a/vendor/github.com/cilium/ebpf/rlimit/doc.go b/vendor/github.com/cilium/ebpf/rlimit/doc.go
new file mode 100644
index 0000000000000000000000000000000000000000..652ea1af5ab50a807455c5d4fd1415db521e73fb
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/rlimit/doc.go
@@ -0,0 +1,2 @@
+// Package rlimit allows raising RLIMIT_MEMLOCK if necessary for the use of BPF.
+package rlimit
diff --git a/vendor/github.com/cilium/ebpf/rlimit/rlimit.go b/vendor/github.com/cilium/ebpf/rlimit/rlimit_linux.go
similarity index 98%
rename from vendor/github.com/cilium/ebpf/rlimit/rlimit.go
rename to vendor/github.com/cilium/ebpf/rlimit/rlimit_linux.go
index 2a6973744f08e6b08c0bd0be1eda5fd13374a2c7..b05699c5f3e0af4e8c4a098c11df8fdbe5d1072c 100644
--- a/vendor/github.com/cilium/ebpf/rlimit/rlimit.go
+++ b/vendor/github.com/cilium/ebpf/rlimit/rlimit_linux.go
@@ -1,4 +1,3 @@
-// Package rlimit allows raising RLIMIT_MEMLOCK if necessary for the use of BPF.
 package rlimit
 
 import (
diff --git a/vendor/github.com/cilium/ebpf/rlimit/rlimit_other.go b/vendor/github.com/cilium/ebpf/rlimit/rlimit_other.go
new file mode 100644
index 0000000000000000000000000000000000000000..9216a565fc362bc29ab77510064b86a267d449ce
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/rlimit/rlimit_other.go
@@ -0,0 +1,6 @@
+//go:build !linux
+
+package rlimit
+
+// RemoveMemlock is a no-op on platforms other than Linux.
+func RemoveMemlock() error { return nil }
diff --git a/vendor/github.com/cilium/ebpf/syscalls.go b/vendor/github.com/cilium/ebpf/syscalls.go
index 4aef7faebc8af4b78f2c85219ca7ab61febcad25..25c84c3c5c1a0112c79ba2db8f421edab7c218be 100644
--- a/vendor/github.com/cilium/ebpf/syscalls.go
+++ b/vendor/github.com/cilium/ebpf/syscalls.go
@@ -10,6 +10,7 @@ import (
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/internal"
+	"github.com/cilium/ebpf/internal/linux"
 	"github.com/cilium/ebpf/internal/sys"
 	"github.com/cilium/ebpf/internal/tracefs"
 	"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{
 		MapType:    sys.MapType(ArrayOfMaps),
 		KeySize:    4,
@@ -76,9 +77,9 @@ var haveNestedMaps = internal.NewFeatureTest("nested maps", "4.12", func() error
 		return nil
 	}
 	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
 	// BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
 	m, err := sys.MapCreate(&sys.MapCreateAttr{
@@ -86,39 +87,39 @@ var haveMapMutabilityModifiers = internal.NewFeatureTest("read- and write-only m
 		KeySize:    4,
 		ValueSize:  4,
 		MaxEntries: 1,
-		MapFlags:   unix.BPF_F_RDONLY_PROG,
+		MapFlags:   sys.BPF_F_RDONLY_PROG,
 	})
 	if err != nil {
 		return internal.ErrNotSupported
 	}
 	_ = m.Close()
 	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.
 	m, err := sys.MapCreate(&sys.MapCreateAttr{
 		MapType:    sys.MapType(Array),
 		KeySize:    4,
 		ValueSize:  4,
 		MaxEntries: 1,
-		MapFlags:   unix.BPF_F_MMAPABLE,
+		MapFlags:   sys.BPF_F_MMAPABLE,
 	})
 	if err != nil {
 		return internal.ErrNotSupported
 	}
 	_ = m.Close()
 	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.
 	m, err := sys.MapCreate(&sys.MapCreateAttr{
 		MapType:    sys.MapType(Array),
 		KeySize:    4,
 		ValueSize:  4,
 		MaxEntries: 1,
-		MapFlags:   unix.BPF_F_INNER_MAP,
+		MapFlags:   sys.BPF_F_INNER_MAP,
 	})
 
 	if err != nil {
@@ -126,16 +127,16 @@ var haveInnerMaps = internal.NewFeatureTest("inner maps", "5.10", func() error {
 	}
 	_ = m.Close()
 	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.
 	m, err := sys.MapCreate(&sys.MapCreateAttr{
 		MapType:    sys.MapType(Hash),
 		KeySize:    4,
 		ValueSize:  4,
 		MaxEntries: 1,
-		MapFlags:   unix.BPF_F_NO_PREALLOC,
+		MapFlags:   sys.BPF_F_NO_PREALLOC,
 	})
 
 	if err != nil {
@@ -143,7 +144,7 @@ var haveNoPreallocMaps = internal.NewFeatureTest("prealloc maps", "4.6", func()
 	}
 	_ = m.Close()
 	return nil
-})
+}, "4.6")
 
 func wrapMapError(err error) error {
 	if err == nil {
@@ -169,7 +170,7 @@ func wrapMapError(err error) error {
 	return err
 }
 
-var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error {
+var haveObjName = internal.NewFeatureTest("object names", func() error {
 	attr := sys.MapCreateAttr{
 		MapType:    sys.MapType(Array),
 		KeySize:    4,
@@ -178,16 +179,24 @@ var haveObjName = internal.NewFeatureTest("object names", "4.15", func() error {
 		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)
-	if err != nil {
+	if errors.Is(err, unix.EPERM) {
+		return nil
+	}
+	if errors.Is(err, unix.EINVAL) {
 		return internal.ErrNotSupported
 	}
+	if err != nil {
+		return err
+	}
 
 	_ = fd.Close()
 	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 {
 		return err
 	}
@@ -200,16 +209,25 @@ var objNameAllowsDot = internal.NewFeatureTest("dot in object names", "5.2", fun
 		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)
-	if err != nil {
+	if errors.Is(err, unix.EPERM) {
+		return nil
+	}
+	if errors.Is(err, unix.EINVAL) {
 		return internal.ErrNotSupported
 	}
+	if err != nil {
+		return err
+	}
 
 	_ = fd.Close()
 	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
 	attr := sys.MapCreateAttr{
 		MapType:    sys.MapType(Hash),
@@ -239,9 +257,9 @@ var haveBatchAPI = internal.NewFeatureTest("map batch api", "5.6", func() error
 		return internal.ErrNotSupported
 	}
 	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{
 		asm.Mov.Reg(asm.R1, asm.R10),
 		asm.Add.Imm(asm.R1, -8),
@@ -257,9 +275,9 @@ var haveProbeReadKernel = internal.NewFeatureTest("bpf_probe_read_kernel", "5.5"
 	}
 	_ = fd.Close()
 	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{
 		asm.Call.Label("prog2").WithSymbol("prog1"),
 		asm.Return(),
@@ -273,10 +291,10 @@ var haveBPFToBPFCalls = internal.NewFeatureTest("bpf2bpf calls", "4.16", func()
 	}
 	_ = fd.Close()
 	return nil
-})
+}, "4.16")
 
-var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", "4.17", func() error {
-	prefix := internal.PlatformPrefix()
+var haveSyscallWrapper = internal.NewFeatureTest("syscall wrapper", func() error {
+	prefix := linux.PlatformPrefix()
 	if prefix == "" {
 		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()
-})
+}, "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{
 		asm.Mov.Imm(asm.R0, 0),
 		asm.Return(),
@@ -334,4 +352,4 @@ var haveProgramExtInfos = internal.NewFeatureTest("program ext_infos", "5.0", fu
 	}
 
 	return err
-})
+}, "5.0")
diff --git a/vendor/github.com/cilium/ebpf/types.go b/vendor/github.com/cilium/ebpf/types.go
index 542c2397cab4f9cebe9228ceb4937a7895e07d43..211b308bbc78cbe8cb5836376385b1d1f3a2dde6 100644
--- a/vendor/github.com/cilium/ebpf/types.go
+++ b/vendor/github.com/cilium/ebpf/types.go
@@ -2,7 +2,6 @@ package ebpf
 
 import (
 	"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
@@ -95,6 +94,14 @@ const (
 	InodeStorage
 	// TaskStorage - Specialized local storage map for task_struct.
 	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.
@@ -120,6 +127,21 @@ func (mt MapType) canStoreProgram() bool {
 	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
 type ProgramType uint32
 
@@ -263,10 +285,10 @@ func (lpo *LoadPinOptions) Marshal() uint32 {
 
 	flags := lpo.Flags
 	if lpo.ReadOnly {
-		flags |= unix.BPF_F_RDONLY
+		flags |= sys.BPF_F_RDONLY
 	}
 	if lpo.WriteOnly {
-		flags |= unix.BPF_F_WRONLY
+		flags |= sys.BPF_F_WRONLY
 	}
 	return flags
 }
diff --git a/vendor/github.com/cilium/ebpf/types_string.go b/vendor/github.com/cilium/ebpf/types_string.go
index ee60b5be5b6402f740a4c04549a579cf393102cb..f06685112c243154b9cc2959f94c7bf8a1ff13c9 100644
--- a/vendor/github.com/cilium/ebpf/types_string.go
+++ b/vendor/github.com/cilium/ebpf/types_string.go
@@ -38,11 +38,15 @@ func _() {
 	_ = x[RingBuf-27]
 	_ = x[InodeStorage-28]
 	_ = 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 {
 	if i >= MapType(len(_MapType_index)-1) {
diff --git a/vendor/github.com/cilium/ebpf/variable.go b/vendor/github.com/cilium/ebpf/variable.go
new file mode 100644
index 0000000000000000000000000000000000000000..288b173a11542523fb7087503bb5e3ac77fdd187
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/variable.go
@@ -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
+}
diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE
deleted file mode 100644
index 2a7cf70da6e498df9c11ab6a5eaa2ddd7af34da4..0000000000000000000000000000000000000000
--- a/vendor/golang.org/x/exp/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright 2009 The Go Authors.
-
-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 LLC 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.
diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS
deleted file mode 100644
index 733099041f84fa1e58611ab2e11af51c1f26d1d2..0000000000000000000000000000000000000000
--- a/vendor/golang.org/x/exp/PATENTS
+++ /dev/null
@@ -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.
diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go
deleted file mode 100644
index 2c033dff47e904fc5cd8643c2e6b5c3d1f42c5fe..0000000000000000000000000000000000000000
--- a/vendor/golang.org/x/exp/constraints/constraints.go
+++ /dev/null
@@ -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
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2e32a5f689ffe14222e3549f1f985752bc56a176..a70850cd8c5d05adb551b647e1f5282a276631e3 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -42,8 +42,8 @@ github.com/cenkalti/rpc2/jsonrpc
 # github.com/cespare/xxhash/v2 v2.3.0
 ## explicit; go 1.11
 github.com/cespare/xxhash/v2
-# github.com/cilium/ebpf v0.16.0
-## explicit; go 1.21
+# github.com/cilium/ebpf v0.17.1
+## explicit; go 1.22
 github.com/cilium/ebpf
 github.com/cilium/ebpf/asm
 github.com/cilium/ebpf/btf
@@ -51,8 +51,10 @@ github.com/cilium/ebpf/internal
 github.com/cilium/ebpf/internal/epoll
 github.com/cilium/ebpf/internal/kallsyms
 github.com/cilium/ebpf/internal/kconfig
+github.com/cilium/ebpf/internal/linux
 github.com/cilium/ebpf/internal/sys
 github.com/cilium/ebpf/internal/sysenc
+github.com/cilium/ebpf/internal/testutils/fdtrace
 github.com/cilium/ebpf/internal/tracefs
 github.com/cilium/ebpf/internal/unix
 github.com/cilium/ebpf/link
@@ -663,9 +665,6 @@ golang.org/x/crypto/blake2b
 golang.org/x/crypto/cryptobyte
 golang.org/x/crypto/cryptobyte/asn1
 golang.org/x/crypto/curve25519
-# golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
-## explicit; go 1.20
-golang.org/x/exp/constraints
 # golang.org/x/net v0.33.0
 ## explicit; go 1.18
 golang.org/x/net/bpf