aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--executor/executor.cc11
-rw-r--r--prog/clone.go1
-rw-r--r--prog/decodeexec.go15
-rw-r--r--prog/encoding.go77
-rw-r--r--prog/encoding_test.go61
-rw-r--r--prog/encodingexec.go17
-rw-r--r--prog/encodingexec_test.go389
-rw-r--r--prog/prog.go34
-rw-r--r--sys/syz-sysgen/sysgen.go23
9 files changed, 455 insertions, 173 deletions
diff --git a/executor/executor.cc b/executor/executor.cc
index e35e48189..950f37cba 100644
--- a/executor/executor.cc
+++ b/executor/executor.cc
@@ -241,6 +241,7 @@ struct thread_t {
int call_num;
int num_args;
intptr_t args[kMaxArgs];
+ call_props_t call_props;
intptr_t res;
uint32 reserrno;
bool fault_injected;
@@ -341,7 +342,7 @@ struct feature_t {
void (*setup)();
};
-static thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos);
+static thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos, call_props_t call_props);
static void handle_completion(thread_t* th);
static void copyout_call_results(thread_t* th);
static void write_call_output(thread_t* th, bool finished);
@@ -673,6 +674,8 @@ retry:
int call_index = 0;
uint64 prog_extra_timeout = 0;
uint64 prog_extra_cover_timeout = 0;
+ call_props_t call_props;
+
for (;;) {
uint64 call_num = read_input(&input_pos);
if (call_num == instr_eof)
@@ -766,6 +769,7 @@ retry:
// Normal syscall.
if (call_num >= ARRAY_SIZE(syscalls))
failmsg("invalid syscall number", "call_num=%llu", call_num);
+ read_call_props_t(call_props, read_input(&input_pos, false));
const call_t* call = &syscalls[call_num];
if (call->attrs.disabled)
failmsg("executing disabled syscall", "syscall=%s", call->name);
@@ -785,7 +789,7 @@ retry:
for (uint64 i = num_args; i < kMaxArgs; i++)
args[i] = 0;
thread_t* th = schedule_call(call_index++, call_num, colliding, copyout_index,
- num_args, args, input_pos);
+ num_args, args, input_pos, call_props);
if (colliding && (call_index % 2) == 0) {
// Don't wait for every other call.
@@ -868,7 +872,7 @@ retry:
}
}
-thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos)
+thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 copyout_index, uint64 num_args, uint64* args, uint64* pos, call_props_t call_props)
{
// Find a spare thread to execute the call.
int i = 0;
@@ -897,6 +901,7 @@ thread_t* schedule_call(int call_index, int call_num, bool colliding, uint64 cop
th->call_index = call_index;
th->call_num = call_num;
th->num_args = num_args;
+ th->call_props = call_props;
for (int i = 0; i < kMaxArgs; i++)
th->args[i] = args[i];
event_set(&th->ready);
diff --git a/prog/clone.go b/prog/clone.go
index c95ae206b..d1e23409b 100644
--- a/prog/clone.go
+++ b/prog/clone.go
@@ -23,6 +23,7 @@ func (p *Prog) Clone() *Prog {
for ai, arg := range c.Args {
c1.Args[ai] = clone(arg, newargs)
}
+ c1.Props = c.Props
p1.Calls[ci] = c1
}
p1.debugValidate()
diff --git a/prog/decodeexec.go b/prog/decodeexec.go
index e2ef2586c..ff1ab5727 100644
--- a/prog/decodeexec.go
+++ b/prog/decodeexec.go
@@ -5,6 +5,7 @@ package prog
import (
"fmt"
+ "reflect"
)
type ExecProg struct {
@@ -14,6 +15,7 @@ type ExecProg struct {
type ExecCall struct {
Meta *Syscall
+ Props CallProps
Index uint64
Args []ExecArg
Copyin []ExecCopyin
@@ -119,6 +121,7 @@ func (dec *execDecoder) parse() {
dec.setErr(fmt.Errorf("bad syscall %v", instr))
return
}
+ dec.readCallProps(&dec.call.Props)
dec.call.Meta = dec.target.Syscalls[instr]
dec.call.Index = dec.read()
for i := dec.read(); i > 0; i-- {
@@ -134,6 +137,18 @@ func (dec *execDecoder) parse() {
}
}
+func (dec *execDecoder) readCallProps(props *CallProps) {
+ props.ForeachProp(func(_, _ string, value reflect.Value) {
+ arg := dec.read()
+ switch kind := value.Kind(); kind {
+ case reflect.Int:
+ value.SetInt(int64(arg))
+ default:
+ panic("Unsupported (yet) kind: " + kind.String())
+ }
+ })
+}
+
func (dec *execDecoder) readArg() ExecArg {
switch typ := dec.read(); typ {
case execArgConst:
diff --git a/prog/encoding.go b/prog/encoding.go
index de0e324b1..3f1c918a7 100644
--- a/prog/encoding.go
+++ b/prog/encoding.go
@@ -7,6 +7,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
+ "reflect"
"strconv"
"strings"
)
@@ -78,7 +79,36 @@ func (ctx *serializer) call(c *Call) {
}
ctx.arg(a)
}
- ctx.printf(")\n")
+ ctx.printf(")")
+
+ defaultProps := DefaultCallProps()
+ anyChangedProps := false
+ c.Props.ForeachProp(func(name, key string, value reflect.Value) {
+ defaultValue := reflect.ValueOf(defaultProps).FieldByName(name)
+ if reflect.DeepEqual(value.Interface(), defaultValue.Interface()) {
+ return
+ }
+
+ if !anyChangedProps {
+ ctx.printf(" (")
+ anyChangedProps = true
+ } else {
+ ctx.printf(", ")
+ }
+
+ ctx.printf(key)
+ switch kind := value.Kind(); kind {
+ case reflect.Int:
+ ctx.printf(": %d", value.Int())
+ default:
+ panic("unable to serialize call prop of type " + kind.String())
+ }
+ })
+ if anyChangedProps {
+ ctx.printf(")")
+ }
+
+ ctx.printf("\n")
}
func (ctx *serializer) arg(arg Arg) {
@@ -286,7 +316,13 @@ func (p *parser) parseProg() (*Prog, error) {
}
}
p.Parse(')')
- p.SkipWs()
+
+ if !p.EOF() && p.Char() == '(' {
+ p.Parse('(')
+ c.Props = p.parseCallProps()
+ p.Parse(')')
+ }
+
if !p.EOF() {
if p.Char() != '#' {
return nil, fmt.Errorf("tailing data (line #%v)", p.l)
@@ -314,6 +350,43 @@ func (p *parser) parseProg() (*Prog, error) {
return prog, nil
}
+func (p *parser) parseCallProps() CallProps {
+ nameToValue := map[string]reflect.Value{}
+ callProps := DefaultCallProps()
+ callProps.ForeachProp(func(_, key string, value reflect.Value) {
+ nameToValue[key] = value
+ })
+
+ for p.e == nil && p.Char() != ')' {
+ propName := p.Ident()
+ value, ok := nameToValue[propName]
+ if !ok {
+ p.eatExcessive(true, "unknown call property: %s", propName)
+ if p.Char() == ',' {
+ p.Parse(',')
+ }
+ continue
+ }
+ switch kind := value.Kind(); kind {
+ case reflect.Int:
+ p.Parse(':')
+ strVal := p.Ident()
+ intV, err := strconv.ParseInt(strVal, 0, 64)
+ if err != nil {
+ p.strictFailf("invalid int value: %s", strVal)
+ } else {
+ value.SetInt(intV)
+ }
+ default:
+ panic("unable to handle call props of type " + kind.String())
+ }
+ if p.Char() != ')' {
+ p.Parse(',')
+ }
+ }
+ return callProps
+}
+
func (p *parser) parseArg(typ Type, dir Dir) (Arg, error) {
r := ""
if p.Char() == '<' {
diff --git a/prog/encoding_test.go b/prog/encoding_test.go
index 4ba9edd50..d7171248f 100644
--- a/prog/encoding_test.go
+++ b/prog/encoding_test.go
@@ -312,6 +312,21 @@ func TestDeserialize(t *testing.T) {
Out: `test$opt2(0x0)`,
StrictErr: `non-nil argument for nil type`,
},
+ {
+ In: `test$opt2(0x0) (non_existing_prop: 123)`,
+ Out: `test$opt2(0x0)`,
+ StrictErr: `unknown call property: non_existing_prop`,
+ },
+ {
+ In: `test$opt2(0x0) (fail_nth: zzz)`,
+ Out: `test$opt2(0x0)`,
+ StrictErr: `invalid int value: zzz`,
+ },
+ {
+ In: `test$opt2(0x0) (non_existing_prop: 123, fail_nth: 1)`,
+ Out: `test$opt2(0x0) (fail_nth: 1)`,
+ StrictErr: `unknown call property: non_existing_prop`,
+ },
})
}
@@ -384,6 +399,52 @@ func testSerializeDeserialize(t *testing.T, p0 *Prog, data0, data1 []byte) (bool
return true, 0, 0
}
+func TestSerializeCallProps(t *testing.T) {
+ target := initTargetTest(t, "test", "64")
+ type SerializeCallPropsTest struct {
+ prog string
+ props []CallProps
+ }
+
+ tests := []SerializeCallPropsTest{
+ {
+ "serialize0(0x0)\n",
+ []CallProps{DefaultCallProps()},
+ },
+ {
+ "serialize0(0x0) ()\n",
+ []CallProps{DefaultCallProps()},
+ },
+ {
+ "serialize0(0x0) (fail_nth: 5)\n",
+ []CallProps{{5}},
+ },
+ {
+ "serialize0(0x0) (fail_nth)\n",
+ nil,
+ },
+ {
+ "serialize0(0x0) (fail_nth: \"5\")\n",
+ nil,
+ },
+ }
+
+ for _, test := range tests {
+ p, err := target.Deserialize([]byte(test.prog), Strict)
+ if test.props != nil && err != nil {
+ t.Fatal(err)
+ } else if test.props == nil && err == nil {
+ t.Errorf("expected an error, but got none\n%s", test.prog)
+ }
+
+ for i, props := range test.props {
+ if !reflect.DeepEqual(props, p.Calls[i].Props) {
+ t.Errorf("%v-th call props differ: %v != %v", i, props, p.Calls[i].Props)
+ }
+ }
+ }
+}
+
func TestDeserializeComments(t *testing.T) {
target := initTargetTest(t, "test", "64")
p, err := target.Deserialize([]byte(`
diff --git a/prog/encodingexec.go b/prog/encodingexec.go
index e0c7ec59d..296fcf0cf 100644
--- a/prog/encodingexec.go
+++ b/prog/encodingexec.go
@@ -6,7 +6,7 @@
// Exec format is an sequence of uint64's which encodes a sequence of calls.
// The sequence is terminated by a speciall call execInstrEOF.
-// Each call is (call ID, copyout index, number of arguments, arguments...).
+// Each call is (call ID, call props, copyout index, number of arguments, arguments...).
// Each argument is (type, size, value).
// There are 4 types of arguments:
// - execArgConst: value is const value
@@ -22,6 +22,7 @@ package prog
import (
"errors"
"fmt"
+ "reflect"
"sort"
)
@@ -89,6 +90,8 @@ func (w *execContext) serializeCall(c *Call) {
w.writeChecksums()
// Generate the call itself.
w.write(uint64(c.Meta.ID))
+ // Generate call properties fragment.
+ w.writeCallProps(c.Props)
if c.Ret != nil && len(c.Ret.uses) != 0 {
if _, ok := w.args[c.Ret]; ok {
panic("argInfo is already created for return value")
@@ -103,6 +106,7 @@ func (w *execContext) serializeCall(c *Call) {
for _, arg := range c.Args {
w.writeArg(arg)
}
+
// Generate copyout instructions that persist interesting return values.
w.writeCopyout(c)
}
@@ -124,6 +128,17 @@ type argInfo struct {
Ret bool
}
+func (w *execContext) writeCallProps(props CallProps) {
+ props.ForeachProp(func(_, _ string, value reflect.Value) {
+ switch kind := value.Kind(); kind {
+ case reflect.Int:
+ w.write(uint64(value.Int()))
+ default:
+ panic("Unsupported (yet) kind: " + kind.String())
+ }
+ })
+}
+
func (w *execContext) writeCopyin(c *Call) {
ForeachArg(c, func(arg Arg, ctx *ArgCtx) {
if ctx.Base == nil {
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index d5b92f59a..a7085be0c 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -54,6 +54,27 @@ func TestSerializeForExec(t *testing.T) {
buf[7] = byte(v >> 56)
return HostEndian.Uint64(buf)
}
+
+ join := func(objects ...interface{}) []uint64 {
+ ret := []uint64{}
+ for _, val := range objects {
+ switch v := val.(type) {
+ case uint64:
+ ret = append(ret, v)
+ case int:
+ ret = append(ret, uint64(v))
+ case []uint64:
+ ret = append(ret, v...)
+ default:
+ panic(fmt.Sprintf("unsupported object type %T", v))
+ }
+ }
+ return ret
+ }
+
+ defaultCallPropsSlice := []uint64{
+ 0xFFFFFFFFFFFFFFFF,
+ }
tests := []struct {
prog string
serialized []uint64
@@ -61,215 +82,244 @@ func TestSerializeForExec(t *testing.T) {
}{
{
"test()",
- []uint64{
- callID("test"), ExecNoCopyout, 0,
+ join(
+ callID("test"), defaultCallPropsSlice,
+ ExecNoCopyout, 0,
execInstrEOF,
- },
+ ),
&ExecProg{
Calls: []ExecCall{
{
Meta: target.SyscallMap["test"],
Index: ExecNoCopyout,
+ Props: DefaultCallProps(),
},
},
},
},
{
"test$int(0x1, 0x2, 0x3, 0x4, 0x5)",
- []uint64{
- callID("test$int"), ExecNoCopyout, 5,
+ join(
+ callID("test$int"), defaultCallPropsSlice,
+ ExecNoCopyout, 5,
execArgConst, 8, 1,
execArgConst, 1, 2,
execArgConst, 2, 3,
execArgConst, 4, 4,
execArgConst, 8, 5,
execInstrEOF,
- },
+ ),
+ nil,
+ },
+ {
+ "test() (fail_nth: 3)",
+ join(
+ callID("test"),
+ 3,
+ ExecNoCopyout, 0,
+ execInstrEOF,
+ ),
nil,
},
{
"test$align0(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
- execInstrCopyin, dataOffset + 4, execArgConst, 4, 2,
- execInstrCopyin, dataOffset + 8, execArgConst, 1, 3,
- execInstrCopyin, dataOffset + 10, execArgConst, 2, 4,
- execInstrCopyin, dataOffset + 16, execArgConst, 8, 5,
- callID("test$align0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2, 1,
+ execInstrCopyin, dataOffset+4, execArgConst, 4, 2,
+ execInstrCopyin, dataOffset+8, execArgConst, 1, 3,
+ execInstrCopyin, dataOffset+10, execArgConst, 2, 4,
+ execInstrCopyin, dataOffset+16, execArgConst, 8, 5,
+ callID("test$align0"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align1(&(0x7f0000000000)={0x1, 0x2, 0x3, 0x4, 0x5})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2, 1,
- execInstrCopyin, dataOffset + 2, execArgConst, 4, 2,
- execInstrCopyin, dataOffset + 6, execArgConst, 1, 3,
- execInstrCopyin, dataOffset + 7, execArgConst, 2, 4,
- execInstrCopyin, dataOffset + 9, execArgConst, 8, 5,
- callID("test$align1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2, 1,
+ execInstrCopyin, dataOffset+2, execArgConst, 4, 2,
+ execInstrCopyin, dataOffset+6, execArgConst, 1, 3,
+ execInstrCopyin, dataOffset+7, execArgConst, 2, 4,
+ execInstrCopyin, dataOffset+9, execArgConst, 8, 5,
+ callID("test$align1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align2(&(0x7f0000000000)={0x42, {[0x43]}, {[0x44]}})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
- execInstrCopyin, dataOffset + 4, execArgConst, 2, 0x44,
- callID("test$align2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+1, execArgConst, 2, 0x43,
+ execInstrCopyin, dataOffset+4, execArgConst, 2, 0x44,
+ callID("test$align2"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align3(&(0x7f0000000000)={0x42, {0x43}, {0x44}})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgConst, 1, 0x43,
- execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
- callID("test$align3"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+1, execArgConst, 1, 0x43,
+ execInstrCopyin, dataOffset+4, execArgConst, 1, 0x44,
+ callID("test$align3"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align4(&(0x7f0000000000)={{0x42, 0x43}, 0x44})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgConst, 2, 0x43,
- execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x44,
- callID("test$align4"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+1, execArgConst, 2, 0x43,
+ execInstrCopyin, dataOffset+4, execArgConst, 1, 0x44,
+ callID("test$align4"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align5(&(0x7f0000000000)={{0x42, []}, {0x43, [0x44, 0x45, 0x46]}, 0x47})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 8, 0x42,
- execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x43,
- execInstrCopyin, dataOffset + 16, execArgConst, 2, 0x44,
- execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x45,
- execInstrCopyin, dataOffset + 20, execArgConst, 2, 0x46,
- execInstrCopyin, dataOffset + 22, execArgConst, 1, 0x47,
- callID("test$align5"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 8, 0x42,
+ execInstrCopyin, dataOffset+8, execArgConst, 8, 0x43,
+ execInstrCopyin, dataOffset+16, execArgConst, 2, 0x44,
+ execInstrCopyin, dataOffset+18, execArgConst, 2, 0x45,
+ execInstrCopyin, dataOffset+20, execArgConst, 2, 0x46,
+ execInstrCopyin, dataOffset+22, execArgConst, 1, 0x47,
+ callID("test$align5"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align6(&(0x7f0000000000)={0x42, [0x43]})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 4, execArgConst, 4, 0x43,
- callID("test$align6"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+4, execArgConst, 4, 0x43,
+ callID("test$align6"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$union0(&(0x7f0000000000)={0x1, @f2=0x2})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 8, 1,
- execInstrCopyin, dataOffset + 8, execArgConst, 1, 2,
- callID("test$union0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 8, 1,
+ execInstrCopyin, dataOffset+8, execArgConst, 1, 2,
+ callID("test$union0"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$union1(&(0x7f0000000000)={@f1=0x42, 0x43})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
- execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x43,
- callID("test$union1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 4, 0x42,
+ execInstrCopyin, dataOffset+8, execArgConst, 1, 0x43,
+ callID("test$union1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$union2(&(0x7f0000000000)={@f1=0x42, 0x43})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 4, 0x42,
- execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x43,
- callID("test$union2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 4, 0x42,
+ execInstrCopyin, dataOffset+4, execArgConst, 1, 0x43,
+ callID("test$union2"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$array0(&(0x7f0000000000)={0x1, [@f0=0x2, @f1=0x3], 0x4})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 1,
- execInstrCopyin, dataOffset + 1, execArgConst, 2, 2,
- execInstrCopyin, dataOffset + 3, execArgConst, 8, 3,
- execInstrCopyin, dataOffset + 11, execArgConst, 8, 4,
- callID("test$array0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 1,
+ execInstrCopyin, dataOffset+1, execArgConst, 2, 2,
+ execInstrCopyin, dataOffset+3, execArgConst, 8, 3,
+ execInstrCopyin, dataOffset+11, execArgConst, 8, 4,
+ callID("test$array0"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$array1(&(0x7f0000000000)={0x42, \"0102030405\"})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgData, 5, letoh64(0x0504030201),
- callID("test$array1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+1, execArgData, 5, letoh64(0x0504030201),
+ callID("test$array1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$array2(&(0x7f0000000000)={0x42, \"aaaaaaaabbbbbbbbccccccccdddddddd\", 0x43})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x42,
- execInstrCopyin, dataOffset + 2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc),
- execInstrCopyin, dataOffset + 18, execArgConst, 2, 0x43,
- callID("test$array2"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2, 0x42,
+ execInstrCopyin, dataOffset+2, execArgData, 16, letoh64(0xbbbbbbbbaaaaaaaa), letoh64(0xddddddddcccccccc),
+ execInstrCopyin, dataOffset+18, execArgConst, 2, 0x43,
+ callID("test$array2"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$end0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1, 0x42,
- execInstrCopyin, dataOffset + 1, execArgConst, 2 | 1<<8, 0x42,
- execInstrCopyin, dataOffset + 3, execArgConst, 4 | 1<<8, 0x42,
- execInstrCopyin, dataOffset + 7, execArgConst, 8 | 1<<8, 0x42,
- callID("test$end0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1, 0x42,
+ execInstrCopyin, dataOffset+1, execArgConst, 2|1<<8, 0x42,
+ execInstrCopyin, dataOffset+3, execArgConst, 4|1<<8, 0x42,
+ execInstrCopyin, dataOffset+7, execArgConst, 8|1<<8, 0x42,
+ callID("test$end0"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$end1(&(0x7f0000000000)={0xe, 0x42, 0x1})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2 | 1<<8, 0xe,
- execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x42,
- execInstrCopyin, dataOffset + 6, execArgConst, 8 | 1<<8, 0x1,
- callID("test$end1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2|1<<8, 0xe,
+ execInstrCopyin, dataOffset+2, execArgConst, 4|1<<8, 0x42,
+ execInstrCopyin, dataOffset+6, execArgConst, 8|1<<8, 0x1,
+ callID("test$end1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$bf0(&(0x7f0000000000)={0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2 | 0<<16 | 10<<24, 0x42,
- execInstrCopyin, dataOffset + 8, execArgConst, 8, 0x42,
- execInstrCopyin, dataOffset + 16, execArgConst, 2 | 0<<16 | 5<<24, 0x42,
- execInstrCopyin, dataOffset + 16, execArgConst, 2 | 5<<16 | 6<<24, 0x42,
- execInstrCopyin, dataOffset + 16, execArgConst, 4 | 11<<16 | 15<<24, 0x42,
- execInstrCopyin, dataOffset + 20, execArgConst, 2 | 0<<16 | 11<<24, 0x42,
- execInstrCopyin, dataOffset + 22, execArgConst, 2 | 1<<8 | 0<<16 | 11<<24, 0x42,
- execInstrCopyin, dataOffset + 24, execArgConst, 1, 0x42,
- callID("test$bf0"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2|0<<16|10<<24, 0x42,
+ execInstrCopyin, dataOffset+8, execArgConst, 8, 0x42,
+ execInstrCopyin, dataOffset+16, execArgConst, 2|0<<16|5<<24, 0x42,
+ execInstrCopyin, dataOffset+16, execArgConst, 2|5<<16|6<<24, 0x42,
+ execInstrCopyin, dataOffset+16, execArgConst, 4|11<<16|15<<24, 0x42,
+ execInstrCopyin, dataOffset+20, execArgConst, 2|0<<16|11<<24, 0x42,
+ execInstrCopyin, dataOffset+22, execArgConst, 2|1<<8|0<<16|11<<24, 0x42,
+ execInstrCopyin, dataOffset+24, execArgConst, 1, 0x42,
+ callID("test$bf0"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
&ExecProg{
Calls: []ExecCall{
{
@@ -281,6 +331,7 @@ func TestSerializeForExec(t *testing.T) {
Value: dataOffset,
},
},
+ Props: DefaultCallProps(),
Copyin: []ExecCopyin{
{
Addr: dataOffset + 0,
@@ -358,108 +409,118 @@ func TestSerializeForExec(t *testing.T) {
},
{
"test$bf1(&(0x7f0000000000)={{0x42, 0x42, 0x42}, 0x42})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 4 | 0<<16 | 10<<24, 0x42,
- execInstrCopyin, dataOffset + 0, execArgConst, 4 | 10<<16 | 10<<24, 0x42,
- execInstrCopyin, dataOffset + 0, execArgConst, 4 | 20<<16 | 10<<24, 0x42,
- execInstrCopyin, dataOffset + 4, execArgConst, 1, 0x42,
- callID("test$bf1"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 4|0<<16|10<<24, 0x42,
+ execInstrCopyin, dataOffset+0, execArgConst, 4|10<<16|10<<24, 0x42,
+ execInstrCopyin, dataOffset+0, execArgConst, 4|20<<16|10<<24, 0x42,
+ execInstrCopyin, dataOffset+4, execArgConst, 1, 0x42,
+ callID("test$bf1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$res1(0xffff)",
- []uint64{
- callID("test$res1"), ExecNoCopyout, 1, execArgConst, 4, 0xffff,
+ join(
+ callID("test$res1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, 4, 0xffff,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$opt3(0x0)",
- []uint64{
- callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8 | 4<<32, 0x64,
+ join(
+ callID("test$opt3"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, 8|4<<32, 0x64,
execInstrEOF,
- },
+ ),
nil,
},
{
// Special value that translates to 0 for all procs.
"test$opt3(0xffffffffffffffff)",
- []uint64{
- callID("test$opt3"), ExecNoCopyout, 1, execArgConst, 8, 0,
+ join(
+ callID("test$opt3"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, 8, 0,
execInstrEOF,
- },
+ ),
nil,
},
{
// NULL pointer must be encoded os 0.
"test$opt1(0x0)",
- []uint64{
- callID("test$opt1"), ExecNoCopyout, 1, execArgConst, 8, 0,
+ join(
+ callID("test$opt1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, 8, 0,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$align7(&(0x7f0000000000)={{0x1, 0x2, 0x3, 0x4, 0x5, 0x6}, 0x42})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 1 | 0<<16 | 1<<24, 0x1,
- execInstrCopyin, dataOffset + 0, execArgConst, 1 | 1<<16 | 1<<24, 0x2,
- execInstrCopyin, dataOffset + 0, execArgConst, 1 | 2<<16 | 1<<24, 0x3,
- execInstrCopyin, dataOffset + 0, execArgConst, 2 | 3<<16 | 1<<24, 0x4,
- execInstrCopyin, dataOffset + 0, execArgConst, 2 | 4<<16 | 1<<24, 0x5,
- execInstrCopyin, dataOffset + 0, execArgConst, 2 | 5<<16 | 1<<24, 0x6,
- execInstrCopyin, dataOffset + 8, execArgConst, 1, 0x42,
- callID("test$align7"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 1|0<<16|1<<24, 0x1,
+ execInstrCopyin, dataOffset+0, execArgConst, 1|1<<16|1<<24, 0x2,
+ execInstrCopyin, dataOffset+0, execArgConst, 1|2<<16|1<<24, 0x3,
+ execInstrCopyin, dataOffset+0, execArgConst, 2|3<<16|1<<24, 0x4,
+ execInstrCopyin, dataOffset+0, execArgConst, 2|4<<16|1<<24, 0x5,
+ execInstrCopyin, dataOffset+0, execArgConst, 2|5<<16|1<<24, 0x6,
+ execInstrCopyin, dataOffset+8, execArgConst, 1, 0x42,
+ callID("test$align7"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$excessive_fields1(0x0)",
- []uint64{
- callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x0,
+ join(
+ callID("test$excessive_fields1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, 0x0,
execInstrEOF,
- },
+ ),
nil,
},
{
"test$excessive_fields1(0xffffffffffffffff)",
- []uint64{
- callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0xffffffffffffffff,
+ join(
+ callID("test$excessive_fields1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0xffffffffffffffff),
execInstrEOF,
- },
+ ),
nil,
},
{
"test$excessive_fields1(0xfffffffffffffffe)",
- []uint64{
- callID("test$excessive_fields1"), ExecNoCopyout, 1, execArgConst, ptrSize, 0x9999999999999999,
+ join(
+ callID("test$excessive_fields1"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, uint64(0x9999999999999999),
execInstrEOF,
- },
+ ),
nil,
},
{
"test$csum_ipv4_tcp(&(0x7f0000000000)={{0x0, 0x1, 0x2}, {{0x0}, \"ab\"}})",
- []uint64{
- execInstrCopyin, dataOffset + 0, execArgConst, 2, 0x0,
- execInstrCopyin, dataOffset + 2, execArgConst, 4 | 1<<8, 0x1,
- execInstrCopyin, dataOffset + 6, execArgConst, 4 | 1<<8, 0x2,
- execInstrCopyin, dataOffset + 10, execArgConst, 2, 0x0,
- execInstrCopyin, dataOffset + 12, execArgData, 1, letoh64(0xab),
- execInstrCopyin, dataOffset + 10, execArgCsum, 2, ExecArgCsumInet, 5,
- ExecArgCsumChunkData, dataOffset + 2, 4,
- ExecArgCsumChunkData, dataOffset + 6, 4,
+ join(
+ execInstrCopyin, dataOffset+0, execArgConst, 2, 0x0,
+ execInstrCopyin, dataOffset+2, execArgConst, 4|1<<8, 0x1,
+ execInstrCopyin, dataOffset+6, execArgConst, 4|1<<8, 0x2,
+ execInstrCopyin, dataOffset+10, execArgConst, 2, 0x0,
+ execInstrCopyin, dataOffset+12, execArgData, 1, letoh64(0xab),
+ execInstrCopyin, dataOffset+10, execArgCsum, 2, ExecArgCsumInet, 5,
+ ExecArgCsumChunkData, dataOffset+2, 4,
+ ExecArgCsumChunkData, dataOffset+6, 4,
ExecArgCsumChunkConst, 0x0600, 2,
ExecArgCsumChunkConst, 0x0300, 2,
- ExecArgCsumChunkData, dataOffset + 10, 3,
- execInstrCopyin, dataOffset + 0, execArgCsum, 2, ExecArgCsumInet, 1,
- ExecArgCsumChunkData, dataOffset + 0, 10,
- callID("test$csum_ipv4_tcp"), ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
+ ExecArgCsumChunkData, dataOffset+10, 3,
+ execInstrCopyin, dataOffset+0, execArgCsum, 2, ExecArgCsumInet, 1,
+ ExecArgCsumChunkData, dataOffset+0, 10,
+ callID("test$csum_ipv4_tcp"), defaultCallPropsSlice,
+ ExecNoCopyout, 1, execArgConst, ptrSize, dataOffset,
execInstrEOF,
- },
+ ),
nil,
},
}
@@ -530,7 +591,7 @@ func TestSerializeForExecOverflow(t *testing.T) {
overflow: false,
gen: func(w *bytes.Buffer) {
fmt.Fprintf(w, "r0 = test$res0()\n")
- for i := 0; i < 58e3; i++ {
+ for i := 0; i < 42e3; i++ {
fmt.Fprintf(w, "test$res1(r0)\n")
}
},
diff --git a/prog/prog.go b/prog/prog.go
index 576348085..6ead4d47e 100644
--- a/prog/prog.go
+++ b/prog/prog.go
@@ -5,6 +5,7 @@ package prog
import (
"fmt"
+ "reflect"
)
type Prog struct {
@@ -13,18 +14,34 @@ type Prog struct {
Comments []string
}
+// These properties are parsed and serialized according to the tag and the type
+// of the corresponding fields.
+// IMPORTANT: keep the exact values of "key" tag for existing props unchanged,
+// otherwise the backwards compatibility would be broken.
+type CallProps struct {
+ FailNth int `key:"fail_nth"`
+}
+
+func DefaultCallProps() CallProps {
+ return CallProps{
+ FailNth: -1,
+ }
+}
+
type Call struct {
Meta *Syscall
Args []Arg
Ret *ResultArg
+ Props CallProps
Comment string
}
func MakeCall(meta *Syscall, args []Arg) *Call {
return &Call{
- Meta: meta,
- Args: args,
- Ret: MakeReturnArg(meta.Ret),
+ Meta: meta,
+ Args: args,
+ Ret: MakeReturnArg(meta.Ret),
+ Props: DefaultCallProps(),
}
}
@@ -420,3 +437,14 @@ func (p *Prog) sanitize(fix bool) error {
}
return nil
}
+
+// TODO: This method might be more generic - it can be applied to any struct.
+func (props *CallProps) ForeachProp(f func(fieldName, key string, value reflect.Value)) {
+ valueObj := reflect.ValueOf(props).Elem()
+ typeObj := valueObj.Type()
+ for i := 0; i < valueObj.NumField(); i++ {
+ fieldValue := valueObj.Field(i)
+ fieldType := typeObj.Field(i)
+ f(fieldType.Name, fieldType.Tag.Get("key"), fieldValue)
+ }
+}
diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go
index 35bea4f3b..fbff765cc 100644
--- a/sys/syz-sysgen/sysgen.go
+++ b/sys/syz-sysgen/sysgen.go
@@ -51,9 +51,15 @@ type OSData struct {
Archs []ArchData
}
+type CallPropDescription struct {
+ Type string
+ Name string
+}
+
type ExecutorData struct {
OSes []OSData
CallAttrs []string
+ CallProps []CallPropDescription
}
var srcDir = flag.String("src", "", "path to root of syzkaller source dir")
@@ -181,6 +187,14 @@ func main() {
data.CallAttrs = append(data.CallAttrs, prog.CppName(attrs.Field(i).Name))
}
+ defaultProps := prog.DefaultCallProps()
+ defaultProps.ForeachProp(func(name, _ string, value reflect.Value) {
+ data.CallProps = append(data.CallProps, CallPropDescription{
+ Type: value.Kind().String(),
+ Name: prog.CppName(name),
+ })
+ })
+
writeExecutorSyscalls(data)
}
@@ -326,6 +340,15 @@ var defsTempl = template.Must(template.New("").Parse(`// AUTOGENERATED FILE
struct call_attrs_t { {{range $attr := $.CallAttrs}}
uint64_t {{$attr}};{{end}}
};
+
+struct call_props_t { {{range $attr := $.CallProps}}
+ {{$attr.Type}} {{$attr.Name}};{{end}}
+};
+
+#define read_call_props_t(var, reader) { \{{range $attr := $.CallProps}}
+ (var).{{$attr.Name}} = ({{$attr.Type}})(reader); \{{end}}
+}
+
{{range $os := $.OSes}}
#if GOOS_{{$os.GOOS}}
#define GOOS "{{$os.GOOS}}"