[pypy-commit] pypy default: a bit of refactoring: do pretty print of *pointers* to strings and lists, so we can still inspect the underyling struct when we do p *val

antocuni noreply at buildbot.pypy.org
Mon Aug 8 17:39:15 CEST 2011


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: 
Changeset: r46375:02272b150b8d
Date: 2011-08-08 17:26 +0200
http://bitbucket.org/pypy/pypy/changeset/02272b150b8d/

Log:	a bit of refactoring: do pretty print of *pointers* to strings and
	lists, so we can still inspect the underyling struct when we do p
	*val

diff --git a/pypy/tool/gdb_pypy.py b/pypy/tool/gdb_pypy.py
--- a/pypy/tool/gdb_pypy.py
+++ b/pypy/tool/gdb_pypy.py
@@ -122,12 +122,31 @@
         return typeids
 
 
+def is_ptr(type, gdb):
+    if gdb is None:
+        import gdb # so we can pass a fake one from the tests
+    return type.code == gdb.TYPE_CODE_PTR
 
-class RpyStringPrinter(object):
+
+class RPyStringPrinter(object):
+    """
+    Pretty printer for rpython strings.
+
+    Note that this pretty prints *pointers* to strings: this way you can do "p
+    val" and see the nice string, and "p *val" to see the underyling struct
+    fields
+    """
     
     def __init__(self, val):
         self.val = val
-        
+
+    @classmethod
+    def lookup(cls, val, gdb=None):
+        t = val.type
+        if is_ptr(t, gdb) and t.target().tag == 'pypy_rpy_string0':
+            return cls(val)
+        return None
+
     def to_string(self):
         chars = self.val['rs_chars']
         length = int(chars['length'])
@@ -137,15 +156,44 @@
         return repr(string) + " (rpy)"
 
 
-def rpy_string_lookup(val):
-    if val.type.tag == 'pypy_rpy_string0':
-        return RpyStringPrinter(val)
-    return None
+class RPyListPrinter(object):
+    """
+    Pretty printer for rpython lists
+
+    Note that this pretty prints *pointers* to lists: this way you can do "p
+    val" and see the nice repr, and "p *val" to see the underyling struct
+    fields
+    """
+
+    def __init__(self, val):
+        self.val = val
+
+    @classmethod
+    def lookup(cls, val, gdb=None):
+        t = val.type
+        if is_ptr(t, gdb) and t.target().tag == 'pypy_list0':
+            return cls(val)
+        return None
+
+    def to_string(self):
+        length = int(self.val['l_length'])
+        array = self.val['l_items']
+        allocated = int(array['length'])
+        items = array['items']
+        itemlist = []
+        for i in range(length):
+            item = items[i]
+            itemlist.append(str(item))
+        str_items = ', '.join(itemlist)
+        return '[%s] (length=%d, allocated=%d, rpy)' % (str_items, length, allocated)
 
 
 try:
     import gdb
     RPyType() # side effects
-    gdb.pretty_printers.append(rpy_string_lookup)
+    gdb.pretty_printers += [
+        RPyStringPrinter.lookup,
+        RPyListPrinter.lookup
+        ]
 except ImportError:
     pass
diff --git a/pypy/tool/test/test_gdb_pypy.py b/pypy/tool/test/test_gdb_pypy.py
--- a/pypy/tool/test/test_gdb_pypy.py
+++ b/pypy/tool/test/test_gdb_pypy.py
@@ -4,6 +4,10 @@
 class FakeGdb(object):
 
     COMMAND_NONE = -1
+    #
+    TYPE_CODE_PTR = 1
+    TYPE_CODE_ARRAY = 2
+    TYPE_CODE_STRUCT = 3
 
     def __init__(self, exprs, progspace=None):
         self.exprs = exprs
@@ -24,20 +28,40 @@
     pass
 
 class Struct(object):
-    def __init__(self, fieldnames):
+    code = FakeGdb.TYPE_CODE_STRUCT
+    
+    def __init__(self, fieldnames, tag):
         self._fields = [Field(name=name) for name in fieldnames]
+        self.tag = tag
 
     def fields(self):
         return self._fields[:]
 
+class Pointer(object):
+    code = FakeGdb.TYPE_CODE_PTR
+
+    def __init__(self, target):
+        self._target = target
+
+    def target(self):
+        return self._target
+
 class Value(dict):
     def __init__(self, *args, **kwds):
+        type_tag = kwds.pop('type_tag', None)
         dict.__init__(self, *args, **kwds)
-        self.type = Struct(self.keys())
+        self.type = Struct(self.keys(), type_tag)
         for key, val in self.iteritems():
             if isinstance(val, dict):
                 self[key] = Value(val)
 
+class PtrValue(Value):
+    def __init__(self, *args, **kwds):
+        # in python gdb, we can use [] to access fields either if we have an
+        # actual struct or a pointer to it, so we just reuse Value here
+        Value.__init__(self, *args, **kwds)
+        self.type = Pointer(self.type)
+
 def test_mock_objects():
     d = {'a': 1,
          'b': 2,
@@ -129,7 +153,24 @@
             'items': map(ord, 'foobar'),
             }
          }
-    string = Value(d)
-    string.type.tag = 'pypy_rpy_string0'
-    printer = gdb_pypy.rpy_string_lookup(string)
+    p_string = PtrValue(d, type_tag='pypy_rpy_string0')
+    printer = gdb_pypy.RPyStringPrinter.lookup(p_string, FakeGdb)
     assert printer.to_string() == "'foobar' (rpy)"
+
+def test_pprint_list():
+    d = {'_gcheader': {
+            'h_tid': 123
+            },
+         'l_length': 3, # the lenght of the rpython list
+         'l_items':
+             # this is the array which contains the items
+             {'_gcheader': {
+                'h_tid': 456
+                },
+              'length': 5, # the lenght of the underlying array
+              'items': [40, 41, 42, -1, -2],
+              }
+         }
+    mylist = PtrValue(d, type_tag='pypy_list0')
+    printer = gdb_pypy.RPyListPrinter.lookup(mylist, FakeGdb)
+    assert printer.to_string() == '[40, 41, 42] (length=3, allocated=5, rpy)'


More information about the pypy-commit mailing list