github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 }