github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/nm/nm_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 "bufio" 9 "bytes" 10 "fmt" 11 "internal/testenv" 12 "io/ioutil" 13 "os" 14 "os/exec" 15 "path/filepath" 16 "runtime" 17 "strings" 18 "testing" 19 "text/template" 20 ) 21 22 var testnmpath string // path to nm command created for testing purposes 23 24 // The TestMain function creates a nm command for testing purposes and 25 // deletes it after the tests have been run. 26 func TestMain(m *testing.M) { 27 os.Exit(testMain(m)) 28 } 29 30 func testMain(m *testing.M) int { 31 if !testenv.HasGoBuild() { 32 return 0 33 } 34 35 tmpDir, err := ioutil.TempDir("", "TestNM") 36 if err != nil { 37 fmt.Println("TempDir failed:", err) 38 return 2 39 } 40 defer os.RemoveAll(tmpDir) 41 42 testnmpath = filepath.Join(tmpDir, "testnm.exe") 43 gotool, err := testenv.GoTool() 44 if err != nil { 45 fmt.Println("GoTool failed:", err) 46 return 2 47 } 48 out, err := exec.Command(gotool, "build", "-o", testnmpath, "cmd/nm").CombinedOutput() 49 if err != nil { 50 fmt.Printf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out)) 51 return 2 52 } 53 54 return m.Run() 55 } 56 57 func TestNonGoExecs(t *testing.T) { 58 testfiles := []string{ 59 "elf/testdata/gcc-386-freebsd-exec", 60 "elf/testdata/gcc-amd64-linux-exec", 61 "macho/testdata/gcc-386-darwin-exec", 62 "macho/testdata/gcc-amd64-darwin-exec", 63 // "pe/testdata/gcc-amd64-mingw-exec", // no symbols! 64 "pe/testdata/gcc-386-mingw-exec", 65 "plan9obj/testdata/amd64-plan9-exec", 66 "plan9obj/testdata/386-plan9-exec", 67 } 68 for _, f := range testfiles { 69 exepath := filepath.Join(runtime.GOROOT(), "src", "debug", f) 70 cmd := exec.Command(testnmpath, exepath) 71 out, err := cmd.CombinedOutput() 72 if err != nil { 73 t.Errorf("go tool nm %v: %v\n%s", exepath, err, string(out)) 74 } 75 } 76 } 77 78 func testGoExec(t *testing.T, iscgo, isexternallinker bool) { 79 tmpdir, err := ioutil.TempDir("", "TestGoExec") 80 if err != nil { 81 t.Fatal(err) 82 } 83 defer os.RemoveAll(tmpdir) 84 85 src := filepath.Join(tmpdir, "a.go") 86 file, err := os.Create(src) 87 if err != nil { 88 t.Fatal(err) 89 } 90 err = template.Must(template.New("main").Parse(testexec)).Execute(file, iscgo) 91 if e := file.Close(); err == nil { 92 err = e 93 } 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 exe := filepath.Join(tmpdir, "a.exe") 99 args := []string{"build", "-o", exe} 100 if iscgo { 101 linkmode := "internal" 102 if isexternallinker { 103 linkmode = "external" 104 } 105 args = append(args, "-ldflags", "-linkmode="+linkmode) 106 } 107 args = append(args, src) 108 out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() 109 if err != nil { 110 t.Fatalf("building test executable failed: %s %s", err, out) 111 } 112 113 out, err = exec.Command(exe).CombinedOutput() 114 if err != nil { 115 t.Fatalf("running test executable failed: %s %s", err, out) 116 } 117 names := make(map[string]string) 118 for _, line := range strings.Split(string(out), "\n") { 119 if line == "" { 120 continue 121 } 122 f := strings.Split(line, "=") 123 if len(f) != 2 { 124 t.Fatalf("unexpected output line: %q", line) 125 } 126 names["main."+f[0]] = f[1] 127 } 128 129 runtimeSyms := map[string]string{ 130 "runtime.text": "T", 131 "runtime.etext": "T", 132 "runtime.rodata": "R", 133 "runtime.erodata": "R", 134 "runtime.epclntab": "R", 135 "runtime.noptrdata": "D", 136 } 137 138 out, err = exec.Command(testnmpath, exe).CombinedOutput() 139 if err != nil { 140 t.Fatalf("go tool nm: %v\n%s", err, string(out)) 141 } 142 scanner := bufio.NewScanner(bytes.NewBuffer(out)) 143 dups := make(map[string]bool) 144 for scanner.Scan() { 145 f := strings.Fields(scanner.Text()) 146 if len(f) < 3 { 147 continue 148 } 149 name := f[2] 150 if addr, found := names[name]; found { 151 if want, have := addr, "0x"+f[0]; have != want { 152 t.Errorf("want %s address for %s symbol, but have %s", want, name, have) 153 } 154 delete(names, name) 155 } 156 if _, found := dups[name]; found { 157 t.Errorf("duplicate name of %q is found", name) 158 } 159 if stype, found := runtimeSyms[name]; found { 160 if runtime.GOOS == "plan9" && stype == "R" { 161 // no read-only data segment symbol on Plan 9 162 stype = "D" 163 } 164 if want, have := stype, strings.ToUpper(f[1]); have != want { 165 t.Errorf("want %s type for %s symbol, but have %s", want, name, have) 166 } 167 delete(runtimeSyms, name) 168 } 169 } 170 err = scanner.Err() 171 if err != nil { 172 t.Fatalf("error reading nm output: %v", err) 173 } 174 if len(names) > 0 { 175 t.Errorf("executable is missing %v symbols", names) 176 } 177 if len(runtimeSyms) > 0 { 178 t.Errorf("executable is missing %v symbols", runtimeSyms) 179 } 180 } 181 182 func TestGoExec(t *testing.T) { 183 testGoExec(t, false, false) 184 } 185 186 func testGoLib(t *testing.T, iscgo bool) { 187 tmpdir, err := ioutil.TempDir("", "TestGoLib") 188 if err != nil { 189 t.Fatal(err) 190 } 191 defer os.RemoveAll(tmpdir) 192 193 gopath := filepath.Join(tmpdir, "gopath") 194 libpath := filepath.Join(gopath, "src", "mylib") 195 196 err = os.MkdirAll(libpath, 0777) 197 if err != nil { 198 t.Fatal(err) 199 } 200 src := filepath.Join(libpath, "a.go") 201 file, err := os.Create(src) 202 if err != nil { 203 t.Fatal(err) 204 } 205 err = template.Must(template.New("mylib").Parse(testlib)).Execute(file, iscgo) 206 if e := file.Close(); err == nil { 207 err = e 208 } 209 if err != nil { 210 t.Fatal(err) 211 } 212 213 args := []string{"install", "mylib"} 214 cmd := exec.Command(testenv.GoToolPath(t), args...) 215 cmd.Env = append(os.Environ(), "GOPATH="+gopath) 216 out, err := cmd.CombinedOutput() 217 if err != nil { 218 t.Fatalf("building test lib failed: %s %s", err, out) 219 } 220 pat := filepath.Join(gopath, "pkg", "*", "mylib.a") 221 ms, err := filepath.Glob(pat) 222 if err != nil { 223 t.Fatal(err) 224 } 225 if len(ms) == 0 { 226 t.Fatalf("cannot found paths for pattern %s", pat) 227 } 228 mylib := ms[0] 229 230 out, err = exec.Command(testnmpath, mylib).CombinedOutput() 231 if err != nil { 232 t.Fatalf("go tool nm: %v\n%s", err, string(out)) 233 } 234 type symType struct { 235 Type string 236 Name string 237 CSym bool 238 Found bool 239 } 240 var syms = []symType{ 241 {"B", "%22%22.Testdata", false, false}, 242 {"T", "%22%22.Testfunc", false, false}, 243 } 244 if iscgo { 245 syms = append(syms, symType{"B", "%22%22.TestCgodata", false, false}) 246 syms = append(syms, symType{"T", "%22%22.TestCgofunc", false, false}) 247 if runtime.GOOS == "darwin" || (runtime.GOOS == "windows" && runtime.GOARCH == "386") { 248 syms = append(syms, symType{"D", "_cgodata", true, false}) 249 syms = append(syms, symType{"T", "_cgofunc", true, false}) 250 } else { 251 syms = append(syms, symType{"D", "cgodata", true, false}) 252 syms = append(syms, symType{"T", "cgofunc", true, false}) 253 } 254 } 255 scanner := bufio.NewScanner(bytes.NewBuffer(out)) 256 for scanner.Scan() { 257 f := strings.Fields(scanner.Text()) 258 var typ, name string 259 var csym bool 260 if iscgo { 261 if len(f) < 4 { 262 continue 263 } 264 csym = !strings.Contains(f[0], "_go_.o") 265 typ = f[2] 266 name = f[3] 267 } else { 268 if len(f) < 3 { 269 continue 270 } 271 typ = f[1] 272 name = f[2] 273 } 274 for i := range syms { 275 sym := &syms[i] 276 if sym.Type == typ && sym.Name == name && sym.CSym == csym { 277 if sym.Found { 278 t.Fatalf("duplicate symbol %s %s", sym.Type, sym.Name) 279 } 280 sym.Found = true 281 } 282 } 283 } 284 err = scanner.Err() 285 if err != nil { 286 t.Fatalf("error reading nm output: %v", err) 287 } 288 for _, sym := range syms { 289 if !sym.Found { 290 t.Errorf("cannot found symbol %s %s", sym.Type, sym.Name) 291 } 292 } 293 } 294 295 func TestGoLib(t *testing.T) { 296 testGoLib(t, false) 297 } 298 299 const testexec = ` 300 package main 301 302 import "fmt" 303 {{if .}}import "C" 304 {{end}} 305 306 func main() { 307 testfunc() 308 } 309 310 var testdata uint32 311 312 func testfunc() { 313 fmt.Printf("main=%p\n", main) 314 fmt.Printf("testfunc=%p\n", testfunc) 315 fmt.Printf("testdata=%p\n", &testdata) 316 } 317 ` 318 319 const testlib = ` 320 package mylib 321 322 {{if .}} 323 // int cgodata = 5; 324 // void cgofunc(void) {} 325 import "C" 326 327 var TestCgodata = C.cgodata 328 329 func TestCgofunc() { 330 C.cgofunc() 331 } 332 {{end}} 333 334 var Testdata uint32 335 336 func Testfunc() {} 337 `