From ee776b41267ee910196b616b7104f0e5ed63d2b2 Mon Sep 17 00:00:00 2001 From: David Chase Date: Mon, 1 Jun 2020 14:30:24 -0400 Subject: [PATCH] runtime: repair slice, string, and channel printing in gdb "Something" changed the names of types in gdb, causing the pretty-printer matchers to fail to match. This tracks that change. Updated runtime-gdb_test.go to include a slice and a channel printing test. (The straightforward printing of a slicevar doesn't work because of compiler DWARF problems describing the slicevar, not gdb problems). Change-Id: I21607a955b9c894f11ecf3763aea2a6dd59a3f42 Reviewed-on: https://go-review.googlesource.com/c/go/+/235926 Run-TryBot: David Chase TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh --- src/runtime/runtime-gdb.py | 19 +++++++----- src/runtime/runtime-gdb_test.go | 55 ++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py index 6139f99485..b883d87f2d 100644 --- a/src/runtime/runtime-gdb.py +++ b/src/runtime/runtime-gdb.py @@ -18,6 +18,7 @@ path to this file based on the path to the runtime package. from __future__ import print_function import re import sys +import gdb print("Loading Go Runtime support.", file=sys.stderr) #http://python3porting.com/differences.html @@ -27,6 +28,12 @@ if sys.version > '3': goobjfile = gdb.current_objfile() or gdb.objfiles()[0] goobjfile.pretty_printers = [] +# Older gdb renders some types differently. +def oldnew(old, new): + if (gdb.VERSION[0] == '7'): + return old + return new + # G state (runtime2.go) def read_runtime_const(varname, default): @@ -102,7 +109,7 @@ class SliceValue: class StringTypePrinter: "Pretty print Go strings." - pattern = re.compile(r'^struct string( \*)?$') + pattern = re.compile(oldnew(r'^struct string( \*)?$',r'^string$')) def __init__(self, val): self.val = val @@ -118,7 +125,7 @@ class StringTypePrinter: class SliceTypePrinter: "Pretty print slices." - pattern = re.compile(r'^struct \[\]') + pattern = re.compile(oldnew(r'^struct \[\]',r'^\[\]')) def __init__(self, val): self.val = val @@ -127,7 +134,7 @@ class SliceTypePrinter: return 'array' def to_string(self): - return str(self.val.type)[6:] # skip 'struct ' + return str(self.val.type)[oldnew(6,0):] # skip 'struct ' for old gdb def children(self): sval = SliceValue(self.val) @@ -195,7 +202,7 @@ class ChanTypePrinter: to inspect their contents with this pretty printer. """ - pattern = re.compile(r'^struct hchan<.*>$') + pattern = re.compile(oldnew(r'^struct hchan<.*>$',r'^chan ')) def __init__(self, val): self.val = val @@ -209,7 +216,7 @@ class ChanTypePrinter: def children(self): # see chan.c chanbuf(). et is the type stolen from hchan::recvq->first->elem et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0] - ptr = (self.val.address + 1).cast(et.pointer()) + ptr = (self.val.address["buf"]).cast(et) for i in range(self.val["qcount"]): j = (self.val["recvx"] + i) % self.val["dataqsiz"] yield ('[{0}]'.format(i), (ptr + j).dereference()) @@ -229,8 +236,6 @@ def makematcher(klass): return matcher goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')]) - - # # Utilities # diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 7cfd5b95dd..f1ff51dad0 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -55,7 +55,9 @@ func checkGdbEnvironment(t *testing.T) { } } -func checkGdbVersion(t *testing.T) { +// checkGdbVersion ensures gdb version is supported, and returns major version +// to allow testing conditional on gdb version. +func checkGdbVersion(t *testing.T) int { // Issue 11214 reports various failures with older versions of gdb. out, err := exec.Command("gdb", "--version").CombinedOutput() if err != nil { @@ -75,6 +77,7 @@ func checkGdbVersion(t *testing.T) { t.Skipf("skipping: gdb version %d.%d too old", major, minor) } t.Logf("gdb version %d.%d", major, minor) + return major } func checkGdbPython(t *testing.T) { @@ -115,8 +118,17 @@ import "runtime" var gslice []string func main() { mapvar := make(map[string]string, 13) + slicemap := make(map[string][]string,11) + chanint := make(chan int, 10) + chanstr := make(chan string, 10) + chanint <- 99 + chanint <- 11 + chanstr <- "spongepants" + chanstr <- "squarebob" mapvar["abc"] = "def" mapvar["ghi"] = "jkl" + slicemap["a"] = []string{"b","c","d"} + slicemap["e"] = []string{"f","g","h"} strvar := "abc" ptrvar := &strvar slicevar := make([]string, 0, 16) @@ -125,6 +137,7 @@ func main() { runtime.KeepAlive(ptrvar) _ = ptrvar // set breakpoint here gslice = slicevar + fmt.Printf("%v, %v, %v\n", slicemap, <-chanint, <-chanstr) runtime.KeepAlive(mapvar) } // END_OF_PROGRAM ` @@ -157,7 +170,7 @@ func testGdbPython(t *testing.T, cgo bool) { checkGdbEnvironment(t) t.Parallel() - checkGdbVersion(t) + gdbMajor := checkGdbVersion(t) checkGdbPython(t) dir, err := ioutil.TempDir("", "go-build") @@ -227,9 +240,18 @@ func testGdbPython(t *testing.T, cgo bool) { "-ex", "echo BEGIN print mapvar\n", "-ex", "print mapvar", "-ex", "echo END\n", + "-ex", "echo BEGIN print slicemap\n", + "-ex", "print slicemap", + "-ex", "echo END\n", "-ex", "echo BEGIN print strvar\n", "-ex", "print strvar", "-ex", "echo END\n", + "-ex", "echo BEGIN print chanint\n", + "-ex", "print chanint", + "-ex", "echo END\n", + "-ex", "echo BEGIN print chanstr\n", + "-ex", "print chanstr", + "-ex", "echo END\n", "-ex", "echo BEGIN info locals\n", "-ex", "info locals", "-ex", "echo END\n", @@ -290,6 +312,25 @@ func testGdbPython(t *testing.T, cgo bool) { t.Fatalf("print mapvar failed: %s", bl) } + // 2 orders, and possible differences in spacing. + sliceMapSfx1 := `map[string][]string = {["e"] = []string = {"f", "g", "h"}, ["a"] = []string = {"b", "c", "d"}}` + sliceMapSfx2 := `map[string][]string = {["a"] = []string = {"b", "c", "d"}, ["e"] = []string = {"f", "g", "h"}}` + if bl := strings.ReplaceAll(blocks["print slicemap"], " ", " "); !strings.HasSuffix(bl, sliceMapSfx1) && !strings.HasSuffix(bl, sliceMapSfx2) { + t.Fatalf("print slicemap failed: %s", bl) + } + + if gdbMajor > 7 { + chanIntSfx := `chan int = {99, 11}` + if bl := strings.ReplaceAll(blocks["print chanint"], " ", " "); !strings.HasSuffix(bl, chanIntSfx) { + t.Fatalf("print chanint failed: %s", bl) + } + + chanStrSfx := `chan string = {"spongepants", "squarebob"}` + if bl := strings.ReplaceAll(blocks["print chanstr"], " ", " "); !strings.HasSuffix(bl, chanStrSfx) { + t.Fatalf("print chanstr failed: %s", bl) + } + } + strVarRe := regexp.MustCompile(`^\$[0-9]+ = (0x[0-9a-f]+\s+)?"abc"$`) if bl := blocks["print strvar"]; !strVarRe.MatchString(bl) { t.Fatalf("print strvar failed: %s", bl) @@ -366,7 +407,7 @@ func TestGdbBacktrace(t *testing.T) { checkGdbEnvironment(t) t.Parallel() - checkGdbVersion(t) + _ = checkGdbVersion(t) dir, err := ioutil.TempDir("", "go-build") if err != nil { @@ -440,7 +481,7 @@ func main() { func TestGdbAutotmpTypes(t *testing.T) { checkGdbEnvironment(t) t.Parallel() - checkGdbVersion(t) + _ = checkGdbVersion(t) if runtime.GOOS == "aix" && testing.Short() { t.Skip("TestGdbAutotmpTypes is too slow on aix/ppc64") @@ -513,7 +554,7 @@ func main() { func TestGdbConst(t *testing.T) { checkGdbEnvironment(t) t.Parallel() - checkGdbVersion(t) + _ = checkGdbVersion(t) dir, err := ioutil.TempDir("", "go-build") if err != nil { @@ -580,7 +621,7 @@ func crash() { func TestGdbPanic(t *testing.T) { checkGdbEnvironment(t) t.Parallel() - checkGdbVersion(t) + _ = checkGdbVersion(t) dir, err := ioutil.TempDir("", "go-build") if err != nil { @@ -658,7 +699,7 @@ func TestGdbInfCallstack(t *testing.T) { } t.Parallel() - checkGdbVersion(t) + _ = checkGdbVersion(t) dir, err := ioutil.TempDir("", "go-build") if err != nil { -- 2.48.1