diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-12-10 15:49:04 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-12-10 16:37:02 +0100 |
| commit | 28bd3e371b1f31cb243f0df56b9c7720971a89db (patch) | |
| tree | ac2ff223b4b855f0bcb554bc65dcff07a2f4e49c /prog | |
| parent | c7ba317e9bfa7672d851df1217c2c3ea045c55f1 (diff) | |
prog: support AUTO args in programs
AUTO arguments can be used for:
- consts
- lens
- pointers
For const's and len's AUTO is replaced with the natural value,
addresses for AUTO pointers are allocated linearly.
This greatly simplifies writing test programs by hand
as most of the time we want these natural values.
Update tests to use AUTO.
Diffstat (limited to 'prog')
| -rw-r--r-- | prog/encoding.go | 85 | ||||
| -rw-r--r-- | prog/encoding_test.go | 8 | ||||
| -rw-r--r-- | prog/size.go | 76 | ||||
| -rw-r--r-- | prog/target.go | 2 |
4 files changed, 128 insertions, 43 deletions
diff --git a/prog/encoding.go b/prog/encoding.go index 2b4e4bf8c..9b4e9c6b6 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -201,6 +201,9 @@ func (target *Target) Deserialize(data []byte, mode DeserializeMode) (*Prog, err if err := prog.validate(); err != nil { return nil, err } + if p.autos != nil { + p.fixupAutos(prog) + } for _, c := range prog.Calls { target.SanitizeCall(c) } @@ -340,9 +343,15 @@ func (p *parser) parseArgImpl(typ Type) (Arg, error) { p.Parse('i') p.Parse('l') return nil, nil + case 'A': + p.Parse('A') + p.Parse('U') + p.Parse('T') + p.Parse('O') + return p.parseAuto(typ) default: - return nil, fmt.Errorf("failed to parse argument at %v (line #%v/%v: %v)", - int(p.Char()), p.l, p.i, p.s) + return nil, fmt.Errorf("failed to parse argument at '%c' (line #%v/%v: %v)", + p.Char(), p.l, p.i, p.s) } } @@ -366,6 +375,15 @@ func (p *parser) parseArgInt(typ Type) (Arg, error) { } } +func (p *parser) parseAuto(typ Type) (Arg, error) { + switch typ.(type) { + case *ConstType, *LenType, *CsumType: + return p.auto(MakeConstArg(typ, 0)), nil + default: + return nil, fmt.Errorf("wrong type %T for AUTO", typ) + } +} + func (p *parser) parseArgRes(typ Type) (Arg, error) { id := p.Ident() var div, add uint64 @@ -409,9 +427,23 @@ func (p *parser) parseArgAddr(typ Type) (Arg, error) { return typ.DefaultArg(), nil } p.Parse('&') - addr, vmaSize, err := p.parseAddr() - if err != nil { - return nil, err + auto := false + var addr, vmaSize uint64 + if p.Char() == 'A' { + p.Parse('A') + p.Parse('U') + p.Parse('T') + p.Parse('O') + if typ1 == nil { + return nil, fmt.Errorf("vma type can't be AUTO") + } + auto = true + } else { + var err error + addr, vmaSize, err = p.parseAddr() + if err != nil { + return nil, err + } } var inner Arg if p.Char() == '=' { @@ -424,6 +456,7 @@ func (p *parser) parseArgAddr(typ Type) (Arg, error) { typ = p.target.makeAnyPtrType(typ.Size(), typ.FieldName()) typ1 = p.target.any.array } + var err error inner, err = p.parseArg(typ1) if err != nil { return nil, err @@ -435,7 +468,11 @@ func (p *parser) parseArgAddr(typ Type) (Arg, error) { if inner == nil { inner = typ1.DefaultArg() } - return MakePointerArg(typ, addr, inner), nil + arg := MakePointerArg(typ, addr, inner) + if auto { + p.auto(arg) + } + return arg, nil } func (p *parser) parseArgString(typ Type) (Arg, error) { @@ -801,6 +838,7 @@ type parser struct { target *Target strict bool vars map[string]*ResultArg + autos map[Arg]bool comment string r *bufio.Scanner @@ -821,6 +859,41 @@ func newParser(target *Target, data []byte, strict bool) *parser { return p } +func (p *parser) auto(arg Arg) Arg { + if p.autos == nil { + p.autos = make(map[Arg]bool) + } + p.autos[arg] = true + return arg +} + +func (p *parser) fixupAutos(prog *Prog) { + s := analyze(nil, prog, nil) + for _, c := range prog.Calls { + p.target.assignSizesArray(c.Args, p.autos) + ForeachArg(c, func(arg Arg, _ *ArgCtx) { + if !p.autos[arg] { + return + } + delete(p.autos, arg) + switch typ := arg.Type().(type) { + case *ConstType: + arg.(*ConstArg).Val = typ.Val + _ = s + case *PtrType: + a := arg.(*PointerArg) + a.Address = s.ma.alloc(nil, a.Res.Size()) + default: + panic(fmt.Sprintf("unsupported auto type %T", typ)) + + } + }) + } + if len(p.autos) != 0 { + panic(fmt.Sprintf("leftoever autos: %+v", p.autos)) + } +} + func (p *parser) Scan() bool { if p.e != nil { return false diff --git a/prog/encoding_test.go b/prog/encoding_test.go index acaf642d5..ac670a8ab 100644 --- a/prog/encoding_test.go +++ b/prog/encoding_test.go @@ -245,6 +245,14 @@ func TestDeserialize(t *testing.T) { input: `test$excessive_fields1(0xfffffffffffffffc)`, output: `test$excessive_fields1(0xffffffffffffffff)`, }, + { + input: `test$auto0(AUTO, &AUTO={AUTO, AUTO, 0x1}, AUTO, 0x0)`, + output: `test$auto0(0x42, &(0x7f0000000040)={0xc, 0x43, 0x1}, 0xc, 0x0)`, + }, + { + input: `test$auto0(AUTO, &AUTO={AUTO, AUTO, AUTO}, AUTO, 0x0)`, + err: regexp.MustCompile(`wrong type \*prog\.IntType for AUTO`), + }, } buf := make([]byte, ExecBufferSize) for _, test := range tests { diff --git a/prog/size.go b/prog/size.go index c16e7f647..8c95d9c6f 100644 --- a/prog/size.go +++ b/prog/size.go @@ -33,7 +33,7 @@ func (target *Target) generateSize(arg Arg, lenType *LenType) uint64 { } } -func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg) { +func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg, autos map[Arg]bool) { // Create a map from field names to args. argsMap := make(map[string]Arg) for _, arg := range args { @@ -44,54 +44,58 @@ func (target *Target) assignSizes(args []Arg, parentsMap map[Arg]Arg) { } // Fill in size arguments. +nextArg: for _, arg := range args { if arg = InnerArg(arg); arg == nil { continue // Pointer to optional len field, no need to fill in value. } - if typ, ok := arg.Type().(*LenType); ok { - a := arg.(*ConstArg) - - buf, ok := argsMap[typ.Buf] - if ok { - a.Val = target.generateSize(InnerArg(buf), typ) + typ, ok := arg.Type().(*LenType) + if !ok { + continue + } + if autos != nil { + if !autos[arg] { continue } + delete(autos, arg) + } + a := arg.(*ConstArg) - if typ.Buf == "parent" { - a.Val = parentsMap[arg].Size() - if typ.BitSize != 0 { - a.Val = a.Val * 8 / typ.BitSize - } - continue + buf, ok := argsMap[typ.Buf] + if ok { + a.Val = target.generateSize(InnerArg(buf), typ) + continue + } + + if typ.Buf == "parent" { + a.Val = parentsMap[arg].Size() + if typ.BitSize != 0 { + a.Val = a.Val * 8 / typ.BitSize } + continue + } - sizeAssigned := false - for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] { - parentName := parent.Type().Name() - if pos := strings.IndexByte(parentName, '['); pos != -1 { - // For template parents, strip arguments. - parentName = parentName[:pos] - } - if typ.Buf == parentName { - a.Val = parent.Size() - if typ.BitSize != 0 { - a.Val = a.Val * 8 / typ.BitSize - } - sizeAssigned = true - break - } + for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] { + parentName := parent.Type().Name() + if pos := strings.IndexByte(parentName, '['); pos != -1 { + // For template parents, strip arguments. + parentName = parentName[:pos] } - if sizeAssigned { + if typ.Buf != parentName { continue } - - panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v", - typ.FieldName(), typ.Buf, argsMap)) + a.Val = parent.Size() + if typ.BitSize != 0 { + a.Val = a.Val * 8 / typ.BitSize + } + continue nextArg } + panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v", + typ.FieldName(), typ.Buf, argsMap)) } } -func (target *Target) assignSizesArray(args []Arg) { +func (target *Target) assignSizesArray(args []Arg, autos map[Arg]bool) { parentsMap := make(map[Arg]Arg) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { @@ -102,18 +106,18 @@ func (target *Target) assignSizesArray(args []Arg) { } }) } - target.assignSizes(args, parentsMap) + target.assignSizes(args, parentsMap, autos) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { if _, ok := arg.Type().(*StructType); ok { - target.assignSizes(arg.(*GroupArg).Inner, parentsMap) + target.assignSizes(arg.(*GroupArg).Inner, parentsMap, autos) } }) } } func (target *Target) assignSizesCall(c *Call) { - target.assignSizesArray(c.Args) + target.assignSizesArray(c.Args, nil) } func (r *randGen) mutateSize(arg *ConstArg, parent []Arg) bool { diff --git a/prog/target.go b/prog/target.go index 360e2e60f..b64af0027 100644 --- a/prog/target.go +++ b/prog/target.go @@ -212,7 +212,7 @@ func (g *Gen) GenerateSpecialArg(typ Type, pcalls *[]*Call) Arg { func (g *Gen) generateArg(typ Type, pcalls *[]*Call, ignoreSpecial bool) Arg { arg, calls := g.r.generateArgImpl(g.s, typ, ignoreSpecial) *pcalls = append(*pcalls, calls...) - g.r.target.assignSizesArray([]Arg{arg}) + g.r.target.assignSizesArray([]Arg{arg}, nil) return arg } |
