diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2015-10-12 10:16:57 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2015-10-12 10:16:57 +0200 |
| commit | 874c5754bb22dbf77d6b600ff91f0f4f1fc5073a (patch) | |
| tree | 0075fbd088046ad5c86e6e972235701d68b3ce7c /tools | |
initial commit
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/execlog/execlog.go | 83 | ||||
| -rw-r--r-- | tools/execprog/execprog.go | 62 | ||||
| -rw-r--r-- | tools/prog2c/prog2c.go | 31 | ||||
| -rw-r--r-- | tools/stress/stress.go | 104 |
4 files changed, 280 insertions, 0 deletions
diff --git a/tools/execlog/execlog.go b/tools/execlog/execlog.go new file mode 100644 index 000000000..5d39bb955 --- /dev/null +++ b/tools/execlog/execlog.go @@ -0,0 +1,83 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +// execlog executes all programs from a log (for non-reproducible crashes). +package main + +import ( + "bufio" + "flag" + "log" + "os" + "strings" + "sync/atomic" + "time" + + "github.com/google/syzkaller/ipc" + "github.com/google/syzkaller/prog" +) + +var ( + flagExecutor = flag.String("executor", "", "path to executor binary") + flagLog = flag.String("log", "", "comma-delimited list of log files to execute") +) + +func main() { + flag.Parse() + var progs [][]byte + for _, fn := range strings.Split(*flagLog, ",") { + logf, err := os.Open(fn) + if err != nil { + log.Fatalf("failed to open log file: %v", err) + } + log.Printf("parsing log %v", fn) + s := bufio.NewScanner(logf) + var cur []byte + var last *prog.Prog + for s.Scan() { + ln := s.Text() + tmp := append(cur, ln...) + tmp = append(tmp, '\n') + p, err := prog.Deserialize(tmp) + if err == nil { + cur = tmp + last = p + continue + } + if last != nil { + progs = append(progs, last.SerializeForExec()) + last = nil + cur = cur[:0] + } + } + if last != nil { + progs = append(progs, last.SerializeForExec()) + } + } + log.Printf("parsed %v programs", len(progs)) + if len(progs) == 0 { + return + } + + var pos uint32 + for p := 0; p < 16; p++ { + go func() { + env, err := ipc.MakeEnv(*flagExecutor, 5*time.Second, 0) + if err != nil { + log.Fatalf("failed to create ipc env: %v", err) + } + for { + idx := int(atomic.AddUint32(&pos, 1) - 1) + if idx%1000 == 0 { + log.Printf("executing %v\n", idx) + } + copy(env.In, progs[idx%len(progs)]) + _, _, _, _, err := env.Exec() + if err != nil { + log.Printf("failed to execute program: %v", err) + } + } + }() + } + select {} +} diff --git a/tools/execprog/execprog.go b/tools/execprog/execprog.go new file mode 100644 index 000000000..9ffe39119 --- /dev/null +++ b/tools/execprog/execprog.go @@ -0,0 +1,62 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "time" + + "github.com/google/syzkaller/ipc" + "github.com/google/syzkaller/prog" +) + +var ( + flagExecutor = flag.String("executor", "", "path to executor binary") + flagProg = flag.String("prog", "", "file with a program to execute") + flagThreaded = flag.Bool("threaded", false, "use threaded mode in executor") + flagDebug = flag.Bool("debug", true, "debug output from executor") + flagStrace = flag.Bool("strace", false, "run executor under strace") + flagCover = flag.Bool("cover", false, "collect coverage") +) + +func main() { + flag.Parse() + data, err := ioutil.ReadFile(*flagProg) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err) + os.Exit(1) + } + p, err := prog.Deserialize(data) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err) + os.Exit(1) + } + var flags uint64 + if *flagThreaded { + flags |= ipc.FlagThreaded + } + if *flagDebug { + flags |= ipc.FlagDebug + } + if *flagStrace { + flags |= ipc.FlagStrace + } + if *flagCover { + flags |= ipc.FlagCover + } + env, err := ipc.MakeEnv(*flagExecutor, 3*time.Second, flags) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err) + os.Exit(1) + } + copy(env.In, p.SerializeForExec()) + output, strace, failed, hanged, err := env.Exec() + fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) + if *flagStrace { + fmt.Printf("strace output:\n%s", strace) + } +} diff --git a/tools/prog2c/prog2c.go b/tools/prog2c/prog2c.go new file mode 100644 index 000000000..9b8e58efa --- /dev/null +++ b/tools/prog2c/prog2c.go @@ -0,0 +1,31 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/google/syzkaller/prog" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "usage: prog2c prog_file\n") + os.Exit(1) + } + data, err := ioutil.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err) + os.Exit(1) + } + p, err := prog.Deserialize(data) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err) + os.Exit(1) + } + src := p.WriteCSource() + os.Stdout.Write(src) +} diff --git a/tools/stress/stress.go b/tools/stress/stress.go new file mode 100644 index 000000000..5b84e81b4 --- /dev/null +++ b/tools/stress/stress.go @@ -0,0 +1,104 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "math/rand" + "os" + "path/filepath" + "regexp" + "time" + + "github.com/google/syzkaller/ipc" + "github.com/google/syzkaller/prog" +) + +var ( + flagCorpus = flag.String("corpus", "", "corpus directory") + flagExecutor = flag.String("executor", "", "path to executor binary") + flagOutput = flag.Bool("output", false, "print executor output to console") + flagDebug = flag.Bool("debug", false, "executor debug output") + + failedRe = regexp.MustCompile("runtime error: |panic: ") +) + +func main() { + flag.Parse() + corpus := readCorpus() + flags := ipc.FlagThreaded + if *flagDebug { + flags |= ipc.FlagDebug + } + env, err := ipc.MakeEnv(*flagExecutor, 5*time.Second, flags) + if err != nil { + failf("failed to create execution environment: %v", err) + } + rs := rand.NewSource(time.Now().UnixNano()) + rnd := rand.New(rs) + for i := 0; ; i++ { + var p *prog.Prog + if len(corpus) == 0 || i%10 != 0 { + p = prog.Generate(rs, 50, nil) + execute(env, p) + p.Mutate(rs, 50, nil) + execute(env, p) + } else { + p = corpus[rnd.Intn(len(corpus))].Clone() + p.Mutate(rs, 50, nil) + execute(env, p) + } + } +} + +func execute(env *ipc.Env, p *prog.Prog) { + if *flagExecutor == "" { + return + } + copy(env.In, p.SerializeForExec()) + output, _, _, _, err := env.Exec() + if err != nil { + fmt.Printf("failed to execute executor: %v\n", err) + } + failed := failedRe.Match(output) + if failed { + fmt.Printf("PROGRAM:\n%s\n", p.Serialize()) + } + if failed || *flagOutput { + os.Stdout.Write(output) + } +} + +func readCorpus() []*prog.Prog { + if *flagCorpus == "" { + return nil + } + files, err := ioutil.ReadDir(*flagCorpus) + if err != nil { + failf("failed to read corpus dir: %v", err) + } + var progs []*prog.Prog + for _, f := range files { + if f.IsDir() { + continue + } + data, err := ioutil.ReadFile(filepath.Join(*flagCorpus, f.Name())) + if err != nil { + failf("failed to read corpus file: %v", err) + } + p, err := prog.Deserialize(data) + if err != nil { + failf("failed to deserialize corpus program: %v", err) + } + progs = append(progs, p) + } + return progs +} + +func failf(msg string, args ...interface{}) { + log.Fatalf(msg, args...) +} |
