github.com/cilium/ebpf@v0.10.0/linker_test.go (about) 1 package ebpf 2 3 import ( 4 "errors" 5 "testing" 6 7 "github.com/cilium/ebpf/asm" 8 "github.com/cilium/ebpf/btf" 9 "github.com/cilium/ebpf/internal" 10 "github.com/cilium/ebpf/internal/testutils" 11 12 qt "github.com/frankban/quicktest" 13 ) 14 15 func TestFindReferences(t *testing.T) { 16 progs := map[string]*ProgramSpec{ 17 "entrypoint": { 18 Type: SocketFilter, 19 Instructions: asm.Instructions{ 20 // Make sure the call doesn't happen at instruction 0 21 // to exercise the relative offset calculation. 22 asm.Mov.Reg(asm.R0, asm.R1), 23 asm.Call.Label("my_func"), 24 asm.Return(), 25 }, 26 License: "MIT", 27 }, 28 "my_other_func": { 29 Instructions: asm.Instructions{ 30 asm.LoadImm(asm.R0, 1337, asm.DWord).WithSymbol("my_other_func"), 31 asm.Return(), 32 }, 33 }, 34 "my_func": { 35 Instructions: asm.Instructions{ 36 asm.Call.Label("my_other_func").WithSymbol("my_func"), 37 asm.Return(), 38 }, 39 }, 40 } 41 42 flattenPrograms(progs, []string{"entrypoint"}) 43 44 prog, err := NewProgram(progs["entrypoint"]) 45 testutils.SkipIfNotSupported(t, err) 46 if err != nil { 47 t.Fatal(err) 48 } 49 defer prog.Close() 50 51 ret, _, err := prog.Test(internal.EmptyBPFContext) 52 if err != nil { 53 t.Fatal(err) 54 } 55 56 if ret != 1337 { 57 t.Errorf("Expected return code 1337, got %d", ret) 58 } 59 } 60 61 func TestForwardFunctionDeclaration(t *testing.T) { 62 testutils.Files(t, testutils.Glob(t, "testdata/fwd_decl-*.elf"), func(t *testing.T, file string) { 63 coll, err := LoadCollectionSpec(file) 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 if coll.ByteOrder != internal.NativeEndian { 69 return 70 } 71 72 spec := coll.Programs["call_fwd"] 73 74 // This program calls an unimplemented forward function declaration. 75 _, err = NewProgram(spec) 76 if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) { 77 t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err) 78 } 79 80 // Append the implementation of fwd(). 81 spec.Instructions = append(spec.Instructions, 82 asm.Mov.Imm32(asm.R0, 23).WithSymbol("fwd"), 83 asm.Return(), 84 ) 85 86 // The body of the subprog we appended does not come with BTF func_infos, 87 // so the verifier will reject it. Load without BTF. 88 for i, ins := range spec.Instructions { 89 if btf.FuncMetadata(&ins) != nil || ins.Source() != nil { 90 sym := ins.Symbol() 91 ref := ins.Reference() 92 ins.Metadata = asm.Metadata{} 93 spec.Instructions[i] = ins.WithSymbol(sym).WithReference(ref) 94 } 95 } 96 97 prog, err := NewProgram(spec) 98 testutils.SkipIfNotSupported(t, err) 99 if err != nil { 100 t.Fatalf("%+v", err) 101 } 102 defer prog.Close() 103 104 ret, _, err := prog.Test(internal.EmptyBPFContext) 105 if err != nil { 106 t.Fatal("Running program:", err) 107 } 108 if ret != 23 { 109 t.Fatalf("Expected 23, got %d", ret) 110 } 111 }) 112 } 113 114 func TestSplitSymbols(t *testing.T) { 115 c := qt.New(t) 116 117 // Splitting an empty insns results in an error. 118 _, err := splitSymbols(asm.Instructions{}) 119 c.Assert(err, qt.IsNotNil, qt.Commentf("empty insns")) 120 121 // Splitting non-empty insns without a leading Symbol is an error. 122 _, err = splitSymbols(asm.Instructions{ 123 asm.Return(), 124 }) 125 c.Assert(err, qt.IsNotNil, qt.Commentf("insns without leading Symbol")) 126 127 // Non-empty insns with a single Instruction that is a Symbol. 128 insns := asm.Instructions{ 129 asm.Return().WithSymbol("sym"), 130 } 131 m, err := splitSymbols(insns) 132 c.Assert(err, qt.IsNil, qt.Commentf("insns with a single Symbol")) 133 134 c.Assert(len(m), qt.Equals, 1) 135 c.Assert(len(m["sym"]), qt.Equals, 1) 136 137 // Insns containing duplicate Symbols. 138 _, err = splitSymbols(asm.Instructions{ 139 asm.Return().WithSymbol("sym"), 140 asm.Return().WithSymbol("sym"), 141 }) 142 c.Assert(err, qt.IsNotNil, qt.Commentf("insns containing duplicate Symbols")) 143 144 // Insns with multiple Symbols and subprogs of various lengths. 145 m, err = splitSymbols(asm.Instructions{ 146 asm.Return().WithSymbol("sym1"), 147 148 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym2"), 149 asm.Return(), 150 151 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym3"), 152 asm.Mov.Imm(asm.R0, 1), 153 asm.Return(), 154 155 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym4"), 156 asm.Mov.Imm(asm.R0, 1), 157 asm.Mov.Imm(asm.R0, 2), 158 asm.Return(), 159 }) 160 c.Assert(err, qt.IsNil, qt.Commentf("insns with multiple Symbols")) 161 162 c.Assert(len(m), qt.Equals, 4) 163 c.Assert(len(m["sym1"]), qt.Equals, 1) 164 c.Assert(len(m["sym2"]), qt.Equals, 2) 165 c.Assert(len(m["sym3"]), qt.Equals, 3) 166 c.Assert(len(m["sym4"]), qt.Equals, 4) 167 }