github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/cmd/objdump/objdump_test.go (about)

     1  // Copyright 2014 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  package main
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"go/build"
    11  	"internal/testenv"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  )
    20  
    21  var tmp, exe string // populated by buildObjdump
    22  
    23  func TestMain(m *testing.M) {
    24  	if !testenv.HasGoBuild() {
    25  		return
    26  	}
    27  	var exitcode int
    28  	if err := buildObjdump(); err == nil {
    29  		exitcode = m.Run()
    30  	} else {
    31  		fmt.Println(err)
    32  		exitcode = 1
    33  	}
    34  	os.RemoveAll(tmp)
    35  	os.Exit(exitcode)
    36  }
    37  
    38  func buildObjdump() error {
    39  	var err error
    40  	tmp, err = ioutil.TempDir("", "TestObjDump")
    41  	if err != nil {
    42  		return fmt.Errorf("TempDir failed: %v", err)
    43  	}
    44  
    45  	exe = filepath.Join(tmp, "testobjdump.exe")
    46  	gotool, err := testenv.GoTool()
    47  	if err != nil {
    48  		return err
    49  	}
    50  	out, err := exec.Command(gotool, "build", "-o", exe, "cmd/objdump").CombinedOutput()
    51  	if err != nil {
    52  		os.RemoveAll(tmp)
    53  		return fmt.Errorf("go build -o %v cmd/objdump: %v\n%s", exe, err, string(out))
    54  	}
    55  
    56  	return nil
    57  }
    58  
    59  var x86Need = []string{
    60  	"JMP main.main(SB)",
    61  	"CALL main.Println(SB)",
    62  	"RET",
    63  }
    64  
    65  var armNeed = []string{
    66  	//"B.LS main.main(SB)", // TODO(rsc): restore; golang.org/issue/9021
    67  	"BL main.Println(SB)",
    68  	"RET",
    69  }
    70  
    71  var ppcNeed = []string{
    72  	"BR main.main(SB)",
    73  	"CALL main.Println(SB)",
    74  	"RET",
    75  }
    76  
    77  var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
    78  
    79  // objdump is fully cross platform: it can handle binaries
    80  // from any known operating system and architecture.
    81  // We could in principle add binaries to testdata and check
    82  // all the supported systems during this test. However, the
    83  // binaries would be about 1 MB each, and we don't want to
    84  // add that much junk to the hg repository. Instead, build a
    85  // binary for the current system (only) and test that objdump
    86  // can handle that one.
    87  
    88  func testDisasm(t *testing.T, printCode bool, flags ...string) {
    89  	goarch := runtime.GOARCH
    90  	if *target != "" {
    91  		f := strings.Split(*target, "/")
    92  		if len(f) != 2 {
    93  			t.Fatalf("-target argument must be goos/goarch")
    94  		}
    95  		defer os.Setenv("GOOS", os.Getenv("GOOS"))
    96  		defer os.Setenv("GOARCH", os.Getenv("GOARCH"))
    97  		os.Setenv("GOOS", f[0])
    98  		os.Setenv("GOARCH", f[1])
    99  		goarch = f[1]
   100  	}
   101  
   102  	hello := filepath.Join(tmp, "hello.exe")
   103  	args := []string{"build", "-o", hello}
   104  	args = append(args, flags...)
   105  	args = append(args, "testdata/fmthello.go")
   106  	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
   107  	if err != nil {
   108  		t.Fatalf("go build fmthello.go: %v\n%s", err, out)
   109  	}
   110  	need := []string{
   111  		"TEXT main.main(SB)",
   112  	}
   113  
   114  	if printCode {
   115  		need = append(need, `	Println("hello, world")`)
   116  	} else {
   117  		need = append(need, "fmthello.go:6")
   118  	}
   119  
   120  	switch goarch {
   121  	case "amd64", "386":
   122  		need = append(need, x86Need...)
   123  	case "arm":
   124  		need = append(need, armNeed...)
   125  	case "ppc64", "ppc64le":
   126  		need = append(need, ppcNeed...)
   127  	}
   128  
   129  	args = []string{
   130  		"-s", "main.main",
   131  		hello,
   132  	}
   133  
   134  	if printCode {
   135  		args = append([]string{"-S"}, args...)
   136  	}
   137  
   138  	out, err = exec.Command(exe, args...).CombinedOutput()
   139  	if err != nil {
   140  		t.Fatalf("objdump fmthello.exe: %v\n%s", err, out)
   141  	}
   142  
   143  	text := string(out)
   144  	ok := true
   145  	for _, s := range need {
   146  		if !strings.Contains(text, s) {
   147  			t.Errorf("disassembly missing '%s'", s)
   148  			ok = false
   149  		}
   150  	}
   151  	if !ok {
   152  		t.Logf("full disassembly:\n%s", text)
   153  	}
   154  }
   155  
   156  func TestDisasm(t *testing.T) {
   157  	switch runtime.GOARCH {
   158  	case "arm64":
   159  		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
   160  	case "mips", "mipsle", "mips64", "mips64le":
   161  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   162  	case "s390x":
   163  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   164  	}
   165  	testDisasm(t, false)
   166  }
   167  
   168  func TestDisasmCode(t *testing.T) {
   169  	switch runtime.GOARCH {
   170  	case "arm64":
   171  		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
   172  	case "mips", "mipsle", "mips64", "mips64le":
   173  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   174  	case "s390x":
   175  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   176  	}
   177  	testDisasm(t, true)
   178  }
   179  
   180  func TestDisasmExtld(t *testing.T) {
   181  	switch runtime.GOOS {
   182  	case "plan9", "windows":
   183  		t.Skipf("skipping on %s", runtime.GOOS)
   184  	}
   185  	switch runtime.GOARCH {
   186  	case "ppc64":
   187  		t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
   188  	case "arm64":
   189  		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
   190  	case "mips64", "mips64le", "mips", "mipsle":
   191  		t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
   192  	case "s390x":
   193  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   194  	}
   195  	// TODO(jsing): Reenable once openbsd/arm has external linking support.
   196  	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
   197  		t.Skip("skipping on openbsd/arm, no support for external linking, issue 10619")
   198  	}
   199  	if !build.Default.CgoEnabled {
   200  		t.Skip("skipping because cgo is not enabled")
   201  	}
   202  	testDisasm(t, false, "-ldflags=-linkmode=external")
   203  }
   204  
   205  func TestDisasmGoobj(t *testing.T) {
   206  	switch runtime.GOARCH {
   207  	case "arm":
   208  		t.Skipf("skipping on %s, issue 19811", runtime.GOARCH)
   209  	case "arm64":
   210  		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
   211  	case "mips", "mipsle", "mips64", "mips64le":
   212  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   213  	case "s390x":
   214  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   215  	}
   216  
   217  	hello := filepath.Join(tmp, "hello.o")
   218  	args := []string{"tool", "compile", "-o", hello}
   219  	args = append(args, "testdata/fmthello.go")
   220  	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
   221  	if err != nil {
   222  		t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
   223  	}
   224  	need := []string{
   225  		"main(SB)",
   226  		"fmthello.go:6",
   227  	}
   228  
   229  	args = []string{
   230  		"-s", "main",
   231  		hello,
   232  	}
   233  
   234  	out, err = exec.Command(exe, args...).CombinedOutput()
   235  	if err != nil {
   236  		t.Fatalf("objdump fmthello.o: %v\n%s", err, out)
   237  	}
   238  
   239  	text := string(out)
   240  	ok := true
   241  	for _, s := range need {
   242  		if !strings.Contains(text, s) {
   243  			t.Errorf("disassembly missing '%s'", s)
   244  			ok = false
   245  		}
   246  	}
   247  	if !ok {
   248  		t.Logf("full disassembly:\n%s", text)
   249  	}
   250  }