github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/cmd/addr2line/addr2line_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  	"internal/testenv"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"runtime"
    16  	"strings"
    17  	"testing"
    18  )
    19  
    20  func loadSyms(t *testing.T) map[string]string {
    21  	cmd := exec.Command(testenv.GoToolPath(t), "tool", "nm", os.Args[0])
    22  	out, err := cmd.CombinedOutput()
    23  	if err != nil {
    24  		t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
    25  	}
    26  	syms := make(map[string]string)
    27  	scanner := bufio.NewScanner(bytes.NewReader(out))
    28  	for scanner.Scan() {
    29  		f := strings.Fields(scanner.Text())
    30  		if len(f) < 3 {
    31  			continue
    32  		}
    33  		syms[f[2]] = f[0]
    34  	}
    35  	if err := scanner.Err(); err != nil {
    36  		t.Fatalf("error reading symbols: %v", err)
    37  	}
    38  	return syms
    39  }
    40  
    41  func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno string) {
    42  	cmd := exec.Command(exepath, os.Args[0])
    43  	cmd.Stdin = strings.NewReader(addr)
    44  	out, err := cmd.CombinedOutput()
    45  	if err != nil {
    46  		t.Fatalf("go tool addr2line %v: %v\n%s", os.Args[0], err, string(out))
    47  	}
    48  	f := strings.Split(string(out), "\n")
    49  	if len(f) < 3 && f[2] == "" {
    50  		t.Fatal("addr2line output must have 2 lines")
    51  	}
    52  	funcname = f[0]
    53  	pathAndLineNo := f[1]
    54  	f = strings.Split(pathAndLineNo, ":")
    55  	if runtime.GOOS == "windows" && len(f) == 3 {
    56  		// Reattach drive letter.
    57  		f = []string{f[0] + ":" + f[1], f[2]}
    58  	}
    59  	if len(f) != 2 {
    60  		t.Fatalf("no line number found in %q", pathAndLineNo)
    61  	}
    62  	return funcname, f[0], f[1]
    63  }
    64  
    65  const symName = "cmd/addr2line.TestAddr2Line"
    66  
    67  func testAddr2Line(t *testing.T, exepath, addr string) {
    68  	funcName, srcPath, srcLineNo := runAddr2Line(t, exepath, addr)
    69  	if symName != funcName {
    70  		t.Fatalf("expected function name %v; got %v", symName, funcName)
    71  	}
    72  	fi1, err := os.Stat("addr2line_test.go")
    73  	if err != nil {
    74  		t.Fatalf("Stat failed: %v", err)
    75  	}
    76  	fi2, err := os.Stat(srcPath)
    77  	if err != nil {
    78  		t.Fatalf("Stat failed: %v", err)
    79  	}
    80  	if !os.SameFile(fi1, fi2) {
    81  		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
    82  	}
    83  	if srcLineNo != "89" {
    84  		t.Fatalf("line number = %v; want 89", srcLineNo)
    85  	}
    86  }
    87  
    88  // This is line 88. The test depends on that.
    89  func TestAddr2Line(t *testing.T) {
    90  	testenv.MustHaveGoBuild(t)
    91  
    92  	syms := loadSyms(t)
    93  
    94  	tmpDir, err := ioutil.TempDir("", "TestAddr2Line")
    95  	if err != nil {
    96  		t.Fatal("TempDir failed: ", err)
    97  	}
    98  	defer os.RemoveAll(tmpDir)
    99  
   100  	exepath := filepath.Join(tmpDir, "testaddr2line.exe")
   101  	out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
   102  	if err != nil {
   103  		t.Fatalf("go build -o %v cmd/addr2line: %v\n%s", exepath, err, string(out))
   104  	}
   105  
   106  	testAddr2Line(t, exepath, syms[symName])
   107  	testAddr2Line(t, exepath, "0x"+syms[symName])
   108  }