github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/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 "github.com/go-quicktest/qt" 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 file := testutils.NativeFile(t, "testdata/fwd_decl-%s.elf") 63 coll, err := LoadCollectionSpec(file) 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 spec := coll.Programs["call_fwd"] 69 70 // This program calls an unimplemented forward function declaration. 71 _, err = NewProgram(spec) 72 if !errors.Is(err, asm.ErrUnsatisfiedProgramReference) { 73 t.Fatal("Expected an error wrapping ErrUnsatisfiedProgramReference, got:", err) 74 } 75 76 // Append the implementation of fwd(). 77 spec.Instructions = append(spec.Instructions, 78 asm.Mov.Imm32(asm.R0, 23).WithSymbol("fwd"), 79 asm.Return(), 80 ) 81 82 // The body of the subprog we appended does not come with BTF func_infos, 83 // so the verifier will reject it. Load without BTF. 84 for i, ins := range spec.Instructions { 85 if btf.FuncMetadata(&ins) != nil || ins.Source() != nil { 86 sym := ins.Symbol() 87 ref := ins.Reference() 88 ins.Metadata = asm.Metadata{} 89 spec.Instructions[i] = ins.WithSymbol(sym).WithReference(ref) 90 } 91 } 92 93 prog, err := NewProgram(spec) 94 testutils.SkipIfNotSupported(t, err) 95 if err != nil { 96 t.Fatalf("%+v", err) 97 } 98 defer prog.Close() 99 100 ret, _, err := prog.Test(internal.EmptyBPFContext) 101 if err != nil { 102 t.Fatal("Running program:", err) 103 } 104 if ret != 23 { 105 t.Fatalf("Expected 23, got %d", ret) 106 } 107 } 108 109 func TestSplitSymbols(t *testing.T) { 110 111 // Splitting an empty insns results in an error. 112 _, err := splitSymbols(asm.Instructions{}) 113 qt.Assert(t, qt.IsNotNil(err), qt.Commentf("empty insns")) 114 115 // Splitting non-empty insns without a leading Symbol is an error. 116 _, err = splitSymbols(asm.Instructions{ 117 asm.Return(), 118 }) 119 qt.Assert(t, qt.IsNotNil(err), qt.Commentf("insns without leading Symbol")) 120 121 // Non-empty insns with a single Instruction that is a Symbol. 122 insns := asm.Instructions{ 123 asm.Return().WithSymbol("sym"), 124 } 125 m, err := splitSymbols(insns) 126 qt.Assert(t, qt.IsNil(err), qt.Commentf("insns with a single Symbol")) 127 128 qt.Assert(t, qt.HasLen(m, 1)) 129 qt.Assert(t, qt.HasLen(m["sym"], 1)) 130 131 // Insns containing duplicate Symbols. 132 _, err = splitSymbols(asm.Instructions{ 133 asm.Return().WithSymbol("sym"), 134 asm.Return().WithSymbol("sym"), 135 }) 136 qt.Assert(t, qt.IsNotNil(err), qt.Commentf("insns containing duplicate Symbols")) 137 138 // Insns with multiple Symbols and subprogs of various lengths. 139 m, err = splitSymbols(asm.Instructions{ 140 asm.Return().WithSymbol("sym1"), 141 142 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym2"), 143 asm.Return(), 144 145 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym3"), 146 asm.Mov.Imm(asm.R0, 1), 147 asm.Return(), 148 149 asm.Mov.Imm(asm.R0, 0).WithSymbol("sym4"), 150 asm.Mov.Imm(asm.R0, 1), 151 asm.Mov.Imm(asm.R0, 2), 152 asm.Return(), 153 }) 154 qt.Assert(t, qt.IsNil(err), qt.Commentf("insns with multiple Symbols")) 155 156 qt.Assert(t, qt.HasLen(m, 4)) 157 qt.Assert(t, qt.HasLen(m["sym1"], 1)) 158 qt.Assert(t, qt.HasLen(m["sym2"], 2)) 159 qt.Assert(t, qt.HasLen(m["sym3"], 3)) 160 qt.Assert(t, qt.HasLen(m["sym4"], 4)) 161 }