diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-08-18 18:38:07 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-08-18 18:47:39 +0200 |
| commit | 4802b0fb7440d76d78efc586b87ff6eea46b6b00 (patch) | |
| tree | 7a1e39eb906a18e0be375f39ec45b0679cee39c4 /sys/syz-sysgen | |
| parent | 19b893936bebc6189c7627d56d1dc454fbd42714 (diff) | |
sys/syz-sysgen: switch to new parser
For now we just generate the old structs from the new AST.
But this allows to delete the old parser entirely.
Diffstat (limited to 'sys/syz-sysgen')
| -rw-r--r-- | sys/syz-sysgen/syscallnr.go | 2 | ||||
| -rw-r--r-- | sys/syz-sysgen/sysgen.go | 228 |
2 files changed, 211 insertions, 19 deletions
diff --git a/sys/syz-sysgen/syscallnr.go b/sys/syz-sysgen/syscallnr.go index 0b41a8634..c67f16166 100644 --- a/sys/syz-sysgen/syscallnr.go +++ b/sys/syz-sysgen/syscallnr.go @@ -7,8 +7,6 @@ import ( "bytes" "sort" "text/template" - - . "github.com/google/syzkaller/sys/sysparser" ) type Arch struct { diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go index 903361af6..a778e4819 100644 --- a/sys/syz-sysgen/sysgen.go +++ b/sys/syz-sysgen/sysgen.go @@ -20,7 +20,7 @@ import ( "strconv" "strings" - . "github.com/google/syzkaller/sys/sysparser" + "github.com/google/syzkaller/pkg/ast" ) var ( @@ -37,23 +37,11 @@ const ( func main() { flag.Parse() - inputFiles, err := filepath.Glob("sys/*\\.txt") - if err != nil { - failf("failed to find input files: %v", err) - } - var r io.Reader = bytes.NewReader(nil) - for _, f := range inputFiles { - inf, err := os.Open(f) - logf(1, "Load descriptions from file %v", f) - if err != nil { - failf("failed to open input file: %v", err) - } - defer inf.Close() - r = io.MultiReader(r, bufio.NewReader(inf)) + top, ok := ast.ParseGlob("sys/*\\.txt", nil) + if !ok { + os.Exit(1) } - - logf(1, "Parse system call descriptions") - desc := Parse(r) + desc := astToDesc(top) unsupportedFlags := make(map[string]int) consts := make(map[string]map[string]uint64) @@ -114,6 +102,212 @@ func main() { } } +type Description struct { + Syscalls []Syscall + Structs map[string]*Struct + Unnamed map[string][]string + Flags map[string][]string + StrFlags map[string][]string + Resources map[string]Resource +} + +type Syscall struct { + Name string + CallName string + Args [][]string + Ret []string +} + +type Struct struct { + Name string + Flds [][]string + IsUnion bool + Packed bool + Varlen bool + Align int +} + +type Resource struct { + Name string + Base string + Values []string +} + +type syscallArray []Syscall + +func (a syscallArray) Len() int { return len(a) } +func (a syscallArray) Less(i, j int) bool { return a[i].Name < a[j].Name } +func (a syscallArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func astToDesc(top []interface{}) *Description { + // As a temporal measure we just convert the new representation to the old one. + // TODO: check for duplicate defines, structs, resources. + // TODO: check for duplicate syscall argument names. + desc := &Description{ + Structs: make(map[string]*Struct), + Unnamed: make(map[string][]string), + Flags: make(map[string][]string), + StrFlags: make(map[string][]string), + Resources: make(map[string]Resource), + } + unnamedSeq := 0 + for _, decl := range top { + switch n := decl.(type) { + case *ast.Resource: + var vals []string + for _, v := range n.Values { + switch { + case v.Ident != "": + vals = append(vals, v.Ident) + default: + if v.ValueHex { + vals = append(vals, fmt.Sprintf("0x%x", v.Value)) + } else { + vals = append(vals, fmt.Sprint(v.Value)) + } + } + } + desc.Resources[n.Name.Name] = Resource{ + Name: n.Name.Name, + Base: n.Base.Name, + Values: vals, + } + case *ast.Call: + call := Syscall{ + Name: n.Name.Name, + CallName: n.CallName, + } + for _, a := range n.Args { + call.Args = append(call.Args, astToDescField(a, desc.Unnamed, &unnamedSeq)) + } + if n.Ret != nil { + call.Ret = astToDescType(n.Ret, desc.Unnamed, &unnamedSeq) + } + desc.Syscalls = append(desc.Syscalls, call) + case *ast.Struct: + str := &Struct{ + Name: n.Name.Name, + IsUnion: n.IsUnion, + } + for _, f := range n.Fields { + str.Flds = append(str.Flds, astToDescField(f, desc.Unnamed, &unnamedSeq)) + } + if n.IsUnion { + for _, attr := range n.Attrs { + switch attr.Name { + case "varlen": + str.Varlen = true + default: + failf("unknown union %v attribute: %v", str.Name, attr.Name) + } + } + } else { + for _, attr := range n.Attrs { + switch { + case attr.Name == "packed": + str.Packed = true + case attr.Name == "align_ptr": + str.Align = 8 // TODO: this must be target pointer size + case strings.HasPrefix(attr.Name, "align_"): + a, err := strconv.ParseUint(attr.Name[6:], 10, 64) + if err != nil { + failf("bad struct %v alignment %v: %v", str.Name, attr.Name, err) + } + if a&(a-1) != 0 || a == 0 || a > 1<<30 { + failf("bad struct %v alignment %v: must be sane power of 2", str.Name, a) + } + str.Align = int(a) + default: + failf("unknown struct %v attribute: %v", str.Name, attr.Name) + } + } + } + if str.IsUnion && len(str.Flds) <= 1 { + failf("union %v has only %v fields, need at least 2", str.Name, len(str.Flds)) + } + fields := make(map[string]bool) + for _, f := range str.Flds { + if f[0] == "parent" { + failf("struct/union %v contains reserved field 'parent'", str.Name) + } + if fields[f[0]] { + failf("duplicate field %v in struct/union %v", f[0], str.Name) + } + fields[f[0]] = true + } + desc.Structs[str.Name] = str + case *ast.IntFlags: + var vals []string + for _, v := range n.Values { + switch { + case v.Ident != "": + vals = append(vals, v.Ident) + default: + if v.ValueHex { + vals = append(vals, fmt.Sprintf("0x%x", v.Value)) + } else { + vals = append(vals, fmt.Sprint(v.Value)) + } + } + } + desc.Flags[n.Name.Name] = vals + case *ast.StrFlags: + var vals []string + for _, v := range n.Values { + vals = append(vals, v.Value) + } + desc.StrFlags[n.Name.Name] = vals + } + } + sort.Sort(syscallArray(desc.Syscalls)) + return desc +} + +func astToDescField(n *ast.Field, unnamed map[string][]string, unnamedSeq *int) []string { + return append([]string{n.Name.Name}, astToDescType(n.Type, unnamed, unnamedSeq)...) +} + +func astToDescType(n *ast.Type, unnamed map[string][]string, unnamedSeq *int) []string { + res := []string{astTypeToStr(n)} + for _, t := range n.Args { + if len(t.Args) == 0 { + res = append(res, astTypeToStr(t)) + continue + } + id := fmt.Sprintf("unnamed%v", *unnamedSeq) + (*unnamedSeq)++ + unnamed[id] = astToDescType(t, unnamed, unnamedSeq) + res = append(res, id) + } + return res +} + +func astTypeToStr(n *ast.Type) string { + res := "" + switch { + case n.Ident != "": + res = n.Ident + case n.String != "": + res = fmt.Sprintf("\"%v\"", n.String) + default: + if n.ValueHex { + res = fmt.Sprintf("0x%x", n.Value) + } else { + res = fmt.Sprint(n.Value) + } + } + if n.Ident2 != "" { + res += ":" + n.Ident2 + } else if n.Value2 != 0 { + if n.Value2Hex { + res += fmt.Sprintf(":0x%x", n.Value2) + } else { + res += ":" + fmt.Sprint(n.Value2) + } + } + return res +} + func readConsts(arch string) map[string]uint64 { constFiles, err := filepath.Glob("sys/*_" + arch + ".const") if err != nil { |
