Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 58 additions & 31 deletions info.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ type ProgramInfo struct {

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

Expand Down Expand Up @@ -372,6 +373,7 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
jitedSize: info.JitedProgLen,
loadTime: time.Duration(info.LoadTime),
verifiedInstructions: info.VerifiedInsns,
numInsns: info.XlatedProgLen,
}

// Supplement OBJ_INFO with data from /proc/self/fdinfo. It contains fields
Expand Down Expand Up @@ -416,9 +418,20 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {

if info.XlatedProgLen > 0 {
pi.insns = make([]byte, info.XlatedProgLen)
info2.XlatedProgLen = info.XlatedProgLen
info2.XlatedProgInsns = sys.SlicePointer(pi.insns)
makeSecondCall = true
var info3 sys.ProgInfo
info3.XlatedProgLen = info.XlatedProgLen
info3.XlatedProgInsns = sys.SlicePointer(pi.insns)

// When kernel.kptr_restrict and net.core.bpf_jit_harden are both set, it causes the
// syscall to abort when trying to readback xlated instructions, skipping other info
// as well. So request xlated instructions separately.
if err := sys.ObjInfo(fd, &info3); err != nil {
return nil, err
}
if info3.XlatedProgInsns.IsNil() {
pi.restricted = true
pi.insns = nil
}
}

if info.NrLineInfo > 0 {
Expand Down Expand Up @@ -477,19 +490,53 @@ func newProgramInfoFromFd(fd *sys.FD) (*ProgramInfo, error) {
if err := sys.ObjInfo(fd, &info2); err != nil {
return nil, err
}
if info.JitedProgLen > 0 && info2.JitedProgInsns.IsNil() {
// JIT information is not available due to kernel.kptr_restrict
pi.jitedInfo.lineInfos = nil
pi.jitedInfo.ksyms = nil
pi.jitedInfo.insns = nil
pi.jitedInfo.funcLens = nil
}
}

if info.XlatedProgLen > 0 && info2.XlatedProgInsns.IsNil() {
pi.restricted = true
pi.insns = nil
pi.lineInfos = nil
pi.funcInfos = nil
pi.jitedInfo = programJitedInfo{}
if len(pi.Name) == len(info.Name)-1 { // Possibly truncated, check BTF info for full name
name, err := readNameFromFunc(&pi)
if err == nil {
pi.Name = name
} // If an error occurs, keep the truncated name, which is better than none
}

return &pi, nil
}

func readNameFromFunc(pi *ProgramInfo) (string, error) {
if pi.numFuncInfos == 0 {
return "", errors.New("no function info")
}

spec, err := pi.btfSpec()
if err != nil {
return "", err
}

funcInfos, err := btf.LoadFuncInfos(
bytes.NewReader(pi.funcInfos),
internal.NativeEndian,
pi.numFuncInfos,
spec,
)
if err != nil {
return "", err
}

for _, funcInfo := range funcInfos {
if funcInfo.Offset == 0 { // Information about the whole program
return funcInfo.Func.Name, nil
}
}
return "", errors.New("no function info about program")
}

func readProgramInfoFromProc(fd *sys.FD, pi *ProgramInfo) error {
var progType uint32
err := scanFdInfo(fd, map[string]interface{}{
Expand Down Expand Up @@ -581,10 +628,6 @@ var ErrRestrictedKernel = internal.ErrRestrictedKernel
// 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 pi.restricted {
return nil, fmt.Errorf("line infos: %w", ErrRestrictedKernel)
}

if len(pi.lineInfos) == 0 {
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
}
Expand Down Expand Up @@ -708,10 +751,6 @@ func (pi *ProgramInfo) Instructions() (asm.Instructions, error) {
//
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
func (pi *ProgramInfo) JitedSize() (uint32, error) {
if pi.restricted {
return 0, fmt.Errorf("jited size: %w", ErrRestrictedKernel)
}

if pi.jitedSize == 0 {
return 0, fmt.Errorf("insufficient permissions, unsupported kernel, or JIT compiler disabled: %w", ErrNotSupported)
}
Expand All @@ -721,20 +760,12 @@ func (pi *ProgramInfo) JitedSize() (uint32, error) {
// TranslatedSize returns the size of the program's translated instructions in
// bytes, after it has been verified and rewritten by the kernel.
//
// Returns an error wrapping [ErrRestrictedKernel] if translated instructions
// are restricted by sysctls.
//
// Available from 4.13. Reading this metadata requires CAP_BPF or equivalent.
func (pi *ProgramInfo) TranslatedSize() (int, error) {
if pi.restricted {
return 0, fmt.Errorf("xlated size: %w", ErrRestrictedKernel)
}

insns := len(pi.insns)
if insns == 0 {
if pi.numInsns == 0 {
return 0, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
}
return insns, nil
return int(pi.numInsns), nil
}

// MapIDs returns the maps related to the program.
Expand Down Expand Up @@ -832,10 +863,6 @@ func (pi *ProgramInfo) JitedFuncLens() ([]uint32, bool) {
// 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 pi.restricted {
return nil, fmt.Errorf("func infos: %w", ErrRestrictedKernel)
}

if len(pi.funcInfos) == 0 {
return nil, fmt.Errorf("insufficient permissions or unsupported kernel: %w", ErrNotSupported)
}
Expand Down