mirror of
https://github.com/golang/go
synced 2024-11-19 20:54:39 -07:00
175 lines
3.7 KiB
Python
175 lines
3.7 KiB
Python
|
# Copyright 2010 The Go Authors. All rights reserved.
|
||
|
# Use of this source code is governed by a BSD-style
|
||
|
# license that can be found in the LICENSE file.
|
||
|
|
||
|
"""GDB Pretty printers and convencience functions for Go's runtime structures.
|
||
|
|
||
|
This script is loaded by GDB when it finds a .debug_gdb_scripts
|
||
|
section in the compiled binary. The [68]l linkers emit this with a
|
||
|
path to this file based on the path to the runtime package.
|
||
|
"""
|
||
|
|
||
|
import sys, re
|
||
|
|
||
|
print >>sys.stderr, "Loading Go Runtime support."
|
||
|
|
||
|
#
|
||
|
# Pretty Printers
|
||
|
#
|
||
|
|
||
|
class StringTypePrinter:
|
||
|
"Pretty print Go strings."
|
||
|
|
||
|
pattern = re.compile(r'^struct string$')
|
||
|
|
||
|
def __init__(self, val):
|
||
|
self.val = val
|
||
|
|
||
|
def display_hint(self):
|
||
|
return 'string'
|
||
|
|
||
|
def to_string(self):
|
||
|
return self.val['str']
|
||
|
|
||
|
|
||
|
class SliceTypePrinter:
|
||
|
"Pretty print slices."
|
||
|
|
||
|
pattern = re.compile(r'^struct \[\]')
|
||
|
|
||
|
def __init__(self, val):
|
||
|
self.val = val
|
||
|
|
||
|
def display_hint(self):
|
||
|
return 'array'
|
||
|
|
||
|
def to_string(self):
|
||
|
return str(self.val.type)[6:] # skip 'struct '
|
||
|
|
||
|
def children(self):
|
||
|
ptr = self.val["array"]
|
||
|
for idx in range(self.val["len"]):
|
||
|
yield ('[%d]' % idx, (ptr + idx).dereference())
|
||
|
|
||
|
|
||
|
class MapTypePrinter:
|
||
|
"""Pretty print map[K]V types.
|
||
|
|
||
|
Map-typed go variables are really pointers. dereference them in gdb
|
||
|
to inspect their contents with this pretty printer.
|
||
|
"""
|
||
|
|
||
|
pattern = re.compile(r'^struct hash<.*>$')
|
||
|
|
||
|
def __init__(self, val):
|
||
|
self.val = val
|
||
|
|
||
|
def display_hint(self):
|
||
|
return 'map'
|
||
|
|
||
|
def to_string(self):
|
||
|
return str(self.val.type)
|
||
|
|
||
|
def children(self):
|
||
|
stab = self.val['st']
|
||
|
i = 0
|
||
|
for v in self.traverse_hash(stab):
|
||
|
yield ("[%d]" % i, v['key'])
|
||
|
yield ("[%d]" % (i + 1), v['val'])
|
||
|
i += 2
|
||
|
|
||
|
def traverse_hash(self, stab):
|
||
|
ptr = stab['entry'].address
|
||
|
end = stab['end']
|
||
|
while ptr < end:
|
||
|
v = ptr.dereference()
|
||
|
ptr = ptr + 1
|
||
|
if v['hash'] == 0: continue
|
||
|
if v['hash'] & 63 == 63: # subtable
|
||
|
for v in self.traverse_hash(v['key'].cast(self.val['st'].type)):
|
||
|
yield v
|
||
|
else:
|
||
|
yield v
|
||
|
|
||
|
|
||
|
class ChanTypePrinter:
|
||
|
"""Pretty print chan[T] types.
|
||
|
|
||
|
Map-typed go variables are really pointers. dereference them in gdb
|
||
|
to inspect their contents with this pretty printer.
|
||
|
"""
|
||
|
|
||
|
pattern = re.compile(r'^struct hchan<.*>$')
|
||
|
|
||
|
def __init__(self, val):
|
||
|
self.val = val
|
||
|
|
||
|
def display_hint(self):
|
||
|
return 'array'
|
||
|
|
||
|
def to_string(self):
|
||
|
return str(self.val.type)
|
||
|
|
||
|
def children(self):
|
||
|
ptr = self.val['recvdataq']
|
||
|
for idx in range(self.val["qcount"]):
|
||
|
yield ('[%d]' % idx, ptr['elem'])
|
||
|
ptr = ptr['link']
|
||
|
|
||
|
#
|
||
|
# Register all the *Printer classes
|
||
|
#
|
||
|
|
||
|
def makematcher(klass):
|
||
|
def matcher(val):
|
||
|
try:
|
||
|
if klass.pattern.match(str(val.type)): return klass(val)
|
||
|
except: pass
|
||
|
return matcher
|
||
|
|
||
|
gdb.current_objfile().pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
|
||
|
|
||
|
|
||
|
#
|
||
|
# Convenience Functions
|
||
|
#
|
||
|
|
||
|
class GoLenFunc(gdb.Function):
|
||
|
"Length of strings, slices, maps or channels"
|
||
|
|
||
|
how = ((StringTypePrinter, 'len' ),
|
||
|
(SliceTypePrinter, 'len'),
|
||
|
(MapTypePrinter, 'count'),
|
||
|
(ChanTypePrinter, 'qcount'))
|
||
|
|
||
|
def __init__(self):
|
||
|
super(GoLenFunc, self).__init__("len")
|
||
|
|
||
|
def invoke(self, obj):
|
||
|
typename = str(obj.type)
|
||
|
for klass, fld in self.how:
|
||
|
if klass.pattern.match(typename):
|
||
|
return obj[fld]
|
||
|
|
||
|
class GoCapFunc(gdb.Function):
|
||
|
"Capacity of slices or channels"
|
||
|
|
||
|
how = ((SliceTypePrinter, 'cap'),
|
||
|
(ChanTypePrinter, 'dataqsiz'))
|
||
|
|
||
|
def __init__(self):
|
||
|
super(GoCapFunc, self).__init__("cap")
|
||
|
|
||
|
def invoke(self, obj):
|
||
|
typename = str(obj.type)
|
||
|
for klass, fld in self.how:
|
||
|
if klass.pattern.match(typename):
|
||
|
return obj[fld]
|
||
|
|
||
|
#
|
||
|
# Register all convience functions and CLI commands
|
||
|
#
|
||
|
for k in vars().values():
|
||
|
if hasattr(k, 'invoke'):
|
||
|
k()
|