diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2022-01-05 20:05:11 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2022-01-11 16:30:08 +0100 |
| commit | 2cfe62f82077ba012aef55db5288985bc0c426d9 (patch) | |
| tree | 501d83deb358a230d157c9d7efc6fc393e239472 | |
| parent | 16e21d13ea26a631e9b3a30c94635b1d565fd78f (diff) | |
pkg/compiler: add out_overlay field attribute
| -rw-r--r-- | docs/syscall_descriptions_syntax.md | 27 | ||||
| -rw-r--r-- | pkg/compiler/attrs.go | 17 | ||||
| -rw-r--r-- | pkg/compiler/check.go | 36 | ||||
| -rw-r--r-- | pkg/compiler/gen.go | 57 | ||||
| -rw-r--r-- | pkg/compiler/testdata/all.txt | 9 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors.txt | 21 | ||||
| -rw-r--r-- | pkg/compiler/testdata/errors2.txt | 12 | ||||
| -rw-r--r-- | pkg/compiler/types.go | 14 | ||||
| -rw-r--r-- | prog/analysis.go | 13 | ||||
| -rw-r--r-- | prog/any.go | 26 | ||||
| -rw-r--r-- | prog/prog.go | 21 | ||||
| -rw-r--r-- | prog/size.go | 17 | ||||
| -rw-r--r-- | prog/types.go | 5 | ||||
| -rw-r--r-- | sys/test/exec.txt | 110 | ||||
| -rw-r--r-- | sys/test/test/overlay | 9 |
15 files changed, 302 insertions, 92 deletions
diff --git a/docs/syscall_descriptions_syntax.md b/docs/syscall_descriptions_syntax.md index 68abd1f71..cf03350e0 100644 --- a/docs/syscall_descriptions_syntax.md +++ b/docs/syscall_descriptions_syntax.md @@ -129,8 +129,31 @@ structname "{" "\n" ``` Fields can have attributes specified in parentheses after the field, independent -of their type. The only attribute is direction (`in/out/inout`). For the field for -which it is specified, the direction attributes on the upper levels are overridden. +of their type. `in/out/inout` attribute specify per-field direction, for example: + +``` +foo { + field0 const[1, int32] (in) + field1 int32 (inout) + field2 fd (out) +} +``` + +`out_overlay` attribute allows to have separate input and output layouts for the struct. +Fields before the `out_overlay` field are input, fields starting from `out_overlay` are output. +Input and output fields overlap in memory (both start from the beginning of the struct in memory). +For example: + +``` +foo { + in0 const[1, int32] + in1 flags[bar, int8] + in2 ptr[in, string] + out0 fd (out_overlay) + out1 int32 +} +``` + Structs can have attributes specified in square brackets after the struct. Attributes are: diff --git a/pkg/compiler/attrs.go b/pkg/compiler/attrs.go index 5de19f884..63ba613d9 100644 --- a/pkg/compiler/attrs.go +++ b/pkg/compiler/attrs.go @@ -19,17 +19,18 @@ type attrDesc struct { } var ( - attrPacked = &attrDesc{Name: "packed"} - attrVarlen = &attrDesc{Name: "varlen"} - attrSize = &attrDesc{Name: "size", HasArg: true} - attrAlign = &attrDesc{Name: "align", HasArg: true} - attrIn = &attrDesc{Name: "in"} - attrOut = &attrDesc{Name: "out"} - attrInOut = &attrDesc{Name: "inout"} + attrPacked = &attrDesc{Name: "packed"} + attrVarlen = &attrDesc{Name: "varlen"} + attrSize = &attrDesc{Name: "size", HasArg: true} + attrAlign = &attrDesc{Name: "align", HasArg: true} + attrIn = &attrDesc{Name: "in"} + attrOut = &attrDesc{Name: "out"} + attrInOut = &attrDesc{Name: "inout"} + attrOutOverlay = &attrDesc{Name: "out_overlay"} structAttrs = makeAttrs(attrPacked, attrSize, attrAlign) unionAttrs = makeAttrs(attrVarlen, attrSize) - fieldAttrs = makeAttrs(attrIn, attrOut, attrInOut) + fieldAttrs = makeAttrs(attrIn, attrOut, attrInOut, attrOutOverlay) callAttrs = make(map[string]*attrDesc) ) diff --git a/pkg/compiler/check.go b/pkg/compiler/check.go index c5fc226d6..676b96c5c 100644 --- a/pkg/compiler/check.go +++ b/pkg/compiler/check.go @@ -182,13 +182,33 @@ func (comp *compiler) checkStructFields(n *ast.Struct, typ, name string) { if len(n.Fields) < 1 { comp.error(n.Pos, "%v %v has no fields, need at least 1 field", typ, name) } - for _, f := range n.Fields { + hasDirections, hasOutOverlay := false, false + for fieldIdx, f := range n.Fields { attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs) - - if attrs[attrIn]+attrs[attrOut]+attrs[attrInOut] > 1 { + dirCount := attrs[attrIn] + attrs[attrOut] + attrs[attrInOut] + if dirCount != 0 { + hasDirections = true + } + if dirCount > 1 { _, typ, _ := f.Info() comp.error(f.Pos, "%v has multiple direction attributes", typ) } + if attrs[attrOutOverlay] > 0 { + if n.IsUnion { + _, typ, name := f.Info() + comp.error(f.Pos, "unknown %v %v attribute %v", typ, name, attrOutOverlay.Name) + } + if fieldIdx == 0 { + comp.error(f.Pos, "%v attribute must not be specified on the first field", attrOutOverlay.Name) + } + if hasOutOverlay || attrs[attrOutOverlay] > 1 { + comp.error(f.Pos, "multiple %v attributes", attrOutOverlay.Name) + } + hasOutOverlay = true + } + if hasDirections && hasOutOverlay { + comp.error(f.Pos, "mix of direction and %v attributes is not supported", attrOutOverlay.Name) + } } } @@ -301,12 +321,22 @@ func (comp *compiler) checkAttributeValues() { } // Check each field's attributes. st := decl.(*ast.Struct) + hasOutOverlay := false for _, f := range st.Fields { + isOut := hasOutOverlay for _, attr := range f.Attrs { desc := fieldAttrs[attr.Ident] if desc.CheckConsts != nil { desc.CheckConsts(comp, f, attr) } + switch attr.Ident { + case attrOutOverlay.Name: + hasOutOverlay = true + isOut = true + } + } + if isOut && comp.getTypeDesc(f.Type).CantBeOut { + comp.error(f.Pos, "%v type must not be used as output", f.Type.Ident) } } } diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go index b4ee50a9b..78cbc54fe 100644 --- a/pkg/compiler/gen.go +++ b/pkg/compiler/gen.go @@ -66,7 +66,7 @@ func (comp *compiler) collectCallArgSizes() map[string][]uint64 { argSizes = append(argSizes, comp.ptrSize) } desc, _, _ := comp.getArgsBase(arg.Type, true) - typ := comp.genField(arg, comp.ptrSize) + typ := comp.genField(arg, comp.ptrSize, prog.DirInOut) // Ignore all types with base (const, flags). We don't have base in syscall args. // Also ignore resources and pointers because fd can be 32-bits and pointer 64-bits, // and then there is no way to fix this. @@ -124,12 +124,13 @@ func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall { fld.SetBool(val != 0) } } + fields, _ := comp.genFieldArray(n.Args, argSizes) return &prog.Syscall{ Name: n.Name.Name, CallName: n.CallName, NR: n.NR, MissingArgs: len(argSizes) - len(n.Args), - Args: comp.genFieldArray(n.Args, argSizes), + Args: fields, Ret: ret, Attrs: attrs, } @@ -271,8 +272,15 @@ func (comp *compiler) layoutStruct(t *prog.StructType) { comp.layoutStructFields(t, varlen, attrs[attrPacked] != 0) t.TypeSize = 0 if !varlen { - for _, f := range t.Fields { - t.TypeSize += f.Size() + var size uint64 + for i, f := range t.Fields { + if i == t.OverlayField { + size = 0 + } + size += f.Size() + if t.TypeSize < size { + t.TypeSize = size + } } sizeAttr, hasSize := attrs[attrSize] if hasSize { @@ -291,9 +299,17 @@ func (comp *compiler) layoutStruct(t *prog.StructType) { func (comp *compiler) layoutStructFields(t *prog.StructType, varlen, packed bool) { var newFields []prog.Field + overlayField0 := t.OverlayField var structAlign, byteOffset, bitOffset uint64 for i, field := range t.Fields { f := field.Type + if i == overlayField0 { + // We layout fields before overlay and the overlay fields effectively as 2 independent structs. + // So if we starting overlay, add any trailign padding/finalize bitfield layout and reset state. + newFields = comp.finalizeStructFields(t, newFields, varlen, structAlign, byteOffset, bitOffset) + t.OverlayField = len(newFields) // update overlay field index after we added paddings + structAlign, byteOffset, bitOffset = 0, 0, 0 + } fieldAlign := uint64(1) if !packed { fieldAlign = f.Alignment() @@ -367,9 +383,9 @@ func (comp *compiler) finalizeStructFields(t *prog.StructType, fields []prog.Fie if bitOffset != 0 { pad := roundup(bitOffset, 8) / 8 byteOffset += pad - i := len(t.Fields) - if i != 0 && t.Fields[i-1].IsBitfield() { - setBitfieldTypeSize(t.Fields[i-1].Type, pad) + i := len(fields) + if i != 0 && fields[i-1].IsBitfield() { + setBitfieldTypeSize(fields[i-1].Type, pad) } else { fields = append(fields, genPad(pad)) } @@ -437,12 +453,26 @@ func genPad(size uint64) prog.Field { } } -func (comp *compiler) genFieldArray(fields []*ast.Field, argSizes []uint64) []prog.Field { +func (comp *compiler) genFieldArray(fields []*ast.Field, argSizes []uint64) ([]prog.Field, int) { + outOverlay := -1 + for i, f := range fields { + attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs) + if attrs[attrOutOverlay] > 0 { + outOverlay = i + } + } var res []prog.Field for i, f := range fields { - res = append(res, comp.genField(f, argSizes[i])) + overlayDir := prog.DirInOut + if outOverlay != -1 { + overlayDir = prog.DirIn + if i >= outOverlay { + overlayDir = prog.DirOut + } + } + res = append(res, comp.genField(f, argSizes[i], overlayDir)) } - return res + return res, outOverlay } func (comp *compiler) genFieldDir(f *ast.Field) (prog.Dir, bool) { @@ -459,8 +489,11 @@ func (comp *compiler) genFieldDir(f *ast.Field) (prog.Dir, bool) { } } -func (comp *compiler) genField(f *ast.Field, argSize uint64) prog.Field { - dir, hasDir := comp.genFieldDir(f) +func (comp *compiler) genField(f *ast.Field, argSize uint64, overlayDir prog.Dir) prog.Field { + dir, hasDir := overlayDir, true + if overlayDir == prog.DirInOut { + dir, hasDir = comp.genFieldDir(f) + } return prog.Field{ Name: f.Name.Name, diff --git a/pkg/compiler/testdata/all.txt b/pkg/compiler/testdata/all.txt index b1adf2321..c9a02f592 100644 --- a/pkg/compiler/testdata/all.txt +++ b/pkg/compiler/testdata/all.txt @@ -287,7 +287,14 @@ s5 { f_inout1 int32[0:1] (inout) } -foo_s0(a ptr[in, s0], b ptr[in, s1], c ptr[in, s2], d ptr[in, s4], e ptr[in, s5]) +s6 { + f0 int32 + f1 r0 + f2 int32 (out_overlay) + f3 r0 +} + +foo_s0(a ptr[in, s0], b ptr[in, s1], c ptr[in, s2], d ptr[in, s4], e ptr[in, s5], f ptr[in, s6]) # Unions. diff --git a/pkg/compiler/testdata/errors.txt b/pkg/compiler/testdata/errors.txt index 65eaf8a97..6cc2e2b0f 100644 --- a/pkg/compiler/testdata/errors.txt +++ b/pkg/compiler/testdata/errors.txt @@ -391,3 +391,24 @@ struct$perfielddir { f5 int32 (out, inout) ### arg/field has multiple direction attributes f6 int32 (in, out, inout) ### arg/field has multiple direction attributes } + +struct$overlay0 { + f0 int32 (out_overlay) ### out_overlay attribute must not be specified on the first field + f1 int32 (out_overlay) ### multiple out_overlay attributes +} + +struct$overlay1 { + f0 int32 + f1 int32 (out_overlay, out_overlay) ### duplicate arg/field f1 attribute out_overlay + f2 int32 (out_overlay) ### multiple out_overlay attributes +} + +struct$overlay2 { + f0 int32 (in) + f1 int32 (out_overlay) ### mix of direction and out_overlay attributes is not supported +} + +union$overlay0 [ + f0 int32 + f1 int32 (out_overlay) ### unknown arg/field f1 attribute out_overlay +] diff --git a/pkg/compiler/testdata/errors2.txt b/pkg/compiler/testdata/errors2.txt index 111db587f..e5a51b4a9 100644 --- a/pkg/compiler/testdata/errors2.txt +++ b/pkg/compiler/testdata/errors2.txt @@ -386,3 +386,15 @@ s405 { f3 int64:16[-65541:-10] ### int range [18446744073709486075:18446744073709551606] is too large for base type of size 16 f4 int16:8[-255:0] ### int range [18446744073709551361:0] is too large for base type of size 8 } + +# Field attributes. + +foo$overlay(a ptr[in, struct$overlay0]) + +struct$overlay0 { + f0 int32 + f1 const[0, int32] (out_overlay) ### const type must not be used as output + f2 ptr[in, int32] ### ptr type must not be used as output + f3 proc[0, 1, int32] ### proc type must not be used as output + f4 bytesize[f1, int32] ### bytesize type must not be used as output +} diff --git a/pkg/compiler/types.go b/pkg/compiler/types.go index 53ba8c86f..8454a92d5 100644 --- a/pkg/compiler/types.go +++ b/pkg/compiler/types.go @@ -19,6 +19,7 @@ type typeDesc struct { Names []string CanBeTypedef bool // can be type alias target? CantBeOpt bool // can't be marked as opt? + CantBeOut bool // can't be used as an explicitly output argument NeedBase bool // needs base type when used as field? MaxColon int // max number of colons (int8:2) on fields OptArgs int // number of optional arguments in Args array @@ -164,6 +165,7 @@ func getIntAlignment(comp *compiler, base prog.IntTypeCommon) uint64 { var typePtr = &typeDesc{ Names: []string{"ptr", "ptr64"}, CanBeArgRet: canBeArg, + CantBeOut: true, CanBeTypedef: true, Args: []namedArg{{Name: "direction", Type: typeArgDir}, {Name: "type", Type: typeArgType}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { @@ -289,6 +291,7 @@ var typeLen = &typeDesc{ Names: []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize", "offsetof"}, CanBeArgRet: canBeArg, CantBeOpt: true, + CantBeOut: true, NeedBase: true, Args: []namedArg{{Name: "len target", Type: typeArgLenTarget}}, Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type { @@ -325,6 +328,7 @@ var typeConst = &typeDesc{ CanBeArgRet: canBeArg, CanBeTypedef: true, CantBeOpt: true, + CantBeOut: true, NeedBase: true, Args: []namedArg{{Name: "value", Type: typeArgInt}}, CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { @@ -367,6 +371,7 @@ var typeFlags = &typeDesc{ CanBeArgRet: canBeArg, CanBeTypedef: true, CantBeOpt: true, + CantBeOut: true, NeedBase: true, Args: []namedArg{{Name: "flags", Type: typeArgFlags}}, CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) { @@ -469,6 +474,7 @@ var typeCsum = &typeDesc{ Names: []string{"csum"}, NeedBase: true, CantBeOpt: true, + CantBeOut: true, OptArgs: 1, Args: []namedArg{ {Name: "csum target", Type: typeArgLenTarget}, @@ -517,6 +523,7 @@ func genCsumKind(t *ast.Type) prog.CsumKind { var typeProc = &typeDesc{ Names: []string{"proc"}, CanBeArgRet: canBeArg, + CantBeOut: true, CanBeTypedef: true, NeedBase: true, Args: []namedArg{ @@ -555,6 +562,7 @@ var typeProc = &typeDesc{ var typeText = &typeDesc{ Names: []string{"text"}, CantBeOpt: true, + CantBeOut: true, Args: []namedArg{{Name: "kind", Type: typeArgTextType}}, Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool { return true @@ -754,6 +762,7 @@ var typeFmt = &typeDesc{ Names: []string{"fmt"}, CanBeTypedef: true, CantBeOpt: true, + CantBeOut: true, Args: []namedArg{ {Name: "format", Type: typeFmtFormat}, {Name: "value", Type: typeArgType, IsArg: true}, @@ -908,7 +917,7 @@ func init() { } // Need to cache type in structTypes before generating fields to break recursion. comp.structTypes[t.Ident] = typ - fields := comp.genFieldArray(s.Fields, make([]uint64, len(s.Fields))) + fields, overlayField := comp.genFieldArray(s.Fields, make([]uint64, len(s.Fields))) switch typ1 := typ.(type) { case *prog.UnionType: typ1.Fields = fields @@ -919,6 +928,9 @@ func init() { } case *prog.StructType: typ1.Fields = fields + if overlayField >= 0 { + typ1.OverlayField = overlayField + } attrs := comp.parseAttrs(structAttrs, s, s.Attrs) if align := attrs[attrAlign]; align != 0 { typ1.TypeAlign = align diff --git a/prog/analysis.go b/prog/analysis.go index 697e1eab5..1b572f0c0 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -132,22 +132,29 @@ func foreachArgImpl(arg Arg, ctx *ArgCtx, f func(Arg, *ArgCtx)) { } switch a := arg.(type) { case *GroupArg: + overlayField := 0 if typ, ok := a.Type().(*StructType); ok { ctx.Parent = &a.Inner ctx.Fields = typ.Fields + overlayField = typ.OverlayField } var totalSize uint64 - for _, arg1 := range a.Inner { + for i, arg1 := range a.Inner { + if i == overlayField { + ctx.Offset = ctx0.Offset + } foreachArgImpl(arg1, ctx, f) size := arg1.Size() ctx.Offset += size - totalSize += size + if totalSize < ctx.Offset { + totalSize = ctx.Offset - ctx0.Offset + } } claimedSize := a.Size() varlen := a.Type().Varlen() if varlen && totalSize > claimedSize || !varlen && totalSize != claimedSize { panic(fmt.Sprintf("bad group arg size %v, should be <= %v for %#v type %#v", - totalSize, claimedSize, a, a.Type())) + totalSize, claimedSize, a, a.Type().Name())) } case *PointerArg: if a.Res != nil { diff --git a/prog/any.go b/prog/any.go index bb80eaa38..16a309c90 100644 --- a/prog/any.go +++ b/prog/any.go @@ -236,18 +236,19 @@ func (target *Target) squashResult(arg *ResultArg, elems *[]Arg) { } func (target *Target) squashGroup(arg *GroupArg, elems *[]Arg) { - var pad uint64 - if typ, ok := arg.Type().(*StructType); ok && typ.Varlen() && typ.AlignAttr != 0 { - var fieldsSize uint64 - for _, fld := range arg.Inner { - fieldsSize += fld.Size() - } - if fieldsSize%typ.AlignAttr != 0 { - pad = typ.AlignAttr - fieldsSize%typ.AlignAttr - } + overlayField := 0 + if typ, ok := arg.Type().(*StructType); ok { + overlayField = typ.OverlayField } - var bitfield uint64 - for _, fld := range arg.Inner { + var bitfield, fieldsSize uint64 + for i, fld := range arg.Inner { + if i != 0 && i == overlayField { + // We don't squash overlay fields. + // Theoretically we could produce a squashed struct with overlay as well, + // but it's quite complex to do. + break + } + fieldsSize += fld.Size() // Squash bitfields separately. if fld.Type().IsBitfield() { bfLen := fld.Type().BitfieldLength() @@ -271,7 +272,8 @@ func (target *Target) squashGroup(arg *GroupArg, elems *[]Arg) { } target.squashPtrImpl(fld, elems) } - if pad != 0 { + // Add padding either due to dynamic alignment or overlay fields. + if pad := arg.Size() - fieldsSize; pad != 0 { elem := target.ensureDataElem(elems) elem.data = append(elem.Data(), make([]byte, pad)...) } diff --git a/prog/prog.go b/prog/prog.go index 86e424299..87b9998b8 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -223,12 +223,21 @@ func (arg *GroupArg) Size() uint64 { } switch typ := typ0.(type) { case *StructType: - var size uint64 - for _, fld := range arg.Inner { - size += fld.Size() - } - if typ.AlignAttr != 0 && size%typ.AlignAttr != 0 { - size += typ.AlignAttr - size%typ.AlignAttr + var size, offset uint64 + for i, fld := range arg.Inner { + if i == typ.OverlayField { + offset = 0 + } + offset += fld.Size() + // Add dynamic alignment at the end and before the overlay part. + if i+1 == len(arg.Inner) || i+1 == typ.OverlayField { + if typ.AlignAttr != 0 && offset%typ.AlignAttr != 0 { + offset += typ.AlignAttr - offset%typ.AlignAttr + } + } + if size < offset { + size = offset + } } return size case *ArrayType: diff --git a/prog/size.go b/prog/size.go index 6eccec50f..1a0b9dcb6 100644 --- a/prog/size.go +++ b/prog/size.go @@ -15,7 +15,7 @@ const ( ) func (target *Target) assignSizes(args []Arg, fields []Field, parentsMap map[Arg]Arg, - syscallArgs []Arg, syscallFields []Field, autos map[Arg]bool) { + syscallArgs []Arg, syscallFields []Field, autos map[Arg]bool, overlayField int) { for _, arg := range args { if arg = InnerArg(arg); arg == nil { continue // Pointer to optional len field, no need to fill in value. @@ -32,9 +32,9 @@ func (target *Target) assignSizes(args []Arg, fields []Field, parentsMap map[Arg } a := arg.(*ConstArg) if typ.Path[0] == SyscallRef { - target.assignSize(a, nil, typ.Path[1:], syscallArgs, syscallFields, parentsMap) + target.assignSize(a, nil, typ.Path[1:], syscallArgs, syscallFields, parentsMap, 0) } else { - target.assignSize(a, a, typ.Path, args, fields, parentsMap) + target.assignSize(a, a, typ.Path, args, fields, parentsMap, overlayField) } } } @@ -42,15 +42,18 @@ func (target *Target) assignSizes(args []Arg, fields []Field, parentsMap map[Arg func (target *Target) assignSizeStruct(dst *ConstArg, buf Arg, path []string, parentsMap map[Arg]Arg) { arg := buf.(*GroupArg) typ := arg.Type().(*StructType) - target.assignSize(dst, buf, path, arg.Inner, typ.Fields, parentsMap) + target.assignSize(dst, buf, path, arg.Inner, typ.Fields, parentsMap, typ.OverlayField) } func (target *Target) assignSize(dst *ConstArg, pos Arg, path []string, args []Arg, - fields []Field, parentsMap map[Arg]Arg) { + fields []Field, parentsMap map[Arg]Arg, overlayField int) { elem := path[0] path = path[1:] var offset uint64 for i, buf := range args { + if i == overlayField { + offset = 0 + } if elem != fields[i].Name { offset += buf.Size() continue @@ -140,11 +143,11 @@ func (target *Target) assignSizesArray(args []Arg, fields []Field, autos map[Arg } }) } - target.assignSizes(args, fields, parentsMap, args, fields, autos) + target.assignSizes(args, fields, parentsMap, args, fields, autos, 0) for _, arg := range args { ForeachSubArg(arg, func(arg Arg, _ *ArgCtx) { if typ, ok := arg.Type().(*StructType); ok { - target.assignSizes(arg.(*GroupArg).Inner, typ.Fields, parentsMap, args, fields, autos) + target.assignSizes(arg.(*GroupArg).Inner, typ.Fields, parentsMap, args, fields, autos, typ.OverlayField) } }) } diff --git a/prog/types.go b/prog/types.go index 86346c50f..08aed6d61 100644 --- a/prog/types.go +++ b/prog/types.go @@ -621,8 +621,9 @@ func (t *PtrType) isDefaultArg(arg Arg) bool { type StructType struct { TypeCommon - Fields []Field - AlignAttr uint64 + Fields []Field + AlignAttr uint64 + OverlayField int // index of the field marked with out_overlay attribute (0 if no attribute) } func (t *StructType) String() string { diff --git a/sys/test/exec.txt b/sys/test/exec.txt index b69236991..0de8e2989 100644 --- a/sys/test/exec.txt +++ b/sys/test/exec.txt @@ -11,41 +11,45 @@ syz_compare_int$3(n const[3], v0 intptr, v1 intptr, v2 intptr) syz_compare_int$4(n const[4], v0 intptr, v1 intptr, v2 intptr, v3 intptr) compare_data [ - align0 align0 - bf0 syz_bf_struct0 - bf1 syz_bf_struct1 - bf2 syz_bf_struct2 - bf3 syz_bf_struct3 - bf4 syz_bf_align[syz_bf_struct4] - bf5 syz_bf_align[syz_bf_struct5] - bf6 syz_bf_align[syz_bf_struct6] - bf7 syz_bf_align[syz_bf_struct7] - bf8 syz_bf_align[syz_bf_struct8] - bf9 syz_bf_align[syz_bf_struct9] - bf10 syz_bf_align[syz_bf_struct10] - bf11 syz_bf_align[syz_bf_struct11] - bf12 syz_bf_align[syz_bf_struct12] - bf13 syz_bf_align[syz_bf_struct13] - bf14 syz_bf_align[syz_bf_struct14] - bf15 syz_bf_align[syz_bf_struct15] - bf16 syz_bf_align[syz_bf_struct16] - bf17 syz_bf_align[syz_bf_struct17] - bf18 syz_bf_align[syz_bf_struct18] - bf19 syz_bf_align[syz_bf_struct19] - bf20 syz_bf_align[syz_bf_struct20] - bf21 syz_bf_align[syz_bf_struct21] - bf22 syz_bf_align[syz_bf_struct22] - bf23 syz_bf_align[syz_bf_struct23] - bf24 syz_bf_align[syz_bf_struct24] - bf25 syz_bf_align[syz_bf_struct25] - str string - blob array[int8] - arr16be array[int16be] - nla array[compare_nla] - fmt0 fmt[oct, int32] - fmt1 fmt[dec, int32] - fmt2 fmt[hex, int32] - fmt3 fmt[dec, flags[flags_with_one_value]] + align0 align0 + bf0 syz_bf_struct0 + bf1 syz_bf_struct1 + bf2 syz_bf_struct2 + bf3 syz_bf_struct3 + bf4 syz_bf_align[syz_bf_struct4] + bf5 syz_bf_align[syz_bf_struct5] + bf6 syz_bf_align[syz_bf_struct6] + bf7 syz_bf_align[syz_bf_struct7] + bf8 syz_bf_align[syz_bf_struct8] + bf9 syz_bf_align[syz_bf_struct9] + bf10 syz_bf_align[syz_bf_struct10] + bf11 syz_bf_align[syz_bf_struct11] + bf12 syz_bf_align[syz_bf_struct12] + bf13 syz_bf_align[syz_bf_struct13] + bf14 syz_bf_align[syz_bf_struct14] + bf15 syz_bf_align[syz_bf_struct15] + bf16 syz_bf_align[syz_bf_struct16] + bf17 syz_bf_align[syz_bf_struct17] + bf18 syz_bf_align[syz_bf_struct18] + bf19 syz_bf_align[syz_bf_struct19] + bf20 syz_bf_align[syz_bf_struct20] + bf21 syz_bf_align[syz_bf_struct21] + bf22 syz_bf_align[syz_bf_struct22] + bf23 syz_bf_align[syz_bf_struct23] + bf24 syz_bf_align[syz_bf_struct24] + bf25 syz_bf_align[syz_bf_struct25] + str string + blob array[int8] + arr16be array[int16be] + nla array[compare_nla] + fmt0 fmt[oct, int32] + fmt1 fmt[dec, int32] + fmt2 fmt[hex, int32] + fmt3 fmt[dec, flags[flags_with_one_value]] + overlayres overlayres + overlay0 overlay0 + overlay1 overlay1 + overlay2 overlay2 ] [varlen] flags_with_one_value = 0 @@ -241,3 +245,39 @@ type syz_bf_align[T] { f0 int8 f1 T } + +resource overlayres8[int8] +resource overlayres16[int16] +resource overlayres32[int32] +resource overlayres64[int64] + +overlay_ctor(a ptr[out, overlayres8], b ptr[out, overlayres16], c ptr[out, overlayres32], d ptr[out, overlayres64]) +overlay_uses(a overlayres8, b overlayres16, c overlayres32, d overlayres64) + +overlayres [ + res8 overlayres8 + res16 overlayres16 + res32 overlayres32 + res64 overlayres64 +] [varlen] + +overlay0 { + i0 int32 + i1 int32 + o0 overlayres32 (out_overlay) + o1 overlayres32 +} + +overlay1 { + i0 int32 + i1 int8 + o0 overlayres8 (out_overlay) + o1 overlayres16 +} + +overlay2 { + i0 int32 + i1 int32 + o0 overlayres64 (out_overlay) + o1 overlayres64 +} diff --git a/sys/test/test/overlay b/sys/test/test/overlay new file mode 100644 index 000000000..54bd97412 --- /dev/null +++ b/sys/test/test/overlay @@ -0,0 +1,9 @@ +syz_compare(&AUTO="1111111122222222", AUTO, &AUTO=@overlay0={0x11111111, 0x22222222, <r0=>0x0, <r1=>0x0}, AUTO) +syz_compare(&AUTO="11111111", AUTO, &AUTO=@overlayres=@res32=r0, AUTO) +syz_compare(&AUTO="22222222", AUTO, &AUTO=@overlayres=@res32=r1, AUTO) +syz_compare(&AUTO="1122334455000000", AUTO, &AUTO=@overlay1={0x44332211, 0x55, <r2=>0x0, <r3=>0x0}, AUTO) +syz_compare(&AUTO="11", AUTO, &AUTO=@overlayres=@res8=r2, AUTO) +syz_compare(&AUTO="3344", AUTO, &AUTO=@overlayres=@res16=r3, AUTO) +syz_compare(&AUTO="11223344556677880000000000000000", AUTO, &AUTO=@overlay2={0x44332211, 0x88776655, <r4=>0x0, <r5=>0x0}, AUTO) +syz_compare(&AUTO="1122334455667788", AUTO, &AUTO=@overlayres=@res64=r4, AUTO) +syz_compare(&AUTO="0000000000000000", AUTO, &AUTO=@overlayres=@res64=r5, AUTO) |
