1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
package link
import (
"errors"
"os"
"testing"
"github.com/go-quicktest/qt"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/internal/testutils"
"github.com/cilium/ebpf/internal/unix"
)
var kprobeMultiSyms = []string{"vprintk", "inet6_release"}
func TestKprobeMulti(t *testing.T) {
testutils.SkipIfNotSupported(t, haveBPFLinkKprobeMulti())
prog := mustLoadProgram(t, ebpf.Kprobe, ebpf.AttachTraceKprobeMulti, "")
km, err := KprobeMulti(prog, KprobeMultiOptions{Symbols: kprobeMultiSyms})
if err != nil {
t.Fatal(err)
}
defer km.Close()
testLink(t, km, prog)
}
func TestKprobeMultiInput(t *testing.T) {
// Program type that loads on all kernels. Not expected to link successfully.
prog := mustLoadProgram(t, ebpf.SocketFilter, 0, "")
// One of Symbols or Addresses must be given.
_, err := KprobeMulti(prog, KprobeMultiOptions{})
if !errors.Is(err, errInvalidInput) {
t.Fatalf("expected errInvalidInput, got: %v", err)
}
// Symbols and Addresses are mutually exclusive.
_, err = KprobeMulti(prog, KprobeMultiOptions{
Symbols: []string{"foo"},
Addresses: []uintptr{1},
})
if !errors.Is(err, errInvalidInput) {
t.Fatalf("expected errInvalidInput, got: %v", err)
}
// One Symbol, two cookies..
_, err = KprobeMulti(prog, KprobeMultiOptions{
Symbols: []string{"one"},
Cookies: []uint64{2, 3},
})
if !errors.Is(err, errInvalidInput) {
t.Fatalf("expected errInvalidInput, got: %v", err)
}
}
func TestKprobeMultiErrors(t *testing.T) {
testutils.SkipIfNotSupported(t, haveBPFLinkKprobeMulti())
prog := mustLoadProgram(t, ebpf.Kprobe, ebpf.AttachTraceKprobeMulti, "")
// Nonexistent kernel symbol.
_, err := KprobeMulti(prog, KprobeMultiOptions{Symbols: []string{"bogus"}})
if !errors.Is(err, os.ErrNotExist) && !errors.Is(err, unix.EINVAL) {
t.Fatalf("expected ErrNotExist or EINVAL, got: %s", err)
}
// Only have a negative test for addresses as it would be hard to maintain a
// proper one.
if _, err := KprobeMulti(prog, KprobeMultiOptions{
Addresses: []uintptr{^uintptr(0)},
}); !errors.Is(err, unix.EINVAL) {
t.Fatalf("expected EINVAL, got: %s", err)
}
}
func TestKprobeMultiCookie(t *testing.T) {
testutils.SkipIfNotSupported(t, haveBPFLinkKprobeMulti())
prog := mustLoadProgram(t, ebpf.Kprobe, ebpf.AttachTraceKprobeMulti, "")
km, err := KprobeMulti(prog, KprobeMultiOptions{
Symbols: kprobeMultiSyms,
Cookies: []uint64{0, 1},
})
if err != nil {
t.Fatal(err)
}
_ = km.Close()
}
func TestKprobeMultiProgramCall(t *testing.T) {
testutils.SkipIfNotSupported(t, haveBPFLinkKprobeMulti())
m, p := newUpdaterMapProg(t, ebpf.Kprobe, ebpf.AttachTraceKprobeMulti)
// For simplicity, just assert the increment happens with any symbol in the array.
opts := KprobeMultiOptions{
Symbols: []string{"__do_sys_getpid", "__do_sys_gettid"},
}
km, err := KprobeMulti(p, opts)
if err != nil {
t.Fatal(err)
}
// Trigger ebpf program call.
unix.Getpid()
unix.Gettid()
// Assert that the value got incremented to at least 2, while allowing
// for bigger values, because we could race with other getpid/gettid
// callers.
assertMapValueGE(t, m, 0, 2)
// Close the link.
if err := km.Close(); err != nil {
t.Fatal(err)
}
// Reset map value to 0 at index 0.
if err := m.Update(uint32(0), uint32(0), ebpf.UpdateExist); err != nil {
t.Fatal(err)
}
// Retrigger the ebpf program call.
unix.Getpid()
unix.Gettid()
// Assert that this time the value has not been updated.
assertMapValue(t, m, 0, 0)
}
func TestHaveBPFLinkKprobeMulti(t *testing.T) {
testutils.CheckFeatureTest(t, haveBPFLinkKprobeMulti)
}
func TestKprobeSession(t *testing.T) {
testutils.SkipIfNotSupported(t, haveBPFLinkKprobeMulti())
prog := mustLoadProgram(t, ebpf.Kprobe, ebpf.AttachTraceKprobeSession, "")
km, err := KprobeMulti(prog, KprobeMultiOptions{Symbols: kprobeMultiSyms, Session: true})
testutils.SkipIfNotSupported(t, err)
qt.Assert(t, qt.IsNil(err))
defer km.Close()
testLink(t, km, prog)
}
func TestHaveBPFLinkKprobeSession(t *testing.T) {
testutils.CheckFeatureTest(t, haveBPFLinkKprobeSession)
}
|