...

Source file src/github.com/cilium/ebpf/linker_test.go

Documentation: github.com/cilium/ebpf

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

View as plain text