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 }