Example #1
0
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
}
Example #2
0
// 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)
	}
}