summaryrefslogtreecommitdiff
path: root/make-gdb.py
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2021-07-25 17:19:09 -0400
committerPaul Smith <psmith@gnu.org>2021-09-05 20:05:02 -0400
commite13fd5c83d9a6df3c303cec7c8791d76f25e1616 (patch)
tree6122cce76c73d19179733c2c236df522e2c07ad0 /make-gdb.py
parent7c4e6b0299774280e3a93060c70c661f459aaf40 (diff)
downloadmake-git-e13fd5c83d9a6df3c303cec7c8791d76f25e1616.tar.gz
* make-gdb.py: Add pretty-printers and clean up.
Create a pretty-printer for next-pointer lists. Create a pretty-printer for stringlists. Change showargv from a function to a command (easier to use). Clean up some Python PEP violations. Add support for testing null pointers and caching gdb.Types.
Diffstat (limited to 'make-gdb.py')
-rw-r--r--make-gdb.py160
1 files changed, 133 insertions, 27 deletions
diff --git a/make-gdb.py b/make-gdb.py
index d5a52854..e06d2729 100644
--- a/make-gdb.py
+++ b/make-gdb.py
@@ -1,11 +1,15 @@
-import re
+"""GDB pretty-printer macros for GNU make."""
+
+import gdb # pylint: disable=import-error
+import gdb.printing # pylint: disable=import-error
-import gdb #pylint: disable=import-error
-import gdb.printing #pylint: disable=import-error
# Memoize types we commonly use
_TYPES = {}
+
+
def getType(tname):
+ """Given a type name return a GDB type."""
global _TYPES
if tname not in _TYPES:
tn = tname.rstrip('*')
@@ -18,48 +22,129 @@ def getType(tname):
_TYPES[tn] = _TYPES[t].pointer()
return _TYPES[tname]
-class ShowArgv(gdb.Function):
- """Return the pretty-print of a null-terminated array of strings
+
+def isNullptr(val):
+ """Return True if the value is a null pointer."""
+ return int(val.cast(getType('unsigned long long'))) == 0
+
+
+class ShowArgv(gdb.Command):
+ """Print 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")
+ """Create the showargv function."""
+ gdb.Command.__init__(self, "showargv", gdb.COMMAND_USER)
+
+ def invoke(self, arg, from_tty):
+ """Show the argv."""
+ args = gdb.string_to_argv(arg)
+ if len(args) != 1:
+ raise gdb.GdbError(self._usage)
+
+ val = gdb.parse_and_eval(args[0])
+ if val is None:
+ raise gdb.GdbError('%s is not a valid expression' % (args[0]))
+
+ strs = []
+ while not isNullptr(val.dereference()):
+ strs.append('"'+val.dereference().string()+'"')
+ val += 1
+
+ gdb.write("[%d] = [%s]\n" % (len(strs), ', '.join(strs)))
+ gdb.flush()
+
- def invoke(self, argv):
- str = '['
+ShowArgv()
+
+
+class ShowNextList(gdb.Command):
+ """Print a structure that has a "next" pointer.
+
+ Argument:
+ A pointer to a struct which contains a "next" member.
+ """
+
+ _usage = 'usage: showlist <listptr>'
+
+ def __init__(self):
+ """Create a "showlist" function."""
+ gdb.Command.__init__(self, "showlist", gdb.COMMAND_USER)
+
+ def invoke(self, arg, from_tty):
+ """Show the elements in the provided list."""
+ args = gdb.string_to_argv(arg)
+ if len(args) != 1:
+ raise gdb.GdbError(self._usage)
+
+ val = gdb.parse_and_eval(args[0])
+ if val is None:
+ raise gdb.GdbError('%s is not a valid expression' % (args[0]))
i = 0
- while argv[i] != 0:
- if i > 0:
- str += ', '
- str += argv[i].string()
+ while not isNullptr(val):
+ gdb.write("%s : %s\n" % (val, val.dereference()))
+ gdb.flush()
i += 1
- str += ']'
- return str
+ val = val['next']
+ gdb.write("%s contains %d elements\n" % (args[0], i))
+ gdb.flush()
-ShowArgv()
+
+ShowNextList()
class FileLocation(object):
- """Print a file location"""
+ """Print a file location."""
def __init__(self, val):
+ """Create a FileLocation object."""
self.val = val
def to_string(self):
- if long(self.val['filenm']):
+ """Convert a FileLocation to a string."""
+ if int(self.val['filenm']):
return "%s:%d" % (str(self.val['filenm']), self.val['lineno'])
- return ''
+ return 'NILF'
+
+
+class StringListPrinter(object):
+ """Print a stringlist."""
+
+ def __init__(self, val):
+ """Create a StringListPrinter object."""
+ self.val = val
+
+ def to_string(self):
+ """Convert a HashTable into a string."""
+ return "size=%d, capacity=%d" % (self.val['idx'], self.val['max'])
+
+ def children(self):
+ """Yield each string in the list."""
+ i = 0
+ elts = self.val['list']
+ while i < self.val['idx']:
+ nm = '[%d] ' % i
+ yield (nm, elts.dereference())
+ i += 1
+ elts += 1
+
+ def display_hint(self):
+ """Show the display hint for the pretty-printer."""
+ return 'array'
+
class VariablePrinter(object):
- """Print a struct variable"""
+ """Print a struct variable."""
def __init__(self, val):
+ """Create a VariablePrinter object."""
self.val = val
def to_string(self):
+ """Convert a VariablePrinter object into a string."""
if self.val['append']:
a = '+='
elif self.val['conditional']:
@@ -80,48 +165,58 @@ class VariablePrinter(object):
self.val['fileinfo'], ','.join(flags),
self.val['name'].string(), a, self.val['value'].string())
+
class HashTablePrinter(object):
- """Manage a hash table."""
+ """Pretty-print a hash table."""
DELITEM = None
def __init__(self, val):
+ """Create a HashTablePrinter object."""
self.val = val
def to_string(self):
+ """Convert a HashTable into a string."""
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):
+ """Yield each ID and value."""
for (i, v) in self.iterator():
nm = '[%d] ' % i
yield (nm, i)
yield (nm, v)
def iterator(self):
+ """Provide an iterator for HashTable."""
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']):
+ for i in range(0, self.val['ht_size']):
v = lst[i]
- if long(v) != 0 and v != HashTablePrinter.DELITEM:
+ if int(v) != 0 and v != HashTablePrinter.DELITEM:
yield (i, v)
def display_hint(self):
+ """Show the display hint for the pretty-printer."""
return 'map'
+
class VariableSetPrinter(object):
- """Print a variable_set"""
+ """Print a variable_set."""
def __init__(self, val):
+ """Create a variable_set pretty-printer."""
self.tbl = HashTablePrinter(val['table'])
def to_string(self):
+ """Convert a variable_set to string."""
return self.tbl.to_string()
def children(self):
+ """Iterate through variables and values."""
for (i, v) in self.tbl.iterator():
ptr = v.cast(getType('struct variable*'))
nm = '[%d] ' % (i)
@@ -129,29 +224,35 @@ class VariableSetPrinter(object):
yield (nm, str(ptr.dereference()))
def display_hint(self):
+ """Show the display hint for the pretty-printer."""
return 'map'
+
class VariableSetListPrinter(object):
- """Print a variable_set_list"""
+ """Print a variable_set_list."""
GLOBALSET = None
def __init__(self, val):
+ """Create a variable_set_list pretty-printer."""
self.val = val
def to_string(self):
+ """Convert a variable_set_list to string."""
return str(self.val.address)
def children(self):
+ """Iterate through variables and values."""
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
+ VariableSetListPrinter.GLOBALSET = gdb.lookup_symbol(
+ 'global_variable_set', block)[0].value().address
ptr = self.val.address
i = 0
- while long(ptr) != 0:
+ while not isNullptr(ptr):
nm = '[%d] ' % (i)
yield (nm, ptr['set'])
- if long(ptr['set']) == long(VariableSetListPrinter.GLOBALSET):
+ if int(ptr['set']) == int(VariableSetListPrinter.GLOBALSET):
yield (nm, "global_variable_set")
else:
yield (nm, str(ptr['set'].dereference()))
@@ -159,17 +260,22 @@ class VariableSetListPrinter(object):
ptr = ptr['next']
def display_hint(self):
+ """Show the display hint for the pretty-printer."""
return 'map'
+
def build_pretty_printer():
+ """Install all the pretty-printers."""
pp = gdb.printing.RegexpCollectionPrettyPrinter("gnumake")
pp.add_printer('floc', r'^floc$', FileLocation)
+ pp.add_printer('stringlist', r'^stringlist$', StringListPrinter)
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)