Skip to content

Commit

Permalink
info: expose bpf_prog_info fields to ProgramInfo
Browse files Browse the repository at this point in the history
Exposes additional metadata fields from `bpf_prog_info` to
`ProgramInfo`:
- jited_prog_len
- xlated_prog_len
- load_time
- verified_insns

Signed-off-by: tyrone-wu <wudevelops@gmail.com>
  • Loading branch information
tyrone-wu authored and ti-mo committed Sep 12, 2024
1 parent 08e7424 commit c63f95d
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 4 deletions.
52 changes: 50 additions & 2 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,12 @@ type ProgramInfo struct {
haveCreatedByUID bool
btf btf.ID
stats *programStats
loadTime time.Duration

maps []MapID
insns []byte
maps []MapID
insns []byte
jitedSize uint32
verifiedInstructions uint32

lineInfos []byte
numLineInfos uint32
Expand Down Expand Up @@ -164,6 +167,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.
Expand Down Expand Up @@ -391,6 +397,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.
Expand All @@ -400,6 +429,25 @@ 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
}

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 {
Expand Down
43 changes: 41 additions & 2 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,55 @@ func TestProgramInfo(t *testing.T) {
}

if name == "proc" {
_, err := info.JitedSize()
qt.Assert(t, qt.IsNotNil(err))

_, err = info.TranslatedSize()
qt.Assert(t, qt.IsNotNil(err))

_, ok := info.CreatedByUID()
qt.Assert(t, qt.IsFalse(ok))

_, ok = info.LoadTime()
qt.Assert(t, qt.IsFalse(ok))

_, ok = info.VerifiedInstructions()
qt.Assert(t, qt.IsFalse(ok))
} else {
uid, ok := info.CreatedByUID()
if testutils.IsKernelLessThan(t, "4.15") {
if jitedSize, err := info.JitedSize(); testutils.IsKernelLessThan(t, "4.13") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsTrue(jitedSize > 0))
}

if xlatedSize, err := info.TranslatedSize(); testutils.IsKernelLessThan(t, "4.13") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsTrue(xlatedSize > 0))
}

if uid, ok := info.CreatedByUID(); testutils.IsKernelLessThan(t, "4.15") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.Equals(uid, uint32(os.Getuid())))
}

if loadTime, ok := info.LoadTime(); testutils.IsKernelLessThan(t, "4.15") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(loadTime > 0))
}

if verifiedInsns, ok := info.VerifiedInstructions(); testutils.IsKernelLessThan(t, "5.16") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(verifiedInsns > 0))
}
}
})
}
Expand Down

0 comments on commit c63f95d

Please sign in to comment.