Commit 5286b2ad authored by David Chase's avatar David Chase

cmd/compile: test delve instead of gdb in ssa/debug_test.go

This seems to deflake the test, and also allows testing
on macOS.

Fixes #31786.

Change-Id: I10bfba46dd4b8e64cb09fdd4dd9d175c1ce1f022
Reviewed-on: https://go-review.googlesource.com/c/go/+/176058
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 0793c810
...@@ -22,24 +22,27 @@ import ( ...@@ -22,24 +22,27 @@ import (
"time" "time"
) )
var update = flag.Bool("u", false, "update test reference files") var (
var verbose = flag.Bool("v", false, "print debugger interactions (very verbose)") update = flag.Bool("u", false, "update test reference files")
var dryrun = flag.Bool("n", false, "just print the command line and first debugging bits") verbose = flag.Bool("v", false, "print debugger interactions (very verbose)")
var useDelve = flag.Bool("d", false, "use Delve (dlv) instead of gdb, use dlv reverence files") dryrun = flag.Bool("n", false, "just print the command line and first debugging bits")
var force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir") useGdb = flag.Bool("g", false, "use Gdb instead of Delve (dlv), use gdb reference files")
force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir")
var repeats = flag.Bool("r", false, "detect repeats in debug steps and don't ignore them") repeats = flag.Bool("r", false, "detect repeats in debug steps and don't ignore them")
var inlines = flag.Bool("i", false, "do inlining for gdb (makes testing flaky till inlining info is correct)") inlines = flag.Bool("i", false, "do inlining for gdb (makes testing flaky till inlining info is correct)")
)
var hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+")
var numRe = regexp.MustCompile("-?[0-9]+") var (
var stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"") hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+")
var leadingDollarNumberRe = regexp.MustCompile("^[$][0-9]+") numRe = regexp.MustCompile("-?[0-9]+")
var optOutGdbRe = regexp.MustCompile("[<]optimized out[>]") stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"")
var numberColonRe = regexp.MustCompile("^ *[0-9]+:") leadingDollarNumberRe = regexp.MustCompile("^[$][0-9]+")
optOutGdbRe = regexp.MustCompile("[<]optimized out[>]")
numberColonRe = regexp.MustCompile("^ *[0-9]+:")
)
var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode
var debugger = "gdb" // For naming files, etc. var debugger = "dlv" // For naming files, etc.
var gogcflags = os.Getenv("GO_GCFLAGS") var gogcflags = os.Getenv("GO_GCFLAGS")
...@@ -98,23 +101,18 @@ func TestNexting(t *testing.T) { ...@@ -98,23 +101,18 @@ func TestNexting(t *testing.T) {
} }
testenv.MustHaveGoBuild(t) testenv.MustHaveGoBuild(t)
if !*useDelve && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") { if *useGdb && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") {
// Running gdb on OSX/darwin is very flaky. // Running gdb on OSX/darwin is very flaky.
// Sometimes it is called ggdb, depending on how it is installed. // Sometimes it is called ggdb, depending on how it is installed.
// It also sometimes requires an admin password typed into a dialog box. // It also sometimes requires an admin password typed into a dialog box.
// Various architectures tend to differ slightly sometimes, and keeping them // Various architectures tend to differ slightly sometimes, and keeping them
// all in sync is a pain for people who don't have them all at hand, // all in sync is a pain for people who don't have them all at hand,
// so limit testing to amd64 (for now) // so limit testing to amd64 (for now)
skipReasons += "not run unless linux-amd64 or -d (delve) or -f (force); " skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64"
} }
if *useDelve { if *useGdb {
debugger = "dlv" debugger = "gdb"
_, err := exec.LookPath("dlv")
if err != nil {
skipReasons += "not run because dlv (requested by -d option) not on path; "
}
} else {
_, err := exec.LookPath(gdb) _, err := exec.LookPath(gdb)
if err != nil { if err != nil {
if runtime.GOOS != "darwin" { if runtime.GOOS != "darwin" {
...@@ -123,12 +121,18 @@ func TestNexting(t *testing.T) { ...@@ -123,12 +121,18 @@ func TestNexting(t *testing.T) {
// On Darwin, MacPorts installs gdb as "ggdb". // On Darwin, MacPorts installs gdb as "ggdb".
_, err = exec.LookPath("ggdb") _, err = exec.LookPath("ggdb")
if err != nil { if err != nil {
skipReasons += "not run because gdb (and also ggdb) not on path; " skipReasons += "not run because gdb (and also ggdb) request by -g option not on path; "
} else { } else {
gdb = "ggdb" gdb = "ggdb"
} }
} }
} }
} else { // Delve
debugger = "dlv"
_, err := exec.LookPath("dlv")
if err != nil {
skipReasons += "not run because dlv not on path; "
}
} }
if skipReasons != "" { if skipReasons != "" {
...@@ -137,14 +141,14 @@ func TestNexting(t *testing.T) { ...@@ -137,14 +141,14 @@ func TestNexting(t *testing.T) {
optFlags := "" // Whatever flags are needed to test debugging of optimized code. optFlags := "" // Whatever flags are needed to test debugging of optimized code.
dbgFlags := "-N -l" dbgFlags := "-N -l"
if !*useDelve && !*inlines { if *useGdb && !*inlines {
// For gdb (default), disable inlining so that a compiler test does not depend on library code. // For gdb (default), disable inlining so that a compiler test does not depend on library code.
// TODO: Technically not necessary in 1.10, but it causes a largish regression that needs investigation. // TODO: Technically not necessary in 1.10 and later, but it causes a largish regression that needs investigation.
optFlags += " -l" optFlags += " -l"
} }
moreargs := []string{} moreargs := []string{}
if !*useDelve && (runtime.GOOS == "darwin" || runtime.GOOS == "windows") { if *useGdb && (runtime.GOOS == "darwin" || runtime.GOOS == "windows") {
// gdb and lldb on Darwin do not deal with compressed dwarf. // gdb and lldb on Darwin do not deal with compressed dwarf.
// also, Windows. // also, Windows.
moreargs = append(moreargs, "-ldflags=-compressdwarf=false") moreargs = append(moreargs, "-ldflags=-compressdwarf=false")
...@@ -158,7 +162,12 @@ func TestNexting(t *testing.T) { ...@@ -158,7 +162,12 @@ func TestNexting(t *testing.T) {
optSubTest(t, debugger+"-opt", "hist", optFlags, 1000, moreargs...) optSubTest(t, debugger+"-opt", "hist", optFlags, 1000, moreargs...)
optSubTest(t, debugger+"-opt", "scopes", optFlags, 1000, moreargs...) optSubTest(t, debugger+"-opt", "scopes", optFlags, 1000, moreargs...)
optSubTest(t, debugger+"-opt", "infloop", optFlags, 10, moreargs...)
// Was optSubtest, this test is observed flaky on Linux in Docker on (busy) macOS, probably because of timing
// glitches in this harness.
// TODO get rid of timing glitches in this harness.
skipSubTest(t, debugger+"-opt", "infloop", optFlags, 10, moreargs...)
} }
// subTest creates a subtest that compiles basename.go with the specified gcflags and additional compiler arguments, // subTest creates a subtest that compiles basename.go with the specified gcflags and additional compiler arguments,
...@@ -172,6 +181,17 @@ func subTest(t *testing.T, tag string, basename string, gcflags string, moreargs ...@@ -172,6 +181,17 @@ func subTest(t *testing.T, tag string, basename string, gcflags string, moreargs
}) })
} }
// skipSubTest is the same as subTest except that it skips the test if execution is not forced (-f)
func skipSubTest(t *testing.T, tag string, basename string, gcflags string, count int, moreargs ...string) {
t.Run(tag+"-"+basename, func(t *testing.T) {
if *force {
testNexting(t, basename, tag, gcflags, count, moreargs...)
} else {
t.Skip("skipping flaky test becaused not forced (-f)")
}
})
}
// optSubTest is the same as subTest except that it skips the test if the runtime and libraries // optSubTest is the same as subTest except that it skips the test if the runtime and libraries
// were not compiled with optimization turned on. (The skip may not be necessary with Go 1.10 and later) // were not compiled with optimization turned on. (The skip may not be necessary with Go 1.10 and later)
func optSubTest(t *testing.T, tag string, basename string, gcflags string, count int, moreargs ...string) { func optSubTest(t *testing.T, tag string, basename string, gcflags string, count int, moreargs ...string) {
...@@ -218,10 +238,10 @@ func testNexting(t *testing.T, base, tag, gcflags string, count int, moreArgs .. ...@@ -218,10 +238,10 @@ func testNexting(t *testing.T, base, tag, gcflags string, count int, moreArgs ..
nextlog := testbase + ".nexts" nextlog := testbase + ".nexts"
tmplog := tmpbase + ".nexts" tmplog := tmpbase + ".nexts"
var dbg dbgr var dbg dbgr
if *useDelve { if *useGdb {
dbg = newDelve(tag, exe)
} else {
dbg = newGdb(tag, exe) dbg = newGdb(tag, exe)
} else {
dbg = newDelve(tag, exe)
} }
h1 := runDbgr(dbg, count) h1 := runDbgr(dbg, count)
if *dryrun { if *dryrun {
...@@ -539,7 +559,7 @@ func (s *delveState) start() { ...@@ -539,7 +559,7 @@ func (s *delveState) start() {
panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err)) panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err))
} }
s.ioState.readExpecting(-1, 5000, "Type 'help' for list of commands.") s.ioState.readExpecting(-1, 5000, "Type 'help' for list of commands.")
expect("Breakpoint [0-9]+ set at ", s.ioState.writeReadExpect("b main.test\n", "[(]dlv[)] ")) s.ioState.writeReadExpect("b main.test\n", "[(]dlv[)] ")
s.stepnext("c") s.stepnext("c")
} }
...@@ -598,7 +618,7 @@ func (s *gdbState) start() { ...@@ -598,7 +618,7 @@ func (s *gdbState) start() {
line := asCommandLine("", s.cmd) line := asCommandLine("", s.cmd)
panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err)) panic(fmt.Sprintf("There was an error [start] running '%s', %v\n", line, err))
} }
s.ioState.readExpecting(-1, -1, "[(]gdb[)] ") s.ioState.readSimpleExpecting("[(]gdb[)] ")
x := s.ioState.writeReadExpect("b main.test\n", "[(]gdb[)] ") x := s.ioState.writeReadExpect("b main.test\n", "[(]gdb[)] ")
expect("Breakpoint [0-9]+ at", x) expect("Breakpoint [0-9]+ at", x)
s.stepnext(run) s.stepnext(run)
...@@ -840,7 +860,7 @@ func (s *ioState) writeReadExpect(ss, expectRE string) tstring { ...@@ -840,7 +860,7 @@ func (s *ioState) writeReadExpect(ss, expectRE string) tstring {
if err != nil { if err != nil {
panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err)) panic(fmt.Sprintf("There was an error writing '%s', %v\n", ss, err))
} }
return s.readExpecting(-1, -1, expectRE) return s.readSimpleExpecting(expectRE)
} }
func (s *ioState) readExpecting(millis, interlineTimeout int, expectedRE string) tstring { func (s *ioState) readExpecting(millis, interlineTimeout int, expectedRE string) tstring {
...@@ -887,6 +907,40 @@ loop: ...@@ -887,6 +907,40 @@ loop:
return s.last return s.last
} }
func (s *ioState) readSimpleExpecting(expectedRE string) tstring {
s.last = tstring{}
var re *regexp.Regexp
if expectedRE != "" {
re = regexp.MustCompile(expectedRE)
}
for {
select {
case x, ok := <-s.outChan:
if !ok {
s.outChan = nil
}
s.last.o += x
case x, ok := <-s.errChan:
if !ok {
s.errChan = nil
}
s.last.e += x
}
if re != nil {
if re.MatchString(s.last.o) {
break
}
if re.MatchString(s.last.e) {
break
}
}
}
if *verbose {
fmt.Printf("<= %s%s", s.last.o, s.last.e)
}
return s.last
}
// replaceEnv returns a new environment derived from env // replaceEnv returns a new environment derived from env
// by removing any existing definition of ev and adding ev=evv. // by removing any existing definition of ev and adding ev=evv.
func replaceEnv(env []string, ev string, evv string) []string { func replaceEnv(env []string, ev string, evv string) []string {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment