rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/runtime/runtime-gdb_test.go (about) 1 package runtime_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "regexp" 11 "runtime" 12 "testing" 13 ) 14 15 func checkGdbPython(t *testing.T) { 16 cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')") 17 out, err := cmd.CombinedOutput() 18 19 if err != nil { 20 t.Skipf("skipping due to issue running gdb: %v", err) 21 } 22 if string(out) != "go gdb python support\n" { 23 t.Skipf("skipping due to lack of python gdb support: %s", out) 24 } 25 } 26 27 const helloSource = ` 28 package main 29 import "fmt" 30 func main() { 31 mapvar := make(map[string]string,5) 32 mapvar["abc"] = "def" 33 mapvar["ghi"] = "jkl" 34 strvar := "abc" 35 ptrvar := &strvar 36 fmt.Println("hi") // line 10 37 _ = ptrvar 38 } 39 ` 40 41 func TestGdbPython(t *testing.T) { 42 if runtime.GOOS == "darwin" { 43 t.Skip("gdb does not work on darwin") 44 } 45 46 checkGdbPython(t) 47 48 dir, err := ioutil.TempDir("", "go-build") 49 if err != nil { 50 t.Fatalf("failed to create temp directory: %v", err) 51 } 52 defer os.RemoveAll(dir) 53 54 src := filepath.Join(dir, "main.go") 55 err = ioutil.WriteFile(src, []byte(helloSource), 0644) 56 if err != nil { 57 t.Fatalf("failed to create file: %v", err) 58 } 59 60 cmd := exec.Command("go", "build", "-o", "a.exe") 61 cmd.Dir = dir 62 out, err := cmd.CombinedOutput() 63 if err != nil { 64 t.Fatalf("building source %v\n%s", err, out) 65 } 66 67 got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", 68 fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()), 69 "-ex", "br main.go:10", 70 "-ex", "run", 71 "-ex", "echo BEGIN info goroutines\n", 72 "-ex", "info goroutines", 73 "-ex", "echo END\n", 74 "-ex", "echo BEGIN print mapvar\n", 75 "-ex", "print mapvar", 76 "-ex", "echo END\n", 77 "-ex", "echo BEGIN print strvar\n", 78 "-ex", "print strvar", 79 "-ex", "echo END\n", 80 "-ex", "echo BEGIN print ptrvar\n", 81 "-ex", "print ptrvar", 82 "-ex", "echo END\n", 83 "-ex", "echo BEGIN goroutine 2 bt\n", 84 "-ex", "goroutine 2 bt", 85 "-ex", "echo END\n", 86 filepath.Join(dir, "a.exe")).CombinedOutput() 87 88 firstLine := bytes.SplitN(got, []byte("\n"), 2)[0] 89 if string(firstLine) != "Loading Go Runtime support." { 90 t.Fatalf("failed to load Go runtime support: %s", firstLine) 91 } 92 93 // Extract named BEGIN...END blocks from output 94 partRe := regexp.MustCompile(`(?ms)^BEGIN ([^\n]*)\n(.*?)\nEND`) 95 blocks := map[string]string{} 96 for _, subs := range partRe.FindAllSubmatch(got, -1) { 97 blocks[string(subs[1])] = string(subs[2]) 98 } 99 100 infoGoroutinesRe := regexp.MustCompile(`\*\s+\d+\s+running\s+`) 101 if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) { 102 t.Fatalf("info goroutines failed: %s", bl) 103 } 104 105 printMapvarRe := regexp.MustCompile(`\Q = map[string]string = {["abc"] = "def", ["ghi"] = "jkl"}\E$`) 106 if bl := blocks["print mapvar"]; !printMapvarRe.MatchString(bl) { 107 t.Fatalf("print mapvar failed: %s", bl) 108 } 109 110 strVarRe := regexp.MustCompile(`\Q = "abc"\E$`) 111 if bl := blocks["print strvar"]; !strVarRe.MatchString(bl) { 112 t.Fatalf("print strvar failed: %s", bl) 113 } 114 115 if bl := blocks["print ptrvar"]; !strVarRe.MatchString(bl) { 116 t.Fatalf("print ptrvar failed: %s", bl) 117 } 118 119 btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`) 120 if bl := blocks["goroutine 2 bt"]; !btGoroutineRe.MatchString(bl) { 121 t.Fatalf("goroutine 2 bt failed: %s", bl) 122 } 123 }