aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-12-28 12:58:10 +0100
committerDmitry Vyukov <dvyukov@google.com>2015-12-28 12:58:10 +0100
commit4eda9b07e5f25565333fdd8eed4e33850bd0f828 (patch)
tree45d2ec43dbc07109ea665432e68bab98f0b2a15c
parent9f9ae3fcc3efc74cbcb805b44575b5c140fa97ee (diff)
prog: don't serialize paddings
Paddings in serialized programs are unnecessary and confusing. Instead restore them implicitly. Also use [,,,,] for arrays.
-rw-r--r--prog/encoding.go90
-rw-r--r--prog/encodingexec.go4
-rw-r--r--prog/mutation_test.go4
-rw-r--r--prog/prog.go7
-rw-r--r--prog/rand.go2
-rw-r--r--prog/validation.go9
-rw-r--r--sys/decl.go9
7 files changed, 95 insertions, 30 deletions
diff --git a/prog/encoding.go b/prog/encoding.go
index bb366ea55..47addb5ef 100644
--- a/prog/encoding.go
+++ b/prog/encoding.go
@@ -43,6 +43,9 @@ func (p *Prog) Serialize() []byte {
}
fmt.Fprintf(buf, "%v(", c.Meta.Name)
for i, a := range c.Args {
+ if sys.IsPad(a.Type) {
+ continue
+ }
if i != 0 {
fmt.Fprintf(buf, ", ")
}
@@ -59,7 +62,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
return
}
if len(a.Uses) != 0 {
- fmt.Fprintf(buf, "[r%v=]", *varSeq)
+ fmt.Fprintf(buf, "<r%v=>", *varSeq)
vars[a] = *varSeq
*varSeq++
}
@@ -86,14 +89,26 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
case ArgData:
fmt.Fprintf(buf, "\"%v\"", hex.EncodeToString(a.Data))
case ArgGroup:
- fmt.Fprintf(buf, "{")
+ var delims []byte
+ switch a.Type.(type) {
+ case sys.StructType:
+ delims = []byte{'{', '}'}
+ case sys.ArrayType:
+ delims = []byte{'[', ']'}
+ default:
+ panic("unknown group type")
+ }
+ buf.Write([]byte{delims[0]})
for i, a1 := range a.Inner {
+ if a1 != nil && sys.IsPad(a1.Type) {
+ continue
+ }
if i != 0 {
fmt.Fprintf(buf, ", ")
}
a1.serialize(buf, vars, varSeq)
}
- fmt.Fprintf(buf, "}")
+ buf.Write([]byte{delims[1]})
default:
panic("unknown arg kind")
}
@@ -123,7 +138,14 @@ func Deserialize(data []byte) (prog *Prog, err error) {
prog.Calls = append(prog.Calls, c)
p.Parse('(')
for i := 0; p.Char() != ')'; i++ {
- arg, err := parseArg(p, vars)
+ if i >= len(meta.Args) {
+ return nil, fmt.Errorf("wrong call arg count: %v, want %v", i+1, len(meta.Args))
+ }
+ typ := meta.Args[i]
+ if sys.IsPad(typ) {
+ return nil, fmt.Errorf("padding in syscall %v arguments", name)
+ }
+ arg, err := parseArg(typ, p, vars)
if err != nil {
return nil, err
}
@@ -155,13 +177,13 @@ func Deserialize(data []byte) (prog *Prog, err error) {
return
}
-func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
+func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
r := ""
- if p.Char() == '[' {
- p.Parse('[')
+ if p.Char() == '<' {
+ p.Parse('<')
r = p.Ident()
p.Parse('=')
- p.Parse(']')
+ p.Parse('>')
}
var arg *Arg
switch p.Char() {
@@ -198,13 +220,21 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
arg.OpAdd = uintptr(v)
}
case '&':
+ var typ1 sys.Type
+ switch t1 := typ.(type) {
+ case sys.PtrType:
+ typ1 = t1.Type
+ case sys.VmaType:
+ default:
+ return nil, fmt.Errorf("& arg is not a pointer: %#v", typ)
+ }
p.Parse('&')
page, off, err := parseAddr(p, true)
if err != nil {
return nil, err
}
p.Parse('=')
- inner, err := parseArg(p, vars)
+ inner, err := parseArg(typ1, p, vars)
if err != nil {
return nil, err
}
@@ -228,19 +258,53 @@ func parseArg(p *parser, vars map[string]*Arg) (*Arg, error) {
}
arg = dataArg(data)
case '{':
+ t1, ok := typ.(sys.StructType)
+ if !ok {
+ return nil, fmt.Errorf("'{' arg is not a struct: %#v", typ)
+ }
p.Parse('{')
var inner []*Arg
- for p.Char() != '}' {
- arg, err := parseArg(p, vars)
+ for i := 0; p.Char() != '}'; i++ {
+ if i >= len(t1.Fields) {
+ return nil, fmt.Errorf("wrong struct arg count: %v, want %v", i+1, len(t1.Fields))
+ }
+ fld := t1.Fields[i]
+ if sys.IsPad(fld) {
+ inner = append(inner, constArg(0))
+ } else {
+ arg, err := parseArg(fld, p, vars)
+ if err != nil {
+ return nil, err
+ }
+ inner = append(inner, arg)
+ if p.Char() != '}' {
+ p.Parse(',')
+ }
+ }
+ }
+ p.Parse('}')
+ if sys.IsPad(t1.Fields[len(t1.Fields)-1]) {
+ inner = append(inner, constArg(0))
+ }
+ arg = groupArg(inner)
+ case '[':
+ t1, ok := typ.(sys.ArrayType)
+ if !ok {
+ return nil, fmt.Errorf("'[' arg is not an array: %#v", typ)
+ }
+ p.Parse('[')
+ var inner []*Arg
+ for i := 0; p.Char() != ']'; i++ {
+ arg, err := parseArg(t1.Type, p, vars)
if err != nil {
return nil, err
}
inner = append(inner, arg)
- if p.Char() != '}' {
+ if p.Char() != ']' {
p.Parse(',')
}
}
- p.Parse('}')
+ p.Parse(']')
arg = groupArg(inner)
case 'n':
p.Parse('n')
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index 3b0d4c28c..3b68f6c98 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -8,6 +8,8 @@ package prog
import (
"fmt"
+
+ "github.com/google/syzkaller/sys"
)
const (
@@ -57,7 +59,7 @@ func (p *Prog) SerializeForExec() []byte {
}
return
}
- if pad, _ := arg1.IsPad(); pad {
+ if sys.IsPad(arg1.Type) {
return
}
if arg1.Kind == ArgData && len(arg1.Data) == 0 {
diff --git a/prog/mutation_test.go b/prog/mutation_test.go
index 37db7cda2..53acba02d 100644
--- a/prog/mutation_test.go
+++ b/prog/mutation_test.go
@@ -212,7 +212,7 @@ func TestMinimize(t *testing.T) {
// Remove a call and replace results.
{
"mmap(&(0x7f0000000000)=nil, (0x1000), 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" +
- "pipe2(&(0x7f0000000000)={[r0=]0x0, 0x0}, 0x0)\n" +
+ "pipe2(&(0x7f0000000000)={<r0=>0x0, 0x0}, 0x0)\n" +
"write(r0, &(0x7f0000000000)=\"1155\", 0x2)\n" +
"sched_yield()\n",
3,
@@ -259,7 +259,7 @@ func TestMinimize(t *testing.T) {
for ti, test := range tests {
p, err := Deserialize([]byte(test.orig))
if err != nil {
- t.Fatalf("failed to deserialize original program: %v", err)
+ t.Fatalf("failed to deserialize original program #%v: %v", ti, err)
}
p1, ci := Minimize(p, test.callIndex, test.pred)
res := p1.Serialize()
diff --git a/prog/prog.go b/prog/prog.go
index 8bc8d6734..e4c1c72ca 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -79,13 +79,6 @@ func (a *Arg) Size(typ sys.Type) uintptr {
}
}
-func (a *Arg) IsPad() (bool, uintptr) {
- if ct, ok := a.Type.(sys.ConstType); ok && ct.Val == 0 && ct.Name() == "pad" {
- return true, ct.TypeSize
- }
- return false, 0
-}
-
func constArg(v uintptr) *Arg {
return &Arg{Kind: ArgConst, Val: v}
}
diff --git a/prog/rand.go b/prog/rand.go
index 0042a5deb..962f9f827 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -462,7 +462,7 @@ func (r *randGen) createResource(s *state, res sys.ResourceType) (arg *Arg, call
// Generate one of them.
meta := metas[r.Intn(len(metas))]
calls := r.generateParticularCall(s, meta)
- assignTypeAndDir(calls[len(calls)-1])
+ //assignTypeAndDir(calls[len(calls)-1])
s1 := newState(s.ct)
s1.analyze(calls[len(calls)-1])
// Now see if we have what we want.
diff --git a/prog/validation.go b/prog/validation.go
index a06f98de6..cc6d1ae61 100644
--- a/prog/validation.go
+++ b/prog/validation.go
@@ -18,12 +18,6 @@ func (p *Prog) validate() error {
ctx := &validCtx{make(map[*Arg]bool), make(map[*Arg]*Arg)}
for _, c := range p.Calls {
if err := c.validate(ctx); err != nil {
-
- fmt.Printf("PROGRAM:\n")
- for _, c := range p.Calls {
- fmt.Printf(" %v: %+v %p\n", c.Meta.Name, c.Args, c.Ret)
- }
-
return err
}
}
@@ -36,6 +30,9 @@ func (p *Prog) validate() error {
}
func (c *Call) validate(ctx *validCtx) error {
+ if c.Meta == nil {
+ return fmt.Errorf("call does not have meta information")
+ }
if len(c.Args) != len(c.Meta.Args) {
return fmt.Errorf("syscall %v: wrong number of arguments, want %v, got %v", c.Meta.Name, len(c.Meta.Args), len(c.Args))
}
diff --git a/sys/decl.go b/sys/decl.go
index 82f1871e1..af3202ae2 100644
--- a/sys/decl.go
+++ b/sys/decl.go
@@ -23,6 +23,13 @@ type Type interface {
Align() uintptr
}
+func IsPad(t Type) bool {
+ if ct, ok := t.(ConstType); ok && ct.IsPad {
+ return true
+ }
+ return false
+}
+
type TypeCommon struct {
TypeName string
IsOptional bool
@@ -313,6 +320,7 @@ type ConstType struct {
TypeCommon
TypeSize uintptr
Val uintptr
+ IsPad bool
}
func (t ConstType) Size() uintptr {
@@ -654,5 +662,6 @@ func makePad(sz uintptr) Type {
TypeCommon: TypeCommon{TypeName: "pad", IsOptional: false},
TypeSize: sz,
Val: 0,
+ IsPad: true,
}
}