github.com/cilium/ebpf@v0.10.0/internal/errors_test.go (about) 1 package internal 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "syscall" 8 "testing" 9 10 "github.com/cilium/ebpf/internal/unix" 11 qt "github.com/frankban/quicktest" 12 ) 13 14 func TestVerifierErrorWhitespace(t *testing.T) { 15 b := []byte("unreachable insn 28") 16 b = append(b, 17 0xa, // \n 18 0xd, // \r 19 0x9, // \t 20 0x20, // space 21 0, 0, // trailing NUL bytes 22 ) 23 24 err := ErrorWithLog("frob", errors.New("test"), b, false) 25 qt.Assert(t, err.Error(), qt.Equals, "frob: test: unreachable insn 28") 26 27 for _, log := range [][]byte{ 28 nil, 29 []byte("\x00"), 30 []byte(" "), 31 } { 32 err = ErrorWithLog("frob", errors.New("test"), log, false) 33 qt.Assert(t, err.Error(), qt.Equals, "frob: test", qt.Commentf("empty log %q has incorrect format", log)) 34 } 35 } 36 37 func TestVerifierErrorWrapping(t *testing.T) { 38 ve := ErrorWithLog("frob", unix.ENOENT, nil, false) 39 qt.Assert(t, ve, qt.ErrorIs, unix.ENOENT, qt.Commentf("should wrap provided error")) 40 qt.Assert(t, ve.Truncated, qt.IsFalse, qt.Commentf("verifier log should not be marked as truncated")) 41 42 ve = ErrorWithLog("frob", unix.EINVAL, nil, true) 43 qt.Assert(t, ve, qt.ErrorIs, unix.EINVAL, qt.Commentf("should wrap provided error")) 44 qt.Assert(t, ve.Truncated, qt.IsTrue, qt.Commentf("verifier log should be marked as truncated")) 45 46 ve = ErrorWithLog("frob", unix.EINVAL, []byte("foo"), false) 47 qt.Assert(t, ve, qt.ErrorIs, unix.EINVAL, qt.Commentf("should wrap provided error")) 48 qt.Assert(t, ve.Error(), qt.Contains, "foo", qt.Commentf("verifier log should appear in error string")) 49 50 ve = ErrorWithLog("frob", unix.ENOSPC, []byte("foo"), true) 51 qt.Assert(t, ve, qt.ErrorIs, unix.ENOSPC, qt.Commentf("should wrap provided error")) 52 qt.Assert(t, ve.Error(), qt.Contains, "foo", qt.Commentf("verifier log should appear in error string")) 53 qt.Assert(t, ve.Truncated, qt.IsTrue, qt.Commentf("verifier log should be marked truncated")) 54 } 55 56 func TestVerifierErrorSummary(t *testing.T) { 57 // Suppress the last line containing 'processed ... insns'. 58 errno524 := readErrorFromFile(t, "testdata/errno524.log") 59 qt.Assert(t, errno524.Error(), qt.Contains, "JIT doesn't support bpf-to-bpf calls") 60 qt.Assert(t, errno524.Error(), qt.Not(qt.Contains), "processed 39 insns") 61 62 // Include the previous line if the current one starts with a tab. 63 invalidMember := readErrorFromFile(t, "testdata/invalid-member.log") 64 qt.Assert(t, invalidMember.Error(), qt.Contains, "STRUCT task_struct size=7744 vlen=218: cpus_mask type_id=109 bitfield_size=0 bits_offset=7744 Invalid member") 65 66 // Only include the last line. 67 issue43 := readErrorFromFile(t, "testdata/issue-43.log") 68 qt.Assert(t, issue43.Error(), qt.Contains, "[11] FUNC helper_func2 type_id=10 vlen != 0") 69 qt.Assert(t, issue43.Error(), qt.Not(qt.Contains), "[10] FUNC_PROTO (anon) return=3 args=(3 arg)") 70 71 // Include instruction that caused invalid register access. 72 invalidR0 := readErrorFromFile(t, "testdata/invalid-R0.log") 73 qt.Assert(t, invalidR0.Error(), qt.Contains, "0: (95) exit: R0 !read_ok") 74 75 // Include symbol that doesn't match context type. 76 invalidCtx := readErrorFromFile(t, "testdata/invalid-ctx-access.log") 77 qt.Assert(t, invalidCtx.Error(), qt.Contains, "func '__x64_sys_recvfrom' arg0 type FWD is not a struct: invalid bpf_context access off=0 size=8") 78 } 79 80 func ExampleVerifierError() { 81 err := &VerifierError{ 82 source: "catastrophe", 83 Cause: syscall.ENOSPC, 84 Log: []string{"first", "second", "third"}, 85 Truncated: false, 86 } 87 88 fmt.Printf("With %%s: %s\n", err) 89 err.Truncated = true 90 fmt.Printf("With %%v and a truncated log: %v\n", err) 91 fmt.Printf("All log lines: %+v\n", err) 92 fmt.Printf("First line: %+1v\n", err) 93 fmt.Printf("Last two lines: %-2v\n", err) 94 95 // Output: With %s: catastrophe: no space left on device: third (2 line(s) omitted) 96 // With %v and a truncated log: catastrophe: no space left on device: second: third (truncated, 1 line(s) omitted) 97 // All log lines: catastrophe: no space left on device: 98 // first 99 // second 100 // third 101 // (truncated) 102 // First line: catastrophe: no space left on device: 103 // first 104 // (2 line(s) omitted) 105 // (truncated) 106 // Last two lines: catastrophe: no space left on device: 107 // (1 line(s) omitted) 108 // second 109 // third 110 // (truncated) 111 } 112 113 func readErrorFromFile(tb testing.TB, file string) *VerifierError { 114 tb.Helper() 115 116 contents, err := os.ReadFile(file) 117 if err != nil { 118 tb.Fatal("Read file:", err) 119 } 120 121 return ErrorWithLog("file", unix.EINVAL, contents, false) 122 }