[68]l: generate debug info for builtin structured types. prettyprinting in gdb. R=rsc CC=golang-dev https://golang.org/cl/3309041
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py new file mode 100644 index 0000000..422809e --- /dev/null +++ b/src/pkg/runtime/runtime-gdb.py
@@ -0,0 +1,174 @@ +# 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()