func main() { os.Args = append(append([]string{}, os.Args[0], "-v=10"), os.Args[1:]...) flag.Parse() cfg, _, err := config.Parse(*flagConfig) if err != nil { Fatalf("%v", err) } if *flagCount > 0 { cfg.Count = *flagCount } if cfg.Count > 4 { cfg.Count = 4 } if len(flag.Args()) != 1 { Fatalf("usage: syz-repro -config=config.file execution.log") } data, err := ioutil.ReadFile(flag.Args()[0]) if err != nil { Fatalf("failed to open log file: %v", err) } vmIndexes := make([]int, cfg.Count) for i := range vmIndexes { vmIndexes[i] = i } go func() { c := make(chan os.Signal, 2) signal.Notify(c, syscall.SIGINT) <-c close(vm.Shutdown) Logf(-1, "shutting down...") <-c Fatalf("terminating") }() res, err := repro.Run(data, cfg, vmIndexes) if err != nil { Logf(0, "reproduction failed: %v", err) } if res == nil { return } fmt.Printf("opts: %+v crepro: %v\n\n", res.Opts, res.CRepro) fmt.Printf("%s\n", res.Prog.Serialize()) if res.CRepro { src, err := csource.Write(res.Prog, res.Opts) if err != nil { Fatalf("failed to generate C repro: %v", err) } if formatted, err := csource.Format(src); err == nil { src = formatted } fmt.Printf("%s\n", src) } }
func (mgr *Manager) vmLoop() { Logf(0, "booting test machines...") reproInstances := 4 if reproInstances > mgr.cfg.Count { reproInstances = mgr.cfg.Count } instances := make([]int, mgr.cfg.Count) for i := range instances { instances[i] = mgr.cfg.Count - i - 1 } runDone := make(chan *RunResult, 1) pendingRepro := make(map[*Crash]bool) reproducing := make(map[string]bool) var reproQueue []*Crash reproDone := make(chan *ReproResult, 1) stopPending := false shutdown := vm.Shutdown for { for crash := range pendingRepro { if reproducing[crash.desc] { continue } delete(pendingRepro, crash) if !mgr.needRepro(crash.desc) { continue } Logf(1, "loop: add to repro queue '%v'", crash.desc) reproducing[crash.desc] = true reproQueue = append(reproQueue, crash) } Logf(1, "loop: shutdown=%v instances=%v/%v %+v repro: pending=%v reproducing=%v queued=%v", shutdown == nil, len(instances), mgr.cfg.Count, instances, len(pendingRepro), len(reproducing), len(reproQueue)) if shutdown == nil { if len(instances) == mgr.cfg.Count { return } } else { for len(reproQueue) != 0 && len(instances) >= reproInstances { last := len(reproQueue) - 1 crash := reproQueue[last] reproQueue[last] = nil reproQueue = reproQueue[:last] vmIndexes := append([]int{}, instances[len(instances)-reproInstances:]...) instances = instances[:len(instances)-reproInstances] Logf(1, "loop: starting repro of '%v' on instances %+v", crash.desc, vmIndexes) go func() { res, err := repro.Run(crash.output, mgr.cfg, vmIndexes) reproDone <- &ReproResult{vmIndexes, crash, res, err} }() } for len(reproQueue) == 0 && len(instances) != 0 { last := len(instances) - 1 idx := instances[last] instances = instances[:last] Logf(1, "loop: starting instance %v", idx) go func() { vmCfg, err := config.CreateVMConfig(mgr.cfg, idx) if err != nil { Fatalf("failed to create VM config: %v", err) } crash, err := mgr.runInstance(vmCfg, idx == 0) runDone <- &RunResult{idx, crash, err} }() } } var stopRequest chan bool if len(reproQueue) != 0 && !stopPending { stopRequest = mgr.vmStop } select { case stopRequest <- true: Logf(1, "loop: issued stop request") stopPending = true case res := <-runDone: Logf(1, "loop: instance %v finished, crash=%v", res.idx, res.crash != nil) if res.err != nil && shutdown != nil { Logf(0, "%v", res.err) } stopPending = false instances = append(instances, res.idx) // On shutdown qemu crashes with "qemu: terminating on signal 2", // which we detect as "lost connection". Don't save that as crash. if shutdown != nil && res.crash != nil && !mgr.isSuppressed(res.crash) { mgr.saveCrash(res.crash) if mgr.needRepro(res.crash.desc) { Logf(1, "loop: add pending repro for '%v'", res.crash.desc) pendingRepro[res.crash] = true } } case res := <-reproDone: crepro := false if res.res != nil { crepro = res.res.CRepro } Logf(1, "loop: repro on instances %+v finished '%v', repro=%v crepro=%v", res.instances, res.crash.desc, res.res != nil, crepro) if res.err != nil { Logf(0, "repro failed: %v", res.err) } delete(reproducing, res.crash.desc) instances = append(instances, res.instances...) mgr.saveRepro(res.crash, res.res) case <-shutdown: Logf(1, "loop: shutting down...") shutdown = nil } } }