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