diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-08-27 15:08:11 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-08-27 15:28:49 +0200 |
| commit | e2ffb4fc9111e28f1d8e0e987cb06172cbbd4e84 (patch) | |
| tree | 8dc4d76063e3430321622cd81763a95a972f2e3a /pkg/compiler/compiler.go | |
| parent | e71c87fbf52c83d8e514e4685d40da4d4d0f1a1c (diff) | |
pkg/compiler: move more const-processing code to compiler
Diffstat (limited to 'pkg/compiler/compiler.go')
| -rw-r--r-- | pkg/compiler/compiler.go | 196 |
1 files changed, 126 insertions, 70 deletions
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 593d9e82c..e85fdf6e2 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -22,113 +22,169 @@ type Prog struct { } // Compile compiles sys description. -func Compile(desc0 *ast.Description, consts map[string]uint64, eh ast.ErrorHandler) *Prog { +func Compile(desc *ast.Description, consts map[string]uint64, eh ast.ErrorHandler) *Prog { if eh == nil { eh = ast.LoggingHandler } + comp := &compiler{ + desc: ast.Clone(desc), + eh: eh, + unsupported: make(map[string]bool), + } - desc := ast.Clone(desc0) - unsup, ok := patchConsts(desc, consts, eh) - if !ok { + comp.assignSyscallNumbers(consts) + comp.patchConsts(consts) + if comp.errors != 0 { return nil } return &Prog{ - Desc: desc, - Unsupported: unsup, + Desc: comp.desc, + Unsupported: comp.unsupported, } } +type compiler struct { + desc *ast.Description + eh ast.ErrorHandler + errors int + + unsupported map[string]bool +} + +func (comp *compiler) error(pos ast.Pos, msg string, args ...interface{}) { + comp.errors++ + comp.warning(pos, msg, args...) +} + +func (comp *compiler) warning(pos ast.Pos, msg string, args ...interface{}) { + comp.eh(pos, fmt.Sprintf(msg, args...)) +} + +// assignSyscallNumbers assigns syscall numbers, discards unsupported syscalls +// and removes no longer irrelevant nodes from the tree (comments, new lines, etc). +func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) { + // Pseudo syscalls starting from syz_ are assigned numbers starting from syzbase. + // Note: the numbers must be stable (not depend on file reading order, etc), + // so we have to do it in 2 passes. + const syzbase = 1000000 + syzcalls := make(map[string]bool) + for _, decl := range comp.desc.Nodes { + c, ok := decl.(*ast.Call) + if !ok { + continue + } + if strings.HasPrefix(c.CallName, "syz_") { + syzcalls[c.CallName] = true + } + } + syznr := make(map[string]uint64) + for i, name := range toArray(syzcalls) { + syznr[name] = syzbase + uint64(i) + } + + var top []ast.Node + for _, decl := range comp.desc.Nodes { + switch decl.(type) { + case *ast.Call: + c := decl.(*ast.Call) + if strings.HasPrefix(c.CallName, "syz_") { + c.NR = syznr[c.CallName] + top = append(top, decl) + continue + } + // Lookup in consts. + str := "__NR_" + c.CallName + nr, ok := consts[str] + if ok { + c.NR = nr + top = append(top, decl) + continue + } + name := "syscall " + c.CallName + if !comp.unsupported[name] { + comp.unsupported[name] = true + comp.warning(c.Pos, "unsupported syscall: %v due to missing const %v", + c.CallName, str) + } + case *ast.IntFlags, *ast.Resource, *ast.Struct, *ast.StrFlags: + top = append(top, decl) + case *ast.NewLine, *ast.Comment, *ast.Include, *ast.Incdir, *ast.Define: + // These are not needed anymore. + default: + panic(fmt.Sprintf("unknown node type: %#v", decl)) + } + } + comp.desc.Nodes = top +} + // patchConsts replaces all symbolic consts with their numeric values taken from consts map. // Updates desc and returns set of unsupported syscalls and flags. // After this pass consts are not needed for compilation. -func patchConsts(desc *ast.Description, consts map[string]uint64, eh ast.ErrorHandler) (map[string]bool, bool) { - broken := false - unsup := make(map[string]bool) +func (comp *compiler) patchConsts(consts map[string]uint64) { var top []ast.Node - for _, decl := range desc.Nodes { + for _, decl := range comp.desc.Nodes { switch decl.(type) { case *ast.IntFlags: // Unsupported flag values are dropped. n := decl.(*ast.IntFlags) var values []*ast.Int for _, v := range n.Values { - if patchIntConst(v.Pos, &v.Value, &v.Ident, consts, unsup, nil, eh) { + if comp.patchIntConst(v.Pos, &v.Value, &v.Ident, consts, nil) { values = append(values, v) } } n.Values = values top = append(top, n) + case *ast.StrFlags: + top = append(top, decl) case *ast.Resource, *ast.Struct, *ast.Call: - if c, ok := decl.(*ast.Call); ok { - // Extract syscall NR. - str := "__NR_" + c.CallName - nr, ok := consts[str] - if !ok { - if name := "syscall " + c.CallName; !unsup[name] { - unsup[name] = true - eh(c.Pos, fmt.Sprintf("unsupported syscall: %v due to missing const %v", - c.CallName, str)) - } - continue - } - c.NR = nr - } // Walk whole tree and replace consts in Int's and Type's. missing := "" - ast.WalkNode(decl, func(n0 ast.Node) { + ast.WalkNode(decl, nil, func(n0, _ ast.Node) { switch n := n0.(type) { case *ast.Int: - patchIntConst(n.Pos, &n.Value, &n.Ident, - consts, unsup, &missing, eh) + comp.patchIntConst(n.Pos, &n.Value, &n.Ident, consts, &missing) case *ast.Type: if c := typeConstIdentifier(n); c != nil { - patchIntConst(c.Pos, &c.Value, &c.Ident, - consts, unsup, &missing, eh) + comp.patchIntConst(c.Pos, &c.Value, &c.Ident, + consts, &missing) if c.HasColon { - patchIntConst(c.Pos2, &c.Value2, &c.Ident2, - consts, unsup, &missing, eh) + comp.patchIntConst(c.Pos2, &c.Value2, &c.Ident2, + consts, &missing) } } } }) if missing == "" { top = append(top, decl) - } else { - // Produce a warning about unsupported syscall/resource/struct. - // Unsupported syscalls are discarded. - // Unsupported resource/struct lead to compilation error. - // Fixing that would require removing all uses of the resource/struct. - typ, pos, name, fatal := "", ast.Pos{}, "", false - switch n := decl.(type) { - case *ast.Call: - typ, pos, name, fatal = "syscall", n.Pos, n.Name.Name, false - case *ast.Resource: - typ, pos, name, fatal = "resource", n.Pos, n.Name.Name, true - case *ast.Struct: - typ, pos, name, fatal = "struct", n.Pos, n.Name.Name, true - default: - panic(fmt.Sprintf("unknown type: %#v", decl)) - } - if id := typ + " " + name; !unsup[id] { - unsup[id] = true - eh(pos, fmt.Sprintf("unsupported %v: %v due to missing const %v", - typ, name, missing)) - } - if fatal { - broken = true - } + continue + } + // Produce a warning about unsupported syscall/resource/struct. + // Unsupported syscalls are discarded. + // Unsupported resource/struct lead to compilation error. + // Fixing that would require removing all uses of the resource/struct. + pos, typ, name := ast.Pos{}, "", "" + fn := comp.error + switch n := decl.(type) { + case *ast.Call: + pos, typ, name = n.Pos, "syscall", n.Name.Name + fn = comp.warning + case *ast.Resource: + pos, typ, name = n.Pos, "resource", n.Name.Name + case *ast.Struct: + pos, typ, name = n.Pos, "struct", n.Name.Name + default: + panic(fmt.Sprintf("unknown type: %#v", decl)) + } + if id := typ + " " + name; !comp.unsupported[id] { + comp.unsupported[id] = true + fn(pos, "unsupported %v: %v due to missing const %v", + typ, name, missing) } - case *ast.StrFlags: - top = append(top, decl) - case *ast.NewLine, *ast.Comment, *ast.Include, *ast.Incdir, *ast.Define: - // These are not needed anymore. - default: - panic(fmt.Sprintf("unknown node type: %#v", decl)) } } - desc.Nodes = top - return unsup, !broken + comp.desc.Nodes = top } // ExtractConsts returns list of literal constants and other info required const value extraction. @@ -136,7 +192,7 @@ func ExtractConsts(desc *ast.Description) (consts, includes, incdirs []string, d constMap := make(map[string]bool) defines = make(map[string]string) - ast.Walk(desc, func(n1 ast.Node) { + ast.Walk(desc, func(n1, _ ast.Node) { switch n := n1.(type) { case *ast.Include: includes = append(includes, n.File.Value) @@ -170,17 +226,17 @@ func ExtractConsts(desc *ast.Description) (consts, includes, incdirs []string, d return } -func patchIntConst(pos ast.Pos, val *uint64, id *string, - consts map[string]uint64, unsup map[string]bool, missing *string, eh ast.ErrorHandler) bool { +func (comp *compiler) patchIntConst(pos ast.Pos, val *uint64, id *string, + consts map[string]uint64, missing *string) bool { if *id == "" { return true } v, ok := consts[*id] if !ok { name := "const " + *id - if !unsup[name] { - unsup[name] = true - eh(pos, fmt.Sprintf("unsupported const: %v", *id)) + if !comp.unsupported[name] { + comp.unsupported[name] = true + comp.warning(pos, "unsupported const: %v", *id) } if missing != nil && *missing == "" { *missing = *id |
