mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-24 03:49:45 +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.
This commit is contained in:
parent
93b4c6f135
commit
402a0dc87e
@ -137,6 +137,28 @@ accept(fd sock, ...) sock
|
||||
listen(fd sock, backlog int32)
|
||||
```
|
||||
|
||||
## Type Aliases
|
||||
|
||||
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.
|
||||
|
||||
## Length
|
||||
|
||||
You can specify length of a particular field in struct or a named argument by using `len`, `bytesize` and `bitsize` types, for example:
|
||||
|
@ -20,6 +20,10 @@ type Description struct {
|
||||
// Node is AST node interface.
|
||||
type Node interface {
|
||||
Info() (pos Pos, typ string, name string)
|
||||
// Clone makes a deep copy of the node.
|
||||
// If newPos is not zero, sets Pos of all nodes to newPos.
|
||||
// If newPos is zero, Pos of nodes is left intact.
|
||||
Clone(newPos Pos) Node
|
||||
}
|
||||
|
||||
// Top-level AST nodes:
|
||||
@ -130,6 +134,16 @@ func (n *StrFlags) Info() (Pos, string, string) {
|
||||
return n.Pos, "string flags", n.Name.Name
|
||||
}
|
||||
|
||||
type TypeDef struct {
|
||||
Pos Pos
|
||||
Name *Ident
|
||||
Type *Type
|
||||
}
|
||||
|
||||
func (n *TypeDef) Info() (Pos, string, string) {
|
||||
return n.Pos, "type", n.Name.Name
|
||||
}
|
||||
|
||||
// Not top-level AST nodes:
|
||||
|
||||
type Ident struct {
|
||||
|
131
pkg/ast/clone.go
131
pkg/ast/clone.go
@ -3,86 +3,89 @@
|
||||
|
||||
package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Clone(desc *Description) *Description {
|
||||
desc1 := &Description{}
|
||||
for _, n := range desc.Nodes {
|
||||
c, ok := n.(cloner)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("unknown top level decl: %#v", n))
|
||||
}
|
||||
desc1.Nodes = append(desc1.Nodes, c.clone())
|
||||
desc1.Nodes = append(desc1.Nodes, n.Clone(Pos{}))
|
||||
}
|
||||
return desc1
|
||||
}
|
||||
|
||||
type cloner interface {
|
||||
clone() Node
|
||||
func selectPos(newPos, oldPos Pos) Pos {
|
||||
if newPos.File != "" || newPos.Off != 0 || newPos.Line != 0 || newPos.Col != 0 {
|
||||
return newPos
|
||||
}
|
||||
return oldPos
|
||||
}
|
||||
|
||||
func (n *NewLine) clone() Node {
|
||||
func (n *NewLine) Clone(newPos Pos) Node {
|
||||
return &NewLine{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Comment) clone() Node {
|
||||
func (n *Comment) Clone(newPos Pos) Node {
|
||||
return &Comment{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Text: n.Text,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Include) clone() Node {
|
||||
func (n *Include) Clone(newPos Pos) Node {
|
||||
return &Include{
|
||||
Pos: n.Pos,
|
||||
File: n.File.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
File: n.File.Clone(newPos).(*String),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Incdir) clone() Node {
|
||||
func (n *Incdir) Clone(newPos Pos) Node {
|
||||
return &Incdir{
|
||||
Pos: n.Pos,
|
||||
Dir: n.Dir.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Dir: n.Dir.Clone(newPos).(*String),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Define) clone() Node {
|
||||
func (n *Define) Clone(newPos Pos) Node {
|
||||
return &Define{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Value: n.Value.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Value: n.Value.Clone(newPos).(*Int),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Resource) clone() Node {
|
||||
func (n *Resource) Clone(newPos Pos) Node {
|
||||
var values []*Int
|
||||
for _, v := range n.Values {
|
||||
values = append(values, v.clone())
|
||||
values = append(values, v.Clone(newPos).(*Int))
|
||||
}
|
||||
return &Resource{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Base: n.Base.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Base: n.Base.Clone(newPos).(*Type),
|
||||
Values: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Call) clone() Node {
|
||||
func (n *TypeDef) Clone(newPos Pos) Node {
|
||||
return &TypeDef{
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Type: n.Type.Clone(newPos).(*Type),
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Call) Clone(newPos Pos) Node {
|
||||
var args []*Field
|
||||
for _, a := range n.Args {
|
||||
args = append(args, a.clone())
|
||||
args = append(args, a.Clone(newPos).(*Field))
|
||||
}
|
||||
var ret *Type
|
||||
if n.Ret != nil {
|
||||
ret = n.Ret.clone()
|
||||
ret = n.Ret.Clone(newPos).(*Type)
|
||||
}
|
||||
return &Call{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
CallName: n.CallName,
|
||||
NR: n.NR,
|
||||
Args: args,
|
||||
@ -90,22 +93,22 @@ func (n *Call) clone() Node {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Struct) clone() Node {
|
||||
func (n *Struct) Clone(newPos Pos) Node {
|
||||
var fields []*Field
|
||||
for _, f := range n.Fields {
|
||||
fields = append(fields, f.clone())
|
||||
fields = append(fields, f.Clone(newPos).(*Field))
|
||||
}
|
||||
var attrs []*Ident
|
||||
for _, a := range n.Attrs {
|
||||
attrs = append(attrs, a.clone())
|
||||
attrs = append(attrs, a.Clone(newPos).(*Ident))
|
||||
}
|
||||
var comments []*Comment
|
||||
for _, c := range n.Comments {
|
||||
comments = append(comments, c.clone().(*Comment))
|
||||
comments = append(comments, c.Clone(newPos).(*Comment))
|
||||
}
|
||||
return &Struct{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Fields: fields,
|
||||
Attrs: attrs,
|
||||
Comments: comments,
|
||||
@ -113,47 +116,47 @@ func (n *Struct) clone() Node {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *IntFlags) clone() Node {
|
||||
func (n *IntFlags) Clone(newPos Pos) Node {
|
||||
var values []*Int
|
||||
for _, v := range n.Values {
|
||||
values = append(values, v.clone())
|
||||
values = append(values, v.Clone(newPos).(*Int))
|
||||
}
|
||||
return &IntFlags{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Values: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StrFlags) clone() Node {
|
||||
func (n *StrFlags) Clone(newPos Pos) Node {
|
||||
var values []*String
|
||||
for _, v := range n.Values {
|
||||
values = append(values, v.clone())
|
||||
values = append(values, v.Clone(newPos).(*String))
|
||||
}
|
||||
return &StrFlags{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Values: values,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Ident) clone() *Ident {
|
||||
func (n *Ident) Clone(newPos Pos) Node {
|
||||
return &Ident{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *String) clone() *String {
|
||||
func (n *String) Clone(newPos Pos) Node {
|
||||
return &String{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Value: n.Value,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Int) clone() *Int {
|
||||
func (n *Int) Clone(newPos Pos) Node {
|
||||
return &Int{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Value: n.Value,
|
||||
ValueHex: n.ValueHex,
|
||||
Ident: n.Ident,
|
||||
@ -161,19 +164,19 @@ func (n *Int) clone() *Int {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Type) clone() *Type {
|
||||
func (n *Type) Clone(newPos Pos) Node {
|
||||
var args []*Type
|
||||
for _, a := range n.Args {
|
||||
args = append(args, a.clone())
|
||||
args = append(args, a.Clone(newPos).(*Type))
|
||||
}
|
||||
return &Type{
|
||||
Pos: n.Pos,
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Value: n.Value,
|
||||
ValueHex: n.ValueHex,
|
||||
Ident: n.Ident,
|
||||
String: n.String,
|
||||
HasColon: n.HasColon,
|
||||
Pos2: n.Pos2,
|
||||
Pos2: selectPos(newPos, n.Pos2),
|
||||
Value2: n.Value2,
|
||||
Value2Hex: n.Value2Hex,
|
||||
Ident2: n.Ident2,
|
||||
@ -181,15 +184,15 @@ func (n *Type) clone() *Type {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Field) clone() *Field {
|
||||
func (n *Field) Clone(newPos Pos) Node {
|
||||
var comments []*Comment
|
||||
for _, c := range n.Comments {
|
||||
comments = append(comments, c.clone().(*Comment))
|
||||
comments = append(comments, c.Clone(newPos).(*Comment))
|
||||
}
|
||||
return &Field{
|
||||
Pos: n.Pos,
|
||||
Name: n.Name.clone(),
|
||||
Type: n.Type.clone(),
|
||||
Pos: selectPos(newPos, n.Pos),
|
||||
Name: n.Name.Clone(newPos).(*Ident),
|
||||
Type: n.Type.Clone(newPos).(*Type),
|
||||
NewBlock: n.NewBlock,
|
||||
Comments: comments,
|
||||
}
|
||||
|
@ -62,6 +62,10 @@ func (res *Resource) serialize(w io.Writer) {
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
||||
|
||||
func (typedef *TypeDef) serialize(w io.Writer) {
|
||||
fmt.Fprintf(w, "type %v %v\n", typedef.Name.Name, fmtType(typedef.Type))
|
||||
}
|
||||
|
||||
func (c *Call) serialize(w io.Writer) {
|
||||
fmt.Fprintf(w, "%v(", c.Name.Name)
|
||||
for i, a := range c.Args {
|
||||
|
@ -128,6 +128,9 @@ func (p *parser) parseTop() Node {
|
||||
return p.parseResource()
|
||||
case tokIdent:
|
||||
name := p.parseIdent()
|
||||
if name.Name == "type" {
|
||||
return p.parseTypeDef()
|
||||
}
|
||||
switch p.tok {
|
||||
case tokLParen:
|
||||
return p.parseCall(name)
|
||||
@ -245,6 +248,17 @@ func (p *parser) parseResource() *Resource {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseTypeDef() *TypeDef {
|
||||
pos0 := p.pos
|
||||
name := p.parseIdent()
|
||||
typ := p.parseType()
|
||||
return &TypeDef{
|
||||
Pos: pos0,
|
||||
Name: name,
|
||||
Type: typ,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseCall(name *Ident) *Call {
|
||||
c := &Call{
|
||||
Pos: name.Pos,
|
||||
|
5
pkg/ast/testdata/all.txt
vendored
5
pkg/ast/testdata/all.txt
vendored
@ -45,3 +45,8 @@ s2 {
|
||||
# comment
|
||||
|
||||
}
|
||||
|
||||
type bool8 int8
|
||||
type net_port proc[1, 2, int16be]
|
||||
type bool16 ### unexpected '\n', expecting int, identifier, string
|
||||
type type4:4 int32 ### unexpected ':', expecting int, identifier, string
|
||||
|
@ -32,6 +32,9 @@ func WalkNode(n0 Node, cb func(n Node)) {
|
||||
for _, v := range n.Values {
|
||||
WalkNode(v, cb)
|
||||
}
|
||||
case *TypeDef:
|
||||
WalkNode(n.Name, cb)
|
||||
WalkNode(n.Type, cb)
|
||||
case *Call:
|
||||
WalkNode(n.Name, cb)
|
||||
for _, f := range n.Args {
|
||||
|
@ -34,7 +34,7 @@ func (comp *compiler) checkNames() {
|
||||
calls := make(map[string]*ast.Call)
|
||||
for _, decl := range comp.desc.Nodes {
|
||||
switch decl.(type) {
|
||||
case *ast.Resource, *ast.Struct:
|
||||
case *ast.Resource, *ast.Struct, *ast.TypeDef:
|
||||
pos, typ, name := decl.Info()
|
||||
if reservedName[name] {
|
||||
comp.error(pos, "%v uses reserved name %v", typ, name)
|
||||
@ -49,6 +49,11 @@ func (comp *compiler) checkNames() {
|
||||
name, prev.Pos)
|
||||
continue
|
||||
}
|
||||
if prev := comp.typedefs[name]; prev != nil {
|
||||
comp.error(pos, "type %v redeclared, previously declared as type alias at %v",
|
||||
name, prev.Pos)
|
||||
continue
|
||||
}
|
||||
if prev := comp.structs[name]; prev != nil {
|
||||
_, typ, _ := prev.Info()
|
||||
comp.error(pos, "type %v redeclared, previously declared as %v at %v",
|
||||
@ -57,6 +62,8 @@ func (comp *compiler) checkNames() {
|
||||
}
|
||||
if res, ok := decl.(*ast.Resource); ok {
|
||||
comp.resources[name] = res
|
||||
} else if n, ok := decl.(*ast.TypeDef); ok {
|
||||
comp.typedefs[name] = n
|
||||
} else if str, ok := decl.(*ast.Struct); ok {
|
||||
comp.structs[name] = str
|
||||
}
|
||||
@ -146,21 +153,34 @@ func (comp *compiler) checkFields() {
|
||||
}
|
||||
|
||||
func (comp *compiler) checkTypes() {
|
||||
for _, decl := range comp.desc.Nodes {
|
||||
switch n := decl.(type) {
|
||||
case *ast.TypeDef:
|
||||
if comp.typedefs[n.Name.Name] == nil {
|
||||
continue
|
||||
}
|
||||
err0 := comp.errors
|
||||
comp.checkType(n.Type, false, false, false, false, true, true)
|
||||
if err0 != comp.errors {
|
||||
delete(comp.typedefs, n.Name.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, decl := range comp.desc.Nodes {
|
||||
switch n := decl.(type) {
|
||||
case *ast.Resource:
|
||||
comp.checkType(n.Base, false, false, false, true)
|
||||
comp.checkType(n.Base, false, false, false, true, false, false)
|
||||
case *ast.Struct:
|
||||
for _, f := range n.Fields {
|
||||
comp.checkType(f.Type, false, false, !n.IsUnion, false)
|
||||
comp.checkType(f.Type, false, false, !n.IsUnion, false, false, false)
|
||||
}
|
||||
comp.checkStruct(n)
|
||||
case *ast.Call:
|
||||
for _, a := range n.Args {
|
||||
comp.checkType(a.Type, true, false, false, false)
|
||||
comp.checkType(a.Type, true, false, false, false, false, false)
|
||||
}
|
||||
if n.Ret != nil {
|
||||
comp.checkType(n.Ret, true, true, false, false)
|
||||
comp.checkType(n.Ret, true, true, false, false, false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -459,7 +479,7 @@ func (comp *compiler) checkStruct(n *ast.Struct) {
|
||||
}
|
||||
}
|
||||
|
||||
func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceBase bool) {
|
||||
func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceBase, isTypedef, isTypedefCtx bool) {
|
||||
if unexpected, _, ok := checkTypeKind(t, kindIdent); !ok {
|
||||
comp.error(t.Pos, "unexpected %v, expect type", unexpected)
|
||||
return
|
||||
@ -469,6 +489,32 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB
|
||||
comp.error(t.Pos, "unknown type %v", t.Ident)
|
||||
return
|
||||
}
|
||||
if desc == typeTypedef {
|
||||
if isTypedefCtx {
|
||||
comp.error(t.Pos, "type aliases can't refer to other type aliases")
|
||||
return
|
||||
}
|
||||
if t.HasColon {
|
||||
comp.error(t.Pos, "type alias %v with ':'", t.Ident)
|
||||
return
|
||||
}
|
||||
if len(t.Args) != 0 {
|
||||
comp.error(t.Pos, "type alias %v with arguments", t.Ident)
|
||||
return
|
||||
}
|
||||
*t = *comp.typedefs[t.Ident].Type.Clone(t.Pos).(*ast.Type)
|
||||
desc = comp.getTypeDesc(t)
|
||||
if isArg && desc.NeedBase {
|
||||
baseTypePos := len(t.Args) - 1
|
||||
if t.Args[baseTypePos].Ident == "opt" {
|
||||
baseTypePos--
|
||||
}
|
||||
copy(t.Args[baseTypePos:], t.Args[baseTypePos+1:])
|
||||
t.Args = t.Args[:len(t.Args)-1]
|
||||
}
|
||||
comp.checkType(t, isArg, isRet, isStruct, isResourceBase, isTypedef, isTypedefCtx)
|
||||
return
|
||||
}
|
||||
if t.HasColon {
|
||||
if !desc.AllowColon {
|
||||
comp.error(t.Pos2, "unexpected ':'")
|
||||
@ -487,6 +533,10 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB
|
||||
comp.error(t.Pos, "%v can't be syscall argument", t.Ident)
|
||||
return
|
||||
}
|
||||
if isTypedef && !desc.CanBeTypedef {
|
||||
comp.error(t.Pos, "%v can't be type alias target", t.Ident)
|
||||
return
|
||||
}
|
||||
if isResourceBase && !desc.ResourceBase {
|
||||
comp.error(t.Pos, "%v can't be resource base (int types can)", t.Ident)
|
||||
return
|
||||
@ -519,7 +569,7 @@ func (comp *compiler) checkType(t *ast.Type, isArg, isRet, isStruct, isResourceB
|
||||
err0 := comp.errors
|
||||
for i, arg := range args {
|
||||
if desc.Args[i].Type == typeArgType {
|
||||
comp.checkType(arg, false, isRet, false, false)
|
||||
comp.checkType(arg, false, isRet, false, false, false, isTypedefCtx)
|
||||
} else {
|
||||
comp.checkTypeArg(t, arg, desc.Args[i])
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ func Compile(desc *ast.Description, consts map[string]uint64, target *targets.Ta
|
||||
ptrSize: target.PtrSize,
|
||||
unsupported: make(map[string]bool),
|
||||
resources: make(map[string]*ast.Resource),
|
||||
typedefs: make(map[string]*ast.TypeDef),
|
||||
structs: make(map[string]*ast.Struct),
|
||||
intFlags: make(map[string]*ast.IntFlags),
|
||||
strFlags: make(map[string]*ast.StrFlags),
|
||||
@ -89,6 +90,7 @@ type compiler struct {
|
||||
|
||||
unsupported map[string]bool
|
||||
resources map[string]*ast.Resource
|
||||
typedefs map[string]*ast.TypeDef
|
||||
structs map[string]*ast.Struct
|
||||
intFlags map[string]*ast.IntFlags
|
||||
strFlags map[string]*ast.StrFlags
|
||||
@ -163,6 +165,9 @@ func (comp *compiler) getTypeDesc(t *ast.Type) *typeDesc {
|
||||
if comp.structs[t.Ident] != nil {
|
||||
return typeStruct
|
||||
}
|
||||
if comp.typedefs[t.Ident] != nil {
|
||||
return typeTypedef
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,6 @@ package compiler
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/google/syzkaller/pkg/ast"
|
||||
@ -13,21 +12,33 @@ import (
|
||||
)
|
||||
|
||||
func TestCompileAll(t *testing.T) {
|
||||
eh := func(pos ast.Pos, msg string) {
|
||||
t.Logf("%v: %v", pos, msg)
|
||||
}
|
||||
desc := ast.ParseGlob(filepath.Join("..", "..", "sys", "linux", "*.txt"), eh)
|
||||
if desc == nil {
|
||||
t.Fatalf("parsing failed")
|
||||
}
|
||||
glob := filepath.Join("..", "..", "sys", "linux", "*_"+runtime.GOARCH+".const")
|
||||
consts := DeserializeConstsGlob(glob, eh)
|
||||
if consts == nil {
|
||||
t.Fatalf("reading consts failed")
|
||||
}
|
||||
prog := Compile(desc, consts, targets.List["linux"]["amd64"], eh)
|
||||
if prog == nil {
|
||||
t.Fatalf("compilation failed")
|
||||
for os, arches := range targets.List {
|
||||
os, arches := os, arches
|
||||
t.Run(os, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
eh := func(pos ast.Pos, msg string) {
|
||||
t.Logf("%v: %v", pos, msg)
|
||||
}
|
||||
path := filepath.Join("..", "..", "sys", os)
|
||||
desc := ast.ParseGlob(filepath.Join(path, "*.txt"), eh)
|
||||
if desc == nil {
|
||||
t.Fatalf("parsing failed")
|
||||
}
|
||||
for arch, target := range arches {
|
||||
arch, target := arch, target
|
||||
t.Run(arch, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
consts := DeserializeConstsGlob(filepath.Join(path, "*_"+arch+".const"), eh)
|
||||
if consts == nil {
|
||||
t.Fatalf("reading consts failed")
|
||||
}
|
||||
prog := Compile(desc, consts, target, eh)
|
||||
if prog == nil {
|
||||
t.Fatalf("compilation failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +49,7 @@ func TestErrors(t *testing.T) {
|
||||
"C1": 1,
|
||||
"C2": 2,
|
||||
}
|
||||
target := targets.List["linux"]["amd64"]
|
||||
target := targets.List["test"]["64"]
|
||||
for _, name := range []string{"errors.txt", "errors2.txt"} {
|
||||
name := name
|
||||
t.Run(name, func(t *testing.T) {
|
||||
@ -69,7 +80,7 @@ func TestFuzz(t *testing.T) {
|
||||
for _, data := range inputs {
|
||||
desc := ast.Parse([]byte(data), "", eh)
|
||||
if desc != nil {
|
||||
Compile(desc, consts, targets.List["linux"]["amd64"], eh)
|
||||
Compile(desc, consts, targets.List["test"]["64"], eh)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -96,7 +107,7 @@ s2 {
|
||||
if desc == nil {
|
||||
t.Fatal("failed to parse")
|
||||
}
|
||||
p := Compile(desc, map[string]uint64{"__NR_foo": 1}, targets.List["linux"]["amd64"], nil)
|
||||
p := Compile(desc, map[string]uint64{"__NR_foo": 1}, targets.List["test"]["64"], nil)
|
||||
if p == nil {
|
||||
t.Fatal("failed to compile")
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) {
|
||||
comp.warning(c.Pos, "unsupported syscall: %v due to missing const %v",
|
||||
c.CallName, str)
|
||||
}
|
||||
case *ast.IntFlags, *ast.Resource, *ast.Struct, *ast.StrFlags:
|
||||
case *ast.IntFlags, *ast.Resource, *ast.Struct, *ast.StrFlags, *ast.TypeDef:
|
||||
top = append(top, decl)
|
||||
case *ast.NewLine, *ast.Comment, *ast.Include, *ast.Incdir, *ast.Define:
|
||||
// These are not needed anymore.
|
||||
@ -176,7 +176,7 @@ func (comp *compiler) patchConsts(consts map[string]uint64) {
|
||||
top = append(top, n)
|
||||
case *ast.StrFlags:
|
||||
top = append(top, decl)
|
||||
case *ast.Resource, *ast.Struct, *ast.Call:
|
||||
case *ast.Resource, *ast.Struct, *ast.Call, *ast.TypeDef:
|
||||
// Walk whole tree and replace consts in Int's and Type's.
|
||||
missing := ""
|
||||
ast.WalkNode(decl, func(n0 ast.Node) {
|
||||
|
63
pkg/compiler/testdata/errors.txt
vendored
63
pkg/compiler/testdata/errors.txt
vendored
@ -178,3 +178,66 @@ define d1 `some C expression`
|
||||
define d2 some C expression
|
||||
define d2 SOMETHING ### duplicate define d2
|
||||
define d3 1
|
||||
|
||||
# Type aliases.
|
||||
|
||||
type bool8 int8[0:1]
|
||||
type bool16 int16[0:1]
|
||||
type net_port proc[100, 1, int16be]
|
||||
resource typeres0[bool8]
|
||||
typestruct {
|
||||
f1 bool8
|
||||
f2 bool16
|
||||
}
|
||||
typeunion [
|
||||
f1 bool8
|
||||
f2 bool16
|
||||
]
|
||||
|
||||
type type0 int8
|
||||
type type0 int8 ### type type0 redeclared, previously declared as type alias at errors.txt:197:6
|
||||
resource type0[int32] ### type type0 redeclared, previously declared as type alias at errors.txt:197:6
|
||||
type0 = 0, 1
|
||||
type type1 type1 ### type aliases can't refer to other type aliases
|
||||
type type2 int8:4 ### unexpected ':', only struct fields can be bitfields
|
||||
type type3 type2 ### unknown type type2
|
||||
type type4 const[0] ### wrong number of arguments for type const, expect value, base type
|
||||
type type5 typeunion ### typeunion can't be type alias target
|
||||
type type6 len[foo, int32] ### len can't be type alias target
|
||||
type type7 len[foo] ### len can't be type alias target
|
||||
resource typeres1[int32]
|
||||
type type8 typeres1 ### typeres1 can't be type alias target
|
||||
type int8 int8 ### type name int8 conflicts with builtin type
|
||||
type opt int8 ### type uses reserved name opt
|
||||
type type9 const[0, int8]
|
||||
type type10 type0 ### type aliases can't refer to other type aliases
|
||||
type type11 typestruct11 ### typestruct11 can't be type alias target
|
||||
type type12 proc[123, 2, int16, opt]
|
||||
type type13 ptr[in, typestruct13]
|
||||
type type14 flags[type0, int32]
|
||||
type type15 const[0, type0] ### unexpected value type0 for base type argument of const type, expect [int8 int16 int32 int64 int16be int32be int64be intptr]
|
||||
type type16 ptr[in, type0] ### type aliases can't refer to other type aliases
|
||||
|
||||
typestruct11 {
|
||||
f type11 ### unknown type type11
|
||||
}
|
||||
|
||||
typestruct12 {
|
||||
f type11 ### unknown type type11
|
||||
}
|
||||
|
||||
typestruct13 {
|
||||
f1 type9
|
||||
f2 type12
|
||||
}
|
||||
|
||||
foo$100(a bool8, b bool16)
|
||||
foo$101(a type5) ### unknown type type5
|
||||
foo$102(a type2) ### unknown type type2
|
||||
foo$103(a type0:4) ### type alias type0 with ':'
|
||||
foo$104(a type0[opt]) ### type alias type0 with arguments
|
||||
foo$105() type0
|
||||
foo$106() type6 ### unknown type type6
|
||||
foo$107(a type9, b type12)
|
||||
foo$108(a flags[type0])
|
||||
foo$109(a ptr[in, type0])
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
type typeDesc struct {
|
||||
Names []string
|
||||
CanBeArg bool // can be argument of syscall?
|
||||
CanBeTypedef bool // can be type alias target?
|
||||
CantBeOpt bool // can't be marked as opt?
|
||||
CantBeRet bool // can't be syscall return (directly or indirectly)?
|
||||
NeedBase bool // needs base type when used as field?
|
||||
@ -54,6 +55,7 @@ const (
|
||||
var typeInt = &typeDesc{
|
||||
Names: []string{"int8", "int16", "int32", "int64", "int16be", "int32be", "int64be", "intptr"},
|
||||
CanBeArg: true,
|
||||
CanBeTypedef: true,
|
||||
AllowColon: true,
|
||||
ResourceBase: true,
|
||||
OptArgs: 1,
|
||||
@ -78,9 +80,10 @@ var typeInt = &typeDesc{
|
||||
}
|
||||
|
||||
var typePtr = &typeDesc{
|
||||
Names: []string{"ptr", "ptr64"},
|
||||
CanBeArg: true,
|
||||
Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}},
|
||||
Names: []string{"ptr", "ptr64"},
|
||||
CanBeArg: true,
|
||||
CanBeTypedef: true,
|
||||
Args: []namedArg{{"direction", typeArgDir}, {"type", typeArgType}},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
base.ArgDir = prog.DirIn // pointers are always in
|
||||
base.TypeSize = comp.ptrSize
|
||||
@ -175,11 +178,12 @@ var typeLen = &typeDesc{
|
||||
}
|
||||
|
||||
var typeConst = &typeDesc{
|
||||
Names: []string{"const"},
|
||||
CanBeArg: true,
|
||||
CantBeOpt: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"value", typeArgInt}},
|
||||
Names: []string{"const"},
|
||||
CanBeArg: true,
|
||||
CanBeTypedef: true,
|
||||
CantBeOpt: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"value", typeArgInt}},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
return &prog.ConstType{
|
||||
IntTypeCommon: base,
|
||||
@ -193,11 +197,12 @@ var typeArgLenTarget = &typeArg{
|
||||
}
|
||||
|
||||
var typeFlags = &typeDesc{
|
||||
Names: []string{"flags"},
|
||||
CanBeArg: true,
|
||||
CantBeOpt: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"flags", typeArgFlags}},
|
||||
Names: []string{"flags"},
|
||||
CanBeArg: true,
|
||||
CanBeTypedef: true,
|
||||
CantBeOpt: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"flags", typeArgFlags}},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
name := args[0].Ident
|
||||
base.TypeName = name
|
||||
@ -334,10 +339,11 @@ func genCsumKind(t *ast.Type) prog.CsumKind {
|
||||
}
|
||||
|
||||
var typeProc = &typeDesc{
|
||||
Names: []string{"proc"},
|
||||
CanBeArg: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}},
|
||||
Names: []string{"proc"},
|
||||
CanBeArg: true,
|
||||
CanBeTypedef: true,
|
||||
NeedBase: true,
|
||||
Args: []namedArg{{"range start", typeArgInt}, {"per-proc values", typeArgInt}},
|
||||
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
start := args[0].Value
|
||||
perProc := args[1].Value
|
||||
@ -522,7 +528,7 @@ var typeArgType = &typeArg{
|
||||
}
|
||||
|
||||
var typeResource = &typeDesc{
|
||||
// No Names, but compiler knows how to match it.
|
||||
// No Names, but getTypeDesc knows how to match it.
|
||||
CanBeArg: true,
|
||||
ResourceBase: true,
|
||||
// Gen is assigned below to avoid initialization loop.
|
||||
@ -544,7 +550,7 @@ func init() {
|
||||
}
|
||||
|
||||
var typeStruct = &typeDesc{
|
||||
// No Names, but compiler knows how to match it.
|
||||
// No Names, but getTypeDesc knows how to match it.
|
||||
CantBeOpt: true,
|
||||
// Varlen/Gen are assigned below due to initialization cycle.
|
||||
}
|
||||
@ -579,6 +585,16 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
var typeTypedef = &typeDesc{
|
||||
// No Names, but getTypeDesc knows how to match it.
|
||||
Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
|
||||
panic("must not be called")
|
||||
},
|
||||
Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
|
||||
panic("must not be called")
|
||||
},
|
||||
}
|
||||
|
||||
var typeArgDir = &typeArg{
|
||||
Kind: kindIdent,
|
||||
Names: []string{"in", "out", "inout"},
|
||||
@ -660,16 +676,14 @@ func init() {
|
||||
typeConst,
|
||||
typeFlags,
|
||||
typeFilename,
|
||||
typeFileoff,
|
||||
typeFileoff, // make a type alias
|
||||
typeVMA,
|
||||
typeSignalno,
|
||||
typeSignalno, // make a type alias
|
||||
typeCsum,
|
||||
typeProc,
|
||||
typeText,
|
||||
typeBuffer,
|
||||
typeBuffer, // make a type alias
|
||||
typeString,
|
||||
typeResource,
|
||||
typeStruct,
|
||||
}
|
||||
for _, desc := range builtins {
|
||||
for _, name := range desc.Names {
|
||||
|
Loading…
Reference in New Issue
Block a user