diff options
| -rw-r--r-- | prog/encoding.go | 36 | ||||
| -rw-r--r-- | prog/minimization.go | 6 | ||||
| -rw-r--r-- | prog/prog.go | 145 | ||||
| -rw-r--r-- | prog/prog_test.go | 4 | ||||
| -rw-r--r-- | prog/rand.go | 6 | ||||
| -rw-r--r-- | prog/types.go | 179 | ||||
| -rw-r--r-- | prog/validation.go | 15 |
7 files changed, 217 insertions, 174 deletions
diff --git a/prog/encoding.go b/prog/encoding.go index f8866b573..1bdff4c6d 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -95,7 +95,7 @@ func (a *PointerArg) serialize(ctx *serializer) { } target := ctx.target ctx.printf("&%v", target.serializeAddr(a)) - if a.Res != nil && target.isDefaultArg(a.Res) && !target.isAnyPtr(a.Type()) { + if a.Res != nil && isDefault(a.Res) && !target.isAnyPtr(a.Type()) { return } ctx.printf("=") @@ -135,7 +135,7 @@ func (a *GroupArg) serialize(ctx *serializer) { lastNonDefault := len(a.Inner) - 1 if a.fixedInnerSize() { for ; lastNonDefault >= 0; lastNonDefault-- { - if !ctx.target.isDefaultArg(a.Inner[lastNonDefault]) { + if !isDefault(a.Inner[lastNonDefault]) { break } } @@ -155,7 +155,7 @@ func (a *GroupArg) serialize(ctx *serializer) { func (a *UnionArg) serialize(ctx *serializer) { ctx.printf("@%v", a.Option.Type().FieldName()) - if ctx.target.isDefaultArg(a.Option) { + if isDefault(a.Option) { return } ctx.printf("=") @@ -245,7 +245,7 @@ func (target *Target) Deserialize(data []byte) (prog *Prog, err error) { c.Comment = strings.TrimSpace(p.s[p.i+1:]) } for i := len(c.Args); i < len(meta.Args); i++ { - c.Args = append(c.Args, target.defaultArg(meta.Args[i])) + c.Args = append(c.Args, meta.Args[i].makeDefaultArg()) } if len(c.Args) != len(meta.Args) { return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args)) @@ -284,7 +284,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]*ResultArg) } if arg == nil { if typ != nil { - arg = target.defaultArg(typ) + arg = typ.makeDefaultArg() } else if r != "" { return nil, fmt.Errorf("named nil argument") } @@ -340,10 +340,10 @@ func (target *Target) parseArgInt(typ Type, p *parser) (Arg, error) { if typ.Optional() { return MakeNullPointerArg(typ), nil } - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil default: eatExcessive(p, true) - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } } @@ -370,7 +370,7 @@ func (target *Target) parseArgRes(typ Type, p *parser, vars map[string]*ResultAr } v := vars[id] if v == nil { - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } arg := MakeResultArg(typ, v, 0) arg.OpDiv = div @@ -386,7 +386,7 @@ func (target *Target) parseArgAddr(typ Type, p *parser, vars map[string]*ResultA case *VmaType: default: eatExcessive(p, true) - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } p.Parse('&') addr, vmaSize, err := target.parseAddr(p) @@ -413,7 +413,7 @@ func (target *Target) parseArgAddr(typ Type, p *parser, vars map[string]*ResultA return MakeVmaPointerArg(typ, addr, vmaSize), nil } if inner == nil { - inner = target.defaultArg(typ1) + inner = typ1.makeDefaultArg() } return MakePointerArg(typ, addr, inner), nil } @@ -421,7 +421,7 @@ func (target *Target) parseArgAddr(typ Type, p *parser, vars map[string]*ResultA func (target *Target) parseArgString(typ Type, p *parser) (Arg, error) { if _, ok := typ.(*BufferType); !ok { eatExcessive(p, true) - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } data, err := deserializeData(p) if err != nil { @@ -457,7 +457,7 @@ func (target *Target) parseArgStruct(typ Type, p *parser, vars map[string]*Resul if !ok { eatExcessive(p, false) p.Parse('}') - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } var inner []Arg for i := 0; p.Char() != '}'; i++ { @@ -481,7 +481,7 @@ func (target *Target) parseArgStruct(typ Type, p *parser, vars map[string]*Resul } p.Parse('}') for len(inner) < len(t1.Fields) { - inner = append(inner, target.defaultArg(t1.Fields[len(inner)])) + inner = append(inner, t1.Fields[len(inner)].makeDefaultArg()) } return MakeGroupArg(typ, inner), nil } @@ -492,7 +492,7 @@ func (target *Target) parseArgArray(typ Type, p *parser, vars map[string]*Result if !ok { eatExcessive(p, false) p.Parse(']') - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } var inner []Arg for i := 0; p.Char() != ']'; i++ { @@ -508,7 +508,7 @@ func (target *Target) parseArgArray(typ Type, p *parser, vars map[string]*Result p.Parse(']') if t1.Kind == ArrayRangeLen && t1.RangeBegin == t1.RangeEnd { for uint64(len(inner)) < t1.RangeBegin { - inner = append(inner, target.defaultArg(t1.Type)) + inner = append(inner, t1.Type.makeDefaultArg()) } inner = inner[:t1.RangeBegin] } @@ -519,7 +519,7 @@ func (target *Target) parseArgUnion(typ Type, p *parser, vars map[string]*Result t1, ok := typ.(*UnionType) if !ok { eatExcessive(p, true) - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } p.Parse('@') name := p.Ident() @@ -532,7 +532,7 @@ func (target *Target) parseArgUnion(typ Type, p *parser, vars map[string]*Result } if optType == nil { eatExcessive(p, true) - return target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } var opt Arg if p.Char() == '=' { @@ -543,7 +543,7 @@ func (target *Target) parseArgUnion(typ Type, p *parser, vars map[string]*Result return nil, err } } else { - opt = target.defaultArg(optType) + opt = optType.makeDefaultArg() } return MakeUnionArg(typ, opt), nil } diff --git a/prog/minimization.go b/prog/minimization.go index 1943ef4ea..021d8e2ea 100644 --- a/prog/minimization.go +++ b/prog/minimization.go @@ -178,12 +178,12 @@ func minimizeInt(ctx *minimizeArgsCtx, arg Arg, path string) bool { return false } a := arg.(*ConstArg) - def := arg.Type().Default() - if a.Val == def { + def := arg.Type().makeDefaultArg().(*ConstArg) + if a.Val == def.Val { return false } v0 := a.Val - a.Val = def + a.Val = def.Val if ctx.pred(ctx.p, ctx.callIndex0) { *ctx.p0 = ctx.p } else { diff --git a/prog/prog.go b/prog/prog.go index 53e0fbe33..edfbd762c 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -60,13 +60,13 @@ func (arg *ConstArg) Value() (uint64, uint64) { return arg.Val, 0 case *LenType: return arg.Val, 0 + case *ResourceType: + return arg.Val, 0 case *CsumType: // Checksums are computed dynamically in executor. return 0, 0 - case *ResourceType: - return arg.Val, 0 case *ProcType: - if arg.Val == typ.Default() { + if arg.Val == procDefaultValue { return 0, 0 } return typ.ValuesStart + arg.Val, typ.ValuesPerProc @@ -276,119 +276,8 @@ func InnerArg(arg Arg) Arg { return arg // Not a pointer. } -func (target *Target) defaultArg(t Type) Arg { - switch typ := t.(type) { - case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType: - return MakeConstArg(t, t.Default()) - case *ResourceType: - return MakeResultArg(t, nil, typ.Default()) - case *BufferType: - if t.Dir() == DirOut { - var sz uint64 - if !typ.Varlen() { - sz = typ.Size() - } - return MakeOutDataArg(t, sz) - } - var data []byte - if !typ.Varlen() { - data = make([]byte, typ.Size()) - } - return MakeDataArg(t, data) - case *ArrayType: - var elems []Arg - if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd { - for i := uint64(0); i < typ.RangeBegin; i++ { - elems = append(elems, target.defaultArg(typ.Type)) - } - } - return MakeGroupArg(t, elems) - case *StructType: - var inner []Arg - for _, field := range typ.Fields { - inner = append(inner, target.defaultArg(field)) - } - return MakeGroupArg(t, inner) - case *UnionType: - return MakeUnionArg(t, target.defaultArg(typ.Fields[0])) - case *VmaType: - if t.Optional() { - return MakeNullPointerArg(t) - } - return MakeVmaPointerArg(t, 0, target.PageSize) - case *PtrType: - if t.Optional() { - return MakeNullPointerArg(t) - } - return MakePointerArg(t, 0, target.defaultArg(typ.Type)) - default: - panic(fmt.Sprintf("unknown arg type: %#v", t)) - } -} - -func (target *Target) isDefaultArg(arg Arg) bool { - if IsPad(arg.Type()) { - return true - } - switch a := arg.(type) { - case *ConstArg: - switch t := a.Type().(type) { - case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType: - return a.Val == t.Default() - default: - panic(fmt.Sprintf("unknown const type: %#v", t)) - } - case *GroupArg: - if !a.fixedInnerSize() && len(a.Inner) != 0 { - return false - } - for _, elem := range a.Inner { - if !target.isDefaultArg(elem) { - return false - } - } - return true - case *UnionArg: - t := a.Type().(*UnionType) - return a.Option.Type().FieldName() == t.Fields[0].FieldName() && - target.isDefaultArg(a.Option) - case *DataArg: - if a.Size() == 0 { - return true - } - if a.Type().Varlen() { - return false - } - if a.Type().Dir() == DirOut { - return true - } - for _, v := range a.Data() { - if v != 0 { - return false - } - } - return true - case *PointerArg: - switch t := a.Type().(type) { - case *PtrType: - if t.Optional() { - return a.IsNull() - } - return a.Address == 0 && target.isDefaultArg(a.Res) - case *VmaType: - if t.Optional() { - return a.IsNull() - } - return a.Address == 0 && a.VmaSize == target.PageSize - default: - panic(fmt.Sprintf("unknown pointer type: %#v", t)) - } - case *ResultArg: - t := a.Type().(*ResourceType) - return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 && - len(a.uses) == 0 && a.Val == t.Default() - } - return false +func isDefault(arg Arg) bool { + return arg.Type().isDefaultArg(arg) } func (p *Prog) insertBefore(c *Call, calls []*Call) { @@ -456,18 +345,20 @@ func replaceResultArg(arg, arg1 *ResultArg) { // removeArg removes all references to/from arg0 from a program. func removeArg(arg0 Arg) { ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) { - if a, ok := arg.(*ResultArg); ok { - if a.Res != nil { - uses := a.Res.uses - if !uses[a] { - panic("broken tree") - } - delete(uses, a) - } - for arg1 := range a.uses { - arg2 := MakeResultArg(arg1.Type(), nil, arg1.Type().Default()) - replaceResultArg(arg1, arg2) + a, ok := arg.(*ResultArg) + if !ok { + return + } + if a.Res != nil { + uses := a.Res.uses + if !uses[a] { + panic("broken tree") } + delete(uses, a) + } + for arg1 := range a.uses { + arg2 := arg1.Type().makeDefaultArg().(*ResultArg) + replaceResultArg(arg1, arg2) } }) } diff --git a/prog/prog_test.go b/prog/prog_test.go index 0628b40e5..c3f20bd6d 100644 --- a/prog/prog_test.go +++ b/prog/prog_test.go @@ -24,8 +24,8 @@ func TestDefault(t *testing.T) { target, _, _ := initTest(t) for _, meta := range target.Syscalls { ForeachType(meta, func(typ Type) { - arg := target.defaultArg(typ) - if !target.isDefaultArg(arg) { + arg := typ.makeDefaultArg() + if !isDefault(arg) { t.Errorf("default arg is not default: %s\ntype: %#v\narg: %#v", typ, typ, arg) } diff --git a/prog/rand.go b/prog/rand.go index 721bbed00..7bded23c6 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -279,7 +279,7 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls [] metas = append(metas, meta) } if len(metas) == 0 { - return MakeResultArg(res, nil, res.Default()), nil + return res.makeDefaultArg(), nil } // Now we have a set of candidate calls that can create the necessary resource. @@ -490,7 +490,7 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A switch typ.(type) { case *IntType, *FlagsType, *ConstType, *ProcType, *VmaType, *ResourceType: - return r.target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } } @@ -499,7 +499,7 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A v := res.Desc.Values[r.Intn(len(res.Desc.Values))] return MakeResultArg(typ, nil, v), nil } - return r.target.defaultArg(typ), nil + return typ.makeDefaultArg(), nil } // Allow infinite recursion for optional pointers. diff --git a/prog/types.go b/prog/types.go index 2e694ef9f..004194707 100644 --- a/prog/types.go +++ b/prog/types.go @@ -53,7 +53,6 @@ type Type interface { FieldName() string Dir() Dir Optional() bool - Default() uint64 Varlen() bool Size() uint64 Format() BinaryFormat @@ -61,6 +60,8 @@ type Type interface { BitfieldLength() uint64 BitfieldMiddle() bool // returns true for all but last bitfield in a group + makeDefaultArg() Arg + isDefaultArg(arg Arg) bool generate(r *randGen, s *state) (arg Arg, calls []*Call) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool @@ -94,10 +95,6 @@ func (t *TypeCommon) Optional() bool { return t.IsOptional } -func (t *TypeCommon) Default() uint64 { - return 0 -} - func (t *TypeCommon) Size() uint64 { if t.IsVarlen { panic(fmt.Sprintf("static type size is not known: %#v", t)) @@ -146,6 +143,16 @@ func (t *ResourceType) String() string { return t.Name() } +func (t *ResourceType) makeDefaultArg() Arg { + return MakeResultArg(t, nil, t.Default()) +} + +func (t *ResourceType) isDefaultArg(arg Arg) bool { + a := arg.(*ResultArg) + return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 && + len(a.uses) == 0 && a.Val == t.Default() +} + func (t *ResourceType) Default() uint64 { return t.Desc.Values[0] } @@ -192,8 +199,12 @@ type ConstType struct { IsPad bool } -func (t *ConstType) Default() uint64 { - return t.Val +func (t *ConstType) makeDefaultArg() Arg { + return MakeConstArg(t, t.Val) +} + +func (t *ConstType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == t.Val } func (t *ConstType) String() string { @@ -218,29 +229,59 @@ type IntType struct { RangeEnd uint64 } +func (t *IntType) makeDefaultArg() Arg { + return MakeConstArg(t, 0) +} + +func (t *IntType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == 0 +} + type FlagsType struct { IntTypeCommon Vals []uint64 BitMask bool } +func (t *FlagsType) makeDefaultArg() Arg { + return MakeConstArg(t, 0) +} + +func (t *FlagsType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == 0 +} + type LenType struct { IntTypeCommon BitSize uint64 // want size in multiple of bits instead of array size Buf string } +func (t *LenType) makeDefaultArg() Arg { + return MakeConstArg(t, 0) +} + +func (t *LenType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == 0 +} + type ProcType struct { IntTypeCommon ValuesStart uint64 ValuesPerProc uint64 } -const MaxPids = 32 +const ( + MaxPids = 32 + procDefaultValue = 0xffffffffffffffff // special value denoting 0 for all procs +) -func (t *ProcType) Default() uint64 { - // Special value denoting 0 for all procs. - return 0xffffffffffffffff +func (t *ProcType) makeDefaultArg() Arg { + return MakeConstArg(t, procDefaultValue) +} + +func (t *ProcType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == procDefaultValue } type CsumKind int @@ -261,6 +302,14 @@ func (t *CsumType) String() string { return "csum" } +func (t *CsumType) makeDefaultArg() Arg { + return MakeConstArg(t, 0) +} + +func (t *CsumType) isDefaultArg(arg Arg) bool { + return arg.(*ConstArg).Val == 0 +} + type VmaType struct { TypeCommon RangeBegin uint64 // in pages @@ -271,6 +320,14 @@ func (t *VmaType) String() string { return "vma" } +func (t *VmaType) makeDefaultArg() Arg { + return MakeNullPointerArg(t) +} + +func (t *VmaType) isDefaultArg(arg Arg) bool { + return arg.(*PointerArg).IsNull() +} + type BufferKind int const ( @@ -306,6 +363,40 @@ func (t *BufferType) String() string { return "buffer" } +func (t *BufferType) makeDefaultArg() Arg { + if t.Dir() == DirOut { + var sz uint64 + if !t.Varlen() { + sz = t.Size() + } + return MakeOutDataArg(t, sz) + } + var data []byte + if !t.Varlen() { + data = make([]byte, t.Size()) + } + return MakeDataArg(t, data) +} + +func (t *BufferType) isDefaultArg(arg Arg) bool { + a := arg.(*DataArg) + if a.Size() == 0 { + return true + } + if a.Type().Varlen() { + return false + } + if a.Type().Dir() == DirOut { + return true + } + for _, v := range a.Data() { + if v != 0 { + return false + } + } + return true +} + type ArrayKind int const ( @@ -325,6 +416,29 @@ func (t *ArrayType) String() string { return fmt.Sprintf("array[%v]", t.Type.String()) } +func (t *ArrayType) makeDefaultArg() Arg { + var elems []Arg + if t.Kind == ArrayRangeLen && t.RangeBegin == t.RangeEnd { + for i := uint64(0); i < t.RangeBegin; i++ { + elems = append(elems, t.Type.makeDefaultArg()) + } + } + return MakeGroupArg(t, elems) +} + +func (t *ArrayType) isDefaultArg(arg Arg) bool { + a := arg.(*GroupArg) + if !a.fixedInnerSize() && len(a.Inner) != 0 { + return false + } + for _, elem := range a.Inner { + if !t.Type.isDefaultArg(elem) { + return false + } + } + return true +} + type PtrType struct { TypeCommon Type Type @@ -334,6 +448,21 @@ func (t *PtrType) String() string { return fmt.Sprintf("ptr[%v, %v]", t.Dir(), t.Type.String()) } +func (t *PtrType) makeDefaultArg() Arg { + if t.Optional() { + return MakeNullPointerArg(t) + } + return MakePointerArg(t, 0, t.Type.makeDefaultArg()) +} + +func (t *PtrType) isDefaultArg(arg Arg) bool { + a := arg.(*PointerArg) + if t.Optional() { + return a.IsNull() + } + return a.Address == 0 && t.Type.isDefaultArg(a.Res) +} + type StructType struct { Key StructKey FldName string @@ -348,6 +477,24 @@ func (t *StructType) FieldName() string { return t.FldName } +func (t *StructType) makeDefaultArg() Arg { + inner := make([]Arg, len(t.Fields)) + for i, field := range t.Fields { + inner[i] = field.makeDefaultArg() + } + return MakeGroupArg(t, inner) +} + +func (t *StructType) isDefaultArg(arg Arg) bool { + a := arg.(*GroupArg) + for i, elem := range a.Inner { + if !t.Fields[i].isDefaultArg(elem) { + return false + } + } + return true +} + type UnionType struct { Key StructKey FldName string @@ -362,6 +509,16 @@ func (t *UnionType) FieldName() string { return t.FldName } +func (t *UnionType) makeDefaultArg() Arg { + return MakeUnionArg(t, t.Fields[0].makeDefaultArg()) +} + +func (t *UnionType) isDefaultArg(arg Arg) bool { + a := arg.(*UnionArg) + return a.Option.Type().FieldName() == t.Fields[0].FieldName() && + t.Fields[0].isDefaultArg(a.Option) +} + type StructDesc struct { TypeCommon Fields []Type diff --git a/prog/validation.go b/prog/validation.go index 5f53e48aa..af27d4187 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -90,20 +90,18 @@ func (ctx *validCtx) validateArg(arg Arg) error { func (arg *ConstArg) validate(ctx *validCtx) error { switch typ := arg.Type().(type) { case *IntType: - if typ.Dir() == DirOut && (arg.Val != 0 && arg.Val != typ.Default()) { + if typ.Dir() == DirOut && !isDefault(arg) { return fmt.Errorf("out int arg '%v' has bad const value %v", typ.Name(), arg.Val) } case *ProcType: - if arg.Val >= typ.ValuesPerProc && arg.Val != typ.Default() { + if arg.Val >= typ.ValuesPerProc && !isDefault(arg) { return fmt.Errorf("per proc arg '%v' has bad value %v", typ.Name(), arg.Val) } case *CsumType: if arg.Val != 0 { return fmt.Errorf("csum arg '%v' has nonzero value %v", typ.Name(), arg.Val) } - case *ConstType: - case *FlagsType: - case *LenType: + case *ConstType, *FlagsType, *LenType: default: return fmt.Errorf("const arg %v has bad type %v", arg, typ.Name()) } @@ -111,7 +109,7 @@ func (arg *ConstArg) validate(ctx *validCtx) error { // We generate output len arguments, which makes sense since it can be // a length of a variable-length array which is not known otherwise. if _, isLen := typ.(*LenType); !isLen { - if arg.Val != 0 && arg.Val != typ.Default() { + if !typ.isDefaultArg(arg) { return fmt.Errorf("output arg '%v'/'%v' has non default value '%+v'", typ.FieldName(), typ.Name(), arg) } @@ -134,7 +132,7 @@ func (arg *ResultArg) validate(ctx *validCtx) error { } ctx.uses[u] = arg } - if typ.Dir() == DirOut && (arg.Val != 0 && arg.Val != typ.Default()) { + if typ.Dir() == DirOut && arg.Val != 0 && arg.Val != typ.Default() { return fmt.Errorf("out resource arg '%v' has bad const value %v", typ.Name(), arg.Val) } if arg.Res != nil { @@ -229,9 +227,6 @@ func (arg *PointerArg) validate(ctx *validCtx) error { if arg.Res != nil { return fmt.Errorf("vma arg '%v' has data", typ.Name()) } - if arg.VmaSize == 0 && typ.Dir() != DirOut && !typ.Optional() { - return fmt.Errorf("vma arg '%v' has size 0", typ.Name()) - } case *PtrType: if arg.Res == nil && !arg.Type().Optional() { return fmt.Errorf("non optional pointer arg '%v' is nil", typ.Name()) |
