goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
goobjfile.pretty_printers = []
+#
+# Value wrappers
+#
+
+class SliceValue:
+ "Wrapper for slice values."
+
+ def __init__(self, val):
+ self.val = val
+
+ @property
+ def len(self):
+ return int(self.val['len'])
+
+ @property
+ def cap(self):
+ return int(self.val['cap'])
+
+ def __getitem__(self, i):
+ if i < 0 or i >= self.len:
+ raise IndexError(i)
+ ptr = self.val["array"]
+ return (ptr + i).dereference()
+
+
#
# Pretty Printers
#
def invoke(self, _arg, _from_tty):
# args = gdb.string_to_argv(arg)
vp = gdb.lookup_type('void').pointer()
- for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
+ if ptr['atomicstatus'] == 6: # 'gdead'
continue
s = ' '
if ptr['m']:
#python3 / newer versions of gdb
pc = int(pc)
except gdb.error:
- pc = int(str(pc), 16)
+ # str(pc) can return things like
+ # "0x429d6c <runtime.gopark+284>", so
+ # chop at first space.
+ pc = int(str(pc).split(None, 1)[0], 16)
blk = gdb.block_for_pc(pc)
- print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
+ print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['atomicstatus'])]), blk.function)
def find_goroutine(goid):
@return tuple (gdb.Value, gdb.Value)
"""
vp = gdb.lookup_type('void').pointer()
- for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
- if ptr['status'] == 6: # 'gdead'
+ for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
+ if ptr['atomicstatus'] == 6: # 'gdead'
continue
if ptr['goid'] == goid:
return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
package runtime_test
import (
+ "bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
"testing"
)
}
`
-func TestGdbLoadRuntimeSupport(t *testing.T) {
+func TestGdbPython(t *testing.T) {
checkGdbPython(t)
dir, err := ioutil.TempDir("", "go-build")
got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
+ "-ex", "br 'main.main'",
+ "-ex", "run",
+ "-ex", "echo BEGIN info goroutines\n",
+ "-ex", "info goroutines",
+ "-ex", "echo END\n",
filepath.Join(dir, "a.exe")).CombinedOutput()
- if string(got) != "Loading Go Runtime support.\n" {
- t.Fatalf("%s", got)
+
+ firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
+ if string(firstLine) != "Loading Go Runtime support." {
+ t.Fatalf("failed to load Go runtime support: %s", firstLine)
+ }
+
+ // Extract named BEGIN...END blocks from output
+ partRe := regexp.MustCompile(`(?ms)^BEGIN ([^\n]*)\n(.*?)\nEND`)
+ blocks := map[string]string{}
+ for _, subs := range partRe.FindAllSubmatch(got, -1) {
+ blocks[string(subs[1])] = string(subs[2])
+ }
+
+ infoGoroutinesRe := regexp.MustCompile(`\d+\s+running\s+runtime`)
+ if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) {
+ t.Fatalf("info goroutines failed: %s", bl)
}
}