1
2
3
4
5
6 package main
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/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
25 var (
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.
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 args stringListValue
41 )
42
43 func 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
49 const usage = `SSA builder and interpreter.
50 Usage: ssadump [-build=[DBCSNFLG]] [-test] [-run] [-interp=[TR]] [-arg=...] package...
51 Use -help flag to display options.
52
53 Examples:
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
58 The -run flag causes ssadump to build the code in a runnable form and run the first
59 package named main.
60
61 Interpretation of the standard "testing" package is no longer supported.
62 `
63
64 func main() {
65 if err := doMain(); err != nil {
66 fmt.Fprintf(os.Stderr, "ssadump: %s\n", err)
67 os.Exit(1)
68 }
69 }
70
71 func doMain() error {
72 flag.Parse()
73 if len(flag.Args()) == 0 {
74 fmt.Fprint(os.Stderr, usage)
75 os.Exit(1)
76 }
77
78 cfg := &packages.Config{
79 Mode: packages.LoadSyntax,
80 Tests: *testFlag,
81 }
82
83
84
85 var wordSize int64 = 8
86 switch build.Default.GOARCH {
87 case "386", "arm":
88 wordSize = 4
89 }
90 sizes := &types.StdSizes{
91 MaxAlign: 8,
92 WordSize: wordSize,
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
108 if *cpuprofile != "" {
109 f, err := os.Create(*cpuprofile)
110 if err != nil {
111 fmt.Fprintln(os.Stderr, err)
112 os.Exit(1)
113 }
114 pprof.StartCPUProfile(f)
115 defer pprof.StopCPUProfile()
116 }
117
118
119
120 if *runFlag {
121 cfg.Mode = packages.LoadAllSyntax
122 }
123 initial, err := packages.Load(cfg, flag.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
135 if *runFlag {
136 mode |= ssa.InstantiateGenerics
137 }
138
139
140 prog, pkgs := ssautil.AllPackages(initial, mode)
141
142 for i, p := 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
150
151 for _, p := range pkgs {
152 p.Build()
153 }
154
155 } else {
156
157
158 prog.Build()
159
160
161
162
163
164
165
166
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.GOARCH, runtime.GOARCH)
174 }
175
176
177 for _, main := range ssautil.MainPackages(pkgs) {
178 fmt.Fprintf(os.Stderr, "Running: %s\n", main.Pkg.Path())
179 os.Exit(interp.Interpret(main, interpMode, sizes, main.Pkg.Path(), args))
180 }
181 return fmt.Errorf("no main package")
182 }
183 return nil
184 }
185
186
187
188 type stringListValue []string
189
190 func newStringListValue(val []string, p *[]string) *stringListValue {
191 *p = val
192 return (*stringListValue)(p)
193 }
194
195 func (ss *stringListValue) Get() interface{} { return []string(*ss) }
196
197 func (ss *stringListValue) String() string { return fmt.Sprintf("%q", *ss) }
198
199 func (ss *stringListValue) Set(s string) error { *ss = append(*ss, s); return nil }
200
View as plain text