github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/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 out, err = exec.Command(testnmpath, exe).CombinedOutput() 130 if err != nil { 131 t.Fatalf("go tool nm: %v\n%s", err, string(out)) 132 } 133 scanner := bufio.NewScanner(bytes.NewBuffer(out)) 134 dups := make(map[string]bool) 135 for scanner.Scan() { 136 f := strings.Fields(scanner.Text()) 137 if len(f) < 3 { 138 continue 139 } 140 name := f[2] 141 if addr, found := names[name]; found { 142 if want, have := addr, "0x"+f[0]; have != want { 143 t.Errorf("want %s address for %s symbol, but have %s", want, name, have) 144 } 145 delete(names, name) 146 } 147 if _, found := dups[name]; found { 148 t.Errorf("duplicate name of %q is found", name) 149 } 150 } 151 err = scanner.Err() 152 if err != nil { 153 t.Fatalf("error reading nm output: %v", err) 154 } 155 if len(names) > 0 { 156 t.Errorf("executable is missing %v symbols", names) 157 } 158 } 159 160 func TestGoExec(t *testing.T) { 161 testGoExec(t, false, false) 162 } 163 164 func testGoLib(t *testing.T, iscgo bool) { 165 tmpdir, err := ioutil.TempDir("", "TestGoLib") 166 if err != nil { 167 t.Fatal(err) 168 } 169 defer os.RemoveAll(tmpdir) 170 171 gopath := filepath.Join(tmpdir, "gopath") 172 libpath := filepath.Join(gopath, "src", "mylib") 173 174 err = os.MkdirAll(libpath, 0777) 175 if err != nil { 176 t.Fatal(err) 177 } 178 src := filepath.Join(libpath, "a.go") 179 file, err := os.Create(src) 180 if err != nil { 181 t.Fatal(err) 182 } 183 err = template.Must(template.New("mylib").Parse(testlib)).Execute(file, iscgo) 184 if e := file.Close(); err == nil { 185 err = e 186 } 187 if err != nil { 188 t.Fatal(err) 189 } 190 191 args := []string{"install", "mylib"} 192 cmd := exec.Command(testenv.GoToolPath(t), args...) 193 cmd.Env = append(os.Environ(), "GOPATH="+gopath) 194 out, err := cmd.CombinedOutput() 195 if err != nil { 196 t.Fatalf("building test lib failed: %s %s", err, out) 197 } 198 pat := filepath.Join(gopath, "pkg", "*", "mylib.a") 199 ms, err := filepath.Glob(pat) 200 if err != nil { 201 t.Fatal(err) 202 } 203 if len(ms) == 0 { 204 t.Fatalf("cannot found paths for pattern %s", pat) 205 } 206 mylib := ms[0] 207 208 out, err = exec.Command(testnmpath, mylib).CombinedOutput() 209 if err != nil { 210 t.Fatalf("go tool nm: %v\n%s", err, string(out)) 211 } 212 type symType struct { 213 Type string 214 Name string 215 CSym bool 216 Found bool 217 } 218 var syms = []symType{ 219 {"B", "%22%22.Testdata", false, false}, 220 {"T", "%22%22.Testfunc", false, false}, 221 } 222 if iscgo { 223 syms = append(syms, symType{"B", "%22%22.TestCgodata", false, false}) 224 syms = append(syms, symType{"T", "%22%22.TestCgofunc", false, false}) 225 if runtime.GOOS == "darwin" || (runtime.GOOS == "windows" && runtime.GOARCH == "386") { 226 syms = append(syms, symType{"D", "_cgodata", true, false}) 227 syms = append(syms, symType{"T", "_cgofunc", true, false}) 228 } else { 229 syms = append(syms, symType{"D", "cgodata", true, false}) 230 syms = append(syms, symType{"T", "cgofunc", true, false}) 231 } 232 } 233 scanner := bufio.NewScanner(bytes.NewBuffer(out)) 234 for scanner.Scan() { 235 f := strings.Fields(scanner.Text()) 236 var typ, name string 237 var csym bool 238 if iscgo { 239 if len(f) < 4 { 240 continue 241 } 242 csym = !strings.Contains(f[0], "_go_.o") 243 typ = f[2] 244 name = f[3] 245 } else { 246 if len(f) < 3 { 247 continue 248 } 249 typ = f[1] 250 name = f[2] 251 } 252 for i := range syms { 253 sym := &syms[i] 254 if sym.Type == typ && sym.Name == name && sym.CSym == csym { 255 if sym.Found { 256 t.Fatalf("duplicate symbol %s %s", sym.Type, sym.Name) 257 } 258 sym.Found = true 259 } 260 } 261 } 262 err = scanner.Err() 263 if err != nil { 264 t.Fatalf("error reading nm output: %v", err) 265 } 266 for _, sym := range syms { 267 if !sym.Found { 268 t.Errorf("cannot found symbol %s %s", sym.Type, sym.Name) 269 } 270 } 271 } 272 273 func TestGoLib(t *testing.T) { 274 testGoLib(t, false) 275 } 276 277 const testexec = ` 278 package main 279 280 import "fmt" 281 {{if .}}import "C" 282 {{end}} 283 284 func main() { 285 testfunc() 286 } 287 288 var testdata uint32 289 290 func testfunc() { 291 fmt.Printf("main=%p\n", main) 292 fmt.Printf("testfunc=%p\n", testfunc) 293 fmt.Printf("testdata=%p\n", &testdata) 294 } 295 ` 296 297 const testlib = ` 298 package mylib 299 300 {{if .}} 301 // int cgodata = 5; 302 // void cgofunc(void) {} 303 import "C" 304 305 var TestCgodata = C.cgodata 306 307 func TestCgofunc() { 308 C.cgofunc() 309 } 310 {{end}} 311 312 var Testdata uint32 313 314 func Testfunc() {} 315 `