2017-05-22 03:28:31 +00:00
|
|
|
// Copyright 2017 syzkaller project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package ast
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2017-08-26 19:36:08 +00:00
|
|
|
func Format(desc *Description) []byte {
|
2017-05-22 03:28:31 +00:00
|
|
|
buf := new(bytes.Buffer)
|
2017-08-26 19:36:08 +00:00
|
|
|
FormatWriter(buf, desc)
|
2017-05-22 03:28:31 +00:00
|
|
|
return buf.Bytes()
|
|
|
|
}
|
|
|
|
|
2017-08-26 19:36:08 +00:00
|
|
|
func FormatWriter(w io.Writer, desc *Description) {
|
|
|
|
for _, n := range desc.Nodes {
|
|
|
|
s, ok := n.(serializer)
|
2017-05-22 03:28:31 +00:00
|
|
|
if !ok {
|
2017-08-26 19:36:08 +00:00
|
|
|
panic(fmt.Sprintf("unknown top level decl: %#v", n))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
2017-08-26 19:36:08 +00:00
|
|
|
s.serialize(w)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
func SerializeNode(n Node) string {
|
|
|
|
s, ok := n.(serializer)
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf("unknown node: %#v", n))
|
|
|
|
}
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
s.serialize(buf)
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
2018-07-09 18:47:07 +00:00
|
|
|
func FormatInt(v uint64, format IntFmt) string {
|
|
|
|
switch format {
|
|
|
|
case IntFmtDec:
|
|
|
|
return fmt.Sprint(v)
|
|
|
|
case IntFmtNeg:
|
|
|
|
return fmt.Sprint(int64(v))
|
|
|
|
case IntFmtHex:
|
|
|
|
return fmt.Sprintf("0x%x", v)
|
|
|
|
case IntFmtChar:
|
|
|
|
return fmt.Sprintf("'%c'", v)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unknown int format %v", format))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-10 13:45:20 +00:00
|
|
|
func FormatStr(v string, format StrFmt) string {
|
|
|
|
switch format {
|
|
|
|
case StrFmtRaw:
|
|
|
|
return fmt.Sprintf(`"%v"`, v)
|
|
|
|
case StrFmtHex:
|
|
|
|
return fmt.Sprintf("`%x`", v)
|
|
|
|
default:
|
|
|
|
panic(fmt.Sprintf("unknown str format %v", format))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type serializer interface {
|
2017-08-26 19:36:08 +00:00
|
|
|
serialize(w io.Writer)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *NewLine) serialize(w io.Writer) {
|
2017-05-22 03:28:31 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Comment) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "#%v\n", n.Text)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Include) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "include <%v>\n", n.File.Value)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Incdir) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "incdir <%v>\n", n.Dir.Value)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Define) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "define %v\t%v\n", n.Name.Name, fmtInt(n.Value))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Resource) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "resource %v[%v]", n.Name.Name, fmtType(n.Base))
|
|
|
|
for i, v := range n.Values {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ": "), fmtInt(v))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *TypeDef) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "type %v%v", n.Name.Name, fmtIdentList(n.Args))
|
|
|
|
if n.Type != nil {
|
|
|
|
fmt.Fprintf(w, " %v\n", fmtType(n.Type))
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
}
|
2020-06-06 05:55:42 +00:00
|
|
|
if n.Struct != nil {
|
|
|
|
n.Struct.serialize(w)
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
}
|
sys: support type aliases (aka typedefs)
Complex types that are often repeated can be given short type aliases using the
following syntax:
```
type identifier underlying_type
```
For example:
```
type signalno int32[0:65]
type net_port proc[20000, 4, int16be]
```
Then, type alias can be used instead of the underlying type in any contexts.
Underlying type needs to be described as if it's a struct field, that is,
with the base type if it's required. However, type alias can be used as syscall
arguments as well. Underlying types are currently restricted to integer types,
`ptr`, `ptr64`, `const`, `flags` and `proc` types.
2018-01-06 13:46:52 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Call) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "%v(", n.Name.Name)
|
|
|
|
for i, a := range n.Args {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ""), fmtField(a))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, ")")
|
2020-06-06 05:55:42 +00:00
|
|
|
if n.Ret != nil {
|
|
|
|
fmt.Fprintf(w, " %v", fmtType(n.Ret))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
2020-06-06 05:55:42 +00:00
|
|
|
if len(n.Attrs) != 0 {
|
2020-08-10 14:43:38 +00:00
|
|
|
fmt.Fprintf(w, " %v", fmtTypeList(n.Attrs, "(", ")"))
|
2020-04-13 11:05:16 +00:00
|
|
|
}
|
2017-05-22 03:28:31 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *Struct) serialize(w io.Writer) {
|
2017-05-22 03:28:31 +00:00
|
|
|
opening, closing := '{', '}'
|
2020-06-06 05:55:42 +00:00
|
|
|
if n.IsUnion {
|
2017-05-22 03:28:31 +00:00
|
|
|
opening, closing = '[', ']'
|
|
|
|
}
|
2020-06-06 05:55:42 +00:00
|
|
|
fmt.Fprintf(w, "%v %c\n", n.Name.Name, opening)
|
2017-05-22 03:28:31 +00:00
|
|
|
// Align all field types to the same column.
|
|
|
|
const tabWidth = 8
|
|
|
|
maxTabs := 0
|
2020-06-06 05:55:42 +00:00
|
|
|
for _, f := range n.Fields {
|
2017-05-22 03:28:31 +00:00
|
|
|
tabs := (len(f.Name.Name) + tabWidth) / tabWidth
|
|
|
|
if maxTabs < tabs {
|
|
|
|
maxTabs = tabs
|
|
|
|
}
|
|
|
|
}
|
2020-06-06 05:55:42 +00:00
|
|
|
for _, f := range n.Fields {
|
2017-05-22 03:28:31 +00:00
|
|
|
if f.NewBlock {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
for _, com := range f.Comments {
|
|
|
|
fmt.Fprintf(w, "#%v\n", com.Text)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\t%v\t", f.Name.Name)
|
|
|
|
for tabs := len(f.Name.Name)/tabWidth + 1; tabs < maxTabs; tabs++ {
|
|
|
|
fmt.Fprintf(w, "\t")
|
|
|
|
}
|
2020-08-10 14:43:38 +00:00
|
|
|
fmt.Fprintf(w, "%v", fmtType(f.Type))
|
|
|
|
if len(f.Attrs) != 0 {
|
|
|
|
fmt.Fprintf(w, "\t%v", fmtTypeList(f.Attrs, "(", ")"))
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
2020-06-06 05:55:42 +00:00
|
|
|
for _, com := range n.Comments {
|
2017-05-22 03:28:31 +00:00
|
|
|
fmt.Fprintf(w, "#%v\n", com.Text)
|
|
|
|
}
|
2018-03-02 10:49:19 +00:00
|
|
|
fmt.Fprintf(w, "%c", closing)
|
2020-08-10 14:43:38 +00:00
|
|
|
if attrs := fmtTypeList(n.Attrs, "[", "]"); attrs != "" {
|
2018-03-02 10:49:19 +00:00
|
|
|
fmt.Fprintf(w, " %v", attrs)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *IntFlags) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "%v = ", n.Name.Name)
|
|
|
|
for i, v := range n.Values {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ""), fmtInt(v))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2020-06-06 05:55:42 +00:00
|
|
|
func (n *StrFlags) serialize(w io.Writer) {
|
|
|
|
fmt.Fprintf(w, "%v = ", n.Name.Name)
|
|
|
|
for i, v := range n.Values {
|
2020-02-10 13:45:20 +00:00
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ""), FormatStr(v.Value, v.Fmt))
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
func fmtField(f *Field) string {
|
|
|
|
return fmt.Sprintf("%v %v", f.Name.Name, fmtType(f.Type))
|
|
|
|
}
|
|
|
|
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
func (n *Type) serialize(w io.Writer) {
|
|
|
|
w.Write([]byte(fmtType(n)))
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
func fmtType(t *Type) string {
|
|
|
|
v := ""
|
|
|
|
switch {
|
|
|
|
case t.Ident != "":
|
|
|
|
v = t.Ident
|
2018-01-23 10:05:51 +00:00
|
|
|
case t.HasString:
|
2020-02-10 13:45:20 +00:00
|
|
|
v = FormatStr(t.String, t.StringFmt)
|
2017-05-22 03:28:31 +00:00
|
|
|
default:
|
2018-07-09 18:47:07 +00:00
|
|
|
v = FormatInt(t.Value, t.ValueFmt)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
2019-05-10 15:15:29 +00:00
|
|
|
for _, c := range t.Colon {
|
|
|
|
v += ":" + fmtType(c)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
2020-08-10 14:43:38 +00:00
|
|
|
v += fmtTypeList(t.Args, "[", "]")
|
2017-05-22 03:28:31 +00:00
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2020-08-10 14:43:38 +00:00
|
|
|
func fmtTypeList(args []*Type, opening, closing string) string {
|
2017-05-22 03:28:31 +00:00
|
|
|
if len(args) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
w := new(bytes.Buffer)
|
2020-08-10 14:43:38 +00:00
|
|
|
fmt.Fprint(w, opening)
|
2017-05-22 03:28:31 +00:00
|
|
|
for i, t := range args {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ""), fmtType(t))
|
|
|
|
}
|
2020-08-10 14:43:38 +00:00
|
|
|
fmt.Fprint(w, closing)
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
return w.String()
|
|
|
|
}
|
|
|
|
|
2018-03-02 10:49:19 +00:00
|
|
|
func fmtIdentList(args []*Ident) string {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
if len(args) == 0 {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
w := new(bytes.Buffer)
|
|
|
|
fmt.Fprintf(w, "[")
|
|
|
|
for i, arg := range args {
|
|
|
|
fmt.Fprintf(w, "%v%v", comma(i, ""), arg.Name)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "]")
|
|
|
|
return w.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func fmtInt(i *Int) string {
|
|
|
|
switch {
|
|
|
|
case i.Ident != "":
|
|
|
|
return i.Ident
|
|
|
|
case i.CExpr != "":
|
|
|
|
return fmt.Sprintf("%v", i.CExpr)
|
|
|
|
default:
|
2018-07-09 18:47:07 +00:00
|
|
|
return FormatInt(i.Value, i.ValueFmt)
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
func comma(i int, or string) string {
|
2017-05-22 03:28:31 +00:00
|
|
|
if i == 0 {
|
pkg/compiler: support type templates
Netlink descriptions contain tons of code duplication,
and need much more for proper descriptions. Introduce
type templates to simplify writing such descriptions
and remove code duplication.
Note: type templates are experimental, have poor error handling
and are subject to change.
Type templates can be declared as follows:
```
type buffer[DIR] ptr[DIR, array[int8]]
type fileoff[BASE] BASE
type nlattr[TYPE, PAYLOAD] {
nla_len len[parent, int16]
nla_type const[TYPE, int16]
payload PAYLOAD
} [align_4]
```
and later used as follows:
```
syscall(a buffer[in], b fileoff[int64], c ptr[in, nlattr[FOO, int32]])
```
2018-01-10 15:13:34 +00:00
|
|
|
return or
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
return ", "
|
|
|
|
}
|