github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/cmd/ssadump/main.go (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // +build go1.5
     6  
     7  // ssadump: a tool for displaying and interpreting the SSA form of Go programs.
     8  package main // import "golang.org/x/tools/cmd/ssadump"
     9  
    10  import (
    11  	"flag"
    12  	"fmt"
    13  	"go/build"
    14  	"go/types"
    15  	"os"
    16  	"runtime"
    17  	"runtime/pprof"
    18  
    19  	"golang.org/x/tools/go/buildutil"
    20  	"golang.org/x/tools/go/loader"
    21  	"golang.org/x/tools/go/ssa"
    22  	"golang.org/x/tools/go/ssa/interp"
    23  	"golang.org/x/tools/go/ssa/ssautil"
    24  )
    25  
    26  var (
    27  	modeFlag = ssa.BuilderModeFlag(flag.CommandLine, "build", 0)
    28  
    29  	testFlag = flag.Bool("test", false, "Loads test code (*_test.go) for imported packages.")
    30  
    31  	runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
    32  
    33  	interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
    34  The value is a sequence of zero or more more of these letters:
    35  R	disable [R]ecover() from panic; show interpreter crash instead.
    36  T	[T]race execution of the program.  Best for single-threaded programs!
    37  `)
    38  )
    39  
    40  const usage = `SSA builder and interpreter.
    41  Usage: ssadump [<flag> ...] <args> ...
    42  Use -help flag to display options.
    43  
    44  Examples:
    45  % ssadump -build=F hello.go              # dump SSA form of a single package
    46  % ssadump -run -interp=T hello.go        # interpret a program, with tracing
    47  % ssadump -run -test unicode -- -test.v  # interpret the unicode package's tests, verbosely
    48  ` + loader.FromArgsUsage +
    49  	`
    50  When -run is specified, ssadump will run the program.
    51  The entry point depends on the -test flag:
    52  if clear, it runs the first package named main.
    53  if set, it runs the tests of each package.
    54  `
    55  
    56  var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
    57  
    58  func init() {
    59  	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
    60  
    61  	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
    62  	// For small machines, use at least 4 threads.
    63  	if os.Getenv("GOMAXPROCS") == "" {
    64  		n := runtime.NumCPU()
    65  		if n < 4 {
    66  			n = 4
    67  		}
    68  		runtime.GOMAXPROCS(n)
    69  	}
    70  }
    71  
    72  func main() {
    73  	if err := doMain(); err != nil {
    74  		fmt.Fprintf(os.Stderr, "ssadump: %s\n", err)
    75  		os.Exit(1)
    76  	}
    77  }
    78  
    79  func doMain() error {
    80  	flag.Parse()
    81  	args := flag.Args()
    82  
    83  	conf := loader.Config{Build: &build.Default}
    84  
    85  	// Choose types.Sizes from conf.Build.
    86  	var wordSize int64 = 8
    87  	switch conf.Build.GOARCH {
    88  	case "386", "arm":
    89  		wordSize = 4
    90  	}
    91  	conf.TypeChecker.Sizes = &types.StdSizes{
    92  		MaxAlign: 8,
    93  		WordSize: wordSize,
    94  	}
    95  
    96  	var interpMode interp.Mode
    97  	for _, c := range *interpFlag {
    98  		switch c {
    99  		case 'T':
   100  			interpMode |= interp.EnableTracing
   101  		case 'R':
   102  			interpMode |= interp.DisableRecover
   103  		default:
   104  			return fmt.Errorf("unknown -interp option: '%c'", c)
   105  		}
   106  	}
   107  
   108  	if len(args) == 0 {
   109  		fmt.Fprint(os.Stderr, usage)
   110  		os.Exit(1)
   111  	}
   112  
   113  	// Profiling support.
   114  	if *cpuprofile != "" {
   115  		f, err := os.Create(*cpuprofile)
   116  		if err != nil {
   117  			fmt.Fprintln(os.Stderr, err)
   118  			os.Exit(1)
   119  		}
   120  		pprof.StartCPUProfile(f)
   121  		defer pprof.StopCPUProfile()
   122  	}
   123  
   124  	// Use the initial packages from the command line.
   125  	args, err := conf.FromArgs(args, *testFlag)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	// The interpreter needs the runtime package.
   131  	if *runFlag {
   132  		conf.Import("runtime")
   133  	}
   134  
   135  	// Load, parse and type-check the whole program.
   136  	iprog, err := conf.Load()
   137  	if err != nil {
   138  		return err
   139  	}
   140  
   141  	// Create and build SSA-form program representation.
   142  	prog := ssautil.CreateProgram(iprog, *modeFlag)
   143  
   144  	// Build and display only the initial packages
   145  	// (and synthetic wrappers), unless -run is specified.
   146  	for _, info := range iprog.InitialPackages() {
   147  		prog.Package(info.Pkg).Build()
   148  	}
   149  
   150  	// Run the interpreter.
   151  	if *runFlag {
   152  		prog.Build()
   153  
   154  		var main *ssa.Package
   155  		pkgs := prog.AllPackages()
   156  		if *testFlag {
   157  			// If -test, run all packages' tests.
   158  			if len(pkgs) > 0 {
   159  				main = prog.CreateTestMainPackage(pkgs...)
   160  			}
   161  			if main == nil {
   162  				return fmt.Errorf("no tests")
   163  			}
   164  		} else {
   165  			// Otherwise, run main.main.
   166  			for _, pkg := range pkgs {
   167  				if pkg.Pkg.Name() == "main" {
   168  					main = pkg
   169  					if main.Func("main") == nil {
   170  						return fmt.Errorf("no func main() in main package")
   171  					}
   172  					break
   173  				}
   174  			}
   175  			if main == nil {
   176  				return fmt.Errorf("no main package")
   177  			}
   178  		}
   179  
   180  		if runtime.GOARCH != build.Default.GOARCH {
   181  			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
   182  				build.Default.GOARCH, runtime.GOARCH)
   183  		}
   184  
   185  		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Pkg.Path(), args)
   186  	}
   187  	return nil
   188  }