GoPLS Viewer

Home|gopls/cmd/ssadump/main.go
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.
6package main // import "golang.org/x/tools/cmd/ssadump"
7
8import (
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/packages"
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
25var (
26    mode = ssa.BuilderMode(0)
27
28    testFlag = flag.Bool("test"false"include implicit test packages and executables")
29
30    runFlag = flag.Bool("run"false"interpret the SSA program")
31
32    interpFlag = flag.String("interp"""`Options controlling the SSA test interpreter.
33The value is a sequence of zero or more more of these letters:
34R    disable [R]ecover() from panic; show interpreter crash instead.
35T    [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    args stringListValue
41)
42
43func init() {
44    flag.Var(&mode"build"ssa.BuilderModeDoc)
45    flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags"buildutil.TagsFlagDoc)
46    flag.Var(&args"arg""add argument to interpreted program")
47}
48
49const usage = `SSA builder and interpreter.
50Usage: ssadump [-build=[DBCSNFLG]] [-test] [-run] [-interp=[TR]] [-arg=...] package...
51Use -help flag to display options.
52
53Examples:
54% ssadump -build=F hello.go              # dump SSA form of a single package
55% ssadump -build=F -test fmt             # dump SSA form of a package and its tests
56% ssadump -run -interp=T hello.go        # interpret a program, with tracing
57
58The -run flag causes ssadump to build the code in a runnable form and run the first
59package named main.
60
61Interpretation of the standard "testing" package is no longer supported.
62`
63
64func main() {
65    if err := doMain(); err != nil {
66        fmt.Fprintf(os.Stderr"ssadump: %s\n"err)
67        os.Exit(1)
68    }
69}
70
71func doMain() error {
72    flag.Parse()
73    if len(flag.Args()) == 0 {
74        fmt.Fprint(os.Stderrusage)
75        os.Exit(1)
76    }
77
78    cfg := &packages.Config{
79        Mode:  packages.LoadSyntax,
80        Tests: *testFlag,
81    }
82
83    // Choose types.Sizes from conf.Build.
84    // TODO(adonovan): remove this when go/packages provides a better way.
85    var wordSize int64 = 8
86    switch build.Default.GOARCH {
87    case "386""arm":
88        wordSize = 4
89    }
90    sizes := &types.StdSizes{
91        MaxAlign8,
92        WordSizewordSize,
93    }
94
95    var interpMode interp.Mode
96    for _c := range *interpFlag {
97        switch c {
98        case 'T':
99            interpMode |= interp.EnableTracing
100        case 'R':
101            interpMode |= interp.DisableRecover
102        default:
103            return fmt.Errorf("unknown -interp option: '%c'"c)
104        }
105    }
106
107    // Profiling support.
108    if *cpuprofile != "" {
109        ferr := os.Create(*cpuprofile)
110        if err != nil {
111            fmt.Fprintln(os.Stderrerr)
112            os.Exit(1)
113        }
114        pprof.StartCPUProfile(f)
115        defer pprof.StopCPUProfile()
116    }
117
118    // Load, parse and type-check the initial packages,
119    // and, if -run, their dependencies.
120    if *runFlag {
121        cfg.Mode = packages.LoadAllSyntax
122    }
123    initialerr := packages.Load(cfgflag.Args()...)
124    if err != nil {
125        return err
126    }
127    if len(initial) == 0 {
128        return fmt.Errorf("no packages")
129    }
130    if packages.PrintErrors(initial) > 0 {
131        return fmt.Errorf("packages contain errors")
132    }
133
134    // Turn on instantiating generics during build if the program will be run.
135    if *runFlag {
136        mode |= ssa.InstantiateGenerics
137    }
138
139    // Create SSA-form program representation.
140    progpkgs := ssautil.AllPackages(initialmode)
141
142    for ip := range pkgs {
143        if p == nil {
144            return fmt.Errorf("cannot build SSA for package %s"initial[i])
145        }
146    }
147
148    if !*runFlag {
149        // Build and display only the initial packages
150        // (and synthetic wrappers).
151        for _p := range pkgs {
152            p.Build()
153        }
154
155    } else {
156        // Run the interpreter.
157        // Build SSA for all packages.
158        prog.Build()
159
160        // Earlier versions of the interpreter needed the runtime
161        // package; however, interp cannot handle unsafe constructs
162        // used during runtime's package initialization at the moment.
163        // The key construct blocking support is:
164        //    *((*T)(unsafe.Pointer(p)))
165        // Unfortunately, this means only trivial programs can be
166        // interpreted by ssadump.
167        if prog.ImportedPackage("runtime") != nil {
168            return fmt.Errorf("-run: program depends on runtime package (interpreter can run only trivial programs)")
169        }
170
171        if runtime.GOARCH != build.Default.GOARCH {
172            return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
173                build.Default.GOARCHruntime.GOARCH)
174        }
175
176        // Run first main package.
177        for _main := range ssautil.MainPackages(pkgs) {
178            fmt.Fprintf(os.Stderr"Running: %s\n"main.Pkg.Path())
179            os.Exit(interp.Interpret(maininterpModesizesmain.Pkg.Path(), args))
180        }
181        return fmt.Errorf("no main package")
182    }
183    return nil
184}
185
186// stringListValue is a flag.Value that accumulates strings.
187// e.g. --flag=one --flag=two would produce []string{"one", "two"}.
188type stringListValue []string
189
190func newStringListValue(val []stringp *[]string) *stringListValue {
191    *p = val
192    return (*stringListValue)(p)
193}
194
195func (ss *stringListValueGet() interface{} { return []string(*ss) }
196
197func (ss *stringListValueString() string { return fmt.Sprintf("%q", *ss) }
198
199func (ss *stringListValueSet(s stringerror { *ss = append(*sss); return nil }
200
MembersX
fmt
doMain.BlockStmt.RangeStmt_3819.p
newStringListValue.p
stringListValue.Set.s
doMain.prog
doMain.BlockStmt.RangeStmt_4691.main
stringListValue.Set.ss
os
runtime
init
main.err
doMain.wordSize
types
doMain.cfg
doMain.sizes
newStringListValue.val
doMain.RangeStmt_3604.p
stringListValue
stringListValue.Get.ss
flag
doMain
doMain.err
doMain.pkgs
doMain.RangeStmt_3604.i
ssa
args
usage
newStringListValue
stringListValue.String
doMain.RangeStmt_2563.c
doMain.BlockStmt.err
doMain.initial
stringListValue.Get
stringListValue.Set
buildutil
packages
doMain.interpMode
doMain.BlockStmt.f
stringListValue.String.ss
build
pprof
interp
ssautil
main
Members
X