aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2022-01-05 20:05:11 +0100
committerDmitry Vyukov <dvyukov@google.com>2022-01-11 16:30:08 +0100
commit2cfe62f82077ba012aef55db5288985bc0c426d9 (patch)
tree501d83deb358a230d157c9d7efc6fc393e239472
parent16e21d13ea26a631e9b3a30c94635b1d565fd78f (diff)
pkg/compiler: add out_overlay field attribute
-rw-r--r--docs/syscall_descriptions_syntax.md27
-rw-r--r--pkg/compiler/attrs.go17
-rw-r--r--pkg/compiler/check.go36
-rw-r--r--pkg/compiler/gen.go57
-rw-r--r--pkg/compiler/testdata/all.txt9
-rw-r--r--pkg/compiler/testdata/errors.txt21
-rw-r--r--pkg/compiler/testdata/errors2.txt12
-rw-r--r--pkg/compiler/types.go14
-rw-r--r--prog/analysis.go13
-rw-r--r--prog/any.go26
-rw-r--r--prog/prog.go21
-rw-r--r--prog/size.go17
-rw-r--r--prog/types.go5
-rw-r--r--sys/test/exec.txt110
-rw-r--r--sys/test/test/overlay9
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)