mirror of
https://github.com/golang/go
synced 2024-11-22 04:34:39 -07:00
pkg/runtime: 2 sanity checks in the runtime-gdb.py prettyprinters.
Don't try to print obviously corrupt slices or interfaces. Doesn't actually solve 3047 or 2818, but seems a good idea anyway. R=rsc, bsiegert CC=golang-dev https://golang.org/cl/5708061
This commit is contained in:
parent
ecdd9f2376
commit
fb2706113f
@ -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 is the type stolen from hchan<T>::recvq->first->elem
|
||||
# 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"]):
|
||||
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,12 +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."
|
||||
# known issue: dtype_name decoded from runtime.commonType is "nested.Foo"
|
||||
# but the dwarf table lists it as "full/path/to/nested.Foo"
|
||||
|
||||
def iface_commontype(obj):
|
||||
if is_iface(obj):
|
||||
go_type_ptr = obj['tab']['_type']
|
||||
elif is_eface(obj):
|
||||
@ -197,15 +197,31 @@ 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()
|
||||
|
||||
dynamic_gdb_type = lookup_type(dtype_name)
|
||||
if dynamic_gdb_type:
|
||||
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:
|
||||
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()
|
||||
|
||||
return dynamic_gdb_type
|
||||
@ -213,15 +229,9 @@ def iface_dtype(obj):
|
||||
def iface_dtype_name(obj):
|
||||
"Decode type name of the data field of an eface or iface struct."
|
||||
|
||||
if is_iface(obj):
|
||||
go_type_ptr = obj['tab']['_type']
|
||||
elif is_eface(obj):
|
||||
go_type_ptr = obj['_type']
|
||||
else:
|
||||
dynamic_go_type = iface_commontype(obj)
|
||||
if dynamic_go_type is None:
|
||||
return
|
||||
|
||||
ct = gdb.lookup_type("struct runtime.commonType").pointer()
|
||||
dynamic_go_type = go_type_ptr['ptr'].cast(ct).dereference()
|
||||
return dynamic_go_type['string'].dereference()['str'].string()
|
||||
|
||||
|
||||
@ -244,7 +254,7 @@ class IfacePrinter:
|
||||
except:
|
||||
return "<bad dynamic type>"
|
||||
|
||||
if not dtype: # trouble looking up, print something reasonable
|
||||
if dtype is None: # trouble looking up, print something reasonable
|
||||
return "(%s)%s" % (iface_dtype_name(self.val), self.val['data'])
|
||||
|
||||
try:
|
||||
@ -267,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'))
|
||||
@ -316,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:
|
||||
@ -339,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
|
||||
|
||||
@ -382,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):
|
||||
@ -403,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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user