diff options
Diffstat (limited to 'src/runtime/runtime-gdb_test.go')
| -rw-r--r-- | src/runtime/runtime-gdb_test.go | 124 |
1 files changed, 107 insertions, 17 deletions
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 110d99064f..4f82646dbb 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -3,6 +3,7 @@ package runtime_test import ( "bytes" "fmt" + "internal/testenv" "io/ioutil" "os" "os/exec" @@ -13,19 +14,22 @@ import ( "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) +func checkGdbEnvironment(t *testing.T) { + testenv.MustHaveGoBuild(t) + if runtime.GOOS == "darwin" { + t.Skip("gdb does not work on darwin") } - if string(out) != "go gdb python support\n" { - t.Skipf("skipping due to lack of python gdb support: %s", out) + if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { + t.Skip("gdb test can fail with GOROOT_FINAL pending") } +} +func checkGdbVersion(t *testing.T) { // Issue 11214 reports various failures with older versions of gdb. - out, err = exec.Command("gdb", "--version").CombinedOutput() + out, err := exec.Command("gdb", "--version").CombinedOutput() + if err != nil { + t.Skipf("skipping: error executing gdb: %v", err) + } re := regexp.MustCompile(`([0-9]+)\.([0-9]+)`) matches := re.FindSubmatch(out) if len(matches) < 3 { @@ -42,6 +46,18 @@ func checkGdbPython(t *testing.T) { t.Logf("gdb version %d.%d", major, minor) } +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) + } +} + const helloSource = ` package main import "fmt" @@ -57,13 +73,8 @@ func main() { ` 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") - } - + checkGdbEnvironment(t) + checkGdbVersion(t) checkGdbPython(t) dir, err := ioutil.TempDir("", "go-build") @@ -104,7 +115,7 @@ func TestGdbPython(t *testing.T) { // stack frames on RISC architectures. canBackTrace := false switch runtime.GOARCH { - case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64", "mips64", "mips64le": + case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64", "mips64", "mips64le", "s390x": canBackTrace = true args = append(args, "-ex", "echo BEGIN goroutine 2 bt\n", @@ -162,3 +173,82 @@ func TestGdbPython(t *testing.T) { t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH) } } + +const backtraceSource = ` +package main + +//go:noinline +func aaa() bool { return bbb() } + +//go:noinline +func bbb() bool { return ccc() } + +//go:noinline +func ccc() bool { return ddd() } + +//go:noinline +func ddd() bool { return f() } + +//go:noinline +func eee() bool { return true } + +var f = eee + +func main() { + _ = aaa() +} +` + +// TestGdbBacktrace tests that gdb can unwind the stack correctly +// using only the DWARF debug info. +func TestGdbBacktrace(t *testing.T) { + checkGdbEnvironment(t) + checkGdbVersion(t) + + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + // Build the source code. + src := filepath.Join(dir, "main.go") + err = ioutil.WriteFile(src, []byte(backtraceSource), 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) + } + + // Execute gdb commands. + args := []string{"-nx", "-batch", + "-ex", "break main.eee", + "-ex", "run", + "-ex", "backtrace", + "-ex", "continue", + filepath.Join(dir, "a.exe"), + } + got, _ := exec.Command("gdb", args...).CombinedOutput() + + // Check that the backtrace matches the source code. + bt := []string{ + "eee", + "ddd", + "ccc", + "bbb", + "aaa", + "main", + } + for i, name := range bt { + s := fmt.Sprintf("#%v.*main\\.%v", i, name) + re := regexp.MustCompile(s) + if found := re.Find(got) != nil; !found { + t.Errorf("could not find '%v' in backtrace", s) + t.Fatalf("gdb output:\n%v", string(got)) + } + } +} |
