gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

handle.go (3031B)


      1 package btf
      2 
      3 import (
      4 	"errors"
      5 	"fmt"
      6 	"os"
      7 
      8 	"github.com/cilium/ebpf/internal/sys"
      9 	"github.com/cilium/ebpf/internal/unix"
     10 )
     11 
     12 // HandleInfo describes a Handle.
     13 type HandleInfo struct {
     14 	// ID of this handle in the kernel. The ID is only valid as long as the
     15 	// associated handle is kept alive.
     16 	ID ID
     17 
     18 	// Name is an identifying name for the BTF, currently only used by the
     19 	// kernel.
     20 	Name string
     21 
     22 	// IsKernel is true if the BTF originated with the kernel and not
     23 	// userspace.
     24 	IsKernel bool
     25 
     26 	// Size of the raw BTF in bytes.
     27 	size uint32
     28 }
     29 
     30 func newHandleInfoFromFD(fd *sys.FD) (*HandleInfo, error) {
     31 	// We invoke the syscall once with a empty BTF and name buffers to get size
     32 	// information to allocate buffers. Then we invoke it a second time with
     33 	// buffers to receive the data.
     34 	var btfInfo sys.BtfInfo
     35 	if err := sys.ObjInfo(fd, &btfInfo); err != nil {
     36 		return nil, fmt.Errorf("get BTF info for fd %s: %w", fd, err)
     37 	}
     38 
     39 	if btfInfo.NameLen > 0 {
     40 		// NameLen doesn't account for the terminating NUL.
     41 		btfInfo.NameLen++
     42 	}
     43 
     44 	// Don't pull raw BTF by default, since it may be quite large.
     45 	btfSize := btfInfo.BtfSize
     46 	btfInfo.BtfSize = 0
     47 
     48 	nameBuffer := make([]byte, btfInfo.NameLen)
     49 	btfInfo.Name, btfInfo.NameLen = sys.NewSlicePointerLen(nameBuffer)
     50 	if err := sys.ObjInfo(fd, &btfInfo); err != nil {
     51 		return nil, err
     52 	}
     53 
     54 	return &HandleInfo{
     55 		ID:       ID(btfInfo.Id),
     56 		Name:     unix.ByteSliceToString(nameBuffer),
     57 		IsKernel: btfInfo.KernelBtf != 0,
     58 		size:     btfSize,
     59 	}, nil
     60 }
     61 
     62 // IsModule returns true if the BTF is for the kernel itself.
     63 func (i *HandleInfo) IsVmlinux() bool {
     64 	return i.IsKernel && i.Name == "vmlinux"
     65 }
     66 
     67 // IsModule returns true if the BTF is for a kernel module.
     68 func (i *HandleInfo) IsModule() bool {
     69 	return i.IsKernel && i.Name != "vmlinux"
     70 }
     71 
     72 // HandleIterator allows enumerating BTF blobs loaded into the kernel.
     73 type HandleIterator struct {
     74 	// The ID of the last retrieved handle. Only valid after a call to Next.
     75 	ID  ID
     76 	err error
     77 }
     78 
     79 // Next retrieves a handle for the next BTF blob.
     80 //
     81 // [Handle.Close] is called if *handle is non-nil to avoid leaking fds.
     82 //
     83 // Returns true if another BTF blob was found. Call [HandleIterator.Err] after
     84 // the function returns false.
     85 func (it *HandleIterator) Next(handle **Handle) bool {
     86 	if *handle != nil {
     87 		(*handle).Close()
     88 		*handle = nil
     89 	}
     90 
     91 	id := it.ID
     92 	for {
     93 		attr := &sys.BtfGetNextIdAttr{Id: id}
     94 		err := sys.BtfGetNextId(attr)
     95 		if errors.Is(err, os.ErrNotExist) {
     96 			// There are no more BTF objects.
     97 			return false
     98 		} else if err != nil {
     99 			it.err = fmt.Errorf("get next BTF ID: %w", err)
    100 			return false
    101 		}
    102 
    103 		id = attr.NextId
    104 		*handle, err = NewHandleFromID(id)
    105 		if errors.Is(err, os.ErrNotExist) {
    106 			// Try again with the next ID.
    107 			continue
    108 		} else if err != nil {
    109 			it.err = fmt.Errorf("retrieve handle for ID %d: %w", id, err)
    110 			return false
    111 		}
    112 
    113 		it.ID = id
    114 		return true
    115 	}
    116 }
    117 
    118 // Err returns an error if iteration failed for some reason.
    119 func (it *HandleIterator) Err() error {
    120 	return it.err
    121 }