func run(t *testing.T, dir, input string, success successPredicate) bool { fmt.Printf("Input: %s\n", input) start := time.Now() var inputs []string for _, i := range strings.Split(input, " ") { if strings.HasSuffix(i, ".go") { i = dir + i } inputs = append(inputs, i) } conf := loader.Config{SourceImports: true} if _, err := conf.FromArgs(inputs, true); err != nil { t.Errorf("FromArgs(%s) failed: %s", inputs, err) return false } conf.Import("runtime") // Print a helpful hint if we don't make it to the end. var hint string defer func() { if hint != "" { fmt.Println("FAIL") fmt.Println(hint) } else { fmt.Println("PASS") } interp.CapturedOutput = nil }() hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input) iprog, err := conf.Load() if err != nil { t.Errorf("conf.Load(%s) failed: %s", inputs, err) return false } prog := ssa2.Create(iprog, ssa2.SanityCheckFunctions) prog.BuildAll() var mainPkg *ssa2.Package var initialPkgs []*ssa2.Package for _, info := range iprog.InitialPackages() { if info.Pkg.Path() == "runtime" { continue // not an initial package } p := prog.Package(info.Pkg) initialPkgs = append(initialPkgs, p) if mainPkg == nil && p.Func("main") != nil { mainPkg = p } } if mainPkg == nil { testmainPkg := prog.CreateTestMainPackage(initialPkgs...) if testmainPkg == nil { t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg) return false } if testmainPkg.Func("main") == nil { t.Errorf("synthetic testmain package has no main") return false } mainPkg = testmainPkg } var out bytes.Buffer interp.CapturedOutput = &out hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input) exitCode := interp.Interpret(mainPkg, 0, 0, &types.StdSizes{8, 8}, inputs[0], []string{}) // The definition of success varies with each file. if err := success(exitCode, out.String()); err != nil { t.Errorf("interp.Interpret(%s) failed: %s", inputs, err) return false } hint = "" // call off the hounds if false { fmt.Println(input, time.Since(start)) // test profiling } return true }
func doMain() error { restart_args := os.Args flag.Parse() args := flag.Args() conf := loader.Config{ Build: &build.Default, SourceImports: true, } // TODO(adonovan): make go/types choose its default Sizes from // build.Default or a specified *build.Context. var wordSize int64 = 8 switch conf.Build.GOARCH { case "386", "arm": wordSize = 4 } conf.TypeChecker.Sizes = &types.StdSizes{ MaxAlign: 8, WordSize: wordSize, } var mode ssa2.BuilderMode = ssa2.NaiveForm for _, c := range *buildFlag { switch c { case 'D': mode |= ssa2.GlobalDebug case 'P': mode |= ssa2.PrintPackages case 'F': mode |= ssa2.PrintFunctions case 'S': mode |= ssa2.LogSource | ssa2.BuildSerially case 'C': mode |= ssa2.SanityCheckFunctions case 'G': conf.SourceImports = false case 'L': mode |= ssa2.BuildSerially case 'I': mode |= ssa2.BareInits default: return fmt.Errorf("unknown -build option: '%c'", c) } } var interpMode interp.Mode var interpTraceMode interp.TraceMode for _, c := range *interpFlag { switch c { case 'I': interpTraceMode |= interp.EnableInitTracing case 'R': interpMode |= interp.DisableRecover case 'S': interpTraceMode |= interp.EnableStmtTracing mode |= ssa2.GlobalDebug case 'T': interpTraceMode |= interp.EnableTracing default: return fmt.Errorf("unknown -interp option: '%c'", c) } } if len(args) == 0 { fmt.Fprint(os.Stderr, usage) os.Exit(1) } // Profiling support. if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // Use the initial packages from the command line. prog_args := args[1:] args, err := conf.FromArgs(args[0:1], *testFlag) if err != nil { return err } // The interpreter needs the runtime package. if *runFlag { conf.Import("runtime") } // Load, parse and type-check the whole program. iprog, err := conf.Load() if err != nil { return err } // Create and build SSA-form program representation. prog := ssa2.Create(iprog, mode) prog.BuildAll() // Run the interpreter. if *runFlag { var main *ssa2.Package pkgs := prog.AllPackages() if *testFlag { // If -test, run all packages' tests. if len(pkgs) > 0 { main = prog.CreateTestMainPackage(pkgs...) } if main == nil { return fmt.Errorf("no tests") } } else { // Otherwise, run main.main. for _, pkg := range pkgs { if pkg.Object.Name() == "main" { main = pkg if main.Func("main") == nil { return fmt.Errorf("no func main() in main package") } break } } if main == nil { return fmt.Errorf("no main package") } } if interpTraceMode&interp.EnableStmtTracing != 0 { gubcmd.Init(gubFlag, restart_args, main.Prog) fn := main.Func("main") if fn != nil { /* Set a breakpoint on the main routine */ interp.SetFnBreakpoint(fn) bp := &gub.Breakpoint{ Hits: 0, Id: gub.BreakpointNext(), Pos: fn.Pos(), EndP: fn.EndP(), Ignore: 0, Kind: "Function", Temp: true, Enabled: true, } gub.BreakpointAdd(bp) } } else if prog.PackagesByPath["github.com/rocky/ssa-interp/trepan"] != nil { fmt.Println("I see you've got trepan imported...") gubcmd.Init(gubFlag, restart_args, main.Prog) } fmt.Println("Running....") if runtime.GOARCH != build.Default.GOARCH { return fmt.Errorf("cross-interpretation is not yet supported (target has GOARCH %s, interpreter has %s)", build.Default.GOARCH, runtime.GOARCH) } interp.Interpret(main, interpMode, interpTraceMode, conf.TypeChecker.Sizes, main.Object.Path(), prog_args) } else { fmt.Println(`Built ok, but not running because "-run" option not given`) } return nil }