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 parses and formats sys files.
|
|
|
|
package ast
|
|
|
|
|
|
|
|
// Pos represents source info for AST nodes.
|
|
|
|
type Pos struct {
|
|
|
|
File string
|
|
|
|
Off int // byte offset, starting at 0
|
|
|
|
Line int // line number, starting at 1
|
|
|
|
Col int // column number, starting at 1 (byte count)
|
|
|
|
}
|
|
|
|
|
2017-08-26 19:36:08 +00:00
|
|
|
// Description contains top-level nodes of a parsed sys description.
|
|
|
|
type Description struct {
|
|
|
|
Nodes []Node
|
|
|
|
}
|
|
|
|
|
|
|
|
// Node is AST node interface.
|
2017-08-27 17:55:14 +00:00
|
|
|
type Node interface {
|
|
|
|
Info() (pos Pos, typ string, name string)
|
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
|
|
|
// Clone makes a deep copy of the node.
|
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
|
|
|
Clone() Node
|
2018-01-10 15:13:34 +00:00
|
|
|
// Walk calls callback cb for all child nodes of this node.
|
|
|
|
// Note: it's not recursive. Use Recursive helper for recursive walk.
|
|
|
|
Walk(cb func(Node))
|
2017-08-27 17:55:14 +00:00
|
|
|
}
|
2017-08-26 19:36:08 +00:00
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
// Top-level AST nodes:
|
|
|
|
|
|
|
|
type NewLine struct {
|
|
|
|
Pos Pos
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *NewLine) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokNewLine], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Comment struct {
|
|
|
|
Pos Pos
|
|
|
|
Text string
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Comment) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokComment], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Include struct {
|
|
|
|
Pos Pos
|
|
|
|
File *String
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Include) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokInclude], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Incdir struct {
|
|
|
|
Pos Pos
|
|
|
|
Dir *String
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Incdir) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokInclude], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Define struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
Value *Int
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Define) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokDefine], n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Resource struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
2017-08-27 17:55:14 +00:00
|
|
|
Base *Type
|
2017-05-22 03:28:31 +00:00
|
|
|
Values []*Int
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Resource) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokResource], n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Call struct {
|
2017-08-18 14:38:41 +00:00
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
CallName string
|
2017-08-26 19:36:08 +00:00
|
|
|
NR uint64
|
2017-08-18 14:38:41 +00:00
|
|
|
Args []*Field
|
|
|
|
Ret *Type
|
2017-05-22 03:28:31 +00:00
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Call) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "syscall", n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Struct struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
Fields []*Field
|
2018-03-02 10:49:19 +00:00
|
|
|
Attrs []*Type
|
2017-05-22 03:28:31 +00:00
|
|
|
Comments []*Comment
|
|
|
|
IsUnion bool
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Struct) Info() (Pos, string, string) {
|
|
|
|
typ := "struct"
|
|
|
|
if n.IsUnion {
|
|
|
|
typ = "union"
|
|
|
|
}
|
|
|
|
return n.Pos, typ, n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type IntFlags struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
Values []*Int
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *IntFlags) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "flags", n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type StrFlags struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
Values []*String
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *StrFlags) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "string flags", n.Name.Name
|
|
|
|
}
|
|
|
|
|
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
|
|
|
type TypeDef struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
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
|
|
|
// Non-template type aliases have only Type filled.
|
|
|
|
// Templates have Args and either Type or Struct filled.
|
|
|
|
Args []*Ident
|
|
|
|
Type *Type
|
|
|
|
Struct *Struct
|
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
|
|
|
}
|
|
|
|
|
|
|
|
func (n *TypeDef) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "type", n.Name.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
// Not top-level AST nodes:
|
|
|
|
|
|
|
|
type Ident struct {
|
|
|
|
Pos Pos
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Ident) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokIdent], n.Name
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type String struct {
|
|
|
|
Pos Pos
|
|
|
|
Value string
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *String) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokString], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Int struct {
|
|
|
|
Pos Pos
|
|
|
|
// Only one of Value, Ident, CExpr is filled.
|
|
|
|
Value uint64
|
|
|
|
ValueHex bool // says if value was in hex (for formatting)
|
|
|
|
Ident string
|
|
|
|
CExpr string
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Int) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, tok2str[tokInt], ""
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Type struct {
|
|
|
|
Pos Pos
|
|
|
|
// Only one of Value, Ident, String is filled.
|
2018-01-23 10:05:51 +00:00
|
|
|
Value uint64
|
|
|
|
ValueHex bool
|
|
|
|
Ident string
|
|
|
|
String string
|
|
|
|
HasString bool
|
2017-05-22 03:28:31 +00:00
|
|
|
// Part after COLON (for ranges and bitfields).
|
2017-08-26 19:36:08 +00:00
|
|
|
HasColon bool
|
|
|
|
Pos2 Pos
|
2017-05-22 03:28:31 +00:00
|
|
|
Value2 uint64
|
|
|
|
Value2Hex bool
|
|
|
|
Ident2 string
|
|
|
|
Args []*Type
|
|
|
|
}
|
|
|
|
|
2017-08-27 17:55:14 +00:00
|
|
|
func (n *Type) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "type", n.Ident
|
|
|
|
}
|
|
|
|
|
2017-05-22 03:28:31 +00:00
|
|
|
type Field struct {
|
|
|
|
Pos Pos
|
|
|
|
Name *Ident
|
|
|
|
Type *Type
|
|
|
|
NewBlock bool // separated from previous fields by a new line
|
|
|
|
Comments []*Comment
|
|
|
|
}
|
2017-08-27 17:55:14 +00:00
|
|
|
|
|
|
|
func (n *Field) Info() (Pos, string, string) {
|
|
|
|
return n.Pos, "arg/field", n.Name.Name
|
|
|
|
}
|