1 // Copyright 2017 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 compiler 5 6 import ( 7 "bytes" 8 "flag" 9 "fmt" 10 "io/ioutil" 11 "path/filepath" 12 "testing" 13 14 "github.com/google/syzkaller/pkg/ast" 15 "github.com/google/syzkaller/pkg/serializer" 16 "github.com/google/syzkaller/sys/targets" 17 ) 18 19 var flagUpdate = flag.Bool("update", false, "reformat all.txt") 20 21 func TestCompileAll(t *testing.T) { 22 for os, arches := range targets.List { 23 os, arches := os, arches 24 t.Run(os, func(t *testing.T) { 25 t.Parallel() 26 eh := func(pos ast.Pos, msg string) { 27 t.Logf("%v: %v", pos, msg) 28 } 29 path := filepath.Join("..", "..", "sys", os) 30 desc := ast.ParseGlob(filepath.Join(path, "*.txt"), eh) 31 if desc == nil { 32 t.Fatalf("parsing failed") 33 } 34 for arch, target := range arches { 35 arch, target := arch, target 36 t.Run(arch, func(t *testing.T) { 37 t.Parallel() 38 consts := DeserializeConstsGlob(filepath.Join(path, "*_"+arch+".const"), eh) 39 if consts == nil { 40 t.Fatalf("reading consts failed") 41 } 42 prog := Compile(desc, consts, target, eh) 43 if prog == nil { 44 t.Fatalf("compilation failed") 45 } 46 }) 47 } 48 }) 49 } 50 } 51 52 func TestNoErrors(t *testing.T) { 53 t.Parallel() 54 consts := map[string]uint64{ 55 "SYS_foo": 1, 56 "C0": 0, 57 "C1": 1, 58 "C2": 2, 59 } 60 for _, name := range []string{"all.txt"} { 61 for _, arch := range []string{"32_shmem", "64"} { 62 name, arch := name, arch 63 t.Run(fmt.Sprintf("%v/%v", name, arch), func(t *testing.T) { 64 t.Parallel() 65 target := targets.List["test"][arch] 66 eh := func(pos ast.Pos, msg string) { 67 t.Logf("%v: %v", pos, msg) 68 } 69 fileName := filepath.Join("testdata", name) 70 data, err := ioutil.ReadFile(fileName) 71 if err != nil { 72 t.Fatal(err) 73 } 74 astDesc := ast.Parse(data, name, eh) 75 if astDesc == nil { 76 t.Fatalf("parsing failed") 77 } 78 formatted := ast.Format(astDesc) 79 if !bytes.Equal(data, formatted) { 80 if *flagUpdate { 81 ioutil.WriteFile(fileName, formatted, 0644) 82 } 83 t.Fatalf("description is not formatted") 84 } 85 constInfo := ExtractConsts(astDesc, target, eh) 86 if constInfo == nil { 87 t.Fatalf("const extraction failed") 88 } 89 desc := Compile(astDesc, consts, target, eh) 90 if desc == nil { 91 t.Fatalf("compilation failed") 92 } 93 if len(desc.Unsupported) != 0 { 94 t.Fatalf("something is unsupported:\n%+v", desc.Unsupported) 95 } 96 out := new(bytes.Buffer) 97 fmt.Fprintf(out, "\n\nRESOURCES:\n") 98 serializer.Write(out, desc.Resources) 99 fmt.Fprintf(out, "\n\nSTRUCTS:\n") 100 serializer.Write(out, desc.StructDescs) 101 fmt.Fprintf(out, "\n\nSYSCALLS:\n") 102 serializer.Write(out, desc.Syscalls) 103 if false { 104 t.Log(out.String()) // useful for debugging 105 } 106 }) 107 } 108 } 109 } 110 111 func TestErrors(t *testing.T) { 112 t.Parallel() 113 for _, arch := range []string{"32_shmem", "64"} { 114 target := targets.List["test"][arch] 115 t.Run(arch, func(t *testing.T) { 116 t.Parallel() 117 em := ast.NewErrorMatcher(t, filepath.Join("testdata", "errors.txt")) 118 desc := ast.Parse(em.Data, "errors.txt", em.ErrorHandler) 119 if desc == nil { 120 em.DumpErrors(t) 121 t.Fatalf("parsing failed") 122 } 123 ExtractConsts(desc, target, em.ErrorHandler) 124 em.Check(t) 125 }) 126 } 127 } 128 129 func TestErrors2(t *testing.T) { 130 t.Parallel() 131 consts := map[string]uint64{ 132 "SYS_foo": 1, 133 "C0": 0, 134 "C1": 1, 135 "C2": 2, 136 } 137 for _, arch := range []string{"32_shmem", "64"} { 138 target := targets.List["test"][arch] 139 t.Run(arch, func(t *testing.T) { 140 t.Parallel() 141 em := ast.NewErrorMatcher(t, filepath.Join("testdata", "errors2.txt")) 142 desc := ast.Parse(em.Data, "errors2.txt", em.ErrorHandler) 143 if desc == nil { 144 em.DumpErrors(t) 145 t.Fatalf("parsing failed") 146 } 147 info := ExtractConsts(desc, target, em.ErrorHandler) 148 if info == nil { 149 em.DumpErrors(t) 150 t.Fatalf("const extraction failed") 151 } 152 Compile(desc, consts, target, em.ErrorHandler) 153 em.Check(t) 154 }) 155 } 156 } 157 158 func TestFuzz(t *testing.T) { 159 t.Parallel() 160 inputs := []string{ 161 "d~^gB`i\u007f?\xb0.", 162 "da[", 163 "define\x98define(define\x98define\x98define\x98define\x98define)define\tdefin", 164 "resource g[g]", 165 } 166 consts := map[string]uint64{"A": 1, "B": 2, "C": 3, "SYS_C": 4} 167 eh := func(pos ast.Pos, msg string) { 168 t.Logf("%v: %v", pos, msg) 169 } 170 for _, data := range inputs { 171 desc := ast.Parse([]byte(data), "", eh) 172 if desc != nil { 173 Compile(desc, consts, targets.List["test"]["64"], eh) 174 } 175 } 176 } 177 178 func TestAlign(t *testing.T) { 179 t.Parallel() 180 const input = ` 181 foo$0(a ptr[in, s0]) 182 s0 { 183 f0 int8 184 f1 int16 185 } 186 187 foo$1(a ptr[in, s1]) 188 s1 { 189 f0 ptr[in, s2, opt] 190 } 191 s2 { 192 f1 s1 193 f2 array[s1, 2] 194 f3 array[array[s1, 2], 2] 195 } 196 ` 197 desc := ast.Parse([]byte(input), "input", nil) 198 if desc == nil { 199 t.Fatal("failed to parse") 200 } 201 p := Compile(desc, map[string]uint64{"SYS_foo": 1}, targets.List["test"]["64"], nil) 202 if p == nil { 203 t.Fatal("failed to compile") 204 } 205 got := p.StructDescs[0].Desc 206 t.Logf("got: %#v", got) 207 } 208