Skip to content

Commit 813cc7a

Browse files
committed
info: expose func info from ProgramInfo
`bpf_prog_info` supports func info since commit torvalds/linux@838e96904ff3 ("bpf: Introduce bpf_func_info"). Signed-off-by: Leon Hwang <[email protected]>
1 parent 457407e commit 813cc7a

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

info.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,64 @@ func (pi *ProgramInfo) KsymAddrs() ([]uintptr, bool) {
532532
return ptrs, pi.numKsymInfos > 0
533533
}
534534

535+
// ProgramFunctionInfo describes a function of an insn in a program.
536+
type ProgramFunctionInfo struct {
537+
// InstructionOffset is the offset of the insn in the program's instructions.
538+
InstructionOffset uint64
539+
540+
// FuncInfo is the BTF function information.
541+
FuncInfo *btf.Func
542+
}
543+
544+
// FuncInfos returns the function information of bpf programs, including
545+
// subprograms, of current bpf program.
546+
//
547+
// Available from 5.0.
548+
func (pi *ProgramInfo) FuncInfos() ([]ProgramFunctionInfo, error) {
549+
if pi.numFuncInfos == 0 {
550+
return nil, nil
551+
}
552+
553+
btfID, ok := pi.BTFID()
554+
if !ok {
555+
return nil, nil
556+
}
557+
558+
handle, err := btf.NewHandleFromID(btfID)
559+
if err != nil {
560+
return nil, fmt.Errorf("unable to get BTF handle: %w", err)
561+
}
562+
defer handle.Close()
563+
564+
btfSpec, err := handle.Spec(nil)
565+
if err != nil {
566+
return nil, fmt.Errorf("unable to get BTF spec: %w", err)
567+
}
568+
569+
funcs := make([]ProgramFunctionInfo, 0, pi.numFuncInfos)
570+
571+
ptr := (*sys.FuncInfo)(unsafe.Pointer(&pi.funcInfos[0]))
572+
funcInfos := unsafe.Slice(ptr, int(pi.numFuncInfos))
573+
for _, funcInfo := range funcInfos {
574+
btfInfo, err := btfSpec.TypeByID(sys.TypeID(funcInfo.TypeId))
575+
if err != nil {
576+
return nil, fmt.Errorf("unable to get BTF type: %w", err)
577+
}
578+
579+
funcBtfInfo, ok := btfInfo.(*btf.Func)
580+
if !ok {
581+
return nil, fmt.Errorf("unexpected BTF type: %T, expected %T", btfInfo, funcBtfInfo)
582+
}
583+
584+
funcs = append(funcs, ProgramFunctionInfo{
585+
InstructionOffset: uint64(funcInfo.InsnOff),
586+
FuncInfo: funcBtfInfo,
587+
})
588+
}
589+
590+
return funcs, nil
591+
}
592+
535593
func scanFdInfo(fd *sys.FD, fields map[string]interface{}) error {
536594
fh, err := os.Open(fmt.Sprintf("/proc/self/fdinfo/%d", fd.Int()))
537595
if err != nil {

info_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,3 +546,56 @@ func TestProgInfoKsym(t *testing.T) {
546546
}
547547
}
548548
}
549+
550+
func TestProgInfoFuncInfo(t *testing.T) {
551+
testutils.SkipOnOldKernel(t, "5.0", "Program func info")
552+
553+
spec, err := LoadCollectionSpec(testutils.NativeFile(t, "testdata/loader-%s.elf"))
554+
if err != nil {
555+
t.Fatal(err)
556+
}
557+
558+
var obj struct {
559+
Main *Program `ebpf:"xdp_prog"`
560+
}
561+
562+
err = spec.LoadAndAssign(&obj, nil)
563+
testutils.SkipIfNotSupported(t, err)
564+
if err != nil {
565+
t.Fatal(err)
566+
}
567+
defer obj.Main.Close()
568+
569+
info, err := obj.Main.Info()
570+
if err != nil {
571+
t.Fatal(err)
572+
}
573+
574+
funcs, err := info.FuncInfos()
575+
if err != nil {
576+
t.Fatalf("failed to get func infos: %v", err)
577+
}
578+
579+
expectedNumFuncInfos := uint32(5)
580+
if info.numFuncInfos != expectedNumFuncInfos {
581+
t.Fatalf("expected %d ksym infos, got %d", expectedNumFuncInfos, info.numFuncInfos)
582+
}
583+
584+
expectedFuncInfo := map[string]bool{
585+
"xdp_prog": false,
586+
"static_fn": false,
587+
"global_fn": false,
588+
"global_fn2": false,
589+
"global_fn3": false,
590+
}
591+
592+
for _, funcInfo := range funcs {
593+
expectedFuncInfo[funcInfo.FuncInfo.Name] = true
594+
}
595+
596+
for fn, found := range expectedFuncInfo {
597+
if !found {
598+
t.Errorf("func %q not found", fn)
599+
}
600+
}
601+
}

0 commit comments

Comments
 (0)