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