github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/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 main.main(SB)",
    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 goarch == "386" {
   152  		if strings.Contains(text, "(IP)") {
   153  			t.Errorf("disassembly contains PC-Relative addressing on 386")
   154  			ok = false
   155  		}
   156  	}
   157  
   158  	if !ok {
   159  		t.Logf("full disassembly:\n%s", text)
   160  	}
   161  }
   162  
   163  func TestDisasm(t *testing.T) {
   164  	switch runtime.GOARCH {
   165  	case "mips", "mipsle", "mips64", "mips64le":
   166  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   167  	case "s390x":
   168  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   169  	}
   170  	testDisasm(t, false)
   171  }
   172  
   173  func TestDisasmCode(t *testing.T) {
   174  	switch runtime.GOARCH {
   175  	case "mips", "mipsle", "mips64", "mips64le":
   176  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   177  	case "s390x":
   178  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   179  	}
   180  	testDisasm(t, true)
   181  }
   182  
   183  func TestDisasmExtld(t *testing.T) {
   184  	switch runtime.GOOS {
   185  	case "plan9", "windows":
   186  		t.Skipf("skipping on %s", runtime.GOOS)
   187  	}
   188  	switch runtime.GOARCH {
   189  	case "ppc64":
   190  		t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
   191  	case "mips64", "mips64le", "mips", "mipsle":
   192  		t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
   193  	case "s390x":
   194  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   195  	}
   196  	// TODO(jsing): Reenable once openbsd/arm has external linking support.
   197  	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
   198  		t.Skip("skipping on openbsd/arm, no support for external linking, issue 10619")
   199  	}
   200  	if !build.Default.CgoEnabled {
   201  		t.Skip("skipping because cgo is not enabled")
   202  	}
   203  	testDisasm(t, false, "-ldflags=-linkmode=external")
   204  }
   205  
   206  func TestDisasmGoobj(t *testing.T) {
   207  	switch runtime.GOARCH {
   208  	case "mips", "mipsle", "mips64", "mips64le":
   209  		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
   210  	case "s390x":
   211  		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
   212  	}
   213  
   214  	hello := filepath.Join(tmp, "hello.o")
   215  	args := []string{"tool", "compile", "-o", hello}
   216  	args = append(args, "testdata/fmthello.go")
   217  	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
   218  	if err != nil {
   219  		t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
   220  	}
   221  	need := []string{
   222  		"main(SB)",
   223  		"fmthello.go:6",
   224  	}
   225  
   226  	args = []string{
   227  		"-s", "main",
   228  		hello,
   229  	}
   230  
   231  	out, err = exec.Command(exe, args...).CombinedOutput()
   232  	if err != nil {
   233  		t.Fatalf("objdump fmthello.o: %v\n%s", err, out)
   234  	}
   235  
   236  	text := string(out)
   237  	ok := true
   238  	for _, s := range need {
   239  		if !strings.Contains(text, s) {
   240  			t.Errorf("disassembly missing '%s'", s)
   241  			ok = false
   242  		}
   243  	}
   244  	if runtime.GOARCH == "386" {
   245  		if strings.Contains(text, "(IP)") {
   246  			t.Errorf("disassembly contains PC-Relative addressing on 386")
   247  			ok = false
   248  		}
   249  	}
   250  	if !ok {
   251  		t.Logf("full disassembly:\n%s", text)
   252  	}
   253  }