1 // Copyright 2015 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package report 5 6 import ( 7 "fmt" 8 "testing" 9 10 "github.com/google/syzkaller/pkg/mgrconfig" 11 "github.com/google/syzkaller/pkg/symbolizer" 12 ) 13 14 func TestLinuxIgnores(t *testing.T) { 15 cfg := &mgrconfig.Config{ 16 TargetOS: "linux", 17 } 18 reporter, err := NewReporter(cfg) 19 if err != nil { 20 t.Fatal(err) 21 } 22 cfg.Ignores = []string{"BUG: bug3"} 23 reporter1, err := NewReporter(cfg) 24 if err != nil { 25 t.Fatal(err) 26 } 27 cfg.Ignores = []string{"BUG: bug3", "BUG: bug1"} 28 reporter2, err := NewReporter(cfg) 29 if err != nil { 30 t.Fatal(err) 31 } 32 cfg.Ignores = []string{"BUG: bug3", "BUG: bug1", "BUG: bug2"} 33 reporter3, err := NewReporter(cfg) 34 if err != nil { 35 t.Fatal(err) 36 } 37 38 const log = ` 39 [ 0.000000] BUG: bug1 40 [ 0.000000] BUG: bug2 41 ` 42 if !reporter.ContainsCrash([]byte(log)) { 43 t.Fatalf("no crash") 44 } 45 if rep := reporter.Parse([]byte(log)); rep.Title != "BUG: bug1" { 46 t.Fatalf("want `BUG: bug1`, found `%v`", rep.Title) 47 } 48 49 if !reporter1.ContainsCrash([]byte(log)) { 50 t.Fatalf("no crash") 51 } 52 if rep := reporter1.Parse([]byte(log)); rep.Title != "BUG: bug1" { 53 t.Fatalf("want `BUG: bug1`, found `%v`", rep.Title) 54 } 55 56 if !reporter2.ContainsCrash([]byte(log)) { 57 t.Fatalf("no crash") 58 } 59 if rep := reporter2.Parse([]byte(log)); rep.Title != "BUG: bug2" { 60 t.Fatalf("want `BUG: bug2`, found `%v`", rep.Title) 61 } 62 63 if reporter3.ContainsCrash([]byte(log)) { 64 t.Fatalf("found crash, should be ignored") 65 } 66 if rep := reporter3.Parse([]byte(log)); rep != nil { 67 t.Fatalf("found `%v`, should be ignored", rep.Title) 68 } 69 } 70 71 func TestLinuxSymbolizeLine(t *testing.T) { 72 tests := []struct { 73 line string 74 result string 75 }{ 76 // Normal symbolization. 77 { 78 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x101/0x185\n", 79 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x101/0x185 foo.c:555\n", 80 }, 81 { 82 "RIP: 0010:[<ffffffff8188c0e6>] [<ffffffff8188c0e6>] foo+0x101/0x185\n", 83 "RIP: 0010:[<ffffffff8188c0e6>] [<ffffffff8188c0e6>] foo+0x101/0x185 foo.c:555\n", 84 }, 85 // Strip "./" file prefix. 86 { 87 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x111/0x185\n", 88 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x111/0x185 foo.h:111\n", 89 }, 90 // Needs symbolization, but symbolizer returns nothing. 91 { 92 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x121/0x185\n", 93 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x121/0x185\n", 94 }, 95 // Needs symbolization, but symbolizer returns error. 96 { 97 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x131/0x185\n", 98 "[ 2713.153531] [<ffffffff82d1b1d9>] foo+0x131/0x185\n", 99 }, 100 // Needs symbolization, but symbol is missing. 101 { 102 "[ 2713.153531] [<ffffffff82d1b1d9>] bar+0x131/0x185\n", 103 "[ 2713.153531] [<ffffffff82d1b1d9>] bar+0x131/0x185\n", 104 }, 105 // Bad offset. 106 { 107 "[ 2713.153531] [<ffffffff82d1b1d9>] bar+0xffffffffffffffffffff/0x185\n", 108 "[ 2713.153531] [<ffffffff82d1b1d9>] bar+0xffffffffffffffffffff/0x185\n", 109 }, 110 // Should not be symbolized. 111 { 112 "WARNING: CPU: 2 PID: 2636 at ipc/shm.c:162 foo+0x101/0x185\n", 113 "WARNING: CPU: 2 PID: 2636 at ipc/shm.c:162 foo+0x101/0x185 foo.c:555\n", 114 }, 115 // Tricky function name. 116 { 117 " [<ffffffff84e5bea0>] do_ipv6_setsockopt.isra.7.part.3+0x101/0x2830 \n", 118 " [<ffffffff84e5bea0>] do_ipv6_setsockopt.isra.7.part.3+0x101/0x2830 net.c:111 \n", 119 }, 120 // Old KASAN frame format (with tab). 121 { 122 "[ 50.419727] baz+0x101/0x200\n", 123 "[ 50.419727] baz+0x101/0x200 baz.c:100\n", 124 }, 125 // Inlined frames. 126 { 127 " [<ffffffff84e5bea0>] foo+0x141/0x185\n", 128 " [<ffffffff84e5bea0>] inlined1 net.c:111 [inline]\n" + 129 " [<ffffffff84e5bea0>] inlined2 mm.c:222 [inline]\n" + 130 " [<ffffffff84e5bea0>] foo+0x141/0x185 kasan.c:333\n", 131 }, 132 // Several symbols with the same name. 133 { 134 "[<ffffffff82d1b1d9>] baz+0x101/0x200\n", 135 "[<ffffffff82d1b1d9>] baz+0x101/0x200 baz.c:100\n", 136 }, 137 } 138 symbols := map[string][]symbolizer.Symbol{ 139 "foo": { 140 {Addr: 0x1000000, Size: 0x190}, 141 }, 142 "do_ipv6_setsockopt.isra.7.part.3": { 143 {Addr: 0x2000000, Size: 0x2830}, 144 }, 145 "baz": { 146 {Addr: 0x3000000, Size: 0x100}, 147 {Addr: 0x4000000, Size: 0x200}, 148 {Addr: 0x5000000, Size: 0x300}, 149 }, 150 } 151 symb := func(bin string, pc uint64) ([]symbolizer.Frame, error) { 152 if bin != "vmlinux" { 153 return nil, fmt.Errorf("unknown pc 0x%x", pc) 154 } 155 switch pc { 156 case 0x1000100: 157 return []symbolizer.Frame{ 158 { 159 File: "/linux/foo.c", 160 Line: 555, 161 }, 162 }, nil 163 case 0x1000110: 164 return []symbolizer.Frame{ 165 { 166 File: "/linux/./foo.h", 167 Line: 111, 168 }, 169 }, nil 170 case 0x1000120: 171 return nil, nil 172 case 0x1000130: 173 return nil, fmt.Errorf("unknown pc 0x%x", pc) 174 case 0x2000100: 175 return []symbolizer.Frame{ 176 { 177 File: "/linux/net.c", 178 Line: 111, 179 }, 180 }, nil 181 case 0x1000140: 182 return []symbolizer.Frame{ 183 { 184 Func: "inlined1", 185 File: "/linux/net.c", 186 Line: 111, 187 Inline: true, 188 }, 189 { 190 Func: "inlined2", 191 File: "/linux/mm.c", 192 Line: 222, 193 Inline: true, 194 }, 195 { 196 Func: "noninlined3", 197 File: "/linux/kasan.c", 198 Line: 333, 199 Inline: false, 200 }, 201 }, nil 202 case 0x4000100: 203 return []symbolizer.Frame{ 204 { 205 File: "/linux/baz.c", 206 Line: 100, 207 }, 208 }, nil 209 default: 210 return nil, fmt.Errorf("unknown pc 0x%x", pc) 211 } 212 } 213 for i, test := range tests { 214 t.Run(fmt.Sprint(i), func(t *testing.T) { 215 result := symbolizeLine(symb, symbols, "vmlinux", "/linux/", []byte(test.line)) 216 if test.result != string(result) { 217 t.Errorf("want %q\n\t get %q", test.result, string(result)) 218 } 219 }) 220 } 221 } 222