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 }