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 }
// BreakpointCommand implements the debugger command: // breakpoint [*fn* | line [column] // which sets a breakpoint. // // The target can either be a function name as fn pkg.fn // or a line and and optional column number. Specifying a column number // may be useful if there is more than one statement on a line or if you // want to distinguish parts of a compound statement. // // See also "info break", "enable", and "disable" and "delete". func BreakpointCommand(args []string) { if len(args) == 1 { InfoBreakpointSubcmd(args) return } name := args[1] fn := gub.GetFunction(name) if fn != nil { if ext := interp.Externals()[name]; ext != nil { gub.Msg("Sorry, %s is a built-in external function.", name) return } interp.SetFnBreakpoint(fn) bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: fn.Pos(), EndP: fn.EndP(), Ignore: 0, Kind: "Function", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) gub.Msg(" Breakpoint %d set in function %s at %s", bpnum, name, ssa2.FmtRange(fn, fn.Pos(), fn.EndP())) return } line, ok := strconv.Atoi(args[1]) if ok != nil { gub.Errmsg("Don't know yet how to deal with a break that doesn't start with a function or integer") return } column := -1 if len(args) == 3 { foo, ok := strconv.Atoi(args[2]) if ok != nil { gub.Errmsg("Don't know how to deal a non-int argument as 2nd parameter yet") return } column = foo } fn = gub.CurFrame().Fn() fset := gub.CurFrame().Fset() position := gub.CurFrame().Position() if position.IsValid() { filename := position.Filename for _, l := range fn.Pkg.Locs() { try := fset.Position(l.Pos()) if try.Filename == filename && line == try.Line { if column == -1 || column == try.Column { bp := &gub.Breakpoint { Hits: 0, Id: gub.BreakpointNext(), Pos: l.Pos(), EndP: l.Pos(), Ignore: 0, Kind: "Statement", Temp: false, Enabled: true, } bpnum := gub.BreakpointAdd(bp) if l.Trace != nil { l.Trace.Breakpoint = true } else if l.Fn != nil { l.Fn.Breakpoint = true bp.Kind = "Function" } else { gub.Errmsg("Internal error setting in file %s line %d, column %d", bpnum, filename, line, try.Column) return } gub.Msg("Breakpoint %d set in file %s line %d, column %d", bpnum, filename, line, try.Column) return } } } suffix := "" if column != -1 { suffix = ", column " + args[2] } gub.Errmsg("Can't find statement in file %s at line %d%s", filename, line, suffix) } }