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