]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/gdb: use goroutine atomicstatus to determine the state
authorHana Kim <hakim@google.com>
Tue, 16 Jan 2018 20:31:12 +0000 (15:31 -0500)
committerHyang-Ah Hana Kim <hyangah@gmail.com>
Tue, 13 Feb 2018 19:23:37 +0000 (19:23 +0000)
Previously find_goroutine determined whether a goroutine is
stopped by checking the sched.sp field. This heuristic doesn't
always hold but causes find_goroutine to return bogus pc/sp
info for running goroutines.

This change uses the atomicstatus bit to determine
the state which is more accurate.

R=go1.11

Change-Id: I537d432d9e0363257120a196ce2ba52da2970f59
Reviewed-on: https://go-review.googlesource.com/49691
Reviewed-by: Austin Clements <austin@google.com>
src/runtime/runtime-gdb.py
src/runtime/runtime-gdb_test.go

index 3e8e1aaa7de275e2f3524c7447624d176f488305..cd16a6cbab70f41bfbe37b8ca410f814882d00d0 100644 (file)
@@ -462,9 +462,11 @@ def find_goroutine(goid):
                return None, None
        # Get the goroutine's saved state.
        pc, sp = ptr['sched']['pc'], ptr['sched']['sp']
-       # If the goroutine is stopped, sched.sp will be non-0.
-       if sp != 0:
+       status = ptr['atomicstatus']&~G_SCAN
+       # Goroutine is not running nor in syscall, so use the info in goroutine
+       if status != G_RUNNING and status != G_SYSCALL:
                return pc.cast(vp), sp.cast(vp)
+
        # If the goroutine is in a syscall, use syscallpc/sp.
        pc, sp = ptr['syscallpc'], ptr['syscallsp']
        if sp != 0:
index 5e0508631f3cbcc66bb2c49f1406e45803dac4f7..c96bb952226f5f8c14d2a639d13836b8e043aa22 100644 (file)
@@ -87,13 +87,24 @@ func main() {
        ptrvar := &strvar
        slicevar := make([]string, 0, 16)
        slicevar = append(slicevar, mapvar["abc"])
-       fmt.Println("hi") // line 13
+       fmt.Println("hi")
        runtime.KeepAlive(ptrvar)
+       _ = ptrvar
        gslice = slicevar
        runtime.KeepAlive(mapvar)
-}
+}  // END_OF_PROGRAM
 `
 
+func lastLine(src []byte) int {
+       eop := []byte("END_OF_PROGRAM")
+       for i, l := range bytes.Split(src, []byte("\n")) {
+               if bytes.Contains(l, eop) {
+                       return i
+               }
+       }
+       return 0
+}
+
 func TestGdbPython(t *testing.T) {
        testGdbPython(t, false)
 }
@@ -128,11 +139,13 @@ func testGdbPython(t *testing.T, cgo bool) {
        }
        buf.WriteString(helloSource)
 
-       src := filepath.Join(dir, "main.go")
-       err = ioutil.WriteFile(src, buf.Bytes(), 0644)
+       src := buf.Bytes()
+
+       err = ioutil.WriteFile(filepath.Join(dir, "main.go"), src, 0644)
        if err != nil {
                t.Fatalf("failed to create file: %v", err)
        }
+       nLines := lastLine(src)
 
        cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
        cmd.Dir = dir
@@ -168,9 +181,16 @@ func testGdbPython(t *testing.T, cgo bool) {
                "-ex", "echo BEGIN goroutine 2 bt\n",
                "-ex", "goroutine 2 bt",
                "-ex", "echo END\n",
+               "-ex", "clear fmt.Println", // clear the previous break point
+               "-ex", fmt.Sprintf("br main.go:%d", nLines), // new break point at the end of main
+               "-ex", "c",
+               "-ex", "echo BEGIN goroutine 1 bt at the end\n",
+               "-ex", "goroutine 1 bt",
+               "-ex", "echo END\n",
                filepath.Join(dir, "a.exe"),
        }
        got, _ := exec.Command("gdb", args...).CombinedOutput()
+       t.Logf("gdb output: %s\n", got)
 
        firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
        if string(firstLine) != "Loading Go Runtime support." {
@@ -232,6 +252,10 @@ func testGdbPython(t *testing.T, cgo bool) {
        if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) {
                t.Fatalf("goroutine 2 bt failed: %s", bl)
        }
+       btGoroutine1AtTheEndRe := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`)
+       if bl := blocks["goroutine 1 bt at the end"]; !btGoroutine1AtTheEndRe.MatchString(bl) {
+               t.Fatalf("goroutine 1 bt at the end failed: %s", bl)
+       }
 }
 
 const backtraceSource = `