Source file src/cmd/addr2line/addr2line_test.go

     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  	"internal/testenv"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  // TestMain executes the test binary as the addr2line command if
    19  // GO_ADDR2LINETEST_IS_ADDR2LINE is set, and runs the tests otherwise.
    20  func TestMain(m *testing.M) {
    21  	if os.Getenv("GO_ADDR2LINETEST_IS_ADDR2LINE") != "" {
    22  		main()
    23  		os.Exit(0)
    24  	}
    25  
    26  	os.Setenv("GO_ADDR2LINETEST_IS_ADDR2LINE", "1") // Set for subprocesses to inherit.
    27  	os.Exit(m.Run())
    28  }
    29  
    30  func loadSyms(t *testing.T, dbgExePath string) map[string]string {
    31  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", dbgExePath)
    32  	out, err := cmd.CombinedOutput()
    33  	if err != nil {
    34  		t.Fatalf("%v: %v\n%s", cmd, err, string(out))
    35  	}
    36  	syms := make(map[string]string)
    37  	scanner := bufio.NewScanner(bytes.NewReader(out))
    38  	for scanner.Scan() {
    39  		f := strings.Fields(scanner.Text())
    40  		if len(f) < 3 {
    41  			continue
    42  		}
    43  		syms[f[2]] = f[0]
    44  	}
    45  	if err := scanner.Err(); err != nil {
    46  		t.Fatalf("error reading symbols: %v", err)
    47  	}
    48  	return syms
    49  }
    50  
    51  func runAddr2Line(t *testing.T, dbgExePath, addr string) (funcname, path, lineno string) {
    52  	cmd := testenv.Command(t, testenv.Executable(t), dbgExePath)
    53  	cmd.Stdin = strings.NewReader(addr)
    54  	out, err := cmd.CombinedOutput()
    55  	if err != nil {
    56  		t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out))
    57  	}
    58  	f := strings.Split(string(out), "\n")
    59  	if len(f) < 3 && f[2] == "" {
    60  		t.Fatal("addr2line output must have 2 lines")
    61  	}
    62  	funcname = f[0]
    63  	pathAndLineNo := f[1]
    64  	f = strings.Split(pathAndLineNo, ":")
    65  	if runtime.GOOS == "windows" && len(f) == 3 {
    66  		// Reattach drive letter.
    67  		f = []string{f[0] + ":" + f[1], f[2]}
    68  	}
    69  	if len(f) != 2 {
    70  		t.Fatalf("no line number found in %q", pathAndLineNo)
    71  	}
    72  	return funcname, f[0], f[1]
    73  }
    74  
    75  const symName = "cmd/addr2line.TestAddr2Line"
    76  
    77  func testAddr2Line(t *testing.T, dbgExePath, addr string) {
    78  	funcName, srcPath, srcLineNo := runAddr2Line(t, dbgExePath, addr)
    79  	if symName != funcName {
    80  		t.Fatalf("expected function name %v; got %v", symName, funcName)
    81  	}
    82  	fi1, err := os.Stat("addr2line_test.go")
    83  	if err != nil {
    84  		t.Fatalf("Stat failed: %v", err)
    85  	}
    86  
    87  	// Debug paths are stored slash-separated, so convert to system-native.
    88  	srcPath = filepath.FromSlash(srcPath)
    89  	fi2, err := os.Stat(srcPath)
    90  	if err != nil {
    91  		t.Fatalf("Stat failed: %v", err)
    92  	}
    93  	if !os.SameFile(fi1, fi2) {
    94  		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
    95  	}
    96  	if want := "102"; srcLineNo != want {
    97  		t.Fatalf("line number = %v; want %s", srcLineNo, want)
    98  	}
    99  }
   100  
   101  // This is line 101. The test depends on that.
   102  func TestAddr2Line(t *testing.T) {
   103  	testenv.MustHaveGoBuild(t)
   104  
   105  	tmpDir := t.TempDir()
   106  
   107  	// Build copy of test binary with debug symbols,
   108  	// since the one running now may not have them.
   109  	exepath := filepath.Join(tmpDir, "testaddr2line_test.exe")
   110  	out, err := testenv.Command(t, testenv.GoToolPath(t), "test", "-c", "-o", exepath, "cmd/addr2line").CombinedOutput()
   111  	if err != nil {
   112  		t.Fatalf("go test -c -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
   113  	}
   114  
   115  	syms := loadSyms(t, exepath)
   116  
   117  	testAddr2Line(t, exepath, syms[symName])
   118  	testAddr2Line(t, exepath, "0x"+syms[symName])
   119  }
   120  

View as plain text