mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-27 13:20:34 +00:00
pkg/ast: support char constants
Frequently it's useful to do something like: int8['a':'z'] punctuation = ',', '-', ':'
This commit is contained in:
parent
c7f6891ca7
commit
1e85f7b9af
@ -247,6 +247,21 @@ The `proc[20000, 4, int16be]` type means that we want to generate an `int16be`
|
||||
integer starting from `20000` and assign `4` values for each process.
|
||||
As a result the executor number `n` will get values in the `[20000 + n * 4, 20000 + (n + 1) * 4)` range.
|
||||
|
||||
## Integer Constants
|
||||
|
||||
Integer constants can be specified as decimal literals, as `0x`-prefixed
|
||||
hex literals, as `'`-surrounded char literals, or as symbolic constants
|
||||
extracted from kernel headers or defined by `define` directives. For example:
|
||||
|
||||
```
|
||||
foo(a const[10])
|
||||
foo(a const[0xabcd])
|
||||
foo(a int8['a':'z'])
|
||||
foo(a const[PATH_MAX])
|
||||
foo(a ptr[in, array[int8, MY_PATH_MAX]])
|
||||
define MY_PATH_MAX PATH_MAX + 2
|
||||
```
|
||||
|
||||
## Misc
|
||||
|
||||
Description files also contain `include` directives that refer to Linux kernel header files,
|
||||
|
@ -169,11 +169,19 @@ func (n *String) Info() (Pos, string, string) {
|
||||
return n.Pos, tok2str[tokString], ""
|
||||
}
|
||||
|
||||
type intFmt int
|
||||
|
||||
const (
|
||||
intFmtDec intFmt = iota
|
||||
intFmtHex
|
||||
intFmtChar
|
||||
)
|
||||
|
||||
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)
|
||||
valueFmt intFmt
|
||||
Ident string
|
||||
CExpr string
|
||||
}
|
||||
@ -186,7 +194,7 @@ type Type struct {
|
||||
Pos Pos
|
||||
// Only one of Value, Ident, String is filled.
|
||||
Value uint64
|
||||
ValueHex bool
|
||||
valueFmt intFmt
|
||||
Ident string
|
||||
String string
|
||||
HasString bool
|
||||
@ -194,7 +202,7 @@ type Type struct {
|
||||
HasColon bool
|
||||
Pos2 Pos
|
||||
Value2 uint64
|
||||
Value2Hex bool
|
||||
value2Fmt intFmt
|
||||
Ident2 string
|
||||
Args []*Type
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ func (n *Int) Clone() Node {
|
||||
return &Int{
|
||||
Pos: n.Pos,
|
||||
Value: n.Value,
|
||||
ValueHex: n.ValueHex,
|
||||
valueFmt: n.valueFmt,
|
||||
Ident: n.Ident,
|
||||
CExpr: n.CExpr,
|
||||
}
|
||||
@ -179,14 +179,14 @@ func (n *Type) Clone() Node {
|
||||
return &Type{
|
||||
Pos: n.Pos,
|
||||
Value: n.Value,
|
||||
ValueHex: n.ValueHex,
|
||||
valueFmt: n.valueFmt,
|
||||
Ident: n.Ident,
|
||||
String: n.String,
|
||||
HasString: n.HasString,
|
||||
HasColon: n.HasColon,
|
||||
Pos2: n.Pos2,
|
||||
Value2: n.Value2,
|
||||
Value2Hex: n.Value2Hex,
|
||||
value2Fmt: n.value2Fmt,
|
||||
Ident2: n.Ident2,
|
||||
Args: args,
|
||||
}
|
||||
|
@ -159,14 +159,14 @@ func fmtType(t *Type) string {
|
||||
case t.HasString:
|
||||
v = fmt.Sprintf("\"%v\"", t.String)
|
||||
default:
|
||||
v = fmtIntValue(t.Value, t.ValueHex)
|
||||
v = fmtIntValue(t.Value, t.valueFmt)
|
||||
}
|
||||
if t.HasColon {
|
||||
switch {
|
||||
case t.Ident2 != "":
|
||||
v += fmt.Sprintf(":%v", t.Ident2)
|
||||
default:
|
||||
v += fmt.Sprintf(":%v", fmtIntValue(t.Value2, t.Value2Hex))
|
||||
v += fmt.Sprintf(":%v", fmtIntValue(t.Value2, t.value2Fmt))
|
||||
}
|
||||
}
|
||||
v += fmtTypeList(t.Args)
|
||||
@ -206,15 +206,21 @@ func fmtInt(i *Int) string {
|
||||
case i.CExpr != "":
|
||||
return fmt.Sprintf("%v", i.CExpr)
|
||||
default:
|
||||
return fmtIntValue(i.Value, i.ValueHex)
|
||||
return fmtIntValue(i.Value, i.valueFmt)
|
||||
}
|
||||
}
|
||||
|
||||
func fmtIntValue(v uint64, hex bool) string {
|
||||
if hex {
|
||||
func fmtIntValue(v uint64, format intFmt) string {
|
||||
switch format {
|
||||
case intFmtDec:
|
||||
return fmt.Sprint(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))
|
||||
}
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
|
||||
func comma(i int, or string) string {
|
||||
|
@ -413,7 +413,7 @@ func (p *parser) parseType() *Type {
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
allowColon = true
|
||||
arg.Value, arg.ValueHex = p.parseIntValue()
|
||||
arg.Value, arg.valueFmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
allowColon = true
|
||||
arg.Ident = p.lit
|
||||
@ -429,7 +429,7 @@ func (p *parser) parseType() *Type {
|
||||
arg.Pos2 = p.pos
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
arg.Value2, arg.Value2Hex = p.parseIntValue()
|
||||
arg.Value2, arg.value2Fmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
arg.Ident2 = p.lit
|
||||
default:
|
||||
@ -479,7 +479,7 @@ func (p *parser) parseInt() *Int {
|
||||
}
|
||||
switch p.tok {
|
||||
case tokInt:
|
||||
i.Value, i.ValueHex = p.parseIntValue()
|
||||
i.Value, i.valueFmt = p.parseIntValue()
|
||||
case tokIdent:
|
||||
i.Ident = p.lit
|
||||
default:
|
||||
@ -489,13 +489,16 @@ func (p *parser) parseInt() *Int {
|
||||
return i
|
||||
}
|
||||
|
||||
func (p *parser) parseIntValue() (uint64, bool) {
|
||||
func (p *parser) parseIntValue() (uint64, intFmt) {
|
||||
if p.lit[0] == '\'' {
|
||||
return uint64(p.lit[1]), intFmtChar
|
||||
}
|
||||
if v, err := strconv.ParseUint(p.lit, 10, 64); err == nil {
|
||||
return v, false
|
||||
return v, intFmtDec
|
||||
}
|
||||
if len(p.lit) > 2 && p.lit[0] == '0' && p.lit[1] == 'x' {
|
||||
if v, err := strconv.ParseUint(p.lit[2:], 16, 64); err == nil {
|
||||
return v, true
|
||||
return v, intFmtHex
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("scanner returned bad integer %q", p.lit))
|
||||
|
@ -200,6 +200,17 @@ func (s *scanner) Scan() (tok token, lit string, pos Pos) {
|
||||
s.Error(pos, fmt.Sprintf("bad integer %q", lit))
|
||||
lit = "0"
|
||||
}
|
||||
case s.ch == '\'':
|
||||
tok = tokInt
|
||||
lit = "0"
|
||||
s.next()
|
||||
s.next()
|
||||
if s.ch != '\'' {
|
||||
s.Error(pos, "char literal is not terminated")
|
||||
return
|
||||
}
|
||||
s.next()
|
||||
lit = string(s.data[pos.Off : pos.Off+3])
|
||||
case s.ch == '_' || s.ch >= 'a' && s.ch <= 'z' || s.ch >= 'A' && s.ch <= 'Z':
|
||||
tok = tokIdent
|
||||
for s.ch == '_' || s.ch == '$' ||
|
||||
|
3
pkg/ast/testdata/all.txt
vendored
3
pkg/ast/testdata/all.txt
vendored
@ -9,6 +9,9 @@ int_flags0 = 0, 0x1, 0xab
|
||||
int_flags1 = 123ab0x ### bad integer "123ab0x"
|
||||
int_flags1 == 0, 1 ### unexpected '=', expecting int, identifier, string
|
||||
int_flags = 0, "foo" ### unexpected string, expecting int, identifier
|
||||
int_flags2 = ' ### char literal is not terminated
|
||||
int_flags3 = 'a ### char literal is not terminated
|
||||
int_flags3 = 'a, 1 ### char literal is not terminated
|
||||
|
||||
str_flags0 = "foo", "bar"
|
||||
str_flags1 = "non terminated ### string literal is not terminated
|
||||
|
@ -5,6 +5,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
@ -15,6 +16,8 @@ import (
|
||||
"github.com/google/syzkaller/sys/targets"
|
||||
)
|
||||
|
||||
var flagUpdate = flag.Bool("update", false, "reformat all.txt")
|
||||
|
||||
func TestCompileAll(t *testing.T) {
|
||||
for os, arches := range targets.List {
|
||||
os, arches := os, arches
|
||||
@ -63,7 +66,8 @@ func TestNoErrors(t *testing.T) {
|
||||
eh := func(pos ast.Pos, msg string) {
|
||||
t.Logf("%v: %v", pos, msg)
|
||||
}
|
||||
data, err := ioutil.ReadFile(filepath.Join("testdata", name))
|
||||
fileName := filepath.Join("testdata", name)
|
||||
data, err := ioutil.ReadFile(fileName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -71,6 +75,13 @@ func TestNoErrors(t *testing.T) {
|
||||
if astDesc == nil {
|
||||
t.Fatalf("parsing failed")
|
||||
}
|
||||
formatted := ast.Format(astDesc)
|
||||
if !bytes.Equal(data, formatted) {
|
||||
if *flagUpdate {
|
||||
ioutil.WriteFile(fileName, formatted, 0644)
|
||||
}
|
||||
t.Fatalf("description is not formatted")
|
||||
}
|
||||
constInfo := ExtractConsts(astDesc, target, eh)
|
||||
if constInfo == nil {
|
||||
t.Fatalf("const extraction failed")
|
||||
|
6
pkg/compiler/testdata/all.txt
vendored
6
pkg/compiler/testdata/all.txt
vendored
@ -6,6 +6,7 @@ foo$1(a int8[C1:C2])
|
||||
foo$2(a ptr[out, array[int32]])
|
||||
foo$3(a union_arg)
|
||||
foo$4() r0
|
||||
foo$5(a int8['a':'z'])
|
||||
|
||||
resource r0[intptr]
|
||||
|
||||
@ -139,8 +140,8 @@ type templ_struct1[C] {
|
||||
}
|
||||
|
||||
union_with_templ_struct [
|
||||
f1 templ_struct0[C1, type0]
|
||||
f2 templ_struct0[C2, struct0]
|
||||
f1 templ_struct0[C1, type0]
|
||||
f2 templ_struct0[C2, struct0]
|
||||
] [varlen]
|
||||
|
||||
struct0 {
|
||||
@ -183,7 +184,6 @@ foo$templ4(a ptr[in, templ_struct1[3]])
|
||||
foo$templ5(a ptr[in, templ_struct1[3]])
|
||||
foo$templ6(a ptr[in, templ_struct4])
|
||||
|
||||
|
||||
# Structs.
|
||||
|
||||
s0 {
|
||||
|
1
pkg/compiler/testdata/errors2.txt
vendored
1
pkg/compiler/testdata/errors2.txt
vendored
@ -183,5 +183,6 @@ foo$505(a proc[20, 0]) ### proc per-process values must not be 0
|
||||
foo$506(a ptr[in, array[int32, 0]]) ### arrays of size 0 are not supported
|
||||
foo$507(a ptr[in, array[int32, 0:0]]) ### arrays of size 0 are not supported
|
||||
foo$508(a ptr[in, string["foo", 3]]) ### string value "foo\x00" exceeds buffer length 3
|
||||
foo$509(a int8['b':'a']) ### bad int range [98:97]
|
||||
|
||||
type type500 proc[C1, 8, int8] ### values starting from 1 with step 8 overflow base type for 32 procs
|
||||
|
Loading…
Reference in New Issue
Block a user