github.com/cilium/ebpf@v0.16.0/internal/errors_test.go (about)

     1  package internal
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/go-quicktest/qt"
     9  
    10  	"github.com/cilium/ebpf/internal/unix"
    11  )
    12  
    13  func TestVerifierErrorWhitespace(t *testing.T) {
    14  	b := []byte("unreachable insn 28")
    15  	b = append(b,
    16  		0xa,  // \n
    17  		0xd,  // \r
    18  		0x9,  // \t
    19  		0x20, // space
    20  		0, 0, // trailing NUL bytes
    21  	)
    22  
    23  	err := ErrorWithLog("frob", errors.New("test"), b)
    24  	qt.Assert(t, qt.Equals(err.Error(), "frob: test: unreachable insn 28"))
    25  
    26  	for _, log := range [][]byte{
    27  		nil,
    28  		[]byte("\x00"),
    29  		[]byte(" "),
    30  	} {
    31  		err = ErrorWithLog("frob", errors.New("test"), log)
    32  		qt.Assert(t, qt.Equals(err.Error(), "frob: test"), qt.Commentf("empty log %q has incorrect format", log))
    33  	}
    34  }
    35  
    36  func TestVerifierErrorWrapping(t *testing.T) {
    37  	ve := ErrorWithLog("frob", unix.ENOENT, nil)
    38  	qt.Assert(t, qt.ErrorIs(ve, unix.ENOENT), qt.Commentf("should wrap provided error"))
    39  
    40  	ve = ErrorWithLog("frob", unix.EINVAL, nil)
    41  	qt.Assert(t, qt.ErrorIs(ve, unix.EINVAL), qt.Commentf("should wrap provided error"))
    42  
    43  	ve = ErrorWithLog("frob", unix.EINVAL, []byte("foo"))
    44  	qt.Assert(t, qt.ErrorIs(ve, unix.EINVAL), qt.Commentf("should wrap provided error"))
    45  	qt.Assert(t, qt.StringContains(ve.Error(), "foo"), qt.Commentf("verifier log should appear in error string"))
    46  
    47  	ve = ErrorWithLog("frob", unix.ENOSPC, []byte("foo"))
    48  	qt.Assert(t, qt.ErrorIs(ve, unix.ENOSPC), qt.Commentf("should wrap provided error"))
    49  	qt.Assert(t, qt.StringContains(ve.Error(), "foo"), qt.Commentf("verifier log should appear in error string"))
    50  }
    51  
    52  func TestVerifierErrorSummary(t *testing.T) {
    53  	// Suppress the last line containing 'processed ... insns'.
    54  	errno524 := readErrorFromFile(t, "testdata/errno524.log")
    55  	qt.Assert(t, qt.StringContains(errno524.Error(), "JIT doesn't support bpf-to-bpf calls"))
    56  	qt.Assert(t, qt.Not(qt.StringContains(errno524.Error(), "processed 39 insns")))
    57  
    58  	// Include the previous line if the current one starts with a tab.
    59  	invalidMember := readErrorFromFile(t, "testdata/invalid-member.log")
    60  	qt.Assert(t, qt.StringContains(invalidMember.Error(), "STRUCT task_struct size=7744 vlen=218: cpus_mask type_id=109 bitfield_size=0 bits_offset=7744 Invalid member"))
    61  
    62  	// Only include the last line.
    63  	issue43 := readErrorFromFile(t, "testdata/issue-43.log")
    64  	qt.Assert(t, qt.StringContains(issue43.Error(), "[11] FUNC helper_func2 type_id=10 vlen != 0"))
    65  	qt.Assert(t, qt.Not(qt.StringContains(issue43.Error(), "[10] FUNC_PROTO (anon) return=3 args=(3 arg)")))
    66  
    67  	// Include instruction that caused invalid register access.
    68  	invalidR0 := readErrorFromFile(t, "testdata/invalid-R0.log")
    69  	qt.Assert(t, qt.StringContains(invalidR0.Error(), "0: (95) exit: R0 !read_ok"))
    70  
    71  	// Include symbol that doesn't match context type.
    72  	invalidCtx := readErrorFromFile(t, "testdata/invalid-ctx-access.log")
    73  	qt.Assert(t, qt.StringContains(invalidCtx.Error(), "func '__x64_sys_recvfrom' arg0 type FWD is not a struct: invalid bpf_context access off=0 size=8"))
    74  }
    75  
    76  func readErrorFromFile(tb testing.TB, file string) *VerifierError {
    77  	tb.Helper()
    78  
    79  	contents, err := os.ReadFile(file)
    80  	if err != nil {
    81  		tb.Fatal("Read file:", err)
    82  	}
    83  
    84  	return ErrorWithLog("file", unix.EINVAL, contents)
    85  }