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  }