github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/_vendor/src/golang.org/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  // ssadump: a tool for displaying and interpreting the SSA form of Go programs.
     6  package main // import "golang.org/x/tools/cmd/ssadump"
     7  
     8  import (
     9  	"flag"
    10  	"fmt"
    11  	"go/build"
    12  	"go/types"
    13  	"os"
    14  	"runtime"
    15  	"runtime/pprof"
    16  
    17  	"golang.org/x/tools/go/buildutil"
    18  	"golang.org/x/tools/go/loader"
    19  	"golang.org/x/tools/go/ssa"
    20  	"golang.org/x/tools/go/ssa/interp"
    21  	"golang.org/x/tools/go/ssa/ssautil"
    22  )
    23  
    24  // flags
    25  var (
    26  	mode = ssa.BuilderMode(0)
    27  
    28  	testFlag = flag.Bool("test", false, "Loads test code (*_test.go) for imported packages.")
    29  
    30  	runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
    31  
    32  	interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
    33  The value is a sequence of zero or more more of these letters:
    34  R	disable [R]ecover() from panic; show interpreter crash instead.
    35  T	[T]race execution of the program.  Best for single-threaded programs!
    36  `)
    37  
    38  	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
    39  )
    40  
    41  func init() {
    42  	flag.Var(&mode, "build", ssa.BuilderModeDoc)
    43  	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
    44  }
    45  
    46  const usage = `SSA builder and interpreter.
    47  Usage: ssadump [<flag> ...] <args> ...
    48  Use -help flag to display options.
    49  
    50  Examples:
    51  % ssadump -build=F hello.go              # dump SSA form of a single package
    52  % ssadump -build=F -test fmt             # dump SSA form of a package and its tests
    53  % ssadump -run -interp=T hello.go        # interpret a program, with tracing
    54  ` + loader.FromArgsUsage +
    55  	`
    56  The -run flag causes ssadump to run the first package named main.
    57  
    58  Interpretation of the standard "testing" package is no longer supported.
    59  `
    60  
    61  func main() {
    62  	if err := doMain(); err != nil {
    63  		fmt.Fprintf(os.Stderr, "ssadump: %s\n", err)
    64  		os.Exit(1)
    65  	}
    66  }
    67  
    68  func doMain() error {
    69  	flag.Parse()
    70  	args := flag.Args()
    71  
    72  	conf := loader.Config{Build: &build.Default}
    73  
    74  	// Choose types.Sizes from conf.Build.
    75  	var wordSize int64 = 8
    76  	switch conf.Build.GOARCH {
    77  	case "386", "arm":
    78  		wordSize = 4
    79  	}
    80  	conf.TypeChecker.Sizes = &types.StdSizes{
    81  		MaxAlign: 8,
    82  		WordSize: wordSize,
    83  	}
    84  
    85  	var interpMode interp.Mode
    86  	for _, c := range *interpFlag {
    87  		switch c {
    88  		case 'T':
    89  			interpMode |= interp.EnableTracing
    90  		case 'R':
    91  			interpMode |= interp.DisableRecover
    92  		default:
    93  			return fmt.Errorf("unknown -interp option: '%c'", c)
    94  		}
    95  	}
    96  
    97  	if len(args) == 0 {
    98  		fmt.Fprint(os.Stderr, usage)
    99  		os.Exit(1)
   100  	}
   101  
   102  	// Profiling support.
   103  	if *cpuprofile != "" {
   104  		f, err := os.Create(*cpuprofile)
   105  		if err != nil {
   106  			fmt.Fprintln(os.Stderr, err)
   107  			os.Exit(1)
   108  		}
   109  		pprof.StartCPUProfile(f)
   110  		defer pprof.StopCPUProfile()
   111  	}
   112  
   113  	// Use the initial packages from the command line.
   114  	args, err := conf.FromArgs(args, *testFlag)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	// The interpreter needs the runtime package.
   120  	if *runFlag {
   121  		conf.Import("runtime")
   122  	}
   123  
   124  	// Load, parse and type-check the whole program.
   125  	lprog, err := conf.Load()
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	// Create and build SSA-form program representation.
   131  	prog := ssautil.CreateProgram(lprog, mode)
   132  
   133  	// Build and display only the initial packages
   134  	// (and synthetic wrappers), unless -run is specified.
   135  	var initpkgs []*ssa.Package
   136  	for _, info := range lprog.InitialPackages() {
   137  		ssapkg := prog.Package(info.Pkg)
   138  		ssapkg.Build()
   139  		if info.Pkg.Path() != "runtime" {
   140  			initpkgs = append(initpkgs, ssapkg)
   141  		}
   142  	}
   143  
   144  	// Run the interpreter.
   145  	if *runFlag {
   146  		prog.Build()
   147  
   148  		var mains []*ssa.Package
   149  		if *testFlag {
   150  			// If -test, run the tests.
   151  			for _, pkg := range initpkgs {
   152  				if main := prog.CreateTestMainPackage(pkg); main != nil {
   153  					mains = append(mains, main)
   154  				}
   155  			}
   156  			if mains == nil {
   157  				return fmt.Errorf("no tests")
   158  			}
   159  		} else {
   160  			// Otherwise, run the main packages.
   161  			mains = ssautil.MainPackages(initpkgs)
   162  			if len(mains) == 0 {
   163  				return fmt.Errorf("no main package")
   164  			}
   165  		}
   166  
   167  		if runtime.GOARCH != build.Default.GOARCH {
   168  			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
   169  				build.Default.GOARCH, runtime.GOARCH)
   170  		}
   171  
   172  		for _, main := range mains {
   173  			if len(mains) > 1 {
   174  				fmt.Fprintf(os.Stderr, "Running: %s\n", main.Pkg.Path())
   175  			}
   176  			interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Pkg.Path(), args)
   177  		}
   178  	}
   179  	return nil
   180  }