mirror of
https://github.com/golang/go
synced 2024-11-19 22:44:45 -07:00
b386c34ef9
Semi-regular merge from tip into dev.ssa. Change-Id: I1627d7c7e6892cd4f1f5da5f3e07389ff1d677ce
165 lines
4.8 KiB
Go
165 lines
4.8 KiB
Go
package runtime_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"regexp"
|
|
"runtime"
|
|
"strconv"
|
|
"testing"
|
|
)
|
|
|
|
func checkGdbPython(t *testing.T) {
|
|
cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')")
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
t.Skipf("skipping due to issue running gdb: %v", err)
|
|
}
|
|
if string(out) != "go gdb python support\n" {
|
|
t.Skipf("skipping due to lack of python gdb support: %s", out)
|
|
}
|
|
|
|
// Issue 11214 reports various failures with older versions of gdb.
|
|
out, err = exec.Command("gdb", "--version").CombinedOutput()
|
|
re := regexp.MustCompile(`([0-9]+)\.([0-9]+)`)
|
|
matches := re.FindSubmatch(out)
|
|
if len(matches) < 3 {
|
|
t.Skipf("skipping: can't determine gdb version from\n%s\n", out)
|
|
}
|
|
major, err1 := strconv.Atoi(string(matches[1]))
|
|
minor, err2 := strconv.Atoi(string(matches[2]))
|
|
if err1 != nil || err2 != nil {
|
|
t.Skipf("skipping: can't determine gdb version: %v, %v", err1, err2)
|
|
}
|
|
if major < 7 || (major == 7 && minor < 7) {
|
|
t.Skipf("skipping: gdb version %d.%d too old", major, minor)
|
|
}
|
|
t.Logf("gdb version %d.%d", major, minor)
|
|
}
|
|
|
|
const helloSource = `
|
|
package main
|
|
import "fmt"
|
|
func main() {
|
|
mapvar := make(map[string]string,5)
|
|
mapvar["abc"] = "def"
|
|
mapvar["ghi"] = "jkl"
|
|
strvar := "abc"
|
|
ptrvar := &strvar
|
|
fmt.Println("hi") // line 10
|
|
_ = ptrvar
|
|
}
|
|
`
|
|
|
|
func TestGdbPython(t *testing.T) {
|
|
if runtime.GOOS == "darwin" {
|
|
t.Skip("gdb does not work on darwin")
|
|
}
|
|
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
|
|
t.Skip("gdb test can fail with GOROOT_FINAL pending")
|
|
}
|
|
|
|
checkGdbPython(t)
|
|
|
|
dir, err := ioutil.TempDir("", "go-build")
|
|
if err != nil {
|
|
t.Fatalf("failed to create temp directory: %v", err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
src := filepath.Join(dir, "main.go")
|
|
err = ioutil.WriteFile(src, []byte(helloSource), 0644)
|
|
if err != nil {
|
|
t.Fatalf("failed to create file: %v", err)
|
|
}
|
|
|
|
cmd := exec.Command("go", "build", "-o", "a.exe")
|
|
cmd.Dir = dir
|
|
out, err := testEnv(cmd).CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("building source %v\n%s", err, out)
|
|
}
|
|
|
|
args := []string{"-nx", "-q", "--batch", "-iex",
|
|
fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
|
|
"-ex", "info auto-load python-scripts",
|
|
"-ex", "br main.go:10",
|
|
"-ex", "run",
|
|
"-ex", "echo BEGIN info goroutines\n",
|
|
"-ex", "info goroutines",
|
|
"-ex", "echo END\n",
|
|
"-ex", "echo BEGIN print mapvar\n",
|
|
"-ex", "print mapvar",
|
|
"-ex", "echo END\n",
|
|
"-ex", "echo BEGIN print strvar\n",
|
|
"-ex", "print strvar",
|
|
"-ex", "echo END\n"}
|
|
|
|
// without framepointer, gdb cannot backtrace our non-standard
|
|
// stack frames on RISC architectures.
|
|
canBackTrace := false
|
|
switch runtime.GOARCH {
|
|
case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64", "mips64", "mips64le":
|
|
canBackTrace = true
|
|
args = append(args,
|
|
"-ex", "echo BEGIN goroutine 2 bt\n",
|
|
"-ex", "goroutine 2 bt",
|
|
"-ex", "echo END\n")
|
|
}
|
|
|
|
args = append(args, filepath.Join(dir, "a.exe"))
|
|
got, _ := exec.Command("gdb", args...).CombinedOutput()
|
|
|
|
firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
|
|
if string(firstLine) != "Loading Go Runtime support." {
|
|
// This can happen when using all.bash with
|
|
// GOROOT_FINAL set, because the tests are run before
|
|
// the final installation of the files.
|
|
cmd := exec.Command("go", "env", "GOROOT")
|
|
cmd.Env = []string{}
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil && bytes.Contains(out, []byte("cannot find GOROOT")) {
|
|
t.Skipf("skipping because GOROOT=%s does not exist", runtime.GOROOT())
|
|
}
|
|
|
|
_, file, _, _ := runtime.Caller(1)
|
|
|
|
t.Logf("package testing source file: %s", file)
|
|
t.Fatalf("failed to load Go runtime support: %s\n%s", firstLine, got)
|
|
}
|
|
|
|
// Extract named BEGIN...END blocks from output
|
|
partRe := regexp.MustCompile(`(?ms)^BEGIN ([^\n]*)\n(.*?)\nEND`)
|
|
blocks := map[string]string{}
|
|
for _, subs := range partRe.FindAllSubmatch(got, -1) {
|
|
blocks[string(subs[1])] = string(subs[2])
|
|
}
|
|
|
|
infoGoroutinesRe := regexp.MustCompile(`\*\s+\d+\s+running\s+`)
|
|
if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) {
|
|
t.Fatalf("info goroutines failed: %s", bl)
|
|
}
|
|
|
|
printMapvarRe := regexp.MustCompile(`\Q = map[string]string = {["abc"] = "def", ["ghi"] = "jkl"}\E$`)
|
|
if bl := blocks["print mapvar"]; !printMapvarRe.MatchString(bl) {
|
|
t.Fatalf("print mapvar failed: %s", bl)
|
|
}
|
|
|
|
strVarRe := regexp.MustCompile(`\Q = "abc"\E$`)
|
|
if bl := blocks["print strvar"]; !strVarRe.MatchString(bl) {
|
|
t.Fatalf("print strvar failed: %s", bl)
|
|
}
|
|
|
|
btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`)
|
|
if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) {
|
|
t.Fatalf("goroutine 2 bt failed: %s", bl)
|
|
} else if !canBackTrace {
|
|
t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH)
|
|
}
|
|
}
|