1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:28:32 -06:00
go/cmd/ssadump/main.go
Alan Donovan 5612f0615f go.tools/ssa: use correct word size for GOARCH during type checking, interpretation.
Also report an error for "cross-interpretation": not supported
due to the interpreter's assumption that host and target
{int,uint,uintptr} are the same.  (Too tedious and messy to fix.)

Tested manually:

% cat d.go
package main
const m = ^uintptr(0)
const w = m>>8&1 + m>>16&1 + m>>32&1
func main() { println(m, w) }

% ./ssadump -build=P -run d.go
package main:
  const m          m = 18446744073709551615:uintptr
  const w          w = 3:uintptr
18446744073709551615 3

% GOARCH=386 ./ssadump -build=P -run d.go
package main:
  const m          m = 4294967295:uintptr
  const w          w = 2:uintptr
Error: Cross-interpretation is not yet supported (target has GOARCH 386, interpreter has amd64).

Fixes golang/go#7080

R=gri
CC=golang-codereviews
https://golang.org/cl/49070043
2014-01-08 14:46:17 -05:00

197 lines
5.0 KiB
Go

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// ssadump: a tool for displaying and interpreting the SSA form of Go programs.
package main
import (
"flag"
"fmt"
"go/build"
"log"
"os"
"runtime"
"runtime/pprof"
"code.google.com/p/go.tools/go/types"
"code.google.com/p/go.tools/importer"
"code.google.com/p/go.tools/ssa"
"code.google.com/p/go.tools/ssa/interp"
)
var buildFlag = flag.String("build", "", `Options controlling the SSA builder.
The value is a sequence of zero or more of these letters:
C perform sanity [C]hecking of the SSA form.
D include [D]ebug info for every function.
P log [P]ackage inventory.
F log [F]unction SSA code.
S log [S]ource locations as SSA builder progresses.
G use binary object files from gc to provide imports (no code).
L build distinct packages seria[L]ly instead of in parallel.
N build [N]aive SSA form: don't replace local loads/stores with registers.
`)
var runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
var interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
The value is a sequence of zero or more more of these letters:
R disable [R]ecover() from panic; show interpreter crash instead.
T [T]race execution of the program. Best for single-threaded programs!
`)
const usage = `SSA builder and interpreter.
Usage: ssadump [<flag> ...] <args> ...
Use -help flag to display options.
Examples:
% ssadump -build=FPG hello.go # quickly dump SSA form of a single package
% ssadump -run -interp=T hello.go # interpret a program, with tracing
% ssadump -run unicode -- -test.v # interpret the unicode package's tests, verbosely
` + importer.InitialPackagesUsage +
`
When -run is specified, ssadump will find the first package that
defines a main function and run it in the interpreter.
If none is found, the tests of each package will be run instead.
`
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func init() {
// If $GOMAXPROCS isn't set, use the full capacity of the machine.
// For small machines, use at least 4 threads.
if os.Getenv("GOMAXPROCS") == "" {
n := runtime.NumCPU()
if n < 4 {
n = 4
}
runtime.GOMAXPROCS(n)
}
}
func main() {
flag.Parse()
args := flag.Args()
impctx := importer.Config{Build: &build.Default}
// TODO(adonovan): make go/types choose its default Sizes from
// build.Default or a specified *build.Context.
var wordSize int64 = 8
switch impctx.Build.GOARCH {
case "386", "arm":
wordSize = 4
}
impctx.TypeChecker.Sizes = &types.StdSizes{
MaxAlign: 8,
WordSize: wordSize,
}
var debugMode bool
var mode ssa.BuilderMode
for _, c := range *buildFlag {
switch c {
case 'D':
debugMode = true
case 'P':
mode |= ssa.LogPackages | ssa.BuildSerially
case 'F':
mode |= ssa.LogFunctions | ssa.BuildSerially
case 'S':
mode |= ssa.LogSource | ssa.BuildSerially
case 'C':
mode |= ssa.SanityCheckFunctions
case 'N':
mode |= ssa.NaiveForm
case 'G':
impctx.Build = nil
case 'L':
mode |= ssa.BuildSerially
default:
log.Fatalf("Unknown -build option: '%c'.", c)
}
}
var interpMode interp.Mode
for _, c := range *interpFlag {
switch c {
case 'T':
interpMode |= interp.EnableTracing
case 'R':
interpMode |= interp.DisableRecover
default:
log.Fatalf("Unknown -interp option: '%c'.", c)
}
}
if len(args) == 0 {
fmt.Fprint(os.Stderr, usage)
os.Exit(1)
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
// Load, parse and type-check the program.
imp := importer.New(&impctx)
infos, args, err := imp.LoadInitialPackages(args)
if err != nil {
log.Fatal(err)
}
// The interpreter needs the runtime package.
if *runFlag {
if _, err := imp.LoadPackage("runtime"); err != nil {
log.Fatalf("LoadPackage(runtime) failed: %s", err)
}
}
// Create and build SSA-form program representation.
prog := ssa.NewProgram(imp.Fset, mode)
if err := prog.CreatePackages(imp); err != nil {
log.Fatal(err)
}
if debugMode {
for _, pkg := range prog.AllPackages() {
pkg.SetDebugMode(true)
}
}
prog.BuildAll()
// Run the interpreter.
if *runFlag {
// If some package defines main, run that.
// Otherwise run all package's tests.
var main *ssa.Package
var pkgs []*ssa.Package
for _, info := range infos {
pkg := prog.Package(info.Pkg)
if pkg.Func("main") != nil {
main = pkg
break
}
pkgs = append(pkgs, pkg)
}
if main == nil && pkgs != nil {
main = prog.CreateTestMainPackage(pkgs...)
}
if main == nil {
log.Fatal("No main package and no tests")
}
if runtime.GOARCH != impctx.Build.GOARCH {
log.Fatalf("Cross-interpretation is not yet supported (target has GOARCH %s, interpreter has %s).",
impctx.Build.GOARCH, runtime.GOARCH)
}
interp.Interpret(main, interpMode, impctx.TypeChecker.Sizes, main.Object.Path(), args)
}
}