summaryrefslogtreecommitdiff
path: root/src/pkg/runtime/runtime-gdb.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime/runtime-gdb.py')
-rw-r--r--src/pkg/runtime/runtime-gdb.py83
1 files changed, 60 insertions, 23 deletions
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index b74705e5f..629c39e98 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -5,7 +5,7 @@
"""GDB Pretty printers and convenience 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
+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.
"""
@@ -58,6 +58,8 @@ class SliceTypePrinter:
return str(self.val.type)[6:] # skip 'struct '
def children(self):
+ if self.val["len"] > self.val["cap"]:
+ return
ptr = self.val["array"]
for idx in range(self.val["len"]):
yield ('[%d]' % idx, (ptr + idx).dereference())
@@ -85,7 +87,7 @@ class MapTypePrinter:
stab = self.val['st']
i = 0
for v in self.traverse_hash(stab):
- yield ("[%d]" % i, v['key'])
+ yield ("[%d]" % i, v['key'])
yield ("[%d]" % (i + 1), v['val'])
i += 2
@@ -122,10 +124,10 @@ class ChanTypePrinter:
return str(self.val.type)
def children(self):
- # see chan.c chanbuf()
- et = [x.type for x in self.val['free'].type.target().fields() if x.name == 'elem'][0]
- ptr = (self.val.address + 1).cast(et.pointer())
- for i in range(self.val["qcount"]):
+ # see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem
+ et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0]
+ ptr = (self.val.address + 1).cast(et.pointer())
+ for i in range(self.val["qcount"]):
j = (self.val["recvx"] + i) % self.val["dataqsiz"]
yield ('[%d]' % i, (ptr + j).dereference())
@@ -184,10 +186,10 @@ def lookup_type(name):
except:
pass
+_rctp_type = gdb.lookup_type("struct runtime.commonType").pointer()
+_rtp_type = gdb.lookup_type("struct runtime._type").pointer()
-def iface_dtype(obj):
- "Decode type of the data field of an eface or iface struct."
-
+def iface_commontype(obj):
if is_iface(obj):
go_type_ptr = obj['tab']['_type']
elif is_eface(obj):
@@ -195,16 +197,43 @@ def iface_dtype(obj):
else:
return
- ct = gdb.lookup_type("struct runtime.commonType").pointer()
- dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference()
+ # sanity check: reflection type description ends in a loop.
+ tt = go_type_ptr['_type'].cast(_rtp_type).dereference()['_type']
+ if tt != tt.cast(_rtp_type).dereference()['_type']:
+ return
+
+ return go_type_ptr['ptr'].cast(_rctp_type).dereference()
+
+
+def iface_dtype(obj):
+ "Decode type of the data field of an eface or iface struct."
+ # known issue: dtype_name decoded from runtime.commonType is "nested.Foo"
+ # but the dwarf table lists it as "full/path/to/nested.Foo"
+
+ dynamic_go_type = iface_commontype(obj)
+ if dynamic_go_type is None:
+ return
dtype_name = dynamic_go_type['string'].dereference()['str'].string()
- type_size = int(dynamic_go_type['size'])
- uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
+
dynamic_gdb_type = lookup_type(dtype_name)
+ if dynamic_gdb_type is None:
+ return
+
+ type_size = int(dynamic_go_type['size'])
+ uintptr_size = int(dynamic_go_type['size'].type.sizeof) # size is itself an uintptr
if type_size > uintptr_size:
- dynamic_gdb_type = dynamic_gdb_type.pointer()
+ dynamic_gdb_type = dynamic_gdb_type.pointer()
+
return dynamic_gdb_type
+def iface_dtype_name(obj):
+ "Decode type name of the data field of an eface or iface struct."
+
+ dynamic_go_type = iface_commontype(obj)
+ if dynamic_go_type is None:
+ return
+ return dynamic_go_type['string'].dereference()['str'].string()
+
class IfacePrinter:
"""Pretty print interface values
@@ -224,6 +253,10 @@ class IfacePrinter:
dtype = iface_dtype(self.val)
except:
return "<bad dynamic type>"
+
+ if dtype is None: # trouble looking up, print something reasonable
+ return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
+
try:
return self.val['data'].cast(dtype).dereference()
except:
@@ -244,7 +277,7 @@ goobjfile.pretty_printers.append(ifacematcher)
class GoLenFunc(gdb.Function):
"Length of strings, slices, maps or channels"
- how = ((StringTypePrinter, 'len' ),
+ how = ((StringTypePrinter, 'len'),
(SliceTypePrinter, 'len'),
(MapTypePrinter, 'count'),
(ChanTypePrinter, 'qcount'))
@@ -293,7 +326,7 @@ class DTypeFunc(gdb.Function):
# Commands
#
-sts = ( 'idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+sts = ('idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
def linked_list(ptr, linkfield):
while ptr:
@@ -316,8 +349,8 @@ class GoroutinesCmd(gdb.Command):
s = ' '
if ptr['m']:
s = '*'
- pc = ptr['sched']['pc'].cast(vp)
- sp = ptr['sched']['sp'].cast(vp)
+ pc = ptr['sched']['pc'].cast(vp)
+ sp = ptr['sched']['sp'].cast(vp)
blk = gdb.block_for_pc(long((pc)))
print s, ptr['goid'], "%8s" % sts[long((ptr['status']))], blk.function
@@ -359,10 +392,10 @@ class GoroutineCmd(gdb.Command):
gdb.parse_and_eval('$sp = 0x%x' % long(sp))
try:
gdb.execute(cmd)
- finally:
+ finally:
gdb.parse_and_eval('$pc = $save_pc')
- gdb.parse_and_eval('$sp = $save_sp')
- save_frame.select()
+ gdb.parse_and_eval('$sp = $save_sp')
+ save_frame.select()
class GoIfaceCmd(gdb.Command):
@@ -380,8 +413,12 @@ class GoIfaceCmd(gdb.Command):
print "Can't parse ", obj, ": ", e
continue
- dtype = iface_dtype(obj)
- if not dtype:
+ if obj['data'] == 0:
+ dtype = "nil"
+ else:
+ dtype = iface_dtype(obj)
+
+ if dtype is None:
print "Not an interface: ", obj.type
continue