blob: d5a528549dce1c52e97d495d46c56d1dc8eb1d47 [file] [log] [blame]
import re
import gdb #pylint: disable=import-error
import gdb.printing #pylint: disable=import-error
# Memoize types we commonly use
_TYPES = {}
def getType(tname):
global _TYPES
if tname not in _TYPES:
tn = tname.rstrip('*')
if tn not in _TYPES:
_TYPES[tn] = gdb.lookup_type(tn)
while tn != tname:
# Want a pointer type
t = tn
tn += '*'
_TYPES[tn] = _TYPES[t].pointer()
return _TYPES[tname]
class ShowArgv(gdb.Function):
"""Return the pretty-print of a null-terminated array of strings
Argument:
A char** where the last one is NULL (e.g., argv)
"""
def __init__(self):
gdb.Function.__init__(self, "showargv")
def invoke(self, argv):
str = '['
i = 0
while argv[i] != 0:
if i > 0:
str += ', '
str += argv[i].string()
i += 1
str += ']'
return str
ShowArgv()
class FileLocation(object):
"""Print a file location"""
def __init__(self, val):
self.val = val
def to_string(self):
if long(self.val['filenm']):
return "%s:%d" % (str(self.val['filenm']), self.val['lineno'])
return ''
class VariablePrinter(object):
"""Print a struct variable"""
def __init__(self, val):
self.val = val
def to_string(self):
if self.val['append']:
a = '+='
elif self.val['conditional']:
a = '?='
else:
a = '='
flags = []
s = str(self.val['flavor'])
if s != 'f_bogus':
flags.append(s)
s = str(self.val['origin'])
if s != 'o_default':
flags.append(s)
s = str(self.val['export'])
if s != 'v_default':
flags.append(s)
return '%s[%s]: "%s" %s "%s"' % (
self.val['fileinfo'], ','.join(flags),
self.val['name'].string(), a, self.val['value'].string())
class HashTablePrinter(object):
"""Manage a hash table."""
DELITEM = None
def __init__(self, val):
self.val = val
def to_string(self):
return "size=%d, capacity=%d, empty=%d, collisions=%d, rehashes=%d" % (
self.val['ht_size'], self.val['ht_capacity'],
self.val['ht_empty_slots'], self.val['ht_collisions'],
self.val['ht_rehashes'])
def children(self):
for (i, v) in self.iterator():
nm = '[%d] ' % i
yield (nm, i)
yield (nm, v)
def iterator(self):
if HashTablePrinter.DELITEM is None:
HashTablePrinter.DELITEM = gdb.lookup_global_symbol('hash_deleted_item').value()
lst = self.val['ht_vec']
for i in xrange(0, self.val['ht_size']):
v = lst[i]
if long(v) != 0 and v != HashTablePrinter.DELITEM:
yield (i, v)
def display_hint(self):
return 'map'
class VariableSetPrinter(object):
"""Print a variable_set"""
def __init__(self, val):
self.tbl = HashTablePrinter(val['table'])
def to_string(self):
return self.tbl.to_string()
def children(self):
for (i, v) in self.tbl.iterator():
ptr = v.cast(getType('struct variable*'))
nm = '[%d] ' % (i)
yield (nm, ptr)
yield (nm, str(ptr.dereference()))
def display_hint(self):
return 'map'
class VariableSetListPrinter(object):
"""Print a variable_set_list"""
GLOBALSET = None
def __init__(self, val):
self.val = val
def to_string(self):
return str(self.val.address)
def children(self):
if VariableSetListPrinter.GLOBALSET is None:
block = gdb.lookup_global_symbol('init_hash_global_variable_set').symtab.static_block()
VariableSetListPrinter.GLOBALSET = gdb.lookup_symbol('global_variable_set', block)[0].value().address
ptr = self.val.address
i = 0
while long(ptr) != 0:
nm = '[%d] ' % (i)
yield (nm, ptr['set'])
if long(ptr['set']) == long(VariableSetListPrinter.GLOBALSET):
yield (nm, "global_variable_set")
else:
yield (nm, str(ptr['set'].dereference()))
i += 1
ptr = ptr['next']
def display_hint(self):
return 'map'
def build_pretty_printer():
pp = gdb.printing.RegexpCollectionPrettyPrinter("gnumake")
pp.add_printer('floc', r'^floc$', FileLocation)
pp.add_printer('variable', r'^variable$', VariablePrinter)
pp.add_printer('hashtable', r'^hash_table$', HashTablePrinter)
pp.add_printer('variableset', r'^variable_set$', VariableSetPrinter)
pp.add_printer('variablesetlist', r'^variable_set_list$', VariableSetListPrinter)
return pp
# Use replace=True so we can re-source this file
gdb.printing.register_pretty_printer(gdb.current_objfile(),
build_pretty_printer(), replace=True)