From 52a33fd516102a98d3753bf69417235b655a68dc Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Thu, 14 Sep 2017 19:25:01 +0200 Subject: prog: remove default target and all global state Now each prog function accepts the desired target explicitly. No global, implicit state involved. This is much cleaner and allows cross-OS/arch testing, etc. --- pkg/csource/csource.go | 6 +++--- pkg/csource/csource_test.go | 24 ++++++++++++------------ pkg/host/host.go | 4 ++-- pkg/host/host_test.go | 24 ++++++++++++++---------- pkg/ipc/ipc_test.go | 11 ++++++----- pkg/repro/repro.go | 6 +++++- 6 files changed, 42 insertions(+), 33 deletions(-) (limited to 'pkg') diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index e1b32e752..8b7c84ad3 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -101,7 +101,7 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { fmt.Fprint(w, hdr) fmt.Fprint(w, "\n") - calls, nvar := generateCalls(exec, opts) + calls, nvar := generateCalls(p.Target, exec, opts) fmt.Fprintf(w, "long r[%v];\n", nvar) if !opts.Repeat { @@ -258,7 +258,7 @@ func generateTestFunc(w io.Writer, opts Options, calls []string, name string) { } } -func generateCalls(exec []byte, opts Options) ([]string, int) { +func generateCalls(target *prog.Target, exec []byte, opts Options) ([]string, int) { read := func() uint64 { if len(exec) < 8 { panic("exec program overflow") @@ -367,7 +367,7 @@ loop: fmt.Fprintf(w, "\twrite_file(\"/sys/kernel/debug/fail_futex/ignore-private\", \"N\");\n") fmt.Fprintf(w, "\tinject_fault(%v);\n", opts.FaultNth) } - meta := prog.Syscalls[instr] + meta := target.Syscalls[instr] emitCall := true if meta.CallName == "syz_test" { emitCall = false diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index 941274cb9..c192566e3 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -17,17 +17,17 @@ import ( _ "github.com/google/syzkaller/sys" ) -func init() { - prog.SetDefaultTarget("linux", runtime.GOARCH) -} - -func initTest(t *testing.T) (rand.Source, int) { +func initTest(t *testing.T) (*prog.Target, rand.Source, int) { t.Parallel() iters := 1 seed := int64(time.Now().UnixNano()) rs := rand.NewSource(seed) t.Logf("seed=%v", seed) - return rs, iters + target, err := prog.GetTarget("linux", runtime.GOARCH) + if err != nil { + t.Fatal(err) + } + return target, rs, iters } func enumerateField(opt Options, field int) []Options { @@ -89,7 +89,7 @@ func allOptionsPermutations() []Options { } func TestOne(t *testing.T) { - rs, _ := initTest(t) + target, rs, _ := initTest(t) opts := Options{ Threaded: true, Collide: true, @@ -99,13 +99,13 @@ func TestOne(t *testing.T) { Repro: true, UseTmpDir: true, } - p := prog.GenerateAllSyzProg(rs) + p := target.GenerateAllSyzProg(rs) testOne(t, p, opts) } func TestOptions(t *testing.T) { - rs, _ := initTest(t) - syzProg := prog.GenerateAllSyzProg(rs) + target, rs, _ := initTest(t) + syzProg := target.GenerateAllSyzProg(rs) t.Logf("syz program:\n%s\n", syzProg.Serialize()) permutations := allOptionsSingle() allPermutations := allOptionsPermutations() @@ -119,10 +119,10 @@ func TestOptions(t *testing.T) { } for i, opts := range permutations { t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { - rs, iters := initTest(t) + target, rs, iters := initTest(t) t.Logf("opts: %+v", opts) for i := 0; i < iters; i++ { - p := prog.Generate(rs, 10, nil) + p := target.Generate(rs, 10, nil) testOne(t, p, opts) } testOne(t, syzProg, opts) diff --git a/pkg/host/host.go b/pkg/host/host.go index 0fa66dfa4..993db175b 100644 --- a/pkg/host/host.go +++ b/pkg/host/host.go @@ -16,7 +16,7 @@ import ( ) // DetectSupportedSyscalls returns list on supported syscalls on host. -func DetectSupportedSyscalls() (map[*prog.Syscall]bool, error) { +func DetectSupportedSyscalls(target *prog.Target) (map[*prog.Syscall]bool, error) { // There are 3 possible strategies: // 1. Executes all syscalls with presumably invalid arguments and check for ENOprog. // But not all syscalls are safe to execute. For example, pause will hang, @@ -29,7 +29,7 @@ func DetectSupportedSyscalls() (map[*prog.Syscall]bool, error) { kallsyms, _ := ioutil.ReadFile("/proc/kallsyms") supported := make(map[*prog.Syscall]bool) - for _, c := range prog.Syscalls { + for _, c := range target.Syscalls { if isSupported(kallsyms, c) { supported[c] = true } diff --git a/pkg/host/host_test.go b/pkg/host/host_test.go index a9130c094..1c40335d7 100644 --- a/pkg/host/host_test.go +++ b/pkg/host/host_test.go @@ -12,19 +12,19 @@ import ( _ "github.com/google/syzkaller/sys" ) -func init() { - prog.SetDefaultTarget("linux", runtime.GOARCH) -} - func TestLog(t *testing.T) { t.Parallel() + target, err := prog.GetTarget("linux", runtime.GOARCH) + if err != nil { + t.Fatal(err) + } // Dump for manual inspection. - supp, err := DetectSupportedSyscalls() + supp, err := DetectSupportedSyscalls(target) if err != nil { t.Skipf("skipping: %v", err) } t.Logf("unsupported:") - for _, c := range prog.Syscalls { + for _, c := range target.Syscalls { s, ok := supp[c] if ok && !s { t.Fatalf("map contains false value") @@ -33,9 +33,9 @@ func TestLog(t *testing.T) { t.Logf("\t%v", c.Name) } } - trans := prog.TransitivelyEnabledCalls(supp) + trans := target.TransitivelyEnabledCalls(supp) t.Logf("transitively unsupported:") - for _, c := range prog.Syscalls { + for _, c := range target.Syscalls { s, ok := trans[c] if ok && !s { t.Fatalf("map contains false value") @@ -48,7 +48,11 @@ func TestLog(t *testing.T) { func TestSupportedSyscalls(t *testing.T) { t.Parallel() - supp, err := DetectSupportedSyscalls() + target, err := prog.GetTarget("linux", runtime.GOARCH) + if err != nil { + t.Fatal(err) + } + supp, err := DetectSupportedSyscalls(target) if err != nil { t.Skipf("skipping: %v", err) } @@ -64,7 +68,7 @@ func TestSupportedSyscalls(t *testing.T) { "stat", } for _, name := range safe { - c := prog.SyscallMap[name] + c := target.SyscallMap[name] if c == nil { t.Fatalf("can't find syscall '%v'", name) } diff --git a/pkg/ipc/ipc_test.go b/pkg/ipc/ipc_test.go index ce04a7540..263e94032 100644 --- a/pkg/ipc/ipc_test.go +++ b/pkg/ipc/ipc_test.go @@ -19,10 +19,6 @@ import ( const timeout = 10 * time.Second -func init() { - prog.SetDefaultTarget("linux", runtime.GOARCH) -} - func buildExecutor(t *testing.T) string { return buildProgram(t, filepath.FromSlash("../../executor/executor.cc")) } @@ -87,6 +83,11 @@ func TestExecute(t *testing.T) { rs, iters := initTest(t) flags := []uint64{0, FlagThreaded, FlagThreaded | FlagCollide} + target, err := prog.GetTarget("linux", runtime.GOARCH) + if err != nil { + t.Fatal(err) + } + bin := buildExecutor(t) defer os.Remove(bin) @@ -103,7 +104,7 @@ func TestExecute(t *testing.T) { defer env.Close() for i := 0; i < iters/len(flags); i++ { - p := prog.Generate(rs, 10, nil) + p := target.Generate(rs, 10, nil) opts := &ExecOpts{} output, _, _, _, err := env.Exec(opts, p) if err != nil { diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index c3aaa8a22..4787b0262 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -65,7 +65,11 @@ func Run(crashLog []byte, cfg *mgrconfig.Config, vmPool *vm.Pool, vmIndexes []in if len(vmIndexes) == 0 { return nil, fmt.Errorf("no VMs provided") } - entries := prog.ParseLog(crashLog) + target, err := prog.GetTarget(cfg.TargetOS, cfg.TargetArch) + if err != nil { + return nil, err + } + entries := target.ParseLog(crashLog) if len(entries) == 0 { return nil, fmt.Errorf("crash log does not contain any programs") } -- cgit mrf-deployment