From d3a93e8370682fa5231bc94faf11ed3681b2ac99 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 19 Oct 2016 14:41:46 +0200 Subject: sys: attach Dir to all types Dir is a static info, so we don't need to compute, propagate and attach it in prog whenever we generate/change programs. Attach Dir to all types. --- prog/analysis.go | 23 +++----- prog/encodingexec.go | 2 +- prog/mutation.go | 8 +-- prog/prio.go | 43 +-------------- prog/prog.go | 11 +--- prog/rand.go | 33 +++++------ prog/validation.go | 10 ++-- sys/decl.go | 153 +++++++++++++++++++++++---------------------------- sysgen/sysgen.go | 89 +++++++++++++++++------------- 9 files changed, 158 insertions(+), 214 deletions(-) diff --git a/prog/analysis.go b/prog/analysis.go index d4ee93d10..24f02903c 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -52,11 +52,11 @@ func (s *state) analyze(c *Call) { foreachArgArray(&c.Args, c.Ret, func(arg, base *Arg, _ *[]*Arg) { switch typ := arg.Type.(type) { case *sys.FilenameType: - if arg.Kind == ArgData && arg.Dir != DirOut { + if arg.Kind == ArgData && arg.Type.Dir() != sys.DirOut { s.files[string(arg.Data)] = true } case *sys.ResourceType: - if arg.Dir != DirIn { + if arg.Type.Dir() != sys.DirIn { s.resources[typ.Desc.Name] = append(s.resources[typ.Desc.Name], arg) // TODO: negative PIDs and add them as well (that's process groups). } @@ -150,8 +150,8 @@ func foreachArg(c *Call, f func(arg, base *Arg, parent *[]*Arg)) { } func assignTypeAndDir(c *Call) error { - var rec func(arg *Arg, typ sys.Type, dir ArgDir) error - rec = func(arg *Arg, typ sys.Type, dir ArgDir) error { + var rec func(arg *Arg, typ sys.Type) error + rec = func(arg *Arg, typ sys.Type) error { if arg.Call != nil && arg.Call != c { panic(fmt.Sprintf("different call is already assigned: %p %p %v %v", arg.Call, c, arg.Call.Meta.Name, c.Meta.Name)) } @@ -162,41 +162,37 @@ func assignTypeAndDir(c *Call) error { arg.Type = typ switch arg.Kind { case ArgPointer: - arg.Dir = DirIn switch typ1 := typ.(type) { case *sys.PtrType: if arg.Res != nil { - if err := rec(arg.Res, typ1.Type, ArgDir(typ1.Dir)); err != nil { + if err := rec(arg.Res, typ1.Type); err != nil { return err } } } case ArgGroup: - arg.Dir = dir switch typ1 := typ.(type) { case *sys.StructType: if len(arg.Inner) != len(typ1.Fields) { return fmt.Errorf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields)) } for i, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Fields[i], dir); err != nil { + if err := rec(arg1, typ1.Fields[i]); err != nil { return err } } case *sys.ArrayType: for _, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Type, dir); err != nil { + if err := rec(arg1, typ1.Type); err != nil { return err } } } case ArgUnion: - arg.Dir = dir - if err := rec(arg.Option, arg.OptionType, dir); err != nil { + if err := rec(arg.Option, arg.OptionType); err != nil { return err } default: - arg.Dir = dir } return nil } @@ -204,7 +200,7 @@ func assignTypeAndDir(c *Call) error { if c.Meta == nil { panic("nil meta") } - if err := rec(arg, c.Meta.Args[i], DirIn); err != nil { + if err := rec(arg, c.Meta.Args[i]); err != nil { return err } } @@ -212,7 +208,6 @@ func assignTypeAndDir(c *Call) error { c.Ret = returnArg() c.Ret.Call = c c.Ret.Type = c.Meta.Ret - c.Ret.Dir = DirOut } return nil } diff --git a/prog/encodingexec.go b/prog/encodingexec.go index 239ef3514..f30cb7073 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -69,7 +69,7 @@ func (p *Prog) SerializeForExec() []byte { if arg1.Kind == ArgData && len(arg1.Data) == 0 { return } - if arg1.Dir != DirOut { + if arg1.Type.Dir() != sys.DirOut { w.write(ExecInstrCopyin) w.write(physicalAddr(arg) + w.args[arg1].Offset) w.writeArg(arg1) diff --git a/prog/mutation.go b/prog/mutation.go index 1b8be02c5..1c16a6347 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -61,7 +61,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { } switch a := arg.Type.(type) { case *sys.IntType, *sys.FlagsType, *sys.FileoffType, *sys.ResourceType, *sys.VmaType: - arg1, calls1 := r.generateArg(s, arg.Type, arg.Dir) + arg1, calls1 := r.generateArg(s, arg.Type) p.replaceArg(arg, arg1, calls1) case *sys.BufferType: switch a.Kind { @@ -123,7 +123,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { if count > uintptr(len(arg.Inner)) { var calls []*Call for count > uintptr(len(arg.Inner)) { - arg1, calls1 := r.generateArg(s, a.Type, arg.Dir) + arg1, calls1 := r.generateArg(s, a.Type) arg.Inner = append(arg.Inner, arg1) for _, c1 := range calls1 { calls = append(calls, c1) @@ -168,7 +168,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { optType = a.Options[r.Intn(len(a.Options))] } p.removeArg(arg.Option) - opt, calls := r.generateArg(s, optType, arg.Dir) + opt, calls := r.generateArg(s, optType) arg1 := unionArg(opt, optType) p.replaceArg(arg, arg1, calls) case *sys.LenType: @@ -344,7 +344,7 @@ func mutationArgs(c *Call) (args, bases []*Arg) { // Well, this is const. return } - if arg.Dir == DirOut { + if arg.Type.Dir() == sys.DirOut { return } if base != nil { diff --git a/prog/prio.go b/prog/prio.go index 3ac1eafe5..a21218dd1 100644 --- a/prog/prio.go +++ b/prog/prio.go @@ -50,7 +50,7 @@ func calcStaticPriorities() [][]float32 { uses[id][c.ID] = weight } } - foreachArgType(c, func(t sys.Type, d ArgDir) { + sys.ForeachType(c, func(t sys.Type) { switch a := t.(type) { case *sys.ResourceType: if a.Desc.Name == "pid" || a.Desc.Name == "uid" || a.Desc.Name == "gid" { @@ -196,47 +196,6 @@ func normalizePrio(prios [][]float32) { } } -func foreachArgType(meta *sys.Call, f func(sys.Type, ArgDir)) { - seen := make(map[sys.Type]bool) - var rec func(t sys.Type, dir ArgDir) - rec = func(t sys.Type, d ArgDir) { - f(t, d) - switch a := t.(type) { - case *sys.ArrayType: - rec(a.Type, d) - case *sys.PtrType: - rec(a.Type, ArgDir(a.Dir)) - case *sys.StructType: - if seen[a] { - return // prune recursion via pointers to structs/unions - } - seen[a] = true - for _, f := range a.Fields { - rec(f, d) - } - case *sys.UnionType: - if seen[a] { - return // prune recursion via pointers to structs/unions - } - seen[a] = true - for _, opt := range a.Options { - rec(opt, d) - } - case *sys.ResourceType, *sys.FileoffType, *sys.BufferType, - *sys.VmaType, *sys.LenType, *sys.FlagsType, *sys.ConstType, - *sys.StrConstType, *sys.IntType, *sys.FilenameType: - default: - panic("unknown type") - } - } - for _, t := range meta.Args { - rec(t, DirIn) - } - if meta.Ret != nil { - rec(meta.Ret, DirOut) - } -} - // ChooseTable allows to do a weighted choice of a syscall for a given syscall // based on call-to-call priorities and a set of enabled syscalls. type ChoiceTable struct { diff --git a/prog/prog.go b/prog/prog.go index aa5e1b86e..550b8416d 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -23,7 +23,6 @@ type Arg struct { Call *Call Type sys.Type Kind ArgKind - Dir ArgDir Val uintptr // value of ArgConst AddrPage uintptr // page index for ArgPointer address, page count for ArgPageSize AddrOffset int // page offset for ArgPointer address @@ -53,14 +52,6 @@ const ( ArgReturn // fake value denoting syscall return value ) -type ArgDir sys.Dir - -const ( - DirIn = ArgDir(sys.DirIn) - DirOut = ArgDir(sys.DirOut) - DirInOut = ArgDir(sys.DirInOut) -) - // Returns inner arg for PtrType args func (a *Arg) InnerArg(typ sys.Type) *Arg { switch typ1 := typ.(type) { @@ -177,7 +168,7 @@ func unionArg(opt *Arg, typ sys.Type) *Arg { } func returnArg() *Arg { - return &Arg{Kind: ArgReturn, Dir: DirOut} + return &Arg{Kind: ArgReturn} } func (p *Prog) insertBefore(c *Call, calls []*Call) { diff --git a/prog/rand.go b/prog/rand.go index 49726afcd..49c1ed193 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -600,7 +600,7 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call { func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Call) { c := &Call{Meta: meta} - c.Args, calls = r.generateArgs(s, meta.Args, DirIn) + c.Args, calls = r.generateArgs(s, meta.Args) calls = append(calls, c) for _, c1 := range calls { assignTypeAndDir(c1) @@ -609,13 +609,13 @@ func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Cal return calls } -func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg, []*Call) { +func (r *randGen) generateArgs(s *state, types []sys.Type) ([]*Arg, []*Call) { var calls []*Call args := make([]*Arg, len(types)) // Generate all args. Size args have the default value 0 for now. for i, typ := range types { - arg, calls1 := r.generateArg(s, typ, dir) + arg, calls1 := r.generateArg(s, typ) if arg == nil { panic(fmt.Sprintf("generated arg is nil for type '%v', types: %+v", typ.Name(), types)) } @@ -628,14 +628,15 @@ func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg, return args, calls } -func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, calls []*Call) { - if dir == DirOut { +func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) { + if typ.Dir() == sys.DirOut { // No need to generate something interesting for output scalar arguments. // But we still need to generate the argument itself so that it can be referenced // in subsequent calls. For the same reason we do generate pointer/array/struct // output arguments (their elements can be referenced in subsequent calls). switch typ.(type) { - case *sys.IntType, *sys.FlagsType, *sys.ConstType, *sys.StrConstType, *sys.FileoffType, *sys.ResourceType: + case *sys.IntType, *sys.FlagsType, *sys.ConstType, *sys.StrConstType, + *sys.FileoffType, *sys.ResourceType, *sys.VmaType: return constArg(0), nil } } @@ -692,7 +693,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal sz = r.randRange(int(a.RangeBegin), int(a.RangeEnd)) } data := make([]byte, sz) - if dir != DirOut { + if a.Dir() != sys.DirOut { for i := range data { data[i] = byte(r.Intn(256)) } @@ -706,7 +707,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal return dataArg(data), nil case sys.BufferSockaddr: data := r.sockaddr(s) - if dir == DirOut { + if a.Dir() == sys.DirOut { for i := range data { data[i] = 0 } @@ -714,7 +715,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal return dataArg(data), nil case sys.BufferAlgType: data := r.algType(s) - if dir == DirOut { + if a.Dir() == sys.DirOut { for i := range data { data[i] = 0 } @@ -722,7 +723,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal return dataArg(data), nil case sys.BufferAlgName: data := r.algName(s) - if dir == DirOut { + if a.Dir() == sys.DirOut { for i := range data { data[i] = 0 } @@ -768,26 +769,26 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal var inner []*Arg var calls []*Call for i := uintptr(0); i < count; i++ { - arg1, calls1 := r.generateArg(s, a.Type, dir) + arg1, calls1 := r.generateArg(s, a.Type) inner = append(inner, arg1) calls = append(calls, calls1...) } return groupArg(inner), calls case *sys.StructType: - if ctor := isSpecialStruct(a); ctor != nil && dir != DirOut { + if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != sys.DirOut { arg, calls = ctor(r, s) return } - args, calls := r.generateArgs(s, a.Fields, dir) + args, calls := r.generateArgs(s, a.Fields) group := groupArg(args) return group, calls case *sys.UnionType: optType := a.Options[r.Intn(len(a.Options))] - opt, calls := r.generateArg(s, optType, dir) + opt, calls := r.generateArg(s, optType) return unionArg(opt, optType), calls case *sys.PtrType: - inner, calls := r.generateArg(s, a.Type, ArgDir(a.Dir)) - if ArgDir(a.Dir) == DirOut && inner == nil { + inner, calls := r.generateArg(s, a.Type) + if a.Dir() == sys.DirOut && inner == nil { // No data, but we should have got size. arg, calls1 := r.addr(s, inner.Size(a.Type), nil) calls = append(calls, calls1...) diff --git a/prog/validation.go b/prog/validation.go index ec407721a..998581e28 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -57,7 +57,7 @@ func (c *Call) validate(ctx *validCtx) error { if arg.Type.Name() != typ.Name() { return fmt.Errorf("syscall %v: arg '%v' type mismatch", c.Meta.Name, typ.Name()) } - if arg.Dir == DirOut { + if arg.Type.Dir() == sys.DirOut { if arg.Val != 0 || arg.AddrPage != 0 || arg.AddrOffset != 0 { return fmt.Errorf("syscall %v: output arg '%v' has data", c.Meta.Name, typ.Name()) } @@ -73,7 +73,7 @@ func (c *Call) validate(ctx *validCtx) error { case ArgResult: case ArgReturn: case ArgConst: - if arg.Dir == DirOut && arg.Val != 0 { + if arg.Type.Dir() == sys.DirOut && arg.Val != 0 { return fmt.Errorf("syscall %v: out resource arg '%v' has bad const value %v", c.Meta.Name, typ.Name(), arg.Val) } default: @@ -112,9 +112,6 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: result arg '%v' has broken link (%+v)", c.Meta.Name, typ.Name(), arg.Res.Uses) } case ArgPointer: - if arg.Dir != DirIn { - return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name()) - } switch typ1 := typ.(type) { case *sys.VmaType: if arg.Res != nil { @@ -124,6 +121,9 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: vma arg '%v' has size 0", c.Meta.Name, typ.Name()) } case *sys.PtrType: + if arg.Type.Dir() != sys.DirIn { + return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name()) + } if arg.Res == nil && !typ.Optional() { return fmt.Errorf("syscall %v: non optional pointer arg '%v' is nil", c.Meta.Name, typ.Name()) } diff --git a/sys/decl.go b/sys/decl.go index 7f7c64c1d..e19e4c028 100644 --- a/sys/decl.go +++ b/sys/decl.go @@ -19,8 +19,17 @@ type Call struct { Ret Type } +type Dir int + +const ( + DirIn Dir = iota + DirOut + DirInOut +) + type Type interface { Name() string + Dir() Dir Optional() bool Default() uintptr Size() uintptr @@ -37,6 +46,7 @@ func IsPad(t Type) bool { type TypeCommon struct { TypeName string + ArgDir Dir IsOptional bool } @@ -52,6 +62,10 @@ func (t *TypeCommon) Default() uintptr { return 0 } +func (t TypeCommon) Dir() Dir { + return t.ArgDir +} + const ( InvalidFD = ^uintptr(0) ) @@ -323,7 +337,6 @@ func (t *ArrayType) InnerType() Type { type PtrType struct { TypeCommon Type Type - Dir Dir } func (t *PtrType) Size() uintptr { @@ -407,14 +420,6 @@ func (t *UnionType) InnerType() Type { return t } -type Dir int - -const ( - DirIn Dir = iota - DirOut - DirInOut -) - var ctors = make(map[string][]*Call) // ResourceConstructors returns a list of calls that can create a resource of the given kind. @@ -431,56 +436,20 @@ func initResources() { func resourceCtors(kind []string, precise bool) []*Call { // Find calls that produce the necessary resources. var metas []*Call - // Recurse into arguments to see if there is an out/inout arg of necessary type. - seen := make(map[Type]bool) - var checkArg func(typ Type, dir Dir) bool - checkArg = func(typ Type, dir Dir) bool { - if resarg, ok := typ.(*ResourceType); ok && dir != DirIn && isCompatibleResource(kind, resarg.Desc.Kind, precise) { - return true - } - switch typ1 := typ.(type) { - case *ArrayType: - if checkArg(typ1.Type, dir) { - return true - } - case *StructType: - if seen[typ1] { - return false // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, fld := range typ1.Fields { - if checkArg(fld, dir) { - return true - } - } - case *UnionType: - if seen[typ1] { - return false // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, opt := range typ1.Options { - if checkArg(opt, dir) { - return true - } - } - case *PtrType: - if checkArg(typ1.Type, typ1.Dir) { - return true - } - } - return false - } for _, meta := range Calls { + // Recurse into arguments to see if there is an out/inout arg of necessary type. ok := false - for _, arg := range meta.Args { - if checkArg(arg, DirIn) { - ok = true - break + ForeachType(meta, func(typ Type) { + if ok { + return } - } - if !ok && meta.Ret != nil && checkArg(meta.Ret, DirOut) { - ok = true - } + switch typ1 := typ.(type) { + case *ResourceType: + if typ1.Dir() != DirIn && isCompatibleResource(kind, typ1.Desc.Kind, precise) { + ok = true + } + } + }) if ok { metas = append(metas, meta) } @@ -526,39 +495,14 @@ func isCompatibleResource(dst, src []string, precise bool) bool { func (c *Call) InputResources() []*ResourceType { var resources []*ResourceType - seen := make(map[Type]bool) - var checkArg func(typ Type, dir Dir) - checkArg = func(typ Type, dir Dir) { + ForeachType(c, func(typ Type) { switch typ1 := typ.(type) { case *ResourceType: - if dir != DirOut && !typ1.IsOptional { + if typ1.Dir() != DirOut && !typ1.IsOptional { resources = append(resources, typ1) } - case *ArrayType: - checkArg(typ1.Type, dir) - case *PtrType: - checkArg(typ1.Type, typ1.Dir) - case *StructType: - if seen[typ1] { - return // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, fld := range typ1.Fields { - checkArg(fld, dir) - } - case *UnionType: - if seen[typ1] { - return // prune recursion via pointers to structs/unions - } - seen[typ1] = true - for _, opt := range typ1.Options { - checkArg(opt, dir) - } } - } - for _, arg := range c.Args { - checkArg(arg, DirIn) - } + }) return resources } @@ -598,6 +542,47 @@ func TransitivelyEnabledCalls(enabled map[*Call]bool) map[*Call]bool { return supported } +func ForeachType(meta *Call, f func(Type)) { + seen := make(map[Type]bool) + var rec func(t Type) + rec = func(t Type) { + f(t) + switch a := t.(type) { + case *PtrType: + rec(a.Type) + case *ArrayType: + rec(a.Type) + case *StructType: + if seen[a] { + return // prune recursion via pointers to structs/unions + } + seen[a] = true + for _, f := range a.Fields { + rec(f) + } + case *UnionType: + if seen[a] { + return // prune recursion via pointers to structs/unions + } + seen[a] = true + for _, opt := range a.Options { + rec(opt) + } + case *ResourceType, *FileoffType, *BufferType, + *VmaType, *LenType, *FlagsType, *ConstType, + *StrConstType, *IntType, *FilenameType: + default: + panic("unknown type") + } + } + for _, t := range meta.Args { + rec(t) + } + if meta.Ret != nil { + rec(meta.Ret) + } +} + var ( Calls []*Call CallCount int diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go index cdc79794c..c66f2af7a 100644 --- a/sysgen/sysgen.go +++ b/sysgen/sysgen.go @@ -162,7 +162,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W fmt.Fprintf(out, "func() { Calls = append(Calls, &Call{Name: \"%v\", CallName: \"%v\"", s.Name, s.CallName) if len(s.Ret) != 0 { fmt.Fprintf(out, ", Ret: ") - generateArg("", "ret", s.Ret[0], s.Ret[1:], desc, consts, true, false, out) + generateArg("", "ret", s.Ret[0], "out", s.Ret[1:], desc, consts, true, false, out) } fmt.Fprintf(out, ", Args: []Type{") for i, a := range s.Args { @@ -170,7 +170,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W fmt.Fprintf(out, ", ") } logf(5, " generate description for arg %v", i) - generateArg("", a[0], a[1], a[2:], desc, consts, true, false, out) + generateArg("", a[0], a[1], "in", a[2:], desc, consts, true, false, out) } if skipCurrentSyscall != "" { logf(0, "unsupported syscall: %v due to %v", s.Name, skipCurrentSyscall) @@ -230,7 +230,7 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write } } fmt.Fprintf(out, "\"%v\": &ResourceDesc{Name: \"%v\", Type: ", name, name) - generateArg("", "resource-type", underlying, nil, desc, consts, true, true, out) + generateArg("", "resource-type", underlying, "inout", nil, desc, consts, true, true, out) fmt.Fprintf(out, ", Kind: []string{") for i, k := range kind { if i != 0 { @@ -253,11 +253,21 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write fmt.Fprintf(out, "}\n") } -func generateStructEntry(str Struct, key string, name string, out io.Writer) { +type structKey struct { + name string + field string + dir string +} + +func generateStructEntry(str Struct, key structKey, out io.Writer) { typ := "StructType" if str.IsUnion { typ = "UnionType" } + name := key.field + if name == "" { + name = key.name + } packed := "" if str.Packed { packed = ", packed: true" @@ -270,11 +280,11 @@ func generateStructEntry(str Struct, key string, name string, out io.Writer) { if str.Align != 0 { align = fmt.Sprintf(", align: %v", str.Align) } - fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", IsOptional: %v} %v %v %v},\n", - key, typ, name, false, packed, align, varlen) + fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n", + key, typ, name, fmtDir(key.dir), false, packed, align, varlen) } -func generateStructFields(str Struct, key string, desc *Description, consts map[string]uint64, out io.Writer) { +func generateStructFields(str Struct, key structKey, desc *Description, consts map[string]uint64, out io.Writer) { typ := "StructType" fields := "Fields" if str.IsUnion { @@ -284,7 +294,7 @@ func generateStructFields(str Struct, key string, desc *Description, consts map[ fmt.Fprintf(out, "{ s := Structs[\"%v\"].(*%v)\n", key, typ) for _, a := range str.Flds { fmt.Fprintf(out, "s.%v = append(s.%v, ", fields, fields) - generateArg(str.Name, a[0], a[1], a[2:], desc, consts, false, true, out) + generateArg(str.Name, a[0], a[1], key.dir, a[2:], desc, consts, false, true, out) fmt.Fprintf(out, ")\n") } fmt.Fprintf(out, "}\n") @@ -301,24 +311,23 @@ func generateStructs(desc *Description, consts map[string]uint64, out io.Writer) // for each field indexed by the name of the parent struct and the // field name. - structMap := make(map[string]Struct) + structMap := make(map[structKey]Struct) for _, str := range desc.Structs { - if _, ok := structMap[str.Name]; ok { - failf("two structs with the same name '%v'", str.Name) + for _, dir := range []string{"in", "out", "inout"} { + structMap[structKey{str.Name, "", dir}] = str } - structMap[str.Name] = str for _, a := range str.Flds { if innerStr, ok := desc.Structs[a[1]]; ok { - structMap[fmt.Sprintf("%v-%v", str.Name, a[0])] = innerStr + for _, dir := range []string{"in", "out", "inout"} { + structMap[structKey{a[1], a[0], dir}] = innerStr + } } } } fmt.Fprintf(out, "var Structs = map[string]Type{\n") for key, str := range structMap { - keyParts := strings.Split(key, "-") - name := keyParts[len(keyParts)-1] - generateStructEntry(str, key, name, out) + generateStructEntry(str, key, out) } fmt.Fprintf(out, "}\n") @@ -351,7 +360,7 @@ func parseRange(buffer string, consts map[string]uint64) (string, string) { } func generateArg( - parent, name, typ string, + parent, name, typ, dir string, a []string, desc *Description, consts map[string]uint64, @@ -369,7 +378,7 @@ func generateArg( } } common := func() string { - return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, IsOptional: %v}", name, opt) + return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, ArgDir: %v, IsOptional: %v}", name, fmtDir(dir), opt) } canBeArg := false switch typ { @@ -393,25 +402,28 @@ func generateArg( if want := 1; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = a[0] opt = false - fmt.Fprintf(out, "&PtrType{%v, Dir: %v, Type: &BufferType{%v, Kind: BufferBlobRand}}", commonHdr, fmtDir(a[0]), common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferBlobRand}}", ptrCommonHdr, common()) case "string": canBeArg = true if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = "in" opt = false - fmt.Fprintf(out, "&PtrType{%v, Dir: %v, Type: &BufferType{%v, Kind: BufferString}}", commonHdr, fmtDir("in"), common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferString}}", ptrCommonHdr, common()) case "filesystem": canBeArg = true if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = "in" opt = false - fmt.Fprintf(out, "&PtrType{%v, Dir: %v, Type: &BufferType{%v, Kind: BufferFilesystem}}", commonHdr, fmtDir("in"), common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferFilesystem}}", ptrCommonHdr, common()) case "sockaddr": if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) @@ -500,7 +512,10 @@ func generateArg( if want := 1; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "&PtrType{%v, Dir: %v, Type: &StrConstType{%v, Val: \"%v\"}}", common(), fmtDir("in"), common(), a[0]+"\\x00") + ptrCommonHdr := common() + dir = "in" + opt = false + fmt.Fprintf(out, "&PtrType{%v, Type: &StrConstType{%v, Val: \"%v\"}}", ptrCommonHdr, common(), a[0]+"\\x00") case "int8", "int16", "int32", "int64", "intptr", "int16be", "int32be", "int64be", "intptrbe": canBeArg = true size, bigEndian := decodeIntType(typ) @@ -534,9 +549,10 @@ func generateArg( if want := 0; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - commonHdr := common() + ptrCommonHdr := common() + dir = "in" opt = false - fmt.Fprintf(out, "&PtrType{%v, Dir: DirIn, Type: &FilenameType{%v}}", commonHdr, common()) + fmt.Fprintf(out, "&PtrType{%v, Type: &FilenameType{%v}}", ptrCommonHdr, common()) case "array": if len(a) != 1 && len(a) != 2 { failf("wrong number of arguments for %v arg %v, want 1 or 2, got %v", typ, name, len(a)) @@ -545,14 +561,14 @@ func generateArg( if a[0] == "int8" { fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRand}", common()) } else { - fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], desc, consts)) + fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], dir, desc, consts)) } } else { begin, end := parseRange(a[1], consts) if a[0] == "int8" { fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end) } else { - fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], desc, consts), begin, end) + fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], dir, desc, consts), begin, end) } } case "ptr": @@ -560,11 +576,12 @@ func generateArg( if want := 2; len(a) != want { failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) } - fmt.Fprintf(out, "&PtrType{%v, Type: %v, Dir: %v}", common(), generateType(a[1], desc, consts), fmtDir(a[0])) + dir = "in" + fmt.Fprintf(out, "&PtrType{%v, Type: %v}", common(), generateType(a[1], a[0], desc, consts)) default: if strings.HasPrefix(typ, "unnamed") { if inner, ok := desc.Unnamed[typ]; ok { - generateArg("", "", inner[0], inner[1:], desc, consts, false, isField, out) + generateArg("", "", inner[0], dir, inner[1:], desc, consts, false, isField, out) } else { failf("unknown unnamed type '%v'", typ) } @@ -572,11 +589,7 @@ func generateArg( if len(a) != 0 { failf("struct '%v' has args", typ) } - if parent == "" { - fmt.Fprintf(out, "Structs[\"%v\"]", typ) - } else { - fmt.Fprintf(out, "Structs[\"%v-%v\"]", parent, origName) - } + fmt.Fprintf(out, "Structs[\"%v\"]", structKey{typ, origName, dir}) } else if _, ok := desc.Resources[typ]; ok { if len(a) != 0 { failf("resource '%v' has args", typ) @@ -592,9 +605,9 @@ func generateArg( } } -func generateType(typ string, desc *Description, consts map[string]uint64) string { +func generateType(typ, dir string, desc *Description, consts map[string]uint64) string { buf := new(bytes.Buffer) - generateArg("", "", typ, nil, desc, consts, false, true, buf) + generateArg("", "", typ, dir, nil, desc, consts, false, true, buf) return buf.String() } -- cgit mrf-deployment