// Copyright 2015 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package report import ( "fmt" "testing" "github.com/google/syzkaller/pkg/mgrconfig" "github.com/google/syzkaller/pkg/symbolizer" ) func TestLinuxIgnores(t *testing.T) { cfg := &mgrconfig.Config{ TargetOS: "linux", } reporter, err := NewReporter(cfg) if err != nil { t.Fatal(err) } cfg.Ignores = []string{"BUG: bug3"} reporter1, err := NewReporter(cfg) if err != nil { t.Fatal(err) } cfg.Ignores = []string{"BUG: bug3", "BUG: bug1"} reporter2, err := NewReporter(cfg) if err != nil { t.Fatal(err) } cfg.Ignores = []string{"BUG: bug3", "BUG: bug1", "BUG: bug2"} reporter3, err := NewReporter(cfg) if err != nil { t.Fatal(err) } const log = ` [ 0.000000] BUG: bug1 [ 0.000000] BUG: bug2 ` if !reporter.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } if rep := reporter.Parse([]byte(log)); rep.Title != "BUG: bug1" { t.Fatalf("want `BUG: bug1`, found `%v`", rep.Title) } if !reporter1.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } if rep := reporter1.Parse([]byte(log)); rep.Title != "BUG: bug1" { t.Fatalf("want `BUG: bug1`, found `%v`", rep.Title) } if !reporter2.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } if rep := reporter2.Parse([]byte(log)); rep.Title != "BUG: bug2" { t.Fatalf("want `BUG: bug2`, found `%v`", rep.Title) } if reporter3.ContainsCrash([]byte(log)) { t.Fatalf("found crash, should be ignored") } if rep := reporter3.Parse([]byte(log)); rep != nil { t.Fatalf("found `%v`, should be ignored", rep.Title) } } func TestLinuxSymbolizeLine(t *testing.T) { tests := []struct { line string result string }{ // Normal symbolization. { "[ 2713.153531] [] foo+0x101/0x185\n", "[ 2713.153531] [] foo+0x101/0x185 foo.c:555\n", }, { "RIP: 0010:[] [] foo+0x101/0x185\n", "RIP: 0010:[] [] foo+0x101/0x185 foo.c:555\n", }, // Strip "./" file prefix. { "[ 2713.153531] [] foo+0x111/0x185\n", "[ 2713.153531] [] foo+0x111/0x185 foo.h:111\n", }, // Needs symbolization, but symbolizer returns nothing. { "[ 2713.153531] [] foo+0x121/0x185\n", "[ 2713.153531] [] foo+0x121/0x185\n", }, // Needs symbolization, but symbolizer returns error. { "[ 2713.153531] [] foo+0x131/0x185\n", "[ 2713.153531] [] foo+0x131/0x185\n", }, // Needs symbolization, but symbol is missing. { "[ 2713.153531] [] bar+0x131/0x185\n", "[ 2713.153531] [] bar+0x131/0x185\n", }, // Bad offset. { "[ 2713.153531] [] bar+0xffffffffffffffffffff/0x185\n", "[ 2713.153531] [] bar+0xffffffffffffffffffff/0x185\n", }, // Should not be symbolized. { "WARNING: CPU: 2 PID: 2636 at ipc/shm.c:162 foo+0x101/0x185\n", "WARNING: CPU: 2 PID: 2636 at ipc/shm.c:162 foo+0x101/0x185 foo.c:555\n", }, // Tricky function name. { " [] do_ipv6_setsockopt.isra.7.part.3+0x101/0x2830 \n", " [] do_ipv6_setsockopt.isra.7.part.3+0x101/0x2830 net.c:111 \n", }, // Old KASAN frame format (with tab). { "[ 50.419727] baz+0x101/0x200\n", "[ 50.419727] baz+0x101/0x200 baz.c:100\n", }, // Inlined frames. { " [] foo+0x141/0x185\n", " [] inlined1 net.c:111 [inline]\n" + " [] inlined2 mm.c:222 [inline]\n" + " [] foo+0x141/0x185 kasan.c:333\n", }, // Several symbols with the same name. { "[] baz+0x101/0x200\n", "[] baz+0x101/0x200 baz.c:100\n", }, } symbols := map[string][]symbolizer.Symbol{ "foo": { {Addr: 0x1000000, Size: 0x190}, }, "do_ipv6_setsockopt.isra.7.part.3": { {Addr: 0x2000000, Size: 0x2830}, }, "baz": { {Addr: 0x3000000, Size: 0x100}, {Addr: 0x4000000, Size: 0x200}, {Addr: 0x5000000, Size: 0x300}, }, } symb := func(bin string, pc uint64) ([]symbolizer.Frame, error) { if bin != "vmlinux" { return nil, fmt.Errorf("unknown pc 0x%x", pc) } switch pc { case 0x1000100: return []symbolizer.Frame{ { File: "/linux/foo.c", Line: 555, }, }, nil case 0x1000110: return []symbolizer.Frame{ { File: "/linux/./foo.h", Line: 111, }, }, nil case 0x1000120: return nil, nil case 0x1000130: return nil, fmt.Errorf("unknown pc 0x%x", pc) case 0x2000100: return []symbolizer.Frame{ { File: "/linux/net.c", Line: 111, }, }, nil case 0x1000140: return []symbolizer.Frame{ { Func: "inlined1", File: "/linux/net.c", Line: 111, Inline: true, }, { Func: "inlined2", File: "/linux/mm.c", Line: 222, Inline: true, }, { Func: "noninlined3", File: "/linux/kasan.c", Line: 333, Inline: false, }, }, nil case 0x4000100: return []symbolizer.Frame{ { File: "/linux/baz.c", Line: 100, }, }, nil default: return nil, fmt.Errorf("unknown pc 0x%x", pc) } } for i, test := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { result := symbolizeLine(symb, symbols, "vmlinux", "/linux/", []byte(test.line)) if test.result != string(result) { t.Errorf("want %q\n\t get %q", test.result, string(result)) } }) } }