forked from cilium/ebpf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
linker_test.go
166 lines (139 loc) · 4.2 KB
/
linker_test.go
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
156
157
158
159
160
161
162
163
164
165
166
package ebpf
import (
"errors"
"testing"
"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/btf"
"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/testutils"
"github.com/go-quicktest/qt"
)
func TestFindReferences(t *testing.T) {
progs := map[string]*ProgramSpec{
"entrypoint": {
Type: SocketFilter,
Instructions: asm.Instructions{
// Make sure the call doesn't happen at instruction 0
// to exercise the relative offset calculation.
asm.Mov.Reg(asm.R0, asm.R1),
asm.Call.Label("my_func"),
asm.Return(),
},
License: "MIT",
},
"my_other_func": {
Instructions: asm.Instructions{
asm.LoadImm(asm.R0, 1337, asm.DWord).WithSymbol("my_other_func"),
asm.Return(),
},
},
"my_func": {
Instructions: asm.Instructions{
asm.Call.Label("my_other_func").WithSymbol("my_func"),
asm.Return(),
},
},
}
flattenPrograms(progs, []string{"entrypoint"})
prog, err := NewProgram(progs["entrypoint"])
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
}
defer prog.Close()
ret, _, err := prog.Test(internal.EmptyBPFContext)
if err != nil {
t.Fatal(err)
}
if ret != 1337 {
t.Errorf("Expected return code 1337, got %d", ret)
}
}
func TestForwardFunctionDeclaration(t *testing.T) {
testutils.Files(t, testutils.Glob(t, "testdata/fwd_decl-*.elf"), func(t *testing.T, file string) {
coll, err := LoadCollectionSpec(file)
if err != nil {
t.Fatal(err)
}
if coll.ByteOrder != internal.NativeEndian {
return
}
spec := coll.Programs["call_fwd"]
// This program calls an unimplemented forward function declaration.
_, err = NewProgram(spec)
if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) {
t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err)
}
// Append the implementation of fwd().
spec.Instructions = append(spec.Instructions,
asm.Mov.Imm32(asm.R0, 23).WithSymbol("fwd"),
asm.Return(),
)
// The body of the subprog we appended does not come with BTF func_infos,
// so the verifier will reject it. Load without BTF.
for i, ins := range spec.Instructions {
if btf.FuncMetadata(&ins) != nil || ins.Source() != nil {
sym := ins.Symbol()
ref := ins.Reference()
ins.Metadata = asm.Metadata{}
spec.Instructions[i] = ins.WithSymbol(sym).WithReference(ref)
}
}
prog, err := NewProgram(spec)
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatalf("%+v", err)
}
defer prog.Close()
ret, _, err := prog.Test(internal.EmptyBPFContext)
if err != nil {
t.Fatal("Running program:", err)
}
if ret != 23 {
t.Fatalf("Expected 23, got %d", ret)
}
})
}
func TestSplitSymbols(t *testing.T) {
// Splitting an empty insns results in an error.
_, err := splitSymbols(asm.Instructions{})
qt.Assert(t, qt.IsNotNil(err), qt.Commentf("empty insns"))
// Splitting non-empty insns without a leading Symbol is an error.
_, err = splitSymbols(asm.Instructions{
asm.Return(),
})
qt.Assert(t, qt.IsNotNil(err), qt.Commentf("insns without leading Symbol"))
// Non-empty insns with a single Instruction that is a Symbol.
insns := asm.Instructions{
asm.Return().WithSymbol("sym"),
}
m, err := splitSymbols(insns)
qt.Assert(t, qt.IsNil(err), qt.Commentf("insns with a single Symbol"))
qt.Assert(t, qt.HasLen(m, 1))
qt.Assert(t, qt.HasLen(m["sym"], 1))
// Insns containing duplicate Symbols.
_, err = splitSymbols(asm.Instructions{
asm.Return().WithSymbol("sym"),
asm.Return().WithSymbol("sym"),
})
qt.Assert(t, qt.IsNotNil(err), qt.Commentf("insns containing duplicate Symbols"))
// Insns with multiple Symbols and subprogs of various lengths.
m, err = splitSymbols(asm.Instructions{
asm.Return().WithSymbol("sym1"),
asm.Mov.Imm(asm.R0, 0).WithSymbol("sym2"),
asm.Return(),
asm.Mov.Imm(asm.R0, 0).WithSymbol("sym3"),
asm.Mov.Imm(asm.R0, 1),
asm.Return(),
asm.Mov.Imm(asm.R0, 0).WithSymbol("sym4"),
asm.Mov.Imm(asm.R0, 1),
asm.Mov.Imm(asm.R0, 2),
asm.Return(),
})
qt.Assert(t, qt.IsNil(err), qt.Commentf("insns with multiple Symbols"))
qt.Assert(t, qt.HasLen(m, 4))
qt.Assert(t, qt.HasLen(m["sym1"], 1))
qt.Assert(t, qt.HasLen(m["sym2"], 2))
qt.Assert(t, qt.HasLen(m["sym3"], 3))
qt.Assert(t, qt.HasLen(m["sym4"], 4))
}