| # 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() |