Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions docs/syscall_descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,9 @@ close(r0)
```

Syscall arguments are always `in`, return values are `out` and pointer indirections
have explicit direction as `ptr` type attribute. Note: for pointer indirections
the direction applies to the whole pointee, and it's not possible to specify the
direction individually for struct fields at the moment
(see [#245](https://github.com/google/syzkaller/issues/245)).
have explicit direction as `ptr` type attribute. Also, it is possible to specify
direction attribute individually for struct fields to account for more complex
producer/consumer scenarious with structs that include both input/output resources.

<div id="values"/>

Expand Down
26 changes: 24 additions & 2 deletions docs/syscall_descriptions_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,14 @@ Structs are described as:

```
structname "{" "\n"
(fieldname type "\n")+
(fieldname type ("(" fieldattribute* ")")? "\n")+
"}" ("[" attribute* "]")?
```

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.

Structs can have attributes specified in square brackets after the struct.
Attributes are:

Expand All @@ -137,10 +141,12 @@ Unions are described as:

```
unionname "[" "\n"
(fieldname type "\n")+
(fieldname type ("(" fieldattribute* ")")? "\n")+
"]" ("[" attribute* "]")?
```

Field attributes are as defined for [structs](#structs).

Unions can have attributes specified in square brackets after the union.
Attributes are:

Expand Down Expand Up @@ -181,6 +187,22 @@ test_struct {
}
```

For more complex producer/consumer scenarios, field attributes can be utilized.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example:

```
resource my_resource_1[int32]
resource my_resource_2[int32]

request_produce1_consume2(..., arg ptr[inout, test_struct])

test_struct {
...
field0 my_resource_1 (out)
field1 my_resource_2 (in)
}
```

## Type Aliases

Complex types that are often repeated can be given short type aliases using the
Expand Down
1 change: 1 addition & 0 deletions pkg/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ type Field struct {
Pos Pos
Name *Ident
Type *Type
Attrs []*Type
NewBlock bool // separated from previous fields by a new line
Comments []*Comment
}
Expand Down
1 change: 1 addition & 0 deletions pkg/ast/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func (n *Field) Clone() Node {
Pos: n.Pos,
Name: n.Name.Clone().(*Ident),
Type: n.Type.Clone().(*Type),
Attrs: cloneTypes(n.Attrs),
NewBlock: n.NewBlock,
Comments: cloneComments(n.Comments),
}
Expand Down
22 changes: 11 additions & 11 deletions pkg/ast/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,7 @@ func (n *Call) serialize(w io.Writer) {
fmt.Fprintf(w, " %v", fmtType(n.Ret))
}
if len(n.Attrs) != 0 {
fmt.Fprintf(w, " (")
for i, t := range n.Attrs {
fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t))
}
fmt.Fprintf(w, ")")
fmt.Fprintf(w, " %v", fmtTypeList(n.Attrs, "(", ")"))
}
fmt.Fprintf(w, "\n")
}
Expand Down Expand Up @@ -148,13 +144,17 @@ func (n *Struct) serialize(w io.Writer) {
for tabs := len(f.Name.Name)/tabWidth + 1; tabs < maxTabs; tabs++ {
fmt.Fprintf(w, "\t")
}
fmt.Fprintf(w, "%v\n", fmtType(f.Type))
fmt.Fprintf(w, "%v", fmtType(f.Type))
if len(f.Attrs) != 0 {
fmt.Fprintf(w, "\t%v", fmtTypeList(f.Attrs, "(", ")"))
}
fmt.Fprintf(w, "\n")
}
for _, com := range n.Comments {
fmt.Fprintf(w, "#%v\n", com.Text)
}
fmt.Fprintf(w, "%c", closing)
if attrs := fmtTypeList(n.Attrs); attrs != "" {
if attrs := fmtTypeList(n.Attrs, "[", "]"); attrs != "" {
fmt.Fprintf(w, " %v", attrs)
}
fmt.Fprintf(w, "\n")
Expand Down Expand Up @@ -197,20 +197,20 @@ func fmtType(t *Type) string {
for _, c := range t.Colon {
v += ":" + fmtType(c)
}
v += fmtTypeList(t.Args)
v += fmtTypeList(t.Args, "[", "]")
return v
}

func fmtTypeList(args []*Type) string {
func fmtTypeList(args []*Type, opening, closing string) string {
if len(args) == 0 {
return ""
}
w := new(bytes.Buffer)
fmt.Fprintf(w, "[")
fmt.Fprint(w, opening)
for i, t := range args {
fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t))
}
fmt.Fprintf(w, "]")
fmt.Fprint(w, closing)
return w.String()
}

Expand Down
19 changes: 15 additions & 4 deletions pkg/ast/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func (p *parser) parseCall(name *Ident) *Call {
}
p.consume(tokLParen)
for p.tok != tokRParen {
c.Args = append(c.Args, p.parseField())
c.Args = append(c.Args, p.parseField(false))
p.expect(tokComma, tokRParen)
p.tryConsume(tokComma)
}
Expand Down Expand Up @@ -376,7 +376,7 @@ func (p *parser) parseStruct(name *Ident) *Struct {
str.Comments = comments
break
}
fld := p.parseField()
fld := p.parseField(true)
fld.NewBlock = newBlock
fld.Comments = comments
str.Fields = append(str.Fields, fld)
Expand All @@ -403,13 +403,24 @@ func (p *parser) parseCommentBlock() []*Comment {
return comments
}

func (p *parser) parseField() *Field {
func (p *parser) parseField(parseAttrs bool) *Field {
name := p.parseIdent()
return &Field{

field := &Field{
Pos: name.Pos,
Name: name,
Type: p.parseType(),
}

if parseAttrs && p.tryConsume(tokLParen) {
field.Attrs = append(field.Attrs, p.parseType())
for p.tryConsume(tokComma) {
field.Attrs = append(field.Attrs, p.parseType())
}
p.consume(tokRParen)
}

return field
}

func (p *parser) parseType() *Type {
Expand Down
13 changes: 13 additions & 0 deletions pkg/ast/testdata/errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ call() ("attr1")
call() (42)
call() ( ### unexpected '\n', expecting int, identifier, string
call() () ### unexpected ')', expecting int, identifier, string
call(foo int32 (attr)) ### unexpected '(', expecting ',', ')'

define FOO bar

Expand Down Expand Up @@ -81,3 +82,15 @@ type templ_struct0[A, B] {
typ const[A, int16]
data B
} [align_4]

s4 {
f0 int8 (attr)
f1 int8 (attr1, attr2[arg1, "arg2"])
f2 int8 ("attr1")
}

s5 {
f0 int8 ( ### unexpected '\n', expecting int, identifier, string

s6 {
f0 int8 () ### unexpected ')', expecting int, identifier, string
3 changes: 3 additions & 0 deletions pkg/ast/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ func (n *Type) walk(cb func(Node)) {
func (n *Field) walk(cb func(Node)) {
cb(n.Name)
cb(n.Type)
for _, a := range n.Attrs {
cb(a)
}
for _, c := range n.Comments {
cb(c)
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/compiler/attrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ var (
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"}

structAttrs = makeAttrs(attrPacked, attrSize, attrAlign)
unionAttrs = makeAttrs(attrVarlen, attrSize)
fieldAttrs = makeAttrs(attrIn, attrOut, attrInOut)
callAttrs = make(map[string]*attrDesc)
)

Expand Down
24 changes: 23 additions & 1 deletion pkg/compiler/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ 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 {
attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs)

if attrs[attrIn]+attrs[attrOut]+attrs[attrInOut] > 1 {
_, typ, _ := f.Info()
comp.error(f.Pos, "%v has multiple direction attributes", typ)
}
}
}

func (comp *compiler) checkFieldGroup(fields []*ast.Field, what, ctx string) {
Expand Down Expand Up @@ -267,6 +275,16 @@ func (comp *compiler) checkAttributeValues() {
desc.CheckConsts(comp, n, attr)
}
}
// Check each field's attributes.
st := decl.(*ast.Struct)
for _, f := range st.Fields {
for _, attr := range f.Attrs {
desc := fieldAttrs[attr.Ident]
if desc.CheckConsts != nil {
desc.CheckConsts(comp, f, attr)
}
}
}
}
}
}
Expand Down Expand Up @@ -614,7 +632,11 @@ func (comp *compiler) checkTypeCtors(t *ast.Type, dir prog.Dir, isArg bool,
}
checked[key] = true
for _, fld := range s.Fields {
comp.checkTypeCtors(fld.Type, dir, false, ctors, inputs, checked)
fldDir, fldHasDir := comp.genFieldDir(fld)
if !fldHasDir {
fldDir = dir
}
comp.checkTypeCtors(fld.Type, fldDir, false, ctors, inputs, checked)
}
return
}
Expand Down
22 changes: 20 additions & 2 deletions pkg/compiler/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,28 @@ func (comp *compiler) genFieldArray(fields []*ast.Field, argSizes []uint64) []pr
return res
}

func (comp *compiler) genFieldDir(f *ast.Field) (prog.Dir, bool) {
attrs := comp.parseAttrs(fieldAttrs, f, f.Attrs)
switch {
case attrs[attrIn] != 0:
return prog.DirIn, true
case attrs[attrOut] != 0:
return prog.DirOut, true
case attrs[attrInOut] != 0:
return prog.DirInOut, true
default:
return prog.DirIn, false
}
}

func (comp *compiler) genField(f *ast.Field, argSize uint64) prog.Field {
dir, hasDir := comp.genFieldDir(f)

return prog.Field{
Name: f.Name.Name,
Type: comp.genType(f.Type, argSize),
Name: f.Name.Name,
Type: comp.genType(f.Type, argSize),
HasDirection: hasDir,
Direction: dir,
}
}

Expand Down
10 changes: 9 additions & 1 deletion pkg/compiler/testdata/all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,15 @@ s4 {
f2 int8
} [size[19]]

foo_s0(a ptr[in, s0], b ptr[in, s1], c ptr[in, s2], d ptr[in, s4])
s5 {
f_in0 int32 (in)
f_in1 int32[0:1] (in)
f_out int32 (out)
f_inout0 int32 (inout)
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])

# Unions.

Expand Down
10 changes: 10 additions & 0 deletions pkg/compiler/testdata/errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,13 @@ struct$fmt0 {
f0 fmt[dec, int8:3] ### unexpected ':', only struct fields can be bitfields
f1 int32:-1 ### bitfield of size 18446744073709551615 is too large for base type of size 32
}

struct$perfielddir {
f0 int32 (in, in) ### duplicate arg/field f0 attribute in
f1 int32 (out, out) ### duplicate arg/field f1 attribute out
f2 int32 (inout, inout) ### duplicate arg/field f2 attribute inout
f3 int32 (in, out) ### arg/field has multiple direction attributes
f4 int32 (in, inout) ### arg/field has multiple direction attributes
f5 int32 (out, inout) ### arg/field has multiple direction attributes
f6 int32 (in, out, inout) ### arg/field has multiple direction attributes
}
Loading