Skip to content

Instantly share code, notes, and snippets.

@urso
Last active September 8, 2017 14:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save urso/4e2c074b11ca6118f6a32a50ba3f13d4 to your computer and use it in GitHub Desktop.
Save urso/4e2c074b11ca6118f6a32a50ba3f13d4 to your computer and use it in GitHub Desktop.
add 'allgroutines <cmd>' to gdb (e.g. `(gdb) allgroutines bt`)
from __future__ import print_function
""" GDB 'allgoroutines' command for executing gdb command within the context of every goroutine at once """
class GoroutineStacks(gdb.Command):
"Print stacktrace for all goroutines."
def __init__(self):
gdb.Command.__init__(self, "allgoroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
def invoke(self, arg, _from_tty):
command = arg
def onGoRoutine(g, pc, sp):
try:
pc = int(pc)
except gdb.error:
pc = int(str(pc).split(None, 1)[0], 16)
save_frame = gdb.selected_frame()
gdb.parse_and_eval('$save_sp = $sp')
gdb.parse_and_eval('$save_pc = $pc')
gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
try:
print("goroutine {} {} {}".format(g['goid'], command, 20*"="))
gdb.execute(command)
finally:
gdb.parse_and_eval('$sp = $save_sp')
gdb.parse_and_eval('$pc = $save_pc')
save_frame.select()
eachGoRoutine(onGoRoutine)
def eachGoRoutine(cb):
vp = gdb.lookup_type('void').pointer()
allgs = SliceValue(gdb.parse_and_eval("'runtime.allgs'"))
for ptr in allgs:
if ptr['atomicstatus'] == 6: # 'gdead'
continue
pc, sp = ptr['sched']['pc'], ptr['sched']['sp']
if sp != 0:
# goroutine is stopped -> report pc/sp as is stored in workqueue
cb(ptr, pc.cast(vp), sp.cast(vp))
continue
pc, sp = ptr['syscallpc'], ptr['syscallsp']
if sp != 0:
# goroutine waiting for syscall completion
cb(ptr, pc.cast(vp), sp.cast(vp))
continue
# Otherwise, the goroutine is running, so it doesn't have
# saved scheduler state. Find G's OS thread.
m = ptr['m']
if m == 0:
continue # hmmm.... No OS thread assigned
for thr in gdb.selected_inferior().threads():
if thr.ptid[1] == m['procid']:
break
else:
continue # can not find OS thread in gdb
curthr = gdb.selected_thread()
try:
thr.switch()
pc = gdb.parse_and_eval('$pc')
sp = gdb.parse_and_eval('$sp')
finally:
curthr.switch()
cb(ptr, pc.cast(vp), sp.cast(vp))
GoroutineStacks()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment