aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-11-11 14:44:01 -0800
committerGitHub <noreply@github.com>2016-11-11 14:44:01 -0800
commit89abacc228e60afe1df0b01d36dc7fe886ca7bcc (patch)
treef0ca6508ab6f3b6ea78e6260c28dd09f37c9d48c
parent85f78e771dced807e5e09b8012ec38333e442bb7 (diff)
parent3a65453870b12f5c42739c27d99df8fc58358f88 (diff)
Merge pull request #86 from google/sys_ptrs
A bunch of changes to sys/prog package
-rw-r--r--host/host.go32
-rw-r--r--prog/analysis.go202
-rw-r--r--prog/clone.go1
-rw-r--r--prog/encoding.go38
-rw-r--r--prog/encodingexec.go16
-rw-r--r--prog/mutation.go86
-rw-r--r--prog/prio.go68
-rw-r--r--prog/prog.go120
-rw-r--r--prog/rand.go323
-rw-r--r--prog/size_test.go3
-rw-r--r--prog/validation.go35
-rw-r--r--sys/README.md16
-rw-r--r--sys/align.go10
-rw-r--r--sys/bpf.txt2
-rw-r--r--sys/decl.go331
-rw-r--r--sys/dri.txt6
-rw-r--r--sys/input.txt6
-rw-r--r--sys/kdbus.txt2
-rw-r--r--sys/key.txt8
-rw-r--r--sys/kvm.txt4
-rw-r--r--sys/perf.txt2
-rwxr-xr-xsys/random.txt4
-rw-r--r--sys/sndcontrol.txt4
-rw-r--r--sys/sndseq.txt2
-rw-r--r--sys/sndtimer.txt2
-rw-r--r--sys/socket.txt9
-rw-r--r--sys/sys.txt163
-rw-r--r--sys/tlk_device.txt2
-rw-r--r--sys/tty.txt2
-rwxr-xr-xsys/tun.txt2
-rw-r--r--sysgen/sysgen.go173
-rw-r--r--sysparser/lexer.go26
-rw-r--r--sysparser/parser.go3
33 files changed, 710 insertions, 993 deletions
diff --git a/host/host.go b/host/host.go
index 220f8aaf6..a58964e8c 100644
--- a/host/host.go
+++ b/host/host.go
@@ -60,11 +60,7 @@ func isSupportedSyzkall(c *sys.Call) bool {
case "syz_test":
return false
case "syz_open_dev":
- ptr, ok := c.Args[0].(sys.PtrType)
- if !ok {
- return true
- }
- fname, ok := ptr.Type.(sys.StrConstType)
+ fname, ok := extractStringConst(c.Args[0])
if !ok {
panic("first open arg is not a pointer to string const")
}
@@ -84,7 +80,7 @@ func isSupportedSyzkall(c *sys.Call) bool {
}
return false
}
- return check(fname.Val[:len(fname.Val)-1])
+ return check(fname)
case "syz_open_pts":
return true
case "syz_fuse_mount":
@@ -99,7 +95,7 @@ func isSupportedSyzkall(c *sys.Call) bool {
}
func isSupportedSocket(c *sys.Call) bool {
- af, ok := c.Args[0].(sys.ConstType)
+ af, ok := c.Args[0].(*sys.ConstType)
if !ok {
println(c.Name)
panic("socket family is not const")
@@ -112,17 +108,27 @@ func isSupportedSocket(c *sys.Call) bool {
}
func isSupportedOpen(c *sys.Call) bool {
- ptr, ok := c.Args[0].(sys.PtrType)
- if !ok {
- panic("first open arg is not a pointer")
- }
- fname, ok := ptr.Type.(sys.StrConstType)
+ fname, ok := extractStringConst(c.Args[0])
if !ok {
return true
}
- fd, err := syscall.Open(fname.Val[:len(fname.Val)-1], syscall.O_RDONLY, 0)
+ fd, err := syscall.Open(fname, syscall.O_RDONLY, 0)
if fd != -1 {
syscall.Close(fd)
}
return err == nil
}
+
+func extractStringConst(typ sys.Type) (string, bool) {
+ ptr, ok := typ.(*sys.PtrType)
+ if !ok {
+ panic("first open arg is not a pointer to string const")
+ }
+ str, ok := ptr.Type.(*sys.BufferType)
+ if !ok || str.Kind != sys.BufferString || len(str.Values) != 1 {
+ return "", false
+ }
+ v := str.Values[0]
+ v = v[:len(v)-1] // string terminating \x00
+ return v, true
+}
diff --git a/prog/analysis.go b/prog/analysis.go
index baf87fbb5..4bf6506f1 100644
--- a/prog/analysis.go
+++ b/prog/analysis.go
@@ -51,18 +51,19 @@ func newState(ct *ChoiceTable) *state {
func (s *state) analyze(c *Call) {
foreachArgArray(&c.Args, c.Ret, func(arg, base *Arg, _ *[]*Arg) {
switch typ := arg.Type.(type) {
- case sys.FilenameType:
- if arg.Kind == ArgData && arg.Dir != DirOut {
- s.files[string(arg.Data)] = true
- }
- case sys.ResourceType:
- if arg.Dir != DirIn {
+ case *sys.ResourceType:
+ if arg.Type.Dir() != sys.DirIn {
s.resources[typ.Desc.Name] = append(s.resources[typ.Desc.Name], arg)
// TODO: negative PIDs and add them as well (that's process groups).
}
- case sys.BufferType:
- if typ.Kind == sys.BufferString && arg.Kind == ArgData && len(arg.Data) != 0 {
- s.strings[string(arg.Data)] = true
+ case *sys.BufferType:
+ if arg.Type.Dir() != sys.DirOut && arg.Kind == ArgData && len(arg.Data) != 0 {
+ switch typ.Kind {
+ case sys.BufferString:
+ s.strings[string(arg.Data)] = true
+ case sys.BufferFilename:
+ s.files[string(arg.Data)] = true
+ }
}
}
})
@@ -149,186 +150,67 @@ func foreachArg(c *Call, f func(arg, base *Arg, parent *[]*Arg)) {
foreachArgArray(&c.Args, nil, f)
}
-func assignTypeAndDir(c *Call) error {
- var rec func(arg *Arg, typ sys.Type, dir ArgDir) error
- rec = func(arg *Arg, typ sys.Type, dir ArgDir) error {
- if arg.Call != nil && arg.Call != c {
- panic(fmt.Sprintf("different call is already assigned: %p %p %v %v", arg.Call, c, arg.Call.Meta.Name, c.Meta.Name))
- }
- arg.Call = c
- if arg.Type != nil && arg.Type.Name() != typ.Name() {
- panic("different type is already assigned: " + arg.Type.Name() + " vs " + typ.Name())
- }
- arg.Type = typ
- switch arg.Kind {
- case ArgPointer:
- arg.Dir = DirIn
- switch typ1 := typ.(type) {
- case sys.PtrType:
- if arg.Res != nil {
- if err := rec(arg.Res, typ1.Type, ArgDir(typ1.Dir)); err != nil {
- return err
- }
- }
- }
- case ArgGroup:
- arg.Dir = dir
- switch typ1 := typ.(type) {
- case *sys.StructType:
- if len(arg.Inner) != len(typ1.Fields) {
- return fmt.Errorf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields))
- }
- for i, arg1 := range arg.Inner {
- if err := rec(arg1, typ1.Fields[i], dir); err != nil {
- return err
- }
- }
- case sys.ArrayType:
- for _, arg1 := range arg.Inner {
- if err := rec(arg1, typ1.Type, dir); err != nil {
- return err
- }
- }
- }
- case ArgUnion:
- arg.Dir = dir
- if err := rec(arg.Option, arg.OptionType, dir); err != nil {
- return err
- }
- default:
- arg.Dir = dir
- }
- return nil
- }
- for i, arg := range c.Args {
- if c.Meta == nil {
- panic("nil meta")
- }
- if err := rec(arg, c.Meta.Args[i], DirIn); err != nil {
- return err
- }
- }
- if c.Ret == nil {
- c.Ret = returnArg()
- c.Ret.Call = c
- c.Ret.Type = c.Meta.Ret
- c.Ret.Dir = DirOut
- }
- return nil
-}
-
-func generateSize(typ sys.Type, arg *Arg, lenType sys.LenType) *Arg {
+func generateSize(arg *Arg, lenType *sys.LenType) *Arg {
if arg == nil {
// Arg is an optional pointer, set size to 0.
- return constArg(0)
+ return constArg(lenType, 0)
}
- switch typ.(type) {
- case sys.VmaType:
- return pageSizeArg(arg.AddrPagesNum, 0)
- case sys.ArrayType:
+ switch arg.Type.(type) {
+ case *sys.VmaType:
+ return pageSizeArg(lenType, arg.AddrPagesNum, 0)
+ case *sys.ArrayType:
if lenType.ByteSize {
- return constArg(arg.Size(typ))
+ return constArg(lenType, arg.Size())
} else {
- return constArg(uintptr(len(arg.Inner)))
+ return constArg(lenType, uintptr(len(arg.Inner)))
}
default:
- return constArg(arg.Size(typ))
+ return constArg(lenType, arg.Size())
}
}
-func assignSizes(types []sys.Type, args []*Arg) {
+func assignSizes(args []*Arg) {
+ // Create a map of args and calculate size of the whole struct.
argsMap := make(map[string]*Arg)
- typesMap := make(map[string]sys.Type)
-
- // Create a map of args and types.
- for i, typ := range types {
- if sys.IsPad(typ) {
+ var parentSize uintptr
+ for _, arg := range args {
+ parentSize += arg.Size()
+ if sys.IsPad(arg.Type) {
continue
}
- if typ.Name() == "parent" {
- panic("parent is reserved len name")
- }
-
- innerArg := args[i].InnerArg(typ)
- innerType := typ.InnerType()
-
- if _, ok := argsMap[typ.Name()]; ok {
- panic(fmt.Sprintf("mutiple args with the same name '%v', types: %+v, args: %+v", typ.Name(), types, args))
- }
- argsMap[typ.Name()] = innerArg
- typesMap[typ.Name()] = innerType
- }
-
- // Calculate size of the whole struct.
- var parentSize uintptr
- for i, typ := range types {
- parentSize += args[i].Size(typ)
+ argsMap[arg.Type.Name()] = arg
}
// Fill in size arguments.
- for i, typ := range types {
- if lenType, ok := typ.InnerType().(sys.LenType); ok {
- lenArg := args[i].InnerArg(typ)
- if lenArg == nil {
- // Pointer to optional len field, no need to fill in value.
- continue
- }
-
- if lenType.Buf == "parent" {
- *lenArg = *constArg(parentSize)
+ for _, arg := range args {
+ if arg = arg.InnerArg(); arg == nil {
+ continue // Pointer to optional len field, no need to fill in value.
+ }
+ if typ, ok := arg.Type.(*sys.LenType); ok {
+ if typ.Buf == "parent" {
+ arg.Val = parentSize
continue
}
- arg, ok := argsMap[lenType.Buf]
+ buf, ok := argsMap[typ.Buf]
if !ok {
- panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v, typesMap: %+v",
- lenType.Name(), lenType.Buf, argsMap, typesMap))
+ panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
+ typ.Name(), typ.Buf, argsMap))
}
- typ := typesMap[lenType.Buf]
- *lenArg = *generateSize(typ, arg, lenType)
+ *arg = *generateSize(buf.InnerArg(), typ)
}
}
}
func assignSizesCall(c *Call) {
- var rec func(arg *Arg, typ sys.Type)
- rec = func(arg *Arg, typ sys.Type) {
- switch arg.Kind {
- case ArgPointer:
- switch typ1 := typ.(type) {
- case sys.PtrType:
- if arg.Res != nil {
- rec(arg.Res, typ1.Type)
- }
- }
- case ArgGroup:
- switch typ1 := typ.(type) {
- case *sys.StructType:
- if len(arg.Inner) != len(typ1.Fields) {
- panic(fmt.Sprintf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields)))
- }
- for i, arg1 := range arg.Inner {
- rec(arg1, typ1.Fields[i])
- }
- assignSizes(typ1.Fields, arg.Inner)
- case sys.ArrayType:
- for _, arg1 := range arg.Inner {
- rec(arg1, typ1.Type)
- }
- }
- case ArgUnion:
- rec(arg.Option, arg.OptionType)
+ assignSizes(c.Args)
+ foreachArg(c, func(arg, base *Arg, parent *[]*Arg) {
+ if _, ok := arg.Type.(*sys.StructType); ok {
+ assignSizes(arg.Inner)
}
- }
- if c.Meta == nil {
- panic("nil meta")
- }
- for i, arg := range c.Args {
- rec(arg, c.Meta.Args[i])
- }
- assignSizes(c.Meta.Args, c.Args)
+ })
}
func sanitizeCall(c *Call) {
diff --git a/prog/clone.go b/prog/clone.go
index 14f9db759..69a54cd4e 100644
--- a/prog/clone.go
+++ b/prog/clone.go
@@ -24,7 +24,6 @@ func (p *Prog) Clone() *Prog {
func (arg *Arg) clone(c *Call, newargs map[*Arg]*Arg) *Arg {
arg1 := new(Arg)
*arg1 = *arg
- arg1.Call = c
arg1.Data = append([]byte{}, arg.Data...)
switch arg.Kind {
case ArgPointer:
diff --git a/prog/encoding.go b/prog/encoding.go
index 01438f5b9..7afe218be 100644
--- a/prog/encoding.go
+++ b/prog/encoding.go
@@ -93,7 +93,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
switch a.Type.(type) {
case *sys.StructType:
delims = []byte{'{', '}'}
- case sys.ArrayType:
+ case *sys.ArrayType:
delims = []byte{'[', ']'}
default:
panic("unknown group type")
@@ -137,7 +137,10 @@ func Deserialize(data []byte) (prog *Prog, err error) {
if meta == nil {
return nil, fmt.Errorf("unknown syscall %v", name)
}
- c := &Call{Meta: meta}
+ c := &Call{
+ Meta: meta,
+ Ret: returnArg(meta.Ret),
+ }
prog.Calls = append(prog.Calls, c)
p.Parse('(')
for i := 0; p.Char() != ')'; i++ {
@@ -164,9 +167,6 @@ func Deserialize(data []byte) (prog *Prog, err error) {
if len(c.Args) != len(meta.Args) {
return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args))
}
- if err := assignTypeAndDir(c); err != nil {
- return nil, err
- }
if r != "" {
vars[r] = c.Ret
}
@@ -196,14 +196,14 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
if err != nil {
return nil, fmt.Errorf("wrong arg value '%v': %v", val, err)
}
- arg = constArg(uintptr(v))
+ arg = constArg(typ, uintptr(v))
case 'r':
id := p.Ident()
v, ok := vars[id]
if !ok || v == nil {
return nil, fmt.Errorf("result %v references unknown variable (vars=%+v)", id, vars)
}
- arg = resultArg(v)
+ arg = resultArg(typ, v)
if p.Char() == '/' {
p.Parse('/')
op := p.Ident()
@@ -225,9 +225,9 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
case '&':
var typ1 sys.Type
switch t1 := typ.(type) {
- case sys.PtrType:
+ case *sys.PtrType:
typ1 = t1.Type
- case sys.VmaType:
+ case *sys.VmaType:
default:
return nil, fmt.Errorf("& arg is not a pointer: %#v", typ)
}
@@ -241,13 +241,13 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
if err != nil {
return nil, err
}
- arg = pointerArg(page, off, size, inner)
+ arg = pointerArg(typ, page, off, size, inner)
case '(':
page, off, _, err := parseAddr(p, false)
if err != nil {
return nil, err
}
- arg = pageSizeArg(page, off)
+ arg = pageSizeArg(typ, page, off)
case '"':
p.Parse('"')
val := ""
@@ -259,7 +259,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
if err != nil {
return nil, fmt.Errorf("data arg has bad value '%v'", val)
}
- arg = dataArg(data)
+ arg = dataArg(typ, data)
case '{':
t1, ok := typ.(*sys.StructType)
if !ok {
@@ -273,7 +273,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
}
fld := t1.Fields[i]
if sys.IsPad(fld) {
- inner = append(inner, constArg(0))
+ inner = append(inner, constArg(fld, 0))
} else {
arg, err := parseArg(fld, p, vars)
if err != nil {
@@ -286,12 +286,12 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
}
}
p.Parse('}')
- if sys.IsPad(t1.Fields[len(t1.Fields)-1]) {
- inner = append(inner, constArg(0))
+ if last := t1.Fields[len(t1.Fields)-1]; sys.IsPad(last) {
+ inner = append(inner, constArg(last, 0))
}
- arg = groupArg(inner)
+ arg = groupArg(typ, inner)
case '[':
- t1, ok := typ.(sys.ArrayType)
+ t1, ok := typ.(*sys.ArrayType)
if !ok {
return nil, fmt.Errorf("'[' arg is not an array: %#v", typ)
}
@@ -308,7 +308,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
}
}
p.Parse(']')
- arg = groupArg(inner)
+ arg = groupArg(typ, inner)
case '@':
t1, ok := typ.(*sys.UnionType)
if !ok {
@@ -331,7 +331,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
if err != nil {
return nil, err
}
- arg = unionArg(opt, optType)
+ arg = unionArg(typ, opt, optType)
case 'n':
p.Parse('n')
p.Parse('i')
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index 239ef3514..4c2cd2524 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -46,7 +46,7 @@ func (p *Prog) SerializeForExec() []byte {
w.args[base] = &argInfo{}
}
w.args[arg] = &argInfo{Offset: w.args[base].CurSize}
- w.args[base].CurSize += arg.Size(arg.Type)
+ w.args[base].CurSize += arg.Size()
})
// Generate copyin instructions that fill in data into pointer arguments.
foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) {
@@ -69,7 +69,7 @@ func (p *Prog) SerializeForExec() []byte {
if arg1.Kind == ArgData && len(arg1.Data) == 0 {
return
}
- if arg1.Dir != DirOut {
+ if arg1.Type.Dir() != sys.DirOut {
w.write(ExecInstrCopyin)
w.write(physicalAddr(arg) + w.args[arg1].Offset)
w.writeArg(arg1)
@@ -105,7 +105,7 @@ func (p *Prog) SerializeForExec() []byte {
instrSeq++
w.write(ExecInstrCopyout)
w.write(physicalAddr(base) + info.Offset)
- w.write(arg.Size(arg.Type))
+ w.write(arg.Size())
default:
panic("bad arg kind in copyout")
}
@@ -147,21 +147,21 @@ func (w *execContext) writeArg(arg *Arg) {
switch arg.Kind {
case ArgConst:
w.write(ExecArgConst)
- w.write(arg.Size(arg.Type))
- w.write(arg.Value(arg.Type))
+ w.write(arg.Size())
+ w.write(arg.Value())
case ArgResult:
w.write(ExecArgResult)
- w.write(arg.Size(arg.Type))
+ w.write(arg.Size())
w.write(w.args[arg.Res].Idx)
w.write(arg.OpDiv)
w.write(arg.OpAdd)
case ArgPointer:
w.write(ExecArgConst)
- w.write(arg.Size(arg.Type))
+ w.write(arg.Size())
w.write(physicalAddr(arg))
case ArgPageSize:
w.write(ExecArgConst)
- w.write(arg.Size(arg.Type))
+ w.write(arg.Size())
w.write(arg.AddrPage * pageSize)
case ArgData:
w.write(ExecArgData)
diff --git a/prog/mutation.go b/prog/mutation.go
index 577e24796..8d5fa36a4 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -57,13 +57,13 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
if base.Kind != ArgPointer || base.Res == nil {
panic("bad base arg")
}
- baseSize = base.Res.Size(base.Res.Type)
+ baseSize = base.Res.Size()
}
switch a := arg.Type.(type) {
- case sys.IntType, sys.FlagsType, sys.FileoffType, sys.ResourceType, sys.VmaType:
- arg1, calls1 := r.generateArg(s, arg.Type, arg.Dir)
- p.replaceArg(arg, arg1, calls1)
- case sys.BufferType:
+ case *sys.IntType, *sys.FlagsType, *sys.ResourceType, *sys.VmaType:
+ arg1, calls1 := r.generateArg(s, arg.Type)
+ p.replaceArg(c, arg, arg1, calls1)
+ case *sys.BufferType:
switch a.Kind {
case sys.BufferBlobRand, sys.BufferBlobRange:
var data []byte
@@ -89,23 +89,16 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
if r.bin() {
arg.Data = mutateData(r, append([]byte{}, arg.Data...), int(0), ^int(0))
} else {
- arg.Data = r.randString(s)
+ arg.Data = r.randString(s, a.Values, a.Dir())
}
- case sys.BufferFilesystem:
- arg.Data = r.filesystem(s)
+ case sys.BufferFilename:
+ arg.Data = []byte(r.filename(s))
case sys.BufferSockaddr:
arg.Data = r.sockaddr(s)
- case sys.BufferAlgType:
- arg.Data = r.algType(s)
- case sys.BufferAlgName:
- arg.Data = r.algName(s)
default:
panic("unknown buffer kind")
}
- case sys.FilenameType:
- filename := r.filename(s)
- arg.Data = []byte(filename)
- case sys.ArrayType:
+ case *sys.ArrayType:
count := uintptr(0)
switch a.Kind {
case sys.ArrayRandLen:
@@ -123,7 +116,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
if count > uintptr(len(arg.Inner)) {
var calls []*Call
for count > uintptr(len(arg.Inner)) {
- arg1, calls1 := r.generateArg(s, a.Type, arg.Dir)
+ arg1, calls1 := r.generateArg(s, a.Type)
arg.Inner = append(arg.Inner, arg1)
for _, c1 := range calls1 {
calls = append(calls, c1)
@@ -131,27 +124,25 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
}
}
for _, c1 := range calls {
- assignTypeAndDir(c1)
sanitizeCall(c1)
}
- assignTypeAndDir(c)
sanitizeCall(c)
p.insertBefore(c, calls)
} else if count < uintptr(len(arg.Inner)) {
for _, arg := range arg.Inner[count:] {
- p.removeArg(arg)
+ p.removeArg(c, arg)
}
arg.Inner = arg.Inner[:count]
}
// TODO: swap elements of the array
- case sys.PtrType:
+ case *sys.PtrType:
// TODO: we don't know size for out args
size := uintptr(1)
if arg.Res != nil {
- size = arg.Res.Size(arg.Res.Type)
+ size = arg.Res.Size()
}
- arg1, calls1 := r.addr(s, size, arg.Res)
- p.replaceArg(arg, arg1, calls1)
+ arg1, calls1 := r.addr(s, a, size, arg.Res)
+ p.replaceArg(c, arg, arg1, calls1)
case *sys.StructType:
ctor := isSpecialStruct(a)
if ctor == nil {
@@ -159,7 +150,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
}
arg1, calls1 := ctor(r, s)
for i, f := range arg1.Inner {
- p.replaceArg(arg.Inner[i], f, calls1)
+ p.replaceArg(c, arg.Inner[i], f, calls1)
calls1 = nil
}
case *sys.UnionType:
@@ -167,23 +158,22 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
for optType.Name() == arg.OptionType.Name() {
optType = a.Options[r.Intn(len(a.Options))]
}
- p.removeArg(arg.Option)
- opt, calls := r.generateArg(s, optType, arg.Dir)
- arg1 := unionArg(opt, optType)
- p.replaceArg(arg, arg1, calls)
- case sys.LenType:
+ p.removeArg(c, arg.Option)
+ opt, calls := r.generateArg(s, optType)
+ arg1 := unionArg(a, opt, optType)
+ p.replaceArg(c, arg, arg1, calls)
+ case *sys.LenType:
panic("bad arg returned by mutationArgs: LenType")
- case sys.ConstType, sys.StrConstType:
+ case *sys.ConstType:
panic("bad arg returned by mutationArgs: ConstType")
default:
panic(fmt.Sprintf("bad arg returned by mutationArgs: %#v, type=%#v", *arg, arg.Type))
}
// Update base pointer if size has increased.
- if base != nil && baseSize < base.Res.Size(base.Res.Type) {
- arg1, calls1 := r.addr(s, base.Res.Size(base.Res.Type), base.Res)
+ if base != nil && baseSize < base.Res.Size() {
+ arg1, calls1 := r.addr(s, base.Type, base.Res.Size(), base.Res)
for _, c1 := range calls1 {
- assignTypeAndDir(c1)
sanitizeCall(c1)
}
p.insertBefore(c, calls1)
@@ -194,8 +184,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
// Update all len fields.
assignSizesCall(c)
- // Assign Arg.Type fields for newly created len args.
- assignTypeAndDir(c)
}
},
1, func() {
@@ -210,7 +198,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) {
)
}
for _, c := range p.Calls {
- assignTypeAndDir(c)
sanitizeCall(c)
}
if err := p.validate(); err != nil {
@@ -254,18 +241,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool) (*Prog, int)
}
}
// Prepend uber-mmap.
- mmap := &Call{
- Meta: sys.CallMap["mmap"],
- Args: []*Arg{
- pointerArg(0, 0, uintptr(hi)+1, nil),
- pageSizeArg(uintptr(hi)+1, 0),
- constArg(sys.PROT_READ | sys.PROT_WRITE),
- constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED),
- constArg(sys.InvalidFD),
- constArg(0),
- },
- }
- assignTypeAndDir(mmap)
+ mmap := createMmapCall(0, uintptr(hi)+1)
p.Calls = append([]*Call{mmap}, p.Calls...)
if callIndex != -1 {
callIndex++
@@ -332,19 +308,23 @@ func mutationArgs(c *Call) (args, bases []*Arg) {
return
}
// These special structs are mutated as a whole.
- case sys.ArrayType:
+ case *sys.ArrayType:
// Don't mutate fixed-size arrays.
if typ.Kind == sys.ArrayRangeLen && typ.RangeBegin == typ.RangeEnd {
return
}
- case sys.LenType:
+ case *sys.LenType:
// Size is updated when the size-of arg change.
return
- case sys.ConstType, sys.StrConstType:
+ case *sys.ConstType:
// Well, this is const.
return
+ case *sys.BufferType:
+ if typ.Kind == sys.BufferString && len(typ.Values) == 1 {
+ return // string const
+ }
}
- if arg.Dir == DirOut {
+ if arg.Type.Dir() == sys.DirOut {
return
}
if base != nil {
diff --git a/prog/prio.go b/prog/prio.go
index 8983c1c92..59a205a5d 100644
--- a/prog/prio.go
+++ b/prog/prio.go
@@ -50,9 +50,9 @@ func calcStaticPriorities() [][]float32 {
uses[id][c.ID] = weight
}
}
- foreachArgType(c, func(t sys.Type, d ArgDir) {
+ sys.ForeachType(c, func(t sys.Type) {
switch a := t.(type) {
- case sys.ResourceType:
+ case *sys.ResourceType:
if a.Desc.Name == "pid" || a.Desc.Name == "uid" || a.Desc.Name == "gid" {
// Pid/uid/gid usually play auxiliary role,
// but massively happen in some structs.
@@ -68,34 +68,35 @@ func calcStaticPriorities() [][]float32 {
noteUsage(float32(w), str)
}
}
- case sys.PtrType:
+ case *sys.PtrType:
if _, ok := a.Type.(*sys.StructType); ok {
noteUsage(1.0, "ptrto-%v", a.Type.Name())
}
if _, ok := a.Type.(*sys.UnionType); ok {
noteUsage(1.0, "ptrto-%v", a.Type.Name())
}
- if arr, ok := a.Type.(sys.ArrayType); ok {
+ if arr, ok := a.Type.(*sys.ArrayType); ok {
noteUsage(1.0, "ptrto-%v", arr.Type.Name())
}
- case sys.BufferType:
+ case *sys.BufferType:
switch a.Kind {
- case sys.BufferBlobRand, sys.BufferBlobRange, sys.BufferFilesystem, sys.BufferAlgType, sys.BufferAlgName:
+ case sys.BufferBlobRand, sys.BufferBlobRange:
case sys.BufferString:
- noteUsage(0.2, "str")
+ if a.SubKind != "" {
+ noteUsage(0.2, fmt.Sprintf("str-%v", a.SubKind))
+ }
case sys.BufferSockaddr:
noteUsage(1.0, "sockaddr")
+ case sys.BufferFilename:
+ noteUsage(1.0, "filename")
default:
panic("unknown buffer kind")
}
- case sys.VmaType:
+ case *sys.VmaType:
noteUsage(0.5, "vma")
- case sys.FilenameType:
- noteUsage(1.0, "filename")
- case sys.IntType:
+ case *sys.IntType:
switch a.Kind {
- case sys.IntPlain:
- case sys.IntRange:
+ case sys.IntPlain, sys.IntFileoff, sys.IntRange:
case sys.IntSignalno:
noteUsage(1.0, "signalno")
case sys.IntInaddr:
@@ -196,47 +197,6 @@ func normalizePrio(prios [][]float32) {
}
}
-func foreachArgType(meta *sys.Call, f func(sys.Type, ArgDir)) {
- seen := make(map[sys.Type]bool)
- var rec func(t sys.Type, dir ArgDir)
- rec = func(t sys.Type, d ArgDir) {
- f(t, d)
- switch a := t.(type) {
- case sys.ArrayType:
- rec(a.Type, d)
- case sys.PtrType:
- rec(a.Type, ArgDir(a.Dir))
- case *sys.StructType:
- if seen[a] {
- return // prune recursion via pointers to structs/unions
- }
- seen[a] = true
- for _, f := range a.Fields {
- rec(f, d)
- }
- case *sys.UnionType:
- if seen[a] {
- return // prune recursion via pointers to structs/unions
- }
- seen[a] = true
- for _, opt := range a.Options {
- rec(opt, d)
- }
- case sys.ResourceType, sys.FileoffType, sys.BufferType,
- sys.VmaType, sys.LenType, sys.FlagsType, sys.ConstType,
- sys.StrConstType, sys.IntType, sys.FilenameType:
- default:
- panic("unknown type")
- }
- }
- for _, t := range meta.Args {
- rec(t, DirIn)
- }
- if meta.Ret != nil {
- rec(meta.Ret, DirOut)
- }
-}
-
// ChooseTable allows to do a weighted choice of a syscall for a given syscall
// based on call-to-call priorities and a set of enabled syscalls.
type ChoiceTable struct {
diff --git a/prog/prog.go b/prog/prog.go
index 9953f3ef0..e3a0febd2 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -20,10 +20,8 @@ type Call struct {
}
type Arg struct {
- Call *Call
Type sys.Type
Kind ArgKind
- Dir ArgDir
Val uintptr // value of ArgConst
AddrPage uintptr // page index for ArgPointer address, page count for ArgPageSize
AddrOffset int // page offset for ArgPointer address
@@ -53,26 +51,17 @@ const (
ArgReturn // fake value denoting syscall return value
)
-type ArgDir sys.Dir
-
-const (
- DirIn = ArgDir(sys.DirIn)
- DirOut = ArgDir(sys.DirOut)
- DirInOut = ArgDir(sys.DirInOut)
-)
-
// Returns inner arg for PtrType args
-func (a *Arg) InnerArg(typ sys.Type) *Arg {
- switch typ1 := typ.(type) {
- case sys.PtrType:
+func (a *Arg) InnerArg() *Arg {
+ switch typ := a.Type.(type) {
+ case *sys.PtrType:
if a.Res == nil {
- if typ.Optional() {
- return nil
- } else {
- panic(fmt.Sprintf("non-optional pointer is nil\narg: %+v\ntype: %+v", a, typ1))
+ if !typ.Optional() {
+ panic(fmt.Sprintf("non-optional pointer is nil\narg: %+v\ntype: %+v", a, typ))
}
+ return nil
} else {
- return a.Res.InnerArg(typ1.Type)
+ return a.Res.InnerArg()
}
default:
return a
@@ -96,43 +85,39 @@ func encodeValue(value, size uintptr, bigEndian bool) uintptr {
}
// Returns value taking endianness into consideration.
-func (a *Arg) Value(typ sys.Type) uintptr {
- switch t := typ.(type) {
- case sys.IntType:
- return encodeValue(a.Val, t.Size(), t.BigEndian)
- case sys.ConstType:
- return encodeValue(a.Val, t.Size(), t.BigEndian)
- case sys.FlagsType:
- return encodeValue(a.Val, t.Size(), t.BigEndian)
- case sys.LenType:
- return encodeValue(a.Val, t.Size(), t.BigEndian)
- case sys.FileoffType:
- return encodeValue(a.Val, t.Size(), t.BigEndian)
+func (a *Arg) Value() uintptr {
+ switch typ := a.Type.(type) {
+ case *sys.IntType:
+ return encodeValue(a.Val, typ.Size(), typ.BigEndian)
+ case *sys.ConstType:
+ return encodeValue(a.Val, typ.Size(), typ.BigEndian)
+ case *sys.FlagsType:
+ return encodeValue(a.Val, typ.Size(), typ.BigEndian)
+ case *sys.LenType:
+ return encodeValue(a.Val, typ.Size(), typ.BigEndian)
}
return a.Val
}
-func (a *Arg) Size(typ sys.Type) uintptr {
- switch typ1 := typ.(type) {
- case sys.IntType, sys.LenType, sys.FlagsType, sys.ConstType, sys.StrConstType,
- sys.FileoffType, sys.ResourceType, sys.VmaType, sys.PtrType:
+func (a *Arg) Size() uintptr {
+ switch typ := a.Type.(type) {
+ case *sys.IntType, *sys.LenType, *sys.FlagsType, *sys.ConstType,
+ *sys.ResourceType, *sys.VmaType, *sys.PtrType:
return typ.Size()
- case sys.FilenameType:
- return uintptr(len(a.Data))
- case sys.BufferType:
+ case *sys.BufferType:
return uintptr(len(a.Data))
case *sys.StructType:
var size uintptr
- for i, f := range typ1.Fields {
- size += a.Inner[i].Size(f)
+ for _, fld := range a.Inner {
+ size += fld.Size()
}
return size
case *sys.UnionType:
- return a.Option.Size(a.OptionType)
- case sys.ArrayType:
+ return a.Option.Size()
+ case *sys.ArrayType:
var size uintptr
for _, in := range a.Inner {
- size += in.Size(typ1.Type)
+ size += in.Size()
}
return size
default:
@@ -140,12 +125,12 @@ func (a *Arg) Size(typ sys.Type) uintptr {
}
}
-func constArg(v uintptr) *Arg {
- return &Arg{Kind: ArgConst, Val: v}
+func constArg(t sys.Type, v uintptr) *Arg {
+ return &Arg{Type: t, Kind: ArgConst, Val: v}
}
-func resultArg(r *Arg) *Arg {
- arg := &Arg{Kind: ArgResult, Res: r}
+func resultArg(t sys.Type, r *Arg) *Arg {
+ arg := &Arg{Type: t, Kind: ArgResult, Res: r}
if r.Uses == nil {
r.Uses = make(map[*Arg]bool)
}
@@ -156,28 +141,28 @@ func resultArg(r *Arg) *Arg {
return arg
}
-func dataArg(data []byte) *Arg {
- return &Arg{Kind: ArgData, Data: append([]byte{}, data...)}
+func dataArg(t sys.Type, data []byte) *Arg {
+ return &Arg{Type: t, Kind: ArgData, Data: append([]byte{}, data...)}
}
-func pointerArg(page uintptr, off int, npages uintptr, obj *Arg) *Arg {
- return &Arg{Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj}
+func pointerArg(t sys.Type, page uintptr, off int, npages uintptr, obj *Arg) *Arg {
+ return &Arg{Type: t, Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj}
}
-func pageSizeArg(npages uintptr, off int) *Arg {
- return &Arg{Kind: ArgPageSize, AddrPage: npages, AddrOffset: off}
+func pageSizeArg(t sys.Type, npages uintptr, off int) *Arg {
+ return &Arg{Type: t, Kind: ArgPageSize, AddrPage: npages, AddrOffset: off}
}
-func groupArg(inner []*Arg) *Arg {
- return &Arg{Kind: ArgGroup, Inner: inner}
+func groupArg(t sys.Type, inner []*Arg) *Arg {
+ return &Arg{Type: t, Kind: ArgGroup, Inner: inner}
}
-func unionArg(opt *Arg, typ sys.Type) *Arg {
- return &Arg{Kind: ArgUnion, Option: opt, OptionType: typ}
+func unionArg(t sys.Type, opt *Arg, typ sys.Type) *Arg {
+ return &Arg{Type: t, Kind: ArgUnion, Option: opt, OptionType: typ}
}
-func returnArg() *Arg {
- return &Arg{Kind: ArgReturn, Dir: DirOut}
+func returnArg(t sys.Type) *Arg {
+ return &Arg{Type: t, Kind: ArgReturn}
}
func (p *Prog) insertBefore(c *Call, calls []*Call) {
@@ -197,8 +182,8 @@ func (p *Prog) insertBefore(c *Call, calls []*Call) {
p.Calls = newCalls
}
-// replaceArg replaces arg with arg1 in p, and inserts calls before arg call.
-func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) {
+// replaceArg replaces arg with arg1 in call c in program p, and inserts calls before arg call.
+func (p *Prog) replaceArg(c *Call, arg, arg1 *Arg, calls []*Call) {
if arg.Kind != ArgConst && arg.Kind != ArgResult && arg.Kind != ArgPointer && arg.Kind != ArgUnion {
panic(fmt.Sprintf("replaceArg: bad arg kind %v", arg.Kind))
}
@@ -209,10 +194,8 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) {
delete(arg.Res.Uses, arg)
}
for _, c := range calls {
- assignTypeAndDir(c)
sanitizeCall(c)
}
- c := arg.Call
p.insertBefore(c, calls)
// Somewhat hacky, but safe and preserves references to arg.
uses := arg.Uses
@@ -222,12 +205,11 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) {
delete(arg.Res.Uses, arg1)
arg.Res.Uses[arg] = true
}
- assignTypeAndDir(c)
sanitizeCall(c)
}
-// removeArg removes all references to/from arg0 from p.
-func (p *Prog) removeArg(arg0 *Arg) {
+// removeArg removes all references to/from arg0 of call c from p.
+func (p *Prog) removeArg(c *Call, arg0 *Arg) {
foreachSubarg(arg0, func(arg, _ *Arg, _ *[]*Arg) {
if arg.Kind == ArgResult {
if _, ok := arg.Res.Uses[arg]; !ok {
@@ -239,8 +221,8 @@ func (p *Prog) removeArg(arg0 *Arg) {
if arg1.Kind != ArgResult {
panic("use references not ArgResult")
}
- arg2 := constArg(arg1.Type.Default())
- p.replaceArg(arg1, arg2, nil)
+ arg2 := constArg(arg1.Type, arg1.Type.Default())
+ p.replaceArg(c, arg1, arg2, nil)
}
})
}
@@ -251,7 +233,7 @@ func (p *Prog) removeCall(idx int) {
copy(p.Calls[idx:], p.Calls[idx+1:])
p.Calls = p.Calls[:len(p.Calls)-1]
for _, arg := range c.Args {
- p.removeArg(arg)
+ p.removeArg(c, arg)
}
- p.removeArg(c.Ret)
+ p.removeArg(c, c.Ret)
}
diff --git a/prog/rand.go b/prog/rand.go
index 18dceeaea..eb24dcc4d 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -193,25 +193,25 @@ func (r *randGen) inport(s *state) uint16 {
return uint16(r.Intn(20))<<8 + 0xab
}
-func (r *randGen) in6addr(s *state) (arg *Arg, calls []*Call) {
+func (r *randGen) in6addr(s *state, typ sys.Type) (arg *Arg, calls []*Call) {
// addr: loopback (big endian)
- return groupArg([]*Arg{
- constArg(0),
- constArg(0),
- constArg(0),
- constArg(1 << 24),
+ return groupArg(typ, []*Arg{
+ constArg(nil, 0),
+ constArg(nil, 0),
+ constArg(nil, 0),
+ constArg(nil, 1<<24),
}), nil
}
-func (r *randGen) inaddrany(s *state) (arg *Arg, calls []*Call) {
+func (r *randGen) inaddrany(s *state, typ sys.Type) (arg *Arg, calls []*Call) {
if r.bin() {
- return r.in6addr(s)
+ return r.in6addr(s, typ)
} else {
- return groupArg([]*Arg{
- constArg(uintptr(r.inaddr(s))),
- constArg(0),
- constArg(0),
- constArg(0),
+ return groupArg(typ, []*Arg{
+ constArg(nil, uintptr(r.inaddr(s))),
+ constArg(nil, 0),
+ constArg(nil, 0),
+ constArg(nil, 0),
}), nil
}
}
@@ -258,7 +258,20 @@ func (r *randGen) sockaddr(s *state) []byte {
return data
}
-func (r *randGen) randString(s *state) []byte {
+func (r *randGen) randString(s *state, vals []string, dir sys.Dir) []byte {
+ data := r.randStringImpl(s, vals)
+ if dir == sys.DirOut {
+ for i := range data {
+ data[i] = 0
+ }
+ }
+ return data
+}
+
+func (r *randGen) randStringImpl(s *state, vals []string) []byte {
+ if len(vals) != 0 {
+ return []byte(vals[r.Intn(len(vals))])
+ }
if len(s.strings) != 0 && r.bin() {
// Return an existing string.
strings := make([]string, 0, len(s.strings))
@@ -288,81 +301,43 @@ func (r *randGen) randString(s *state) []byte {
return buf.Bytes()
}
-func (r *randGen) filesystem(s *state) []byte {
- dict := []string{"sysfs", "rootfs", "ramfs", "tmpfs", "devtmpfs", "debugfs",
- "securityfs", "sockfs", "pipefs", "anon_inodefs", "devpts", "ext3", "ext2", "ext4",
- "hugetlbfs", "vfat", "ecryptfs", "kdbusfs", "fuseblk", "fuse", "rpc_pipefs",
- "nfs", "nfs4", "nfsd", "binfmt_misc", "autofs", "xfs", "jfs", "msdos", "ntfs",
- "minix", "hfs", "hfsplus", "qnx4", "ufs", "btrfs", "configfs", "ncpfs", "qnx6",
- "exofs", "befs", "vxfs", "gfs2", "gfs2meta", "fusectl", "bfs", "nsfs", "efs",
- "cifs", "efivarfs", "affs", "tracefs", "bdev", "ocfs2", "ocfs2_dlmfs", "hpfs",
- "proc", "afs", "reiserfs", "jffs2", "romfs", "aio", "sysv", "v7", "udf",
- "ceph", "pstore", "adfs", "9p", "hostfs", "squashfs", "cramfs", "iso9660",
- "coda", "nilfs2", "logfs", "overlay", "f2fs", "omfs", "ubifs", "openpromfs"}
- return []byte(dict[r.Intn(len(dict))] + "\x00")
-}
-
-func (r *randGen) algType(s *state) []byte {
- dict := []string{"aead", "hash", "rng", "skcipher"}
- res := make([]byte, 14)
- copy(res, dict[r.Intn(len(dict))])
- return res
-}
-
-func (r *randGen) algName(s *state) []byte {
- dict := []string{"cmac(aes)", "ecb(aes)", "cbc(aes)", "hmac(sha1)", "pcbc(fcrypt)", "ghash",
- "jitterentropy_rng", "stdrng", "stdrng", "stdrng", "stdrng", "hmac(sha256)", "stdrng",
- "stdrng", "stdrng", "stdrng", "stdrng", "842", "lz4hc", "lz4", "lzo", "crct10dif", "crc32",
- "crc32c", "michael_mic", "zlib", "deflate", "poly1305", "chacha20", "salsa20", "seed",
- "anubis", "khazad", "xeta", "xtea", "tea", "ecb(arc4)", "arc4", "cast6", "cast5", "camellia",
- "aes", "tnepres", "serpent", "twofish", "blowfish", "fcrypt", "des3_ede", "des", "tgr128",
- "tgr160", "tgr192", "wp256", "wp384", "wp512", "sha384", "sha512", "sha224", "sha256",
- "sha1", "rmd320", "rmd256", "rmd160", "rmd128", "md5", "md4", "digest_null", "compress_null",
- "ecb(cipher_null)", "cipher_null", "rsa", "poly1305", "xts(serpent)", "lrw(serpent)",
- "ctr(serpent)", "cbc(serpent)", "__ecb-serpent-sse2", "ecb(serpent)", "__xts-serpent-sse2",
- "__lrw-serpent-sse2", "__ctr-serpent-sse2", "__cbc-serpent-sse2", "__ecb-serpent-sse2",
- "salsa20", "xts(twofish)", "lrw(twofish)", "ctr(twofish)", "cbc(twofish)", "ecb(twofish)",
- "twofish", "ctr(blowfish)", "cbc(blowfish)", "ecb(blowfish)", "blowfish", "xts(camellia)",
- "lrw(camellia)", "ctr(camellia)", "cbc(camellia)", "ecb(camellia)", "camellia", "ctr(des3_ede)",
- "cbc(des3_ede)", "ecb(des3_ede)", "des3_ede", "aes"}
- res := make([]byte, 64)
- copy(res, dict[r.Intn(len(dict))])
- return res
-}
-
func isSpecialStruct(typ sys.Type) func(r *randGen, s *state) (*Arg, []*Call) {
- if _, ok := typ.(*sys.StructType); !ok {
+ a, ok := typ.(*sys.StructType)
+ if !ok {
panic("must be a struct")
}
switch typ.Name() {
case "timespec":
return func(r *randGen, s *state) (*Arg, []*Call) {
- return r.timespec(s, false)
+ return r.timespec(s, a, false)
}
case "timeval":
return func(r *randGen, s *state) (*Arg, []*Call) {
- return r.timespec(s, true)
+ return r.timespec(s, a, true)
}
case "in6_addr":
return func(r *randGen, s *state) (*Arg, []*Call) {
- return r.in6addr(s)
+ return r.in6addr(s, a)
}
case "in_addr_any":
return func(r *randGen, s *state) (*Arg, []*Call) {
- return r.inaddrany(s)
+ return r.inaddrany(s, a)
}
}
return nil
}
-func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) {
+func (r *randGen) timespec(s *state, typ *sys.StructType, usec bool) (arg *Arg, calls []*Call) {
// We need to generate timespec/timeval that are either (1) definitely in the past,
// or (2) definitely in unreachable fututre, or (3) few ms ahead of now.
// Note timespec/timeval can be absolute or relative to now.
r.choose(
1, func() {
// now for relative, past for absolute
- arg = groupArg([]*Arg{constArg(0), constArg(0)})
+ arg = groupArg(typ, []*Arg{
+ constArg(typ.Fields[0], 0),
+ constArg(typ.Fields[1], 0),
+ })
},
1, func() {
// few ms ahead for relative, past for absolute
@@ -370,46 +345,77 @@ func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) {
if usec {
nsec /= 1e3
}
- arg = groupArg([]*Arg{constArg(0), constArg(nsec)})
+ arg = groupArg(typ, []*Arg{
+ constArg(typ.Fields[0], 0),
+ constArg(typ.Fields[1], nsec),
+ })
},
1, func() {
// unreachable fututre for both relative and absolute
- arg = groupArg([]*Arg{constArg(2e9), constArg(0)})
+ arg = groupArg(typ, []*Arg{
+ constArg(typ.Fields[0], 2e9),
+ constArg(typ.Fields[1], 0),
+ })
},
1, func() {
// few ms ahead for absolute
- tp := groupArg([]*Arg{constArg(0), constArg(0)})
+ meta := sys.CallMap["clock_gettime"]
+ ptrArgType := meta.Args[1].(*sys.PtrType)
+ argType := ptrArgType.Type.(*sys.StructType)
+ tp := groupArg(argType, []*Arg{
+ constArg(argType.Fields[0], 0),
+ constArg(argType.Fields[1], 0),
+ })
var tpaddr *Arg
- tpaddr, calls = r.addr(s, 2*ptrSize, tp)
+ tpaddr, calls = r.addr(s, ptrArgType, 2*ptrSize, tp)
gettime := &Call{
- Meta: sys.CallMap["clock_gettime"],
+ Meta: meta,
Args: []*Arg{
- constArg(sys.CLOCK_REALTIME),
+ constArg(meta.Args[0], sys.CLOCK_REALTIME),
tpaddr,
},
+ Ret: returnArg(meta.Ret),
}
calls = append(calls, gettime)
- sec := resultArg(tp.Inner[0])
- nsec := resultArg(tp.Inner[1])
+ sec := resultArg(typ.Fields[0], tp.Inner[0])
+ nsec := resultArg(typ.Fields[1], tp.Inner[1])
if usec {
nsec.OpDiv = 1e3
nsec.OpAdd = 10 * 1e3
} else {
nsec.OpAdd = 10 * 1e6
}
- arg = groupArg([]*Arg{sec, nsec})
+ arg = groupArg(typ, []*Arg{sec, nsec})
},
)
return
}
-func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) {
+// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
+func createMmapCall(start, npages uintptr) *Call {
+ meta := sys.CallMap["mmap"]
+ mmap := &Call{
+ Meta: meta,
+ Args: []*Arg{
+ pointerArg(meta.Args[0], start, 0, npages, nil),
+ pageSizeArg(meta.Args[1], npages, 0),
+ constArg(meta.Args[2], sys.PROT_READ|sys.PROT_WRITE),
+ constArg(meta.Args[3], sys.MAP_ANONYMOUS|sys.MAP_PRIVATE|sys.MAP_FIXED),
+ constArg(meta.Args[4], sys.InvalidFD),
+ constArg(meta.Args[5], 0),
+ },
+ Ret: returnArg(meta.Ret),
+ }
+ return mmap
+}
+
+func (r *randGen) addr1(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) {
npages := (size + pageSize - 1) / pageSize
if npages == 0 {
npages = 1
}
if r.oneOf(10) {
- return r.randPageAddr(s, npages, data, false), nil
+ return r.randPageAddr(s, typ, npages, data, false), nil
}
for i := uintptr(0); i < maxPages-npages; i++ {
free := true
@@ -422,24 +428,14 @@ func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) {
if !free {
continue
}
- c := &Call{
- Meta: sys.CallMap["mmap"],
- Args: []*Arg{
- pointerArg(i, 0, npages, nil),
- pageSizeArg(npages, 0),
- constArg(sys.PROT_READ | sys.PROT_WRITE),
- constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED),
- constArg(sys.InvalidFD),
- constArg(0),
- },
- }
- return pointerArg(i, 0, 0, data), []*Call{c}
+ c := createMmapCall(i, npages)
+ return pointerArg(typ, i, 0, 0, data), []*Call{c}
}
- return r.randPageAddr(s, npages, data, false), nil
+ return r.randPageAddr(s, typ, npages, data, false), nil
}
-func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) {
- arg, calls := r.addr1(s, size, data)
+func (r *randGen) addr(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) {
+ arg, calls := r.addr1(s, typ, size, data)
if arg.Kind != ArgPointer {
panic("bad")
}
@@ -457,7 +453,7 @@ func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) {
return arg, calls
}
-func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *Arg {
+func (r *randGen) randPageAddr(s *state, typ sys.Type, npages uintptr, data *Arg, vma bool) *Arg {
var starts []uintptr
for i := uintptr(0); i < maxPages-npages; i++ {
busy := true
@@ -483,13 +479,13 @@ func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *A
if !vma {
npages = 0
}
- return pointerArg(page, 0, npages, data)
+ return pointerArg(typ, page, 0, npages, data)
}
-func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, calls []*Call) {
+func (r *randGen) createResource(s *state, res *sys.ResourceType) (arg *Arg, calls []*Call) {
if r.inCreateResource {
special := res.SpecialValues()
- return constArg(special[r.Intn(len(special))]), nil
+ return constArg(res, special[r.Intn(len(special))]), nil
}
r.inCreateResource = true
defer func() { r.inCreateResource = false }()
@@ -516,7 +512,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call
metas = append(metas, meta)
}
if len(metas) == 0 {
- return constArg(res.Default()), nil
+ return constArg(res, res.Default()), nil
}
// Now we have a set of candidate calls that can create the necessary resource.
@@ -535,7 +531,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call
}
if len(allres) != 0 {
// Bingo!
- arg := resultArg(allres[r.Intn(len(allres))])
+ arg := resultArg(res, allres[r.Intn(len(allres))])
return arg, calls
}
switch meta.Name {
@@ -599,23 +595,25 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call {
}
func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Call) {
- c := &Call{Meta: meta}
- c.Args, calls = r.generateArgs(s, meta.Args, DirIn)
+ c := &Call{
+ Meta: meta,
+ Ret: returnArg(meta.Ret),
+ }
+ c.Args, calls = r.generateArgs(s, meta.Args)
calls = append(calls, c)
for _, c1 := range calls {
- assignTypeAndDir(c1)
sanitizeCall(c1)
}
return calls
}
-func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg, []*Call) {
+func (r *randGen) generateArgs(s *state, types []sys.Type) ([]*Arg, []*Call) {
var calls []*Call
args := make([]*Arg, len(types))
// Generate all args. Size args have the default value 0 for now.
for i, typ := range types {
- arg, calls1 := r.generateArg(s, typ, dir)
+ arg, calls1 := r.generateArg(s, typ)
if arg == nil {
panic(fmt.Sprintf("generated arg is nil for type '%v', types: %+v", typ.Name(), types))
}
@@ -623,36 +621,37 @@ func (r *randGen) generateArgs(s *state, types []sys.Type, dir ArgDir) ([]*Arg,
calls = append(calls, calls1...)
}
- assignSizes(types, args)
+ assignSizes(args)
return args, calls
}
-func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, calls []*Call) {
- if dir == DirOut {
+func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) {
+ if typ.Dir() == sys.DirOut {
// No need to generate something interesting for output scalar arguments.
// But we still need to generate the argument itself so that it can be referenced
// in subsequent calls. For the same reason we do generate pointer/array/struct
// output arguments (their elements can be referenced in subsequent calls).
switch typ.(type) {
- case sys.IntType, sys.FlagsType, sys.ConstType, sys.StrConstType, sys.FileoffType, sys.ResourceType:
- return constArg(0), nil
+ case *sys.IntType, *sys.FlagsType, *sys.ConstType,
+ *sys.ResourceType, *sys.VmaType:
+ return constArg(typ, 0), nil
}
}
if typ.Optional() && r.oneOf(5) {
- if _, ok := typ.(sys.BufferType); ok {
+ if _, ok := typ.(*sys.BufferType); ok {
panic("impossible") // parent PtrType must be Optional instead
}
- return constArg(typ.Default()), nil
+ return constArg(typ, typ.Default()), nil
}
switch a := typ.(type) {
- case sys.ResourceType:
+ case *sys.ResourceType:
r.choose(
1, func() {
special := a.SpecialValues()
- arg = constArg(special[r.Intn(len(special))])
+ arg = constArg(a, special[r.Intn(len(special))])
},
90, func() {
// Get an existing resource.
@@ -664,7 +663,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
}
}
if len(allres) != 0 {
- arg = resultArg(allres[r.Intn(len(allres))])
+ arg = resultArg(a, allres[r.Intn(len(allres))])
} else {
arg, calls = r.createResource(s, a)
}
@@ -675,16 +674,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
},
)
return arg, calls
- case sys.FileoffType:
- // TODO: can do better
- var arg *Arg
- r.choose(
- 90, func() { arg = constArg(0) },
- 10, func() { arg = constArg(r.rand(100)) },
- 1, func() { arg = constArg(r.randInt()) },
- )
- return arg, nil
- case sys.BufferType:
+ case *sys.BufferType:
switch a.Kind {
case sys.BufferBlobRand, sys.BufferBlobRange:
sz := r.randBufLen()
@@ -692,56 +682,38 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
sz = r.randRange(int(a.RangeBegin), int(a.RangeEnd))
}
data := make([]byte, sz)
- if dir != DirOut {
+ if a.Dir() != sys.DirOut {
for i := range data {
data[i] = byte(r.Intn(256))
}
}
- return dataArg(data), nil
+ return dataArg(a, data), nil
case sys.BufferString:
- data := r.randString(s)
- return dataArg(data), nil
- case sys.BufferFilesystem:
- data := r.filesystem(s)
- return dataArg(data), nil
+ data := r.randString(s, a.Values, a.Dir())
+ return dataArg(a, data), nil
+ case sys.BufferFilename:
+ filename := r.filename(s)
+ return dataArg(a, []byte(filename)), nil
case sys.BufferSockaddr:
data := r.sockaddr(s)
- if dir == DirOut {
- for i := range data {
- data[i] = 0
- }
- }
- return dataArg(data), nil
- case sys.BufferAlgType:
- data := r.algType(s)
- if dir == DirOut {
- for i := range data {
- data[i] = 0
- }
- }
- return dataArg(data), nil
- case sys.BufferAlgName:
- data := r.algName(s)
- if dir == DirOut {
+ if a.Dir() == sys.DirOut {
for i := range data {
data[i] = 0
}
}
- return dataArg(data), nil
+ return dataArg(a, data), nil
default:
panic("unknown buffer kind")
}
- case sys.VmaType:
+ case *sys.VmaType:
npages := r.randPageCount()
- arg := r.randPageAddr(s, npages, nil, true)
+ arg := r.randPageAddr(s, a, npages, nil, true)
return arg, nil
- case sys.FlagsType:
- return constArg(r.flags(a.Vals)), nil
- case sys.ConstType:
- return constArg(a.Val), nil
- case sys.StrConstType:
- return dataArg([]byte(a.Val)), nil
- case sys.IntType:
+ case *sys.FlagsType:
+ return constArg(a, r.flags(a.Vals)), nil
+ case *sys.ConstType:
+ return constArg(a, a.Val), nil
+ case *sys.IntType:
v := r.randInt()
switch a.Kind {
case sys.IntSignalno:
@@ -750,14 +722,17 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
v = uintptr(r.inaddr(s))
case sys.IntInport:
v = uintptr(r.inport(s))
+ case sys.IntFileoff:
+ r.choose(
+ 90, func() { v = 0 },
+ 10, func() { v = r.rand(100) },
+ 1, func() { v = r.randInt() },
+ )
case sys.IntRange:
v = r.randRangeInt(a.RangeBegin, a.RangeEnd)
}
- return constArg(v), nil
- case sys.FilenameType:
- filename := r.filename(s)
- return dataArg([]byte(filename)), nil
- case sys.ArrayType:
+ return constArg(a, v), nil
+ case *sys.ArrayType:
count := uintptr(0)
switch a.Kind {
case sys.ArrayRandLen:
@@ -768,28 +743,28 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
var inner []*Arg
var calls []*Call
for i := uintptr(0); i < count; i++ {
- arg1, calls1 := r.generateArg(s, a.Type, dir)
+ arg1, calls1 := r.generateArg(s, a.Type)
inner = append(inner, arg1)
calls = append(calls, calls1...)
}
- return groupArg(inner), calls
+ return groupArg(a, inner), calls
case *sys.StructType:
- if ctor := isSpecialStruct(a); ctor != nil && dir != DirOut {
+ if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != sys.DirOut {
arg, calls = ctor(r, s)
return
}
- args, calls := r.generateArgs(s, a.Fields, dir)
- group := groupArg(args)
+ args, calls := r.generateArgs(s, a.Fields)
+ group := groupArg(a, args)
return group, calls
case *sys.UnionType:
optType := a.Options[r.Intn(len(a.Options))]
- opt, calls := r.generateArg(s, optType, dir)
- return unionArg(opt, optType), calls
- case sys.PtrType:
- inner, calls := r.generateArg(s, a.Type, ArgDir(a.Dir))
- if ArgDir(a.Dir) == DirOut && inner == nil {
+ opt, calls := r.generateArg(s, optType)
+ return unionArg(a, opt, optType), calls
+ case *sys.PtrType:
+ inner, calls := r.generateArg(s, a.Type)
+ if a.Dir() == sys.DirOut && inner == nil {
// No data, but we should have got size.
- arg, calls1 := r.addr(s, inner.Size(a.Type), nil)
+ arg, calls1 := r.addr(s, a, inner.Size(), nil)
calls = append(calls, calls1...)
return arg, calls
}
@@ -798,15 +773,15 @@ func (r *randGen) generateArg(s *state, typ sys.Type, dir ArgDir) (arg *Arg, cal
// So try to reuse a previously used address.
addrs := s.resources["iocbptr"]
addr := addrs[r.Intn(len(addrs))]
- arg = pointerArg(addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner)
+ arg = pointerArg(a, addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner)
return arg, calls
}
- arg, calls1 := r.addr(s, inner.Size(a.Type), inner)
+ arg, calls1 := r.addr(s, a, inner.Size(), inner)
calls = append(calls, calls1...)
return arg, calls
- case sys.LenType:
+ case *sys.LenType:
// Return placeholder value of 0 while generating len args.
- return constArg(0), nil
+ return constArg(a, 0), nil
default:
panic("unknown argument type")
}
diff --git a/prog/size_test.go b/prog/size_test.go
index 41068e713..ad1ba8740 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -16,7 +16,6 @@ func TestAssignSizeRandom(t *testing.T) {
data0 := p.Serialize()
for _, call := range p.Calls {
assignSizesCall(call)
- assignTypeAndDir(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@@ -26,7 +25,6 @@ func TestAssignSizeRandom(t *testing.T) {
data0 := p.Serialize()
for _, call := range p.Calls {
assignSizesCall(call)
- assignTypeAndDir(call)
}
if data1 := p.Serialize(); !bytes.Equal(data0, data1) {
t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1)
@@ -113,7 +111,6 @@ func TestAssignSize(t *testing.T) {
}
for _, call := range p.Calls {
assignSizesCall(call)
- assignTypeAndDir(call)
}
p1 := strings.TrimSpace(string(p.Serialize()))
if p1 != test.sizedProg {
diff --git a/prog/validation.go b/prog/validation.go
index a1b68ba1b..701d0ce3d 100644
--- a/prog/validation.go
+++ b/prog/validation.go
@@ -41,9 +41,6 @@ func (c *Call) validate(ctx *validCtx) error {
if arg == nil {
return fmt.Errorf("syscall %v: nil arg", c.Meta.Name)
}
- if arg.Call != c {
- return fmt.Errorf("syscall %v: arg has wrong call, call=%p, arg=%+v", c.Meta.Name, c, *arg)
- }
if ctx.args[arg] {
return fmt.Errorf("syscall %v: arg is referenced several times in the tree", c.Meta.Name)
}
@@ -55,9 +52,9 @@ func (c *Call) validate(ctx *validCtx) error {
return fmt.Errorf("syscall %v: no type", c.Meta.Name)
}
if arg.Type.Name() != typ.Name() {
- return fmt.Errorf("syscall %v: arg '%v' type mismatch", c.Meta.Name, typ.Name())
+ return fmt.Errorf("syscall %v: type name mismatch: %v vs %v", c.Meta.Name, arg.Type.Name(), typ.Name())
}
- if arg.Dir == DirOut {
+ if arg.Type.Dir() == sys.DirOut {
if arg.Val != 0 || arg.AddrPage != 0 || arg.AddrOffset != 0 {
return fmt.Errorf("syscall %v: output arg '%v' has data", c.Meta.Name, typ.Name())
}
@@ -68,23 +65,17 @@ func (c *Call) validate(ctx *validCtx) error {
}
}
switch arg.Type.(type) {
- case sys.ResourceType:
+ case *sys.ResourceType:
switch arg.Kind {
case ArgResult:
case ArgReturn:
case ArgConst:
- if arg.Dir == DirOut && arg.Val != 0 {
+ if arg.Type.Dir() == sys.DirOut && arg.Val != 0 {
return fmt.Errorf("syscall %v: out resource arg '%v' has bad const value %v", c.Meta.Name, typ.Name(), arg.Val)
}
default:
return fmt.Errorf("syscall %v: fd arg '%v' has bad kind %v", c.Meta.Name, typ.Name(), arg.Kind)
}
- case sys.FilenameType:
- switch arg.Kind {
- case ArgData:
- default:
- return fmt.Errorf("syscall %v: filename arg '%v' has bad kind %v", c.Meta.Name, typ.Name(), arg.Kind)
- }
case *sys.StructType, *sys.ArrayType:
switch arg.Kind {
case ArgGroup:
@@ -105,25 +96,25 @@ func (c *Call) validate(ctx *validCtx) error {
return fmt.Errorf("syscall %v: result arg '%v' has no reference", c.Meta.Name, typ.Name())
}
if !ctx.args[arg.Res] {
- return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %v %p%+v",
- c.Meta.Name, typ.Name(), arg, arg, arg.Res.Call.Meta.Name, arg.Res, arg.Res)
+ return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %p%+v",
+ c.Meta.Name, typ.Name(), arg, arg, arg.Res, arg.Res)
}
if _, ok := arg.Res.Uses[arg]; !ok {
return fmt.Errorf("syscall %v: result arg '%v' has broken link (%+v)", c.Meta.Name, typ.Name(), arg.Res.Uses)
}
case ArgPointer:
- if arg.Dir != DirIn {
- return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name())
- }
switch typ1 := typ.(type) {
- case sys.VmaType:
+ case *sys.VmaType:
if arg.Res != nil {
return fmt.Errorf("syscall %v: vma arg '%v' has data", c.Meta.Name, typ.Name())
}
if arg.AddrPagesNum == 0 {
return fmt.Errorf("syscall %v: vma arg '%v' has size 0", c.Meta.Name, typ.Name())
}
- case sys.PtrType:
+ case *sys.PtrType:
+ if arg.Type.Dir() != sys.DirIn {
+ return fmt.Errorf("syscall %v: pointer arg '%v' has output direction", c.Meta.Name, typ.Name())
+ }
if arg.Res == nil && !typ.Optional() {
return fmt.Errorf("syscall %v: non optional pointer arg '%v' is nil", c.Meta.Name, typ.Name())
}
@@ -151,7 +142,7 @@ func (c *Call) validate(ctx *validCtx) error {
return err
}
}
- case sys.ArrayType:
+ case *sys.ArrayType:
for _, arg1 := range arg.Inner {
if err := checkArg(arg1, typ1.Type); err != nil {
return err
@@ -185,7 +176,7 @@ func (c *Call) validate(ctx *validCtx) error {
return nil
}
for i, arg := range c.Args {
- if c.Ret.Kind != ArgReturn {
+ if arg.Kind == ArgReturn {
return fmt.Errorf("syscall %v: arg '%v' has wrong return kind", c.Meta.Name, arg.Type.Name())
}
if err := checkArg(arg, c.Meta.Args[i]); err != nil {
diff --git a/sys/README.md b/sys/README.md
index 18b3c76ab..8125a7b7c 100644
--- a/sys/README.md
+++ b/sys/README.md
@@ -23,7 +23,7 @@ Pseudo-formal grammar of syscall description:
type = typename [ "[" type-options "]" ]
typename = "const" | "intN" | "intptr" | "flags" | "array" | "ptr" |
"buffer" | "string" | "strconst" | "filename" |
- "fileoff" | "len" | "bytesize" | "vma"
+ "len" | "bytesize" | "vma"
type-options = [type-opt ["," type-opt]]
```
common type-options include:
@@ -44,12 +44,12 @@ rest of the type-options are type-specific:
type of the object; direction (in/out/inout)
"buffer": a pointer to a memory buffer (like read/write buffer argument), type-options:
direction (in/out/inout)
- "string": a pointer to a memory buffer, similar to buffer[in]
- "strconst": a pointer to a constant string, type-options:
- the underlying string (for example "/dev/dsp")
+ "string": a zero-terminated memory buffer (no pointer indirection implied), type-options:
+ either a string value in quotes for constant strings (e.g. "foo"),
+ or a reference to string flags,
+ optionally followed by a buffer size (string values will be padded with \x00 to that size)
"filename": a file/link/dir name
- "fileoff": offset within a file, type-options:
- argname of the file
+ "fileoff": offset within a file
"len": length of another field (for array it is number of elements), type-options:
argname of the object
"bytesize": similar to "len", but always denotes the size in bytes, type-options:
@@ -62,6 +62,10 @@ Flags are described as:
```
flagname = const ["," const]*
```
+or for string flags as:
+```
+ flagname = "\"" literal "\"" ["," "\"" literal "\""]*
+```
### Structs
diff --git a/sys/align.go b/sys/align.go
index 055a433f8..1b1ea66ac 100644
--- a/sys/align.go
+++ b/sys/align.go
@@ -7,9 +7,9 @@ func initAlign() {
var rec func(t Type)
rec = func(t Type) {
switch t1 := t.(type) {
- case PtrType:
+ case *PtrType:
rec(t1.Type)
- case ArrayType:
+ case *ArrayType:
rec(t1.Type)
case *StructType:
if !t1.padded {
@@ -49,10 +49,10 @@ func addAlignment(t *StructType) {
fields = append(fields, makePad(pad))
}
fields = append(fields, f)
- if at, ok := f.(ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
+ if at, ok := f.(*ArrayType); ok && (at.Kind == ArrayRandLen || (at.Kind == ArrayRangeLen && at.RangeBegin != at.RangeEnd)) {
varLen = true
}
- if at, ok := f.(BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
+ if at, ok := f.(*BufferType); ok && (at.Kind == BufferBlobRand || (at.Kind == BufferBlobRange && at.RangeBegin != at.RangeEnd)) {
varLen = true
}
if varLen && i != len(t.Fields)-1 {
@@ -71,7 +71,7 @@ func addAlignment(t *StructType) {
}
func makePad(sz uintptr) Type {
- return ConstType{
+ return &ConstType{
TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
TypeSize: sz,
Val: 0,
diff --git a/sys/bpf.txt b/sys/bpf.txt
index 68b4c0ab9..e7338cc53 100644
--- a/sys/bpf.txt
+++ b/sys/bpf.txt
@@ -52,7 +52,7 @@ bpf_prog {
type flags[bpf_prog_type, int32]
ninsn len[insns, int32]
insns ptr[in, array[bpf_insn]]
- license string
+ license ptr[in, string]
loglev int32
logsize len[log, int32]
log buffer[out]
diff --git a/sys/decl.go b/sys/decl.go
index 89773b0dd..84c2f8c08 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -19,17 +19,25 @@ type Call struct {
Ret Type
}
+type Dir int
+
+const (
+ DirIn Dir = iota
+ DirOut
+ DirInOut
+)
+
type Type interface {
Name() string
+ Dir() Dir
Optional() bool
Default() uintptr
Size() uintptr
Align() uintptr
- InnerType() Type // returns inner type for PtrType
}
func IsPad(t Type) bool {
- if ct, ok := t.(ConstType); ok && ct.IsPad {
+ if ct, ok := t.(*ConstType); ok && ct.IsPad {
return true
}
return false
@@ -37,21 +45,26 @@ func IsPad(t Type) bool {
type TypeCommon struct {
TypeName string
+ ArgDir Dir
IsOptional bool
}
-func (t TypeCommon) Name() string {
+func (t *TypeCommon) Name() string {
return t.TypeName
}
-func (t TypeCommon) Optional() bool {
+func (t *TypeCommon) Optional() bool {
return t.IsOptional
}
-func (t TypeCommon) Default() uintptr {
+func (t *TypeCommon) Default() uintptr {
return 0
}
+func (t TypeCommon) Dir() Dir {
+ return t.ArgDir
+}
+
const (
InvalidFD = ^uintptr(0)
)
@@ -68,55 +81,30 @@ type ResourceType struct {
Desc *ResourceDesc
}
-func (t ResourceType) Default() uintptr {
+func (t *ResourceType) Default() uintptr {
return t.Desc.Values[0]
}
-func (t ResourceType) SpecialValues() []uintptr {
+func (t *ResourceType) SpecialValues() []uintptr {
return t.Desc.Values
}
-func (t ResourceType) Size() uintptr {
+func (t *ResourceType) Size() uintptr {
return t.Desc.Type.Size()
}
-func (t ResourceType) Align() uintptr {
+func (t *ResourceType) Align() uintptr {
return t.Desc.Type.Align()
}
-func (t ResourceType) InnerType() Type {
- return t
-}
-
-type FileoffType struct {
- TypeCommon
- TypeSize uintptr
- BigEndian bool
- File string
-}
-
-func (t FileoffType) Size() uintptr {
- return t.TypeSize
-}
-
-func (t FileoffType) Align() uintptr {
- return t.Size()
-}
-
-func (t FileoffType) InnerType() Type {
- return t
-}
-
type BufferKind int
const (
BufferBlobRand BufferKind = iota
BufferBlobRange
BufferString
+ BufferFilename
BufferSockaddr
- BufferFilesystem
- BufferAlgType
- BufferAlgName
)
type BufferType struct {
@@ -124,48 +112,48 @@ type BufferType struct {
Kind BufferKind
RangeBegin uintptr // for BufferBlobRange kind
RangeEnd uintptr // for BufferBlobRange kind
+ SubKind string
+ Values []string // possible values for BufferString kind
}
-func (t BufferType) Size() uintptr {
+func (t *BufferType) Size() uintptr {
switch t.Kind {
- case BufferAlgType:
- return 14
- case BufferAlgName:
- return 64
+ case BufferString:
+ size := 0
+ for _, s := range t.Values {
+ if size != 0 && size != len(s) {
+ size = 0
+ break
+ }
+ size = len(s)
+ }
+ if size != 0 {
+ return uintptr(size)
+ }
case BufferBlobRange:
if t.RangeBegin == t.RangeEnd {
return t.RangeBegin
}
- fallthrough
- default:
- panic(fmt.Sprintf("buffer size is not statically known: %v", t.Name()))
}
+ panic(fmt.Sprintf("buffer size is not statically known: %v", t.Name()))
}
-func (t BufferType) Align() uintptr {
+func (t *BufferType) Align() uintptr {
return 1
}
-func (t BufferType) InnerType() Type {
- return t
-}
-
type VmaType struct {
TypeCommon
}
-func (t VmaType) Size() uintptr {
+func (t *VmaType) Size() uintptr {
return ptrSize
}
-func (t VmaType) Align() uintptr {
+func (t *VmaType) Align() uintptr {
return t.Size()
}
-func (t VmaType) InnerType() Type {
- return t
-}
-
type LenType struct {
TypeCommon
TypeSize uintptr
@@ -174,18 +162,14 @@ type LenType struct {
Buf string
}
-func (t LenType) Size() uintptr {
+func (t *LenType) Size() uintptr {
return t.TypeSize
}
-func (t LenType) Align() uintptr {
+func (t *LenType) Align() uintptr {
return t.Size()
}
-func (t LenType) InnerType() Type {
- return t
-}
-
type FlagsType struct {
TypeCommon
TypeSize uintptr
@@ -193,18 +177,14 @@ type FlagsType struct {
Vals []uintptr
}
-func (t FlagsType) Size() uintptr {
+func (t *FlagsType) Size() uintptr {
return t.TypeSize
}
-func (t FlagsType) Align() uintptr {
+func (t *FlagsType) Align() uintptr {
return t.Size()
}
-func (t FlagsType) InnerType() Type {
- return t
-}
-
type ConstType struct {
TypeCommon
TypeSize uintptr
@@ -213,36 +193,14 @@ type ConstType struct {
IsPad bool
}
-func (t ConstType) Size() uintptr {
+func (t *ConstType) Size() uintptr {
return t.TypeSize
}
-func (t ConstType) Align() uintptr {
+func (t *ConstType) Align() uintptr {
return t.Size()
}
-func (t ConstType) InnerType() Type {
- return t
-}
-
-type StrConstType struct {
- TypeCommon
- TypeSize uintptr
- Val string
-}
-
-func (t StrConstType) Size() uintptr {
- return uintptr(len(t.Val))
-}
-
-func (t StrConstType) Align() uintptr {
- return 1
-}
-
-func (t StrConstType) InnerType() Type {
- return t
-}
-
type IntKind int
const (
@@ -250,6 +208,7 @@ const (
IntSignalno
IntInaddr
IntInport
+ IntFileoff // offset within a file
IntRange
)
@@ -262,34 +221,14 @@ type IntType struct {
RangeEnd int64
}
-func (t IntType) Size() uintptr {
+func (t *IntType) Size() uintptr {
return t.TypeSize
}
-func (t IntType) Align() uintptr {
+func (t *IntType) Align() uintptr {
return t.Size()
}
-func (t IntType) InnerType() Type {
- return t
-}
-
-type FilenameType struct {
- TypeCommon
-}
-
-func (t FilenameType) Size() uintptr {
- panic("filename size is not statically known")
-}
-
-func (t FilenameType) Align() uintptr {
- return 1
-}
-
-func (t FilenameType) InnerType() Type {
- return t
-}
-
type ArrayKind int
const (
@@ -305,39 +244,30 @@ type ArrayType struct {
RangeEnd uintptr
}
-func (t ArrayType) Size() uintptr {
+func (t *ArrayType) Size() uintptr {
if t.RangeBegin == t.RangeEnd {
return t.RangeBegin * t.Type.Size()
}
return 0 // for trailing embed arrays
}
-func (t ArrayType) Align() uintptr {
+func (t *ArrayType) Align() uintptr {
return t.Type.Align()
}
-func (t ArrayType) InnerType() Type {
- return t
-}
-
type PtrType struct {
TypeCommon
Type Type
- Dir Dir
}
-func (t PtrType) Size() uintptr {
+func (t *PtrType) Size() uintptr {
return ptrSize
}
-func (t PtrType) Align() uintptr {
+func (t *PtrType) Align() uintptr {
return t.Size()
}
-func (t PtrType) InnerType() Type {
- return t.Type.InnerType()
-}
-
type StructType struct {
TypeCommon
Fields []Type
@@ -370,10 +300,6 @@ func (t *StructType) Align() uintptr {
return align
}
-func (t *StructType) InnerType() Type {
- return t
-}
-
type UnionType struct {
TypeCommon
Options []Type
@@ -403,18 +329,6 @@ func (t *UnionType) Align() uintptr {
return align
}
-func (t *UnionType) InnerType() Type {
- return t
-}
-
-type Dir int
-
-const (
- DirIn Dir = iota
- DirOut
- DirInOut
-)
-
var ctors = make(map[string][]*Call)
// ResourceConstructors returns a list of calls that can create a resource of the given kind.
@@ -431,56 +345,20 @@ func initResources() {
func resourceCtors(kind []string, precise bool) []*Call {
// Find calls that produce the necessary resources.
var metas []*Call
- // Recurse into arguments to see if there is an out/inout arg of necessary type.
- seen := make(map[Type]bool)
- var checkArg func(typ Type, dir Dir) bool
- checkArg = func(typ Type, dir Dir) bool {
- if resarg, ok := typ.(ResourceType); ok && dir != DirIn && isCompatibleResource(kind, resarg.Desc.Kind, precise) {
- return true
- }
- switch typ1 := typ.(type) {
- case ArrayType:
- if checkArg(typ1.Type, dir) {
- return true
- }
- case *StructType:
- if seen[typ1] {
- return false // prune recursion via pointers to structs/unions
- }
- seen[typ1] = true
- for _, fld := range typ1.Fields {
- if checkArg(fld, dir) {
- return true
- }
- }
- case *UnionType:
- if seen[typ1] {
- return false // prune recursion via pointers to structs/unions
- }
- seen[typ1] = true
- for _, opt := range typ1.Options {
- if checkArg(opt, dir) {
- return true
- }
- }
- case PtrType:
- if checkArg(typ1.Type, typ1.Dir) {
- return true
- }
- }
- return false
- }
for _, meta := range Calls {
+ // Recurse into arguments to see if there is an out/inout arg of necessary type.
ok := false
- for _, arg := range meta.Args {
- if checkArg(arg, DirIn) {
- ok = true
- break
+ ForeachType(meta, func(typ Type) {
+ if ok {
+ return
}
- }
- if !ok && meta.Ret != nil && checkArg(meta.Ret, DirOut) {
- ok = true
- }
+ switch typ1 := typ.(type) {
+ case *ResourceType:
+ if typ1.Dir() != DirIn && isCompatibleResource(kind, typ1.Desc.Kind, precise) {
+ ok = true
+ }
+ }
+ })
if ok {
metas = append(metas, meta)
}
@@ -524,41 +402,16 @@ func isCompatibleResource(dst, src []string, precise bool) bool {
return true
}
-func (c *Call) InputResources() []ResourceType {
- var resources []ResourceType
- seen := make(map[Type]bool)
- var checkArg func(typ Type, dir Dir)
- checkArg = func(typ Type, dir Dir) {
+func (c *Call) InputResources() []*ResourceType {
+ var resources []*ResourceType
+ ForeachType(c, func(typ Type) {
switch typ1 := typ.(type) {
- case ResourceType:
- if dir != DirOut && !typ1.IsOptional {
+ case *ResourceType:
+ if typ1.Dir() != DirOut && !typ1.IsOptional {
resources = append(resources, typ1)
}
- case ArrayType:
- checkArg(typ1.Type, dir)
- case PtrType:
- checkArg(typ1.Type, typ1.Dir)
- case *StructType:
- if seen[typ1] {
- return // prune recursion via pointers to structs/unions
- }
- seen[typ1] = true
- for _, fld := range typ1.Fields {
- checkArg(fld, dir)
- }
- case *UnionType:
- if seen[typ1] {
- return // prune recursion via pointers to structs/unions
- }
- seen[typ1] = true
- for _, opt := range typ1.Options {
- checkArg(opt, dir)
- }
}
- }
- for _, arg := range c.Args {
- checkArg(arg, DirIn)
- }
+ })
return resources
}
@@ -598,6 +451,46 @@ func TransitivelyEnabledCalls(enabled map[*Call]bool) map[*Call]bool {
return supported
}
+func ForeachType(meta *Call, f func(Type)) {
+ seen := make(map[Type]bool)
+ var rec func(t Type)
+ rec = func(t Type) {
+ f(t)
+ switch a := t.(type) {
+ case *PtrType:
+ rec(a.Type)
+ case *ArrayType:
+ rec(a.Type)
+ case *StructType:
+ if seen[a] {
+ return // prune recursion via pointers to structs/unions
+ }
+ seen[a] = true
+ for _, f := range a.Fields {
+ rec(f)
+ }
+ case *UnionType:
+ if seen[a] {
+ return // prune recursion via pointers to structs/unions
+ }
+ seen[a] = true
+ for _, opt := range a.Options {
+ rec(opt)
+ }
+ case *ResourceType, *BufferType, *VmaType, *LenType,
+ *FlagsType, *ConstType, *IntType:
+ default:
+ panic("unknown type")
+ }
+ }
+ for _, t := range meta.Args {
+ rec(t)
+ }
+ if meta.Ret != nil {
+ rec(meta.Ret)
+ }
+}
+
var (
Calls []*Call
CallCount int
diff --git a/sys/dri.txt b/sys/dri.txt
index 3c5753f23..bc35016e4 100644
--- a/sys/dri.txt
+++ b/sys/dri.txt
@@ -10,9 +10,9 @@ resource drm_agp_handle[intptr]
resource drm_gem_handle[int32]
resource drm_gem_name[int32]
-syz_open_dev$dri(dev strconst["/dev/dri/card#"], id intptr, flags flags[open_flags]) fd_dri
-syz_open_dev$dricontrol(dev strconst["/dev/dri/controlD#"], id intptr, flags flags[open_flags]) fd_dri
-syz_open_dev$drirender(dev strconst["/dev/dri/renderD#"], id intptr, flags flags[open_flags]) fd_dri
+syz_open_dev$dri(dev ptr[in, string["/dev/dri/card#"]], id intptr, flags flags[open_flags]) fd_dri
+syz_open_dev$dricontrol(dev ptr[in, string["/dev/dri/controlD#"]], id intptr, flags flags[open_flags]) fd_dri
+syz_open_dev$drirender(dev ptr[in, string["/dev/dri/renderD#"]], id intptr, flags flags[open_flags]) fd_dri
ioctl$DRM_IOCTL_VERSION(fd fd_dri, cmd const[DRM_IOCTL_VERSION], arg ptr[in, drm_version])
ioctl$DRM_IOCTL_GET_UNIQUE(fd fd_dri, cmd const[DRM_IOCTL_GET_UNIQUE], arg ptr[in, drm_unique_out])
diff --git a/sys/input.txt b/sys/input.txt
index 236d6c89c..4266c2b2b 100644
--- a/sys/input.txt
+++ b/sys/input.txt
@@ -6,10 +6,10 @@ include <linux/input.h>
resource fd_evdev[fd]
# There seems to be nothing special we can do with this fd.
-syz_open_dev$mouse(dev strconst["/dev/input/mouse#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$mice(dev strconst["/dev/input/mice"], id const[0], flags flags[open_flags]) fd
+syz_open_dev$mouse(dev ptr[in, string["/dev/input/mouse#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$mice(dev ptr[in, string["/dev/input/mice"]], id const[0], flags flags[open_flags]) fd
-syz_open_dev$evdev(dev strconst["/dev/input/event#"], id intptr, flags flags[open_flags]) fd_evdev
+syz_open_dev$evdev(dev ptr[in, string["/dev/input/event#"]], id intptr, flags flags[open_flags]) fd_evdev
write$evdev(fd fd_evdev, data ptr[in, array[input_event]], len bytesize[data])
diff --git a/sys/kdbus.txt b/sys/kdbus.txt
index 5d40b8625..97bd49e70 100644
--- a/sys/kdbus.txt
+++ b/sys/kdbus.txt
@@ -6,7 +6,7 @@ include <uapi/linux/fcntl.h>
resource fd_kdbus[fd]
-openat$kdbus(fd const[AT_FDCWD], file strconst["/dev/kdbus"], flags flags[open_flags], mode const[0]) fd_kdbus
+openat$kdbus(fd const[AT_FDCWD], file ptr[in, string["/dev/kdbus"]], flags flags[open_flags], mode const[0]) fd_kdbus
ioctl$kdbus_bus_make(fd fd_kdbus, cmd const[KDBUS_CMD_BUS_MAKE], arg ptr[in, kdbus_cmd_bus_make])
ioctl$kdbus_ep_make(fd fd_kdbus, cmd const[KDBUS_CMD_ENDPOINT_MAKE], arg ptr[in, kdbus_cmd_ep_make])
ioctl$kdbus_ep_update(fd fd_kdbus, cmd const[KDBUS_CMD_ENDPOINT_UPDATE], arg ptr[in, kdbus_cmd_ep_update])
diff --git a/sys/key.txt b/sys/key.txt
index 6c431682c..c0b18f5e8 100644
--- a/sys/key.txt
+++ b/sys/key.txt
@@ -6,17 +6,17 @@ include <uapi/linux/keyctl.h>
resource key[int32]: KEY_SPEC_THREAD_KEYRING, KEY_SPEC_PROCESS_KEYRING, KEY_SPEC_SESSION_KEYRING, KEY_SPEC_USER_KEYRING, KEY_SPEC_USER_SESSION_KEYRING, KEY_SPEC_GROUP_KEYRING, KEY_SPEC_REQKEY_AUTH_KEY, KEY_SPEC_REQUESTOR_KEYRING
-add_key(type string, desc string, payload buffer[in, opt], paylen len[payload], keyring flags[keyring_type]) key
-request_key(type string, desc string, callout string, keyring flags[keyring_type]) key
+add_key(type ptr[in, string], desc ptr[in, string], payload buffer[in, opt], paylen len[payload], keyring flags[keyring_type]) key
+request_key(type ptr[in, string], desc ptr[in, string], callout ptr[in, string], keyring flags[keyring_type]) key
keyctl$get_keyring_id(code const[KEYCTL_GET_KEYRING_ID], key key, create intptr)
-keyctl$join(code const[KEYCTL_JOIN_SESSION_KEYRING], session string)
+keyctl$join(code const[KEYCTL_JOIN_SESSION_KEYRING], session ptr[in, string])
keyctl$update(code const[KEYCTL_UPDATE], key key, payload buffer[in, opt], paylen len[payload])
keyctl$revoke(code const[KEYCTL_REVOKE], key key)
keyctl$describe(code const[KEYCTL_DESCRIBE], key key, desc buffer[out], len len[desc])
keyctl$clear(code const[KEYCTL_CLEAR], key key)
keyctl$link(code const[KEYCTL_LINK], key1 key, key2 key)
keyctl$unlink(code const[KEYCTL_UNLINK], key1 key, key2 key)
-keyctl$search(code const[KEYCTL_SEARCH], key key, type string, desc string, ring key)
+keyctl$search(code const[KEYCTL_SEARCH], key key, type ptr[in, string], desc ptr[in, string], ring key)
keyctl$read(code const[KEYCTL_READ], key key, payload buffer[out], len len[payload])
keyctl$chown(code const[KEYCTL_CHOWN], key key, uid uid, gid gid)
# perm is a mask of KEY_POS_VIEW, etc consants, but they cover almost whole int32.
diff --git a/sys/kvm.txt b/sys/kvm.txt
index b80f4ce72..96e73d74e 100644
--- a/sys/kvm.txt
+++ b/sys/kvm.txt
@@ -9,7 +9,7 @@ resource fd_kvm[fd]
resource fd_kvmvm[fd]
resource fd_kvmcpu[fd]
-syz_open_dev$kvm(dev strconst["/dev/kvm"], id const[0], flags flags[open_flags]) fd_kvm
+syz_open_dev$kvm(dev ptr[in, string["/dev/kvm"]], id const[0], flags flags[open_flags]) fd_kvm
ioctl$KVM_CREATE_VM(fd fd_kvm, cmd const[KVM_CREATE_VM], type const[0]) fd_kvmvm
ioctl$KVM_GET_MSR_INDEX_LIST(fd fd_kvm, cmd const[KVM_GET_MSR_INDEX_LIST], arg ptr[in, kvm_msr_list])
@@ -99,7 +99,7 @@ ioctl$KVM_SET_GUEST_DEBUG(fd fd_kvmcpu, cmd const[KVM_SET_GUEST_DEBUG], arg ptr[
ioctl$KVM_SMI(fd fd_kvmcpu, cmd const[KVM_SMI])
# TODO: extend support (there are some ioctls)
-openat$xenevtchn(fd const[AT_FDCWD], file strconst["/dev/xen/evtchn"], flags flags[open_flags], mode const[0]) fd
+openat$xenevtchn(fd const[AT_FDCWD], file ptr[in, string["/dev/xen/evtchn"]], flags flags[open_flags], mode const[0]) fd
kvm_mem_region_flags = KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_READONLY, KVM_MEMSLOT_INVALID, KVM_MEMSLOT_INCOHERENT
kvm_mp_state = KVM_MP_STATE_RUNNABLE, KVM_MP_STATE_UNINITIALIZED, KVM_MP_STATE_INIT_RECEIVED, KVM_MP_STATE_HALTED, KVM_MP_STATE_SIPI_RECEIVED, KVM_MP_STATE_STOPPED, KVM_MP_STATE_CHECK_STOP, KVM_MP_STATE_OPERATING, KVM_MP_STATE_LOAD
diff --git a/sys/perf.txt b/sys/perf.txt
index a860d75c8..e35ad22b9 100644
--- a/sys/perf.txt
+++ b/sys/perf.txt
@@ -15,7 +15,7 @@ ioctl$PERF_EVENT_IOC_REFRESH(fd fd_perf, cmd const[PERF_EVENT_IOC_REFRESH], refr
ioctl$PERF_EVENT_IOC_PERIOD(fd fd_perf, cmd const[PERF_EVENT_IOC_PERIOD], period ptr[in, int64])
ioctl$PERF_EVENT_IOC_ID(fd fd_perf, cmd const[PERF_EVENT_IOC_ID], id ptr[out, int64])
ioctl$PERF_EVENT_IOC_SET_OUTPUT(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_OUTPUT], other fd_perf)
-ioctl$PERF_EVENT_IOC_SET_FILTER(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_FILTER], filter string)
+ioctl$PERF_EVENT_IOC_SET_FILTER(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_FILTER], filter ptr[in, string])
ioctl$PERF_EVENT_IOC_SET_BPF(fd fd_perf, cmd const[PERF_EVENT_IOC_SET_BPF], prog fd_bpf_prog)
perf_flags = PERF_FLAG_FD_NO_GROUP, PERF_FLAG_FD_OUTPUT, PERF_FLAG_PID_CGROUP, PERF_FLAG_FD_CLOEXEC
diff --git a/sys/random.txt b/sys/random.txt
index 7c8fd11c0..234d1be40 100755
--- a/sys/random.txt
+++ b/sys/random.txt
@@ -5,8 +5,8 @@ include <linux/random.h>
resource fd_random[fd]
-syz_open_dev$random(dev strconst["/dev/random"], id const[0], flags flags[open_flags]) fd_random
-syz_open_dev$urandom(dev strconst["/dev/urandom"], id const[0], flags flags[open_flags]) fd_random
+syz_open_dev$random(dev ptr[in, string["/dev/random"]], id const[0], flags flags[open_flags]) fd_random
+syz_open_dev$urandom(dev ptr[in, string["/dev/urandom"]], id const[0], flags flags[open_flags]) fd_random
ioctl$RNDGETENTCNT(fd fd_random, cmd const[RNDGETENTCNT], arg ptr[out, int32])
ioctl$RNDADDTOENTCNT(fd fd_random, cmd const[RNDADDTOENTCNT], arg ptr[in, int32])
diff --git a/sys/sndcontrol.txt b/sys/sndcontrol.txt
index 20d5cc320..1ec602f03 100644
--- a/sys/sndcontrol.txt
+++ b/sys/sndcontrol.txt
@@ -5,7 +5,7 @@ include <sound/asound.h>
resource fd_sndctrl[fd]
-syz_open_dev$sndctrl(dev strconst["/dev/snd/controlC#"], id intptr, flags flags[open_flags]) fd_sndctrl
+syz_open_dev$sndctrl(dev ptr[in, string["/dev/snd/controlC#"]], id intptr, flags flags[open_flags]) fd_sndctrl
ioctl$SNDRV_CTL_IOCTL_PVERSION(fd fd_sndctrl, cmd const[SNDRV_CTL_IOCTL_PVERSION], arg buffer[out])
ioctl$SNDRV_CTL_IOCTL_CARD_INFO(fd fd_sndctrl, cmd const[SNDRV_CTL_IOCTL_CARD_INFO], arg buffer[out])
@@ -61,7 +61,7 @@ snd_ctl_elem_info {
items int32
item int32
name array[int8, 64]
- nameptr string
+ nameptr ptr[in, string]
namelen len[nameptr, int32]
pad1 array[const[0, int8], 44]
d array[int16, 4]
diff --git a/sys/sndseq.txt b/sys/sndseq.txt
index 62a844ed7..40ad7118d 100644
--- a/sys/sndseq.txt
+++ b/sys/sndseq.txt
@@ -6,7 +6,7 @@ include <sound/asequencer.h>
resource fd_sndseq[fd]
-syz_open_dev$sndseq(dev strconst["/dev/snd/seq"], id const[0], flags flags[open_flags]) fd_sndseq
+syz_open_dev$sndseq(dev ptr[in, string["/dev/snd/seq"]], id const[0], flags flags[open_flags]) fd_sndseq
write$sndseq(fd fd_sndseq, data ptr[in, array[snd_seq_event]], len bytesize[data])
ioctl$SNDRV_SEQ_IOCTL_PVERSION(fd fd_sndseq, cmd const[SNDRV_SEQ_IOCTL_PVERSION], arg ptr[out, int32])
diff --git a/sys/sndtimer.txt b/sys/sndtimer.txt
index 67e0a13a8..f7eebc2af 100644
--- a/sys/sndtimer.txt
+++ b/sys/sndtimer.txt
@@ -5,7 +5,7 @@ include <sound/asound.h>
resource fd_sndtimer[fd]
-syz_open_dev$sndtimer(dev strconst["/dev/snd/timer"], id const[0], flags flags[open_flags]) fd_sndtimer
+syz_open_dev$sndtimer(dev ptr[in, string["/dev/snd/timer"]], id const[0], flags flags[open_flags]) fd_sndtimer
ioctl$SNDRV_TIMER_IOCTL_PVERSION(fd fd_sndtimer, cmd const[SNDRV_TIMER_IOCTL_PVERSION], arg ptr[out, int32])
ioctl$SNDRV_TIMER_IOCTL_NEXT_DEVICE(fd fd_sndtimer, cmd const[SNDRV_TIMER_IOCTL_NEXT_DEVICE], arg ptr[in, snd_timer_id])
diff --git a/sys/socket.txt b/sys/socket.txt
index b2db95849..74728194f 100644
--- a/sys/socket.txt
+++ b/sys/socket.txt
@@ -46,7 +46,7 @@ ioctl$SIOCINQ(fd sock, cmd const[SIOCINQ], arg ptr[out, int32])
setsockopt$sock_void(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_void], optval const[0], optlen const[0])
getsockopt$sock_int(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_int], optval ptr[out, int32], optlen ptr[inout, len[optval, int32]])
setsockopt$sock_int(fd sock, level const[SOL_SOCKET], optname flags[sockopt_opt_sock_int], optval ptr[in, int32], optlen len[optval])
-setsockopt$sock_str(fd sock, level const[SOL_SOCKET], optname const[SO_BINDTODEVICE], optval string, optlen len[optval])
+setsockopt$sock_str(fd sock, level const[SOL_SOCKET], optname const[SO_BINDTODEVICE], optval ptr[in, string], optlen len[optval])
getsockopt$sock_linger(fd sock, level const[SOL_SOCKET], optname const[SO_LINGER], optval ptr[out, linger], optlen ptr[inout, len[optval, int32]])
setsockopt$sock_linger(fd sock, level const[SOL_SOCKET], optname const[SO_LINGER], optval ptr[in, linger], optlen len[optval])
getsockopt$sock_cred(fd sock, level const[SOL_SOCKET], optname const[SO_PEERCRED], optval ptr[out, ucred], optlen ptr[inout, len[optval, int32]])
@@ -273,10 +273,10 @@ sendmmsg$alg(fd sock_algconn, mmsg ptr[in, array[msghdr_alg]], vlen len[mmsg], f
sockaddr_alg {
family const[AF_ALG, int16]
- type salg_type
+ type string[salg_type, 14]
feat flags[af_alg_type, int32]
mask flags[af_alg_type, int32]
- name salg_name
+ name string[salg_name, 64]
}
msghdr_alg {
@@ -320,6 +320,9 @@ cmsghdr_alg_assoc {
af_alg_type = CRYPTO_ALG_TYPE_MASK, CRYPTO_ALG_TYPE_CIPHER, CRYPTO_ALG_TYPE_COMPRESS, CRYPTO_ALG_TYPE_AEAD, CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_ABLKCIPHER, CRYPTO_ALG_TYPE_GIVCIPHER, CRYPTO_ALG_TYPE_DIGEST, CRYPTO_ALG_TYPE_HASH, CRYPTO_ALG_TYPE_SHASH, CRYPTO_ALG_TYPE_AHASH, CRYPTO_ALG_TYPE_RNG, CRYPTO_ALG_TYPE_AKCIPHER, CRYPTO_ALG_TYPE_PCOMPRESS, CRYPTO_ALG_LARVAL, CRYPTO_ALG_DEAD, CRYPTO_ALG_DYING, CRYPTO_ALG_ASYNC, CRYPTO_ALG_NEED_FALLBACK, CRYPTO_ALG_GENIV, CRYPTO_ALG_TESTED, CRYPTO_ALG_INSTANCE, CRYPTO_ALG_KERN_DRIVER_ONLY, CRYPTO_ALG_INTERNAL
+salg_type = "aead", "hash", "rng", "skcipher"
+salg_name = "cmac(aes)", "ecb(aes)", "cbc(aes)", "hmac(sha1)", "pcbc(fcrypt)", "ghash", "jitterentropy_rng", "stdrng", "stdrng", "stdrng", "stdrng", "hmac(sha256)", "stdrng", "stdrng", "stdrng", "stdrng", "stdrng", "842", "lz4hc", "lz4", "lzo", "crct10dif", "crc32", "crc32c", "michael_mic", "zlib", "deflate", "poly1305", "chacha20", "salsa20", "seed", "anubis", "khazad", "xeta", "xtea", "tea", "ecb(arc4)", "arc4", "cast6", "cast5", "camellia", "aes", "tnepres", "serpent", "twofish", "blowfish", "fcrypt", "des3_ede", "des", "tgr128", "tgr160", "tgr192", "wp256", "wp384", "wp512", "sha384", "sha512", "sha224", "sha256", "sha1", "rmd320", "rmd256", "rmd160", "rmd128", "md5", "md4", "digest_null", "compress_null", "ecb(cipher_null)", "cipher_null", "rsa", "poly1305", "xts(serpent)", "lrw(serpent)", "ctr(serpent)", "cbc(serpent)", "__ecb-serpent-sse2", "ecb(serpent)", "__xts-serpent-sse2", "__lrw-serpent-sse2", "__ctr-serpent-sse2", "__cbc-serpent-sse2", "__ecb-serpent-sse2", "salsa20", "xts(twofish)", "lrw(twofish)", "ctr(twofish)", "cbc(twofish)", "ecb(twofish)", "twofish", "ctr(blowfish)", "cbc(blowfish)", "ecb(blowfish)", "blowfish", "xts(camellia)", "lrw(camellia)", "ctr(camellia)", "cbc(camellia)", "ecb(camellia)", "camellia", "ctr(des3_ede)", "cbc(des3_ede)", "ecb(des3_ede)", "des3_ede", "aes"
+
diff --git a/sys/sys.txt b/sys/sys.txt
index be0d10860..c6da9a800 100644
--- a/sys/sys.txt
+++ b/sys/sys.txt
@@ -79,14 +79,14 @@ openat(fd fd_dir, file filename, flags flags[open_flags], mode flags[open_mode])
creat(file filename, mode flags[open_mode]) fd
close(fd fd)
read(fd fd, buf buffer[out], count len[buf]) len[buf]
-pread64(fd fd, buf buffer[out], count len[buf], pos fileoff[fd])
+pread64(fd fd, buf buffer[out], count len[buf], pos fileoff)
readv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec])
-preadv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec], off fileoff[fd])
+preadv(fd fd, vec ptr[in, array[iovec_out]], vlen len[vec], off fileoff)
write(fd fd, buf buffer[in], count len[buf]) len[buf]
-pwrite64(fd fd, buf buffer[in], count len[buf], pos fileoff[fd])
+pwrite64(fd fd, buf buffer[in], count len[buf], pos fileoff)
writev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec])
-pwritev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], off fileoff[fd])
-lseek(fd fd, offset fileoff[fd], whence flags[seek_whence])
+pwritev(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], off fileoff)
+lseek(fd fd, offset fileoff, whence flags[seek_whence])
dup(oldfd fd) fd
dup2(oldfd fd, newfd fd) fd
@@ -96,9 +96,9 @@ pipe(pipefd ptr[out, pipefd])
pipe2(pipefd ptr[out, pipefd], flags flags[pipe_flags])
tee(fdin fd, fdout fd, len int64, f flags[splice_flags])
-splice(fdin fd, offin fileoff[fdin], fdout fd, offout fileoff[fdout], len int64, f flags[splice_flags])
+splice(fdin fd, offin fileoff, fdout fd, offout fileoff, len int64, f flags[splice_flags])
vmsplice(fd fd, vec ptr[in, array[iovec_in]], vlen len[vec], f flags[splice_flags])
-sendfile(fdout fd, fdin fd, off ptr[inout, fileoff[fdin, int64], opt], count int64)
+sendfile(fdout fd, fdin fd, off ptr[inout, fileoff[int64], opt], count int64)
stat(file filename, statbuf ptr[out, stat])
lstat(file filename, statbuf ptr[out, stat])
@@ -136,14 +136,14 @@ ioctl$UFFDIO_WAKE(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range])
ioctl$UFFDIO_COPY(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range])
ioctl$UFFDIO_ZEROPAGE(fd fd_uffd, cmd const[UFFDIO_WAKE], arg ptr[in, uffdio_range])
-mmap(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd, offset fileoff[fd]) vma
+mmap(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd, offset fileoff) vma
munmap(addr vma, len len[addr])
mremap(addr vma, len len[addr], newlen len[newaddr], flags flags[mremap_flags], newaddr vma) vma
remap_file_pages(addr vma, size len[addr], prot flags[mmap_prot], pgoff intptr, flags flags[mmap_flags])
mprotect(addr vma, len len[addr], prot flags[mmap_prot])
msync(addr vma, len len[addr], f flags[msync_flags])
madvise(addr vma, len len[addr], advice flags[madvise_flags])
-fadvise64(fd fd, offset fileoff[fd], len intptr, advice flags[fadvise_flags])
+fadvise64(fd fd, offset fileoff, len intptr, advice flags[fadvise_flags])
readahead(fd fd, off intptr, count intptr)
mbind(addr vma, len len[addr], mode flags[mbind_mode], nodemask ptr[in, int64], maxnode intptr, flags flags[mbind_flags])
move_pages(pid pid, nr len[pages], pages ptr[in, array[vma]], nodes ptr[in, array[int32], opt], status ptr[out, array[int32]], flags flags[move_pages_flags])
@@ -156,7 +156,7 @@ mlock2(addr vma, size len[addr], flags flags[mlock_flags])
munlock(addr vma, size len[addr])
mlockall(flags flags[mlockall_flags])
munlockall()
-memfd_create(name string, flags flags[memfd_flags]) fd
+memfd_create(name ptr[in, string], flags flags[memfd_flags]) fd
unshare(flags flags[clone_flags])
kcmp(pid1 pid, pid2 pid, type flags[kcmp_flags], fd1 fd, fd2 fd)
@@ -220,7 +220,7 @@ prctl$intptr(option flags[prctl_code_intptr], arg intptr)
prctl$getreaper(option flags[prctl_code_getreaper], arg ptr[out, intptr])
prctl$setendian(option const[PR_SET_ENDIAN], arg flags[prctl_endian])
prctl$setfpexc(option const[PR_SET_FPEXC], arg flags[prctl_fpexc])
-prctl$setname(option const[PR_SET_NAME], name string)
+prctl$setname(option const[PR_SET_NAME], name ptr[in, string])
prctl$getname(option const[PR_GET_NAME], name buffer[out])
prctl$setptracer(option const[PR_SET_PTRACER], pid pid)
prctl$seccomp(option const[PR_SET_SECCOMP], mode flags[prctl_seccomp_mode], prog ptr[in, sock_fprog])
@@ -230,12 +230,12 @@ arch_prctl(code flags[arch_prctl_code], addr buffer[in])
seccomp(op flags[seccomp_op], flags flags[seccomp_flags], prog ptr[in, sock_fprog])
resource fd_mq[fd]
-mq_open(name string, flags flags[mq_open_flags], mode flags[open_mode], attr ptr[in, mq_attr]) fd_mq
+mq_open(name ptr[in, string], flags flags[mq_open_flags], mode flags[open_mode], attr ptr[in, mq_attr]) fd_mq
mq_timedsend(mqd fd_mq, msg buffer[in], msglen len[msg], prio intptr, timeout ptr[in, timespec, opt])
mq_timedreceive(mqd fd_mq, msg buffer[out], msglen len[msg], prio intptr, timeout ptr[in, timespec, opt])
mq_notify(mqd fd_mq, notif ptr[in, sigevent])
mq_getsetattr(mqd fd_mq, attr ptr[in, mq_attr], oldattr ptr[out, mq_attr, opt])
-mq_unlink(name string)
+mq_unlink(name ptr[in, string])
resource ipc[int32]: 0, 0xffffffffffffffff
resource ipc_msq[ipc]
@@ -345,21 +345,23 @@ getdents64(fd fd_dir, ent buffer[out], count len[ent])
name_to_handle_at(fd fd_dir, file filename, handle ptr[in, file_handle], mnt ptr[out, int32], flags flags[name_to_handle_at_flags])
open_by_handle_at(mountdirfd fd, handle ptr[in, file_handle], flags flags[open_flags])
-mount(src filename, dst filename, type filesystem, flags flags[mount_flags], data buffer[in])
-mount$fs(src filesystem, dst filename, type filesystem, flags flags[mount_flags], data buffer[in])
+mount(src filename, dst filename, type ptr[in, string[filesystem]], flags flags[mount_flags], data buffer[in])
+mount$fs(src ptr[in, string[filesystem]], dst filename, type ptr[in, string[filesystem]], flags flags[mount_flags], data buffer[in])
umount2(path filename, flags flags[umount_flags])
pivot_root(new_root filename, put_old filename)
-sysfs$1(option flags[sysfs_opt1], fsname string)
-sysfs$2(option flags[sysfs_opt2], fsindex intptr, fsname buffer[out])
-sysfs$3(option flags[sysfs_opt3])
+filesystem = "sysfs", "rootfs", "ramfs", "tmpfs", "devtmpfs", "debugfs", "securityfs", "sockfs", "pipefs", "anon_inodefs", "devpts", "ext3", "ext2", "ext4", "hugetlbfs", "vfat", "ecryptfs", "kdbusfs", "fuseblk", "fuse", "rpc_pipefs", "nfs", "nfs4", "nfsd", "binfmt_misc", "autofs", "xfs", "jfs", "msdos", "ntfs", "minix", "hfs", "hfsplus", "qnx4", "ufs", "btrfs", "configfs", "ncpfs", "qnx6", "exofs", "befs", "vxfs", "gfs2", "gfs2meta", "fusectl", "bfs", "nsfs", "efs", "cifs", "efivarfs", "affs", "tracefs", "bdev", "ocfs2", "ocfs2_dlmfs", "hpfs", "proc", "afs", "reiserfs", "jffs2", "romfs", "aio", "sysv", "v7", "udf", "ceph", "pstore", "adfs", "9p", "hostfs", "squashfs", "cramfs", "iso9660", "coda", "nilfs2", "logfs", "overlay", "f2fs", "omfs", "ubifs", "openpromfs"
+
+sysfs$1(option const[1], fsname ptr[in, string])
+sysfs$2(option const[2], fsindex intptr, fsname buffer[out])
+sysfs$3(option const[3])
statfs(path filename, buf buffer[out])
fstatfs(fd fd, buf buffer[out])
uselib(lib filename)
-init_module(mod string, len len[mod], args string)
-finit_module(fd fd, args string, flags flags[finit_module_flags])
-delete_module(name string, flags flags[delete_module_flags])
+init_module(mod ptr[in, string], len len[mod], args ptr[in, string])
+finit_module(fd fd, args ptr[in, string], flags flags[finit_module_flags])
+delete_module(name ptr[in, string], flags flags[delete_module_flags])
kexec_load(entry intptr, nr_segments len[segments], segments ptr[in, array[kexec_segment]], flags flags[kexec_load_flags])
get_kernel_syms(table buffer[out])
syslog(cmd flags[syslog_cmd], buf buffer[out, opt], len len[buf])
@@ -381,18 +383,18 @@ ioprio_set$pid(which flags[ioprio_which_pid], who pid, prio intptr)
ioprio_set$uid(which flags[ioprio_which_uid], who uid, prio intptr)
setns(fd fd, type flags[ns_type])
-setxattr(path filename, name string, val string, size len[val], flags flags[setxattr_flags])
-lsetxattr(path filename, name string, val string, size len[val], flags flags[setxattr_flags])
-fsetxattr(fd fd, name string, val string, size len[val], flags flags[setxattr_flags])
-getxattr(path filename, name string, val buffer[out], size len[val])
-lgetxattr(path filename, name string, val buffer[out], size len[val])
-fgetxattr(fd fd, name string, val buffer[out], size len[val])
+setxattr(path filename, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags])
+lsetxattr(path filename, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags])
+fsetxattr(fd fd, name ptr[in, string], val ptr[in, string], size len[val], flags flags[setxattr_flags])
+getxattr(path filename, name ptr[in, string], val buffer[out], size len[val])
+lgetxattr(path filename, name ptr[in, string], val buffer[out], size len[val])
+fgetxattr(fd fd, name ptr[in, string], val buffer[out], size len[val])
listxattr(path filename, list buffer[out], size len[list])
llistxattr(path filename, list buffer[out], size len[list])
flistxattr(fd fd, list buffer[out], size len[list])
-removexattr(path filename, name string)
-lremovexattr(path filename, name string)
-fremovexattr(fd fd, name string)
+removexattr(path filename, name ptr[in, string])
+lremovexattr(path filename, name ptr[in, string])
+fremovexattr(fd fd, name ptr[in, string])
resource timerid[int32]
timer_create(id flags[clock_id], ev ptr[in, sigevent], timerid ptr[out, timerid])
@@ -463,55 +465,55 @@ membarrier(cmd const[1], flags const[0])
# These devices are relatively safe (don't reboot and don't corrupt kernel memory).
# They need a more comprehensive support. But let at least open them for now,
# maybe fuzzer will be able to skrew them in a useful way.
-syz_open_dev$floppy(dev strconst["/dev/fd#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$pktcdvd(dev strconst["/dev/pktcdvd/control"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$lightnvm(dev strconst["/dev/lightnvm/control"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$vcs(dev strconst["/dev/vcs"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$vcsn(dev strconst["/dev/vcs#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$vcsa(dev strconst["/dev/vcsa#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$vga_arbiter(dev strconst["/dev/vga_arbiter"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$vhci(dev strconst["/dev/vhci"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$userio(dev strconst["/dev/userio"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$rtc(dev strconst["/dev/rtc"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$rfkill(dev strconst["/dev/rfkill"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$qat_adf_ctl(dev strconst["/dev/qat_adf_ctl"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$ppp(dev strconst["/dev/ppp"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$mixer(dev strconst["/dev/mixer"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$irnet(dev strconst["/dev/irnet"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$hwrng(dev strconst["/dev/hwrng"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$hpet(dev strconst["/dev/hpet"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$hidraw0(dev strconst["/dev/hidraw0"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$fb0(dev strconst["/dev/fb0"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$cuse(dev strconst["/dev/cuse"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$console(dev strconst["/dev/console"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$capi20(dev strconst["/dev/capi20"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$autofs(dev strconst["/dev/autofs"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$binder(dev strconst["/dev/binder"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$ion(dev strconst["/dev/ion"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$keychord(dev strconst["/dev/keychord"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$zygote(dev strconst["/dev/socket/zygote"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$sw_sync(dev strconst["/dev/sw_sync"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$sr(dev strconst["/dev/sr0"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$sequencer(dev strconst["/dev/sequencer"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$sequencer2(dev strconst["/dev/sequencer2"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$dsp(dev strconst["/dev/dsp"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$audio(dev strconst["/dev/audio"], id const[0], flags flags[open_flags]) fd
-syz_open_dev$usbmon(dev strconst["/dev/usbmon#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$sg(dev strconst["/dev/sg#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$midi(dev strconst["/dev/midi#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$loop(dev strconst["/dev/loop#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$ircomm(dev strconst["/dev/ircomm#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$dspn(dev strconst["/dev/dsp#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$dmmidi(dev strconst["/dev/dmmidi#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$admmidi(dev strconst["/dev/admmidi#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$adsp(dev strconst["/dev/adsp#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$amidi(dev strconst["/dev/amidi#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$audion(dev strconst["/dev/audio#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$usb(dev strconst["/dev/bus/usb/00#/00#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$sndhw(dev strconst["/dev/snd/hwC#D#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$sndmidi(dev strconst["/dev/snd/midiC#D#"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$sndpcmc(dev strconst["/dev/snd/pcmC#D#c"], id intptr, flags flags[open_flags]) fd
-syz_open_dev$sndpcmp(dev strconst["/dev/snd/pcmC#D#p"], id intptr, flags flags[open_flags]) fd
+syz_open_dev$floppy(dev ptr[in, string["/dev/fd#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$pktcdvd(dev ptr[in, string["/dev/pktcdvd/control"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$lightnvm(dev ptr[in, string["/dev/lightnvm/control"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$vcs(dev ptr[in, string["/dev/vcs"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$vcsn(dev ptr[in, string["/dev/vcs#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$vcsa(dev ptr[in, string["/dev/vcsa#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$vga_arbiter(dev ptr[in, string["/dev/vga_arbiter"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$vhci(dev ptr[in, string["/dev/vhci"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$userio(dev ptr[in, string["/dev/userio"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$rtc(dev ptr[in, string["/dev/rtc"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$rfkill(dev ptr[in, string["/dev/rfkill"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$qat_adf_ctl(dev ptr[in, string["/dev/qat_adf_ctl"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$ppp(dev ptr[in, string["/dev/ppp"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$mixer(dev ptr[in, string["/dev/mixer"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$irnet(dev ptr[in, string["/dev/irnet"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$hwrng(dev ptr[in, string["/dev/hwrng"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$hpet(dev ptr[in, string["/dev/hpet"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$hidraw0(dev ptr[in, string["/dev/hidraw0"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$fb0(dev ptr[in, string["/dev/fb0"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$cuse(dev ptr[in, string["/dev/cuse"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$console(dev ptr[in, string["/dev/console"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$capi20(dev ptr[in, string["/dev/capi20"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$autofs(dev ptr[in, string["/dev/autofs"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$binder(dev ptr[in, string["/dev/binder"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$ion(dev ptr[in, string["/dev/ion"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$keychord(dev ptr[in, string["/dev/keychord"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$zygote(dev ptr[in, string["/dev/socket/zygote"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$sw_sync(dev ptr[in, string["/dev/sw_sync"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$sr(dev ptr[in, string["/dev/sr0"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$sequencer(dev ptr[in, string["/dev/sequencer"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$sequencer2(dev ptr[in, string["/dev/sequencer2"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$dsp(dev ptr[in, string["/dev/dsp"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$audio(dev ptr[in, string["/dev/audio"]], id const[0], flags flags[open_flags]) fd
+syz_open_dev$usbmon(dev ptr[in, string["/dev/usbmon#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$sg(dev ptr[in, string["/dev/sg#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$midi(dev ptr[in, string["/dev/midi#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$loop(dev ptr[in, string["/dev/loop#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$ircomm(dev ptr[in, string["/dev/ircomm#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$dspn(dev ptr[in, string["/dev/dsp#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$dmmidi(dev ptr[in, string["/dev/dmmidi#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$admmidi(dev ptr[in, string["/dev/admmidi#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$adsp(dev ptr[in, string["/dev/adsp#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$amidi(dev ptr[in, string["/dev/amidi#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$audion(dev ptr[in, string["/dev/audio#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$usb(dev ptr[in, string["/dev/bus/usb/00#/00#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$sndhw(dev ptr[in, string["/dev/snd/hwC#D#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$sndmidi(dev ptr[in, string["/dev/snd/midiC#D#"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$sndpcmc(dev ptr[in, string["/dev/snd/pcmC#D#c"]], id intptr, flags flags[open_flags]) fd
+syz_open_dev$sndpcmp(dev ptr[in, string["/dev/snd/pcmC#D#p"]], id intptr, flags flags[open_flags]) fd
@@ -1167,9 +1169,6 @@ ioprio_which_uid = IOPRIO_WHO_USER
setxattr_flags = XATTR_CREATE, XATTR_REPLACE
ns_type = 0, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWUTS
personality_flags = PER_LINUX, PER_SVR4, PER_SVR3, PER_OSR5, PER_WYSEV386, PER_ISCR4, PER_BSD, PER_XENIX, PER_LINUX32, PER_IRIX32, PER_IRIXN32, PER_IRIX64, PER_RISCOS, PER_SOLARIS, PER_UW7, PER_OSF4, PER_HPUX, ADDR_NO_RANDOMIZE, MMAP_PAGE_ZERO, ADDR_COMPAT_LAYOUT, READ_IMPLIES_EXEC, ADDR_LIMIT_32BIT, SHORT_INODE, WHOLE_SECONDS, STICKY_TIMEOUTS, ADDR_LIMIT_3GB
-sysfs_opt1 = 1
-sysfs_opt2 = 2
-sysfs_opt3 = 3
clock_id = CLOCK_REALTIME, CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_BOOTTIME, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID
sigprocmask_how = SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK
getitimer_which = ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF
diff --git a/sys/tlk_device.txt b/sys/tlk_device.txt
index 7535d16f7..1d5bd8229 100644
--- a/sys/tlk_device.txt
+++ b/sys/tlk_device.txt
@@ -12,7 +12,7 @@ include <security/tlk_driver/ote_protocol.h>
resource fd_tlk[fd]
resource te_session_id[int32]
-syz_open_dev$tlk_device(dev strconst["/dev/tlk_device"], id const[0], flags flags[open_flags]) fd_tlk
+syz_open_dev$tlk_device(dev ptr[in, string["/dev/tlk_device"]], id const[0], flags flags[open_flags]) fd_tlk
ioctl$TE_IOCTL_OPEN_CLIENT_SESSION(fd fd_tlk, cmd const[TE_IOCTL_OPEN_CLIENT_SESSION], arg ptr[inout, te_opensession])
ioctl$TE_IOCTL_CLOSE_CLIENT_SESSION(fd fd_tlk, cmd const[TE_IOCTL_CLOSE_CLIENT_SESSION], arg ptr[inout, te_closesession])
diff --git a/sys/tty.txt b/sys/tty.txt
index 67b11b754..e9717806c 100644
--- a/sys/tty.txt
+++ b/sys/tty.txt
@@ -8,7 +8,7 @@ include <uapi/linux/fcntl.h>
resource fd_tty[fd]
-openat$ptmx(fd const[AT_FDCWD], file strconst["/dev/ptmx"], flags flags[open_flags], mode const[0]) fd_tty
+openat$ptmx(fd const[AT_FDCWD], file ptr[in, string["/dev/ptmx"]], flags flags[open_flags], mode const[0]) fd_tty
syz_open_pts(fd fd_tty, flags flags[open_flags]) fd_tty
ioctl$TCGETS(fd fd_tty, cmd const[TCGETS], arg ptr[out, termios])
ioctl$TCSETS(fd fd_tty, cmd const[TCSETS], arg ptr[in, termios])
diff --git a/sys/tun.txt b/sys/tun.txt
index 04e640786..a730ed86a 100755
--- a/sys/tun.txt
+++ b/sys/tun.txt
@@ -6,7 +6,7 @@ include <linux/virtio_net.h>
resource fd_tun[fd]
-syz_open_dev$tun(dev strconst["/dev/net/tun"], id const[0], flags flags[open_flags]) fd_tun
+syz_open_dev$tun(dev ptr[in, string["/dev/net/tun"]], id const[0], flags flags[open_flags]) fd_tun
write$tun(fd fd_tun, buf ptr[in, tun_buffer], count len[buf])
ioctl$TUNGETFEATURES(fd fd_tun, cmd const[TUNGETFEATURES], arg ptr[out, int32])
diff --git a/sysgen/sysgen.go b/sysgen/sysgen.go
index d197b774b..fda931b14 100644
--- a/sysgen/sysgen.go
+++ b/sysgen/sysgen.go
@@ -162,7 +162,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W
fmt.Fprintf(out, "func() { Calls = append(Calls, &Call{Name: \"%v\", CallName: \"%v\"", s.Name, s.CallName)
if len(s.Ret) != 0 {
fmt.Fprintf(out, ", Ret: ")
- generateArg("", "ret", s.Ret[0], s.Ret[1:], desc, consts, true, false, out)
+ generateArg("", "ret", s.Ret[0], "out", s.Ret[1:], desc, consts, true, false, out)
}
fmt.Fprintf(out, ", Args: []Type{")
for i, a := range s.Args {
@@ -170,7 +170,7 @@ func generate(arch string, desc *Description, consts map[string]uint64, out io.W
fmt.Fprintf(out, ", ")
}
logf(5, " generate description for arg %v", i)
- generateArg("", a[0], a[1], a[2:], desc, consts, true, false, out)
+ generateArg("", a[0], a[1], "in", a[2:], desc, consts, true, false, out)
}
if skipCurrentSyscall != "" {
logf(0, "unsupported syscall: %v due to %v", s.Name, skipCurrentSyscall)
@@ -230,7 +230,7 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write
}
}
fmt.Fprintf(out, "\"%v\": &ResourceDesc{Name: \"%v\", Type: ", name, name)
- generateArg("", "resource-type", underlying, nil, desc, consts, true, true, out)
+ generateArg("", "resource-type", underlying, "inout", nil, desc, consts, true, true, out)
fmt.Fprintf(out, ", Kind: []string{")
for i, k := range kind {
if i != 0 {
@@ -253,11 +253,21 @@ func generateResources(desc *Description, consts map[string]uint64, out io.Write
fmt.Fprintf(out, "}\n")
}
-func generateStructEntry(str Struct, key string, name string, out io.Writer) {
+type structKey struct {
+ name string
+ field string
+ dir string
+}
+
+func generateStructEntry(str Struct, key structKey, out io.Writer) {
typ := "StructType"
if str.IsUnion {
typ = "UnionType"
}
+ name := key.field
+ if name == "" {
+ name = key.name
+ }
packed := ""
if str.Packed {
packed = ", packed: true"
@@ -270,11 +280,11 @@ func generateStructEntry(str Struct, key string, name string, out io.Writer) {
if str.Align != 0 {
align = fmt.Sprintf(", align: %v", str.Align)
}
- fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", IsOptional: %v} %v %v %v},\n",
- key, typ, name, false, packed, align, varlen)
+ fmt.Fprintf(out, "\"%v\": &%v{TypeCommon: TypeCommon{TypeName: \"%v\", ArgDir: %v, IsOptional: %v} %v %v %v},\n",
+ key, typ, name, fmtDir(key.dir), false, packed, align, varlen)
}
-func generateStructFields(str Struct, key string, desc *Description, consts map[string]uint64, out io.Writer) {
+func generateStructFields(str Struct, key structKey, desc *Description, consts map[string]uint64, out io.Writer) {
typ := "StructType"
fields := "Fields"
if str.IsUnion {
@@ -284,7 +294,7 @@ func generateStructFields(str Struct, key string, desc *Description, consts map[
fmt.Fprintf(out, "{ s := Structs[\"%v\"].(*%v)\n", key, typ)
for _, a := range str.Flds {
fmt.Fprintf(out, "s.%v = append(s.%v, ", fields, fields)
- generateArg(str.Name, a[0], a[1], a[2:], desc, consts, false, true, out)
+ generateArg(str.Name, a[0], a[1], key.dir, a[2:], desc, consts, false, true, out)
fmt.Fprintf(out, ")\n")
}
fmt.Fprintf(out, "}\n")
@@ -301,24 +311,23 @@ func generateStructs(desc *Description, consts map[string]uint64, out io.Writer)
// for each field indexed by the name of the parent struct and the
// field name.
- structMap := make(map[string]Struct)
+ structMap := make(map[structKey]Struct)
for _, str := range desc.Structs {
- if _, ok := structMap[str.Name]; ok {
- failf("two structs with the same name '%v'", str.Name)
+ for _, dir := range []string{"in", "out", "inout"} {
+ structMap[structKey{str.Name, "", dir}] = str
}
- structMap[str.Name] = str
for _, a := range str.Flds {
if innerStr, ok := desc.Structs[a[1]]; ok {
- structMap[fmt.Sprintf("%v-%v", str.Name, a[0])] = innerStr
+ for _, dir := range []string{"in", "out", "inout"} {
+ structMap[structKey{a[1], a[0], dir}] = innerStr
+ }
}
}
}
fmt.Fprintf(out, "var Structs = map[string]Type{\n")
for key, str := range structMap {
- keyParts := strings.Split(key, "-")
- name := keyParts[len(keyParts)-1]
- generateStructEntry(str, key, name, out)
+ generateStructEntry(str, key, out)
}
fmt.Fprintf(out, "}\n")
@@ -351,7 +360,7 @@ func parseRange(buffer string, consts map[string]uint64) (string, string) {
}
func generateArg(
- parent, name, typ string,
+ parent, name, typ, dir string,
a []string,
desc *Description,
consts map[string]uint64,
@@ -369,7 +378,7 @@ func generateArg(
}
}
common := func() string {
- return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, IsOptional: %v}", name, opt)
+ return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: %v, ArgDir: %v, IsOptional: %v}", name, fmtDir(dir), opt)
}
canBeArg := false
switch typ {
@@ -378,61 +387,89 @@ func generateArg(
size := uint64(ptrSize)
bigEndian := false
if isField {
- if want := 2; len(a) != want {
+ if want := 1; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- size, bigEndian = decodeIntType(a[1])
+ size, bigEndian = decodeIntType(a[0])
} else {
- if want := 1; len(a) != want {
+ if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
}
- fmt.Fprintf(out, "FileoffType{%v, File: \"%v\", TypeSize: %v, BigEndian: %v}", common(), a[0], size, bigEndian)
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntFileoff}", common(), size, bigEndian)
case "buffer":
canBeArg = true
if want := 1; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- commonHdr := common()
+ ptrCommonHdr := common()
+ dir = a[0]
opt = false
- fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferBlobRand}}", commonHdr, fmtDir(a[0]), common())
+ fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferBlobRand}}", ptrCommonHdr, common())
case "string":
- canBeArg = true
- if want := 0; len(a) != want {
- failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
+ if len(a) != 0 && len(a) != 1 && len(a) != 2 {
+ failf("wrong number of arguments for %v arg %v, want 0-2, got %v", typ, name, len(a))
+ }
+ var vals []string
+ subkind := ""
+ if len(a) >= 1 {
+ if a[0][0] == '"' {
+ vals = append(vals, a[0][1:len(a[0])-1])
+ } else {
+ vals1, ok := desc.StrFlags[a[0]]
+ if !ok {
+ failf("unknown string flags %v", a[0])
+ }
+ vals = append([]string{}, vals1...)
+ subkind = a[0]
+ }
}
- commonHdr := common()
- opt = false
- fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferString}}", commonHdr, fmtDir("in"), common())
- case "filesystem":
- canBeArg = true
- if want := 0; len(a) != want {
- failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
+ for i, s := range vals {
+ vals[i] = s + "\x00"
}
- commonHdr := common()
- opt = false
- fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: BufferType{%v, Kind: BufferFilesystem}}", commonHdr, fmtDir("in"), common())
+ if len(a) >= 2 {
+ var size uint64
+ if v, ok := consts[a[1]]; ok {
+ size = v
+ } else {
+ v, err := strconv.ParseUint(a[1], 10, 64)
+ if err != nil {
+ failf("failed to parse string length for %v", name, a[1])
+ }
+ size = v
+ }
+ for i, s := range vals {
+ if uint64(len(s)) > size {
+ failf("string value %q exceeds buffer length %v for arg %v", s, size, name)
+ }
+ for uint64(len(s)) < size {
+ s += "\x00"
+ }
+ vals[i] = s
+ }
+ }
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferString, SubKind: %q, Values: %#v}", common(), subkind, vals)
case "sockaddr":
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "BufferType{%v, Kind: BufferSockaddr}", common())
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferSockaddr}", common())
case "salg_type":
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "BufferType{%v, Kind: BufferAlgType}", common())
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferAlgType}", common())
case "salg_name":
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "BufferType{%v, Kind: BufferAlgName}", common())
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferAlgName}", common())
case "vma":
canBeArg = true
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "VmaType{%v}", common())
+ fmt.Fprintf(out, "&VmaType{%v}", common())
case "len", "bytesize":
canBeArg = true
size := uint64(ptrSize)
@@ -447,7 +484,7 @@ func generateArg(
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
}
- fmt.Fprintf(out, "LenType{%v, Buf: \"%v\", TypeSize: %v, BigEndian: %v, ByteSize: %v}", common(), a[0], size, bigEndian, typ == "bytesize")
+ fmt.Fprintf(out, "&LenType{%v, Buf: \"%v\", TypeSize: %v, BigEndian: %v, ByteSize: %v}", common(), a[0], size, bigEndian, typ == "bytesize")
case "flags":
canBeArg = true
size := uint64(ptrSize)
@@ -467,9 +504,9 @@ func generateArg(
failf("unknown flag %v", a[0])
}
if len(vals) == 0 {
- fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian)
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian)
} else {
- fmt.Fprintf(out, "FlagsType{%v, TypeSize: %v, BigEndian: %v, Vals: []uintptr{%v}}", common(), size, bigEndian, strings.Join(vals, ","))
+ fmt.Fprintf(out, "&FlagsType{%v, TypeSize: %v, BigEndian: %v, Vals: []uintptr{%v}}", common(), size, bigEndian, strings.Join(vals, ","))
}
case "const":
canBeArg = true
@@ -494,22 +531,16 @@ func generateArg(
val = "0"
skipSyscall(fmt.Sprintf("missing const %v", a[0]))
}
- fmt.Fprintf(out, "ConstType{%v, TypeSize: %v, BigEndian: %v, Val: uintptr(%v)}", common(), size, bigEndian, val)
- case "strconst":
- canBeArg = true
- if want := 1; len(a) != want {
- failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
- }
- fmt.Fprintf(out, "PtrType{%v, Dir: %v, Type: StrConstType{%v, Val: \"%v\"}}", common(), fmtDir("in"), common(), a[0]+"\\x00")
+ fmt.Fprintf(out, "&ConstType{%v, TypeSize: %v, BigEndian: %v, Val: uintptr(%v)}", common(), size, bigEndian, val)
case "int8", "int16", "int32", "int64", "intptr", "int16be", "int32be", "int64be", "intptrbe":
canBeArg = true
size, bigEndian := decodeIntType(typ)
switch len(a) {
case 0:
- fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian)
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v}", common(), size, bigEndian)
case 1:
begin, end := parseRange(a[0], consts)
- fmt.Fprintf(out, "IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntRange, RangeBegin: %v, RangeEnd: %v}", common(), size, bigEndian, begin, end)
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: %v, BigEndian: %v, Kind: IntRange, RangeBegin: %v, RangeEnd: %v}", common(), size, bigEndian, begin, end)
default:
failf("wrong number of arguments for %v arg %v, want 0 or 1, got %v", typ, name, len(a))
}
@@ -518,41 +549,42 @@ func generateArg(
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "IntType{%v, TypeSize: 4, Kind: IntSignalno}", common())
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: 4, Kind: IntSignalno}", common())
case "in_addr":
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "IntType{%v, TypeSize: 4, Kind: IntInaddr}", common())
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: 4, Kind: IntInaddr}", common())
case "in_port":
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "IntType{%v, TypeSize: 2, Kind: IntInport}", common())
+ fmt.Fprintf(out, "&IntType{%v, TypeSize: 2, Kind: IntInport}", common())
case "filename":
canBeArg = true
if want := 0; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- commonHdr := common()
+ ptrCommonHdr := common()
+ dir = "in"
opt = false
- fmt.Fprintf(out, "PtrType{%v, Dir: DirIn, Type: FilenameType{%v}}", commonHdr, common())
+ fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferFilename}}", ptrCommonHdr, common())
case "array":
if len(a) != 1 && len(a) != 2 {
failf("wrong number of arguments for %v arg %v, want 1 or 2, got %v", typ, name, len(a))
}
if len(a) == 1 {
if a[0] == "int8" {
- fmt.Fprintf(out, "BufferType{%v, Kind: BufferBlobRand}", common())
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRand}", common())
} else {
- fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], desc, consts))
+ fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], dir, desc, consts))
}
} else {
begin, end := parseRange(a[1], consts)
if a[0] == "int8" {
- fmt.Fprintf(out, "BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end)
+ fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end)
} else {
- fmt.Fprintf(out, "ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], desc, consts), begin, end)
+ fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], dir, desc, consts), begin, end)
}
}
case "ptr":
@@ -560,11 +592,12 @@ func generateArg(
if want := 2; len(a) != want {
failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a))
}
- fmt.Fprintf(out, "PtrType{%v, Type: %v, Dir: %v}", common(), generateType(a[1], desc, consts), fmtDir(a[0]))
+ dir = "in"
+ fmt.Fprintf(out, "&PtrType{%v, Type: %v}", common(), generateType(a[1], a[0], desc, consts))
default:
if strings.HasPrefix(typ, "unnamed") {
if inner, ok := desc.Unnamed[typ]; ok {
- generateArg("", "", inner[0], inner[1:], desc, consts, false, isField, out)
+ generateArg("", "", inner[0], dir, inner[1:], desc, consts, false, isField, out)
} else {
failf("unknown unnamed type '%v'", typ)
}
@@ -572,16 +605,12 @@ func generateArg(
if len(a) != 0 {
failf("struct '%v' has args", typ)
}
- if parent == "" {
- fmt.Fprintf(out, "Structs[\"%v\"]", typ)
- } else {
- fmt.Fprintf(out, "Structs[\"%v-%v\"]", parent, origName)
- }
+ fmt.Fprintf(out, "Structs[\"%v\"]", structKey{typ, origName, dir})
} else if _, ok := desc.Resources[typ]; ok {
if len(a) != 0 {
failf("resource '%v' has args", typ)
}
- fmt.Fprintf(out, "ResourceType{%v, Desc: Resources[\"%v\"]}", common(), typ)
+ fmt.Fprintf(out, "&ResourceType{%v, Desc: Resources[\"%v\"]}", common(), typ)
return
} else {
failf("unknown arg type \"%v\" for %v", typ, name)
@@ -592,9 +621,9 @@ func generateArg(
}
}
-func generateType(typ string, desc *Description, consts map[string]uint64) string {
+func generateType(typ, dir string, desc *Description, consts map[string]uint64) string {
buf := new(bytes.Buffer)
- generateArg("", "", typ, nil, desc, consts, false, true, buf)
+ generateArg("", "", typ, dir, nil, desc, consts, false, true, buf)
return buf.String()
}
diff --git a/sysparser/lexer.go b/sysparser/lexer.go
index 06210a584..a3b8f58ed 100644
--- a/sysparser/lexer.go
+++ b/sysparser/lexer.go
@@ -18,6 +18,7 @@ type Description struct {
Structs map[string]Struct
Unnamed map[string][]string
Flags map[string][]string
+ StrFlags map[string][]string
Resources map[string]Resource
}
@@ -51,6 +52,7 @@ func Parse(in io.Reader) *Description {
structs := make(map[string]Struct)
unnamed := make(map[string][]string)
flags := make(map[string][]string)
+ strflags := make(map[string][]string)
resources := make(map[string]Resource)
var str *Struct
for p.Scan() {
@@ -93,6 +95,9 @@ func Parse(in io.Reader) *Description {
}
fields := make(map[string]bool)
for _, f := range str.Flds {
+ if f[0] == "parent" {
+ failf("struct/union %v contains reserved field 'parent'", str.Name)
+ }
if fields[f[0]] {
failf("duplicate field %v in struct/union %v", f[0], str.Name)
}
@@ -189,12 +194,24 @@ func Parse(in io.Reader) *Description {
case '=':
// flag
p.Parse('=')
- vals := []string{p.Ident()}
- for !p.EOF() {
+ str := p.Char() == '"'
+ var vals []string
+ for {
+ v := p.Ident()
+ if str {
+ v = v[1 : len(v)-1]
+ }
+ vals = append(vals, v)
+ if p.EOF() {
+ break
+ }
p.Parse(',')
- vals = append(vals, p.Ident())
}
- flags[name] = vals
+ if str {
+ strflags[name] = vals
+ } else {
+ flags[name] = vals
+ }
case '{', '[':
p.Parse(ch)
if _, ok := structs[name]; ok {
@@ -221,6 +238,7 @@ func Parse(in io.Reader) *Description {
Structs: structs,
Unnamed: unnamed,
Flags: flags,
+ StrFlags: strflags,
Resources: resources,
}
}
diff --git a/sysparser/parser.go b/sysparser/parser.go
index 590847b0e..d5021eee6 100644
--- a/sysparser/parser.go
+++ b/sysparser/parser.go
@@ -70,11 +70,10 @@ func (p *parser) Ident() string {
start, end := p.i, 0
if p.Char() == '"' {
p.Parse('"')
- start++
for p.Char() != '"' {
p.i++
}
- end = p.i
+ end = p.i + 1
p.Parse('"')
} else {
for p.i < len(p.s) &&