aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/compiler/compiler.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-01-10 16:13:34 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-01-13 12:52:09 +0100
commit6b52293f4defa6b45b564d037fd641be5d6d0e0e (patch)
tree53c7f28df3fd2666ca165ce7231d470c9d1e2dc5 /pkg/compiler/compiler.go
parent9dc808a65eb3f44d64e078b79bcac0f0510629f6 (diff)
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication, and need much more for proper descriptions. Introduce type templates to simplify writing such descriptions and remove code duplication. Note: type templates are experimental, have poor error handling and are subject to change. Type templates can be declared as follows: ``` type buffer[DIR] ptr[DIR, array[int8]] type fileoff[BASE] BASE type nlattr[TYPE, PAYLOAD] { nla_len len[parent, int16] nla_type const[TYPE, int16] payload PAYLOAD } [align_4] ``` and later used as follows: ``` syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]]) ```
Diffstat (limited to 'pkg/compiler/compiler.go')
-rw-r--r--pkg/compiler/compiler.go66
1 files changed, 60 insertions, 6 deletions
diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go
index 6019bda94..98348b0f8 100644
--- a/pkg/compiler/compiler.go
+++ b/pkg/compiler/compiler.go
@@ -39,6 +39,8 @@ type Prog struct {
StructDescs []*prog.KeyedStruct
// Set of unsupported syscalls/flags.
Unsupported map[string]bool
+ // Returned if consts was nil.
+ fileConsts map[string]*ConstInfo
}
// Compile compiles sys description.
@@ -65,6 +67,20 @@ func Compile(desc *ast.Description, consts map[string]uint64, target *targets.Ta
for name, typedef := range builtinTypedefs {
comp.typedefs[name] = typedef
}
+ comp.typecheck()
+ // The subsequent, more complex, checks expect basic validity of the tree,
+ // in particular corrent number of type arguments. If there were errors,
+ // don't proceed to avoid out-of-bounds references to type arguments.
+ if comp.errors != 0 {
+ return nil
+ }
+ if consts == nil {
+ fileConsts := comp.extractConsts()
+ if comp.errors != 0 {
+ return nil
+ }
+ return &Prog{fileConsts: fileConsts}
+ }
comp.assignSyscallNumbers(consts)
comp.patchConsts(consts)
comp.check()
@@ -177,9 +193,11 @@ func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc {
func (comp *compiler) getArgsBase(t *ast.Type, field string, dir prog.Dir, isArg bool) (
*typeDesc, []*ast.Type, prog.IntTypeCommon) {
desc := comp.getTypeDesc(t)
+ if desc == nil {
+ panic(fmt.Sprintf("no type desc for %#v", *t))
+ }
args, opt := removeOpt(t)
- size := sizeUnassigned
- com := genCommon(t.Ident, field, size, dir, opt)
+ com := genCommon(t.Ident, field, sizeUnassigned, dir, opt != nil)
base := genIntCommon(com, 0, false)
if desc.NeedBase {
base.TypeSize = comp.ptrSize
@@ -192,12 +210,48 @@ func (comp *compiler) getArgsBase(t *ast.Type, field string, dir prog.Dir, isArg
return desc, args, base
}
-func removeOpt(t *ast.Type) ([]*ast.Type, bool) {
+func (comp *compiler) foreachType(n0 ast.Node,
+ cb func(*ast.Type, *typeDesc, []*ast.Type, prog.IntTypeCommon)) {
+ switch n := n0.(type) {
+ case *ast.Call:
+ for _, arg := range n.Args {
+ comp.foreachSubType(arg.Type, true, cb)
+ }
+ if n.Ret != nil {
+ comp.foreachSubType(n.Ret, true, cb)
+ }
+ case *ast.Resource:
+ comp.foreachSubType(n.Base, false, cb)
+ case *ast.Struct:
+ for _, f := range n.Fields {
+ comp.foreachSubType(f.Type, false, cb)
+ }
+ case *ast.TypeDef:
+ if len(n.Args) == 0 {
+ comp.foreachSubType(n.Type, false, cb)
+ }
+ default:
+ panic(fmt.Sprintf("unexpected node %#v", n0))
+ }
+}
+
+func (comp *compiler) foreachSubType(t *ast.Type, isArg bool,
+ cb func(*ast.Type, *typeDesc, []*ast.Type, prog.IntTypeCommon)) {
+ desc, args, base := comp.getArgsBase(t, "", prog.DirIn, isArg)
+ cb(t, desc, args, base)
+ for i, arg := range args {
+ if desc.Args[i].Type == typeArgType {
+ comp.foreachSubType(arg, false, cb)
+ }
+ }
+}
+
+func removeOpt(t *ast.Type) ([]*ast.Type, *ast.Type) {
args := t.Args
- if len(args) != 0 && args[len(args)-1].Ident == "opt" {
- return args[:len(args)-1], true
+ if last := len(args) - 1; last >= 0 && args[last].Ident == "opt" {
+ return args[:last], args[last]
}
- return args, false
+ return args, nil
}
func (comp *compiler) parseIntType(name string) (size uint64, bigEndian bool) {