handle.go 3.0 KB

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