Home | History | Annotate | Download | only in compiler
      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