aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-10-19 14:41:46 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-11-11 14:27:54 -0800
commitd3a93e8370682fa5231bc94faf11ed3681b2ac99 (patch)
treea3f5827fe456cb7cc5f47e870c6069c0497ca3e5
parent959ec07095ff4ec4423a1365e0f0f94844a77507 (diff)
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.
-rw-r--r--prog/analysis.go23
-rw-r--r--prog/encodingexec.go2
-rw-r--r--prog/mutation.go8
-rw-r--r--prog/prio.go43
-rw-r--r--prog/prog.go11
-rw-r--r--prog/rand.go33
-rw-r--r--prog/validation.go10
-rw-r--r--sys/decl.go153
-rw-r--r--sysgen/sysgen.go89
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()
}