Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

info: expose more prog jited info #1598

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Changes from 1 commit
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
Prev Previous commit
info: add tests for recent ProgramInfo API additions
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>
ti-mo committed Dec 4, 2024
commit 7514cdfe9abfd3cdea2c56f7f18d0a9b938760e7
135 changes: 83 additions & 52 deletions info_test.go
Original file line number Diff line number Diff line change
@@ -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,
@@ -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) {
@@ -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,
@@ -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, "")))
}
}
Loading