mirror of https://github.com/golang/go.git
runtime: fix GDB goroutine N command when N is running
The current implementation of "goroutine N cmd" assumes it can get goroutine N's state from the goroutine's sched buffer. But this only works if the goroutine is blocked. Extend find_goroutine so that, if there is no saved scheduler state for a goorutine, it tries to find the thread the goroutine is running on and use the thread's current register state. We also extend find_goroutine to understand saved syscall register state. Fixes #13887. Change-Id: I739008a8987471deaa4a9da918655e4042cf969b Reviewed-on: https://go-review.googlesource.com/45031 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
631cdec676
commit
2465971781
|
|
@ -416,8 +416,37 @@ def find_goroutine(goid):
|
|||
if ptr['atomicstatus'] == 6: # 'gdead'
|
||||
continue
|
||||
if ptr['goid'] == goid:
|
||||
return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
|
||||
return None, None
|
||||
break
|
||||
else:
|
||||
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:
|
||||
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:
|
||||
return pc.cast(vp), sp.cast(vp)
|
||||
# Otherwise, the goroutine is running, so it doesn't have
|
||||
# saved scheduler state. Find G's OS thread.
|
||||
m = ptr['m']
|
||||
if m == 0:
|
||||
return None, None
|
||||
for thr in gdb.selected_inferior().threads():
|
||||
if thr.ptid[1] == m['procid']:
|
||||
break
|
||||
else:
|
||||
return None, None
|
||||
# Get scheduler state from the G's OS thread state.
|
||||
curthr = gdb.selected_thread()
|
||||
try:
|
||||
thr.switch()
|
||||
pc = gdb.parse_and_eval('$pc')
|
||||
sp = gdb.parse_and_eval('$sp')
|
||||
finally:
|
||||
curthr.switch()
|
||||
return pc.cast(vp), sp.cast(vp)
|
||||
|
||||
|
||||
class GoroutineCmd(gdb.Command):
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@ func testGdbPython(t *testing.T, cgo bool) {
|
|||
"-ex", "info locals",
|
||||
"-ex", "echo END\n",
|
||||
"-ex", "down", // back to fmt.Println (goroutine 2 below only works at bottom of stack. TODO: fix that)
|
||||
"-ex", "echo BEGIN goroutine 1 bt\n",
|
||||
"-ex", "goroutine 1 bt",
|
||||
"-ex", "echo END\n",
|
||||
"-ex", "echo BEGIN goroutine 2 bt\n",
|
||||
"-ex", "goroutine 2 bt",
|
||||
"-ex", "echo END\n",
|
||||
|
|
@ -213,8 +216,13 @@ func testGdbPython(t *testing.T, cgo bool) {
|
|||
t.Fatalf("info locals failed: %s", bl)
|
||||
}
|
||||
|
||||
btGoroutineRe := regexp.MustCompile(`^#0\s+(0x[0-9a-f]+\s+in\s+)?runtime.+at`)
|
||||
if bl := blocks["goroutine 2 bt"]; !btGoroutineRe.MatchString(bl) {
|
||||
btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?fmt\.Println.+at`)
|
||||
if bl := blocks["goroutine 1 bt"]; !btGoroutine1Re.MatchString(bl) {
|
||||
t.Fatalf("goroutine 1 bt failed: %s", bl)
|
||||
}
|
||||
|
||||
btGoroutine2Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?runtime.+at`)
|
||||
if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) {
|
||||
t.Fatalf("goroutine 2 bt failed: %s", bl)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue