Skip to content

Commit

Permalink
info: add tests for recent ProgramInfo API additions
Browse files Browse the repository at this point in the history
Added tests for:
- FuncInfos()
- LineInfos()
- JitedKsymAddrs()
- JitedInsns()
- JitedLineInfos()
- JitedFuncLens()

The existing test for JitedKsymAddrs was removed because it's not strictly
necessary to load a CollectionSpec to exercise it. It obscured the fact that
it seems like kernels before at least 5.4 need to have a subprog for jited
addrs to be returned in prog info.

TestProgInfoFuncInfos was removed for a similar reason. It's possible to
craft a program using the asm package that meets the criteria for exercising
FuncInfos() and LineInfos() in a deterministic way, no need to load a Collection.

Signed-off-by: Timo Beckers <timo@isovalent.com>
  • Loading branch information
ti-mo committed Dec 4, 2024
1 parent f38bc38 commit 7514cdf
Showing 1 changed file with 83 additions and 52 deletions.
135 changes: 83 additions & 52 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,30 @@ import (
"github.com/cilium/ebpf/internal/testutils"
)

var btfFn = &btf.Func{
Name: "_",
Type: &btf.FuncProto{
Return: &btf.Int{Size: 16},
Params: []btf.FuncParam{},
},
Linkage: btf.StaticFunc,
}

var multiprogSpec = &ProgramSpec{
Name: "test",
Type: SocketFilter,
Instructions: asm.Instructions{
btf.WithFuncMetadata(asm.LoadImm(asm.R0, 0, asm.DWord), btfFn).
WithSource(asm.Comment("line info")),
asm.Call.Label("fn"),
asm.Return(),
btf.WithFuncMetadata(asm.LoadImm(asm.R0, 0, asm.DWord), btfFn).
WithSource(asm.Comment("line info")).WithSymbol("fn"),
asm.Return(),
},
License: "MIT",
}

func TestMapInfoFromProc(t *testing.T) {
hash, err := NewMap(&MapSpec{
Type: Hash,
Expand Down Expand Up @@ -130,6 +154,13 @@ func TestProgramInfo(t *testing.T) {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(verifiedInsns > 0))
}

if insns, ok := info.JitedInsns(); testutils.IsKernelLessThan(t, "4.13") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(insns) > 0))
}
}

func TestProgramInfoProc(t *testing.T) {
Expand All @@ -142,6 +173,58 @@ func TestProgramInfoProc(t *testing.T) {
validateProgInfo(t, info)
}

func TestProgramInfoBTF(t *testing.T) {
prog, err := NewProgram(multiprogSpec)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
t.Cleanup(func() { prog.Close() })

info, err := prog.Info()
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))

// On kernels before 5.x, nr_jited_ksyms is not set for programs without subprogs.
// It's included here since this test uses a bpf program with subprogs.
if addrs, ok := info.JitedKsymAddrs(); testutils.IsKernelLessThan(t, "4.18") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(addrs) > 0))
}

if lens, ok := info.JitedFuncLens(); testutils.IsKernelLessThan(t, "4.18") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(lens) > 0))
}

if infos, ok := info.JitedLineInfos(); testutils.IsKernelLessThan(t, "5.0") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(infos) > 0))
}

if funcs, err := info.FuncInfos(); testutils.IsKernelLessThan(t, "5.0") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.HasLen(funcs, 2))
qt.Assert(t, qt.ContentEquals(funcs[0].Func, btfFn))
qt.Assert(t, qt.ContentEquals(funcs[1].Func, btfFn))
}

if lines, err := info.LineInfos(); testutils.IsKernelLessThan(t, "5.0") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.HasLen(lines, 2))
qt.Assert(t, qt.Equals(lines[0].Line.Line(), "line info"))
qt.Assert(t, qt.Equals(lines[1].Line.Line(), "line info"))
}
}

func TestProgramInfoMapIDs(t *testing.T) {
arr, err := NewMap(&MapSpec{
Type: Array,
Expand Down Expand Up @@ -495,55 +578,3 @@ func TestZero(t *testing.T) {
qt.Assert(t, qt.IsTrue(zero(&inul)))
qt.Assert(t, qt.IsFalse(zero(&ione)))
}

func TestProgInfoKsym(t *testing.T) {
testutils.SkipOnOldKernel(t, "4.18", "Program ksym addresses")

spec, err := LoadCollectionSpec(testutils.NativeFile(t, "testdata/loader-%s.elf"))
qt.Assert(t, qt.IsNil(err))

var obj struct {
Prog *Program `ebpf:"xdp_prog"`
}
err = spec.LoadAndAssign(&obj, nil)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
defer obj.Prog.Close()

info, err := obj.Prog.Info()
qt.Assert(t, qt.IsNil(err))

addrs, ok := info.JitedKsymAddrs()
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.HasLen(addrs, 5))
for _, addr := range addrs {
qt.Assert(t, qt.Not(qt.Equals(addr, 0)))
}
}

func TestProgInfoFuncInfos(t *testing.T) {
testutils.SkipOnOldKernel(t, "5.0", "Program func info")

spec, err := LoadCollectionSpec(testutils.NativeFile(t, "testdata/loader-%s.elf"))
qt.Assert(t, qt.IsNil(err))

var obj struct {
Prog *Program `ebpf:"xdp_prog"`
}
err = spec.LoadAndAssign(&obj, nil)
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
defer obj.Prog.Close()

info, err := obj.Prog.Info()
qt.Assert(t, qt.IsNil(err))

funcs, err := info.FuncInfos()
qt.Assert(t, qt.IsNil(err))

qt.Assert(t, qt.HasLen(funcs, 5))
for _, fo := range funcs {
qt.Assert(t, qt.IsNotNil(fo.Func))
qt.Assert(t, qt.Not(qt.Equals(fo.Func.Name, "")))
}
}

0 comments on commit 7514cdf

Please sign in to comment.