summaryrefslogtreecommitdiffstats
path: root/libpython.py
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2010-02-25 20:36:47 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2010-02-25 20:36:47 -0500
commit8f8e182856fed32ce0a67a04cc054bb7e88d1e14 (patch)
treeae98bf6124e8e4af2711c2fe319c84afde293a26 /libpython.py
parentbb12aba0beb09ecc262a8e61a7b49b5aef1049b9 (diff)
downloadlibpython-8f8e182856fed32ce0a67a04cc054bb7e88d1e14.tar.gz
libpython-8f8e182856fed32ce0a67a04cc054bb7e88d1e14.tar.xz
libpython-8f8e182856fed32ce0a67a04cc054bb7e88d1e14.zip
Rewrite the type lookup using flags where possible, eliminating need for "is_py3k" hack
Diffstat (limited to 'libpython.py')
-rw-r--r--libpython.py102
1 files changed, 59 insertions, 43 deletions
diff --git a/libpython.py b/libpython.py
index 1ede863..2f1e0ec 100644
--- a/libpython.py
+++ b/libpython.py
@@ -49,6 +49,16 @@ TODO: better handling of "instance"
import gdb
+Py_TPFLAGS_INT_SUBCLASS = (1L<<23)
+Py_TPFLAGS_LONG_SUBCLASS = (1L<<24)
+Py_TPFLAGS_LIST_SUBCLASS = (1L<<25)
+Py_TPFLAGS_TUPLE_SUBCLASS = (1L<<26)
+Py_TPFLAGS_STRING_SUBCLASS = (1L<<27)
+Py_TPFLAGS_UNICODE_SUBCLASS = (1L<<28)
+Py_TPFLAGS_DICT_SUBCLASS = (1L<<29)
+Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L<<30)
+Py_TPFLAGS_TYPE_SUBCLASS = (1L<<31)
+
class NullPyObjectPtr(RuntimeError):
pass
@@ -63,17 +73,6 @@ def safe_range(val):
# threshold in case the data was corrupted
return xrange(safety_limit(val))
-def is_py3k():
- # This code assumes that a libpython's DWARF data has actually been
- # loaded by the point that this function is called
- sym = gdb.lookup_symbol('PyBytes_Type')[0]
- if sym:
- #...then PyBytes_Type exists, assume this is libpython3.*
- return True
- else:
- #...then PyBytes_Type doesn't exist, assume this is libpython2.*
- return False
-
class PyObjectPtr(object):
"""
Class wrapping a gdb.Value that's a either a (PyObject*) within the
@@ -168,31 +167,62 @@ class PyObjectPtr(object):
long(self._gdbval))
@classmethod
- def subclass_for_tp_name(cls, tp_name):
- if tp_name == 'str':
- if is_py3k():
- return PyUnicodeObjectPtr
- else:
- return PyStringObjectPtr
- if tp_name == 'int':
- if is_py3k():
- return PyLongObjectPtr
- else:
- return PyIntObjectPtr
+ def subclass_from_type(cls, t):
+ '''
+ Given a PyTypeObjectPtr instance wrapping a gdb.Value that's a
+ (PyTypeObject*), determine the corresponding subclass of PyObjectPtr
+ to use
+
+ Ideally, we would look up the symbols for the global types, but that
+ isn't working yet:
+ (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
+ Traceback (most recent call last):
+ File "<string>", line 1, in <module>
+ NotImplementedError: Symbol type not yet supported in Python scripts.
+ Error while executing Python code.
+
+ For now, we use tp_flags, after doing some string comparisons on the
+ tp_name for some special-cases that don't seem to be visible through flags
+ '''
+ try:
+ tp_name = t.field('tp_name').string()
+ tp_flags = int(t.field('tp_flags'))
+ except RuntimeError:
+ # Handle any kind of error e.g. NULL ptrs by simply using the base
+ # class
+ return cls
+
+ #print 'tp_flags = 0x%08x' % tp_flags
+ #print 'tp_name = %r' % tp_name
name_map = {'bool' : PyBoolObjectPtr,
'classobj': PyClassObjectPtr,
- 'dict': PyDictObjectPtr,
'instance': PyInstanceObjectPtr,
- 'list': PyListObjectPtr,
- 'long': PyLongObjectPtr,
'NoneType': PyNoneStructPtr,
- 'tuple': PyTupleObjectPtr,
'frame': PyFrameObjectPtr,
- 'unicode': PyUnicodeObjectPtr,
}
if tp_name in name_map:
return name_map[tp_name]
+
+ if tp_flags & Py_TPFLAGS_INT_SUBCLASS:
+ return PyIntObjectPtr
+ if tp_flags & Py_TPFLAGS_LONG_SUBCLASS:
+ return PyLongObjectPtr
+ if tp_flags & Py_TPFLAGS_LIST_SUBCLASS:
+ return PyListObjectPtr
+ if tp_flags & Py_TPFLAGS_TUPLE_SUBCLASS:
+ return PyTupleObjectPtr
+ if tp_flags & Py_TPFLAGS_STRING_SUBCLASS:
+ return PyStringObjectPtr
+ if tp_flags & Py_TPFLAGS_UNICODE_SUBCLASS:
+ return PyUnicodeObjectPtr
+ if tp_flags & Py_TPFLAGS_DICT_SUBCLASS:
+ return PyDictObjectPtr
+ #if tp_flags & Py_TPFLAGS_BASE_EXC_SUBCLASS:
+ # return something
+ #if tp_flags & Py_TPFLAGS_TYPE_SUBCLASS:
+ # return PyTypeObjectPtr
+
# Use the base class:
return cls
@@ -200,26 +230,12 @@ class PyObjectPtr(object):
def from_pyobject_ptr(cls, gdbval):
'''
Try to locate the appropriate derived class dynamically, and cast
- the pointer accordingly:
- For now, we just do string comparison on the tp_name
- Other approaches:
- (i) look up the symbols for the global types, but that isn't working yet:
- (gdb) python print gdb.lookup_symbol('PyList_Type')[0].value
- Traceback (most recent call last):
- File "<string>", line 1, in <module>
- NotImplementedError: Symbol type not yet supported in Python scripts.
- Error while executing Python code.
- (ii) look at tp_flags, looking e.g. for Py_TPFLAGS_LIST_SUBCLASS however
- this would rely on the values of those flags.
-
- So we go with the simple approach of looking at tp_name
+ the pointer accordingly.
'''
#
try:
p = PyObjectPtr(gdbval)
- t = p.type()
- tp_name = t.field('tp_name').string()
- cls = cls.subclass_for_tp_name(tp_name)
+ cls = cls.subclass_from_type(p.type())
return cls(gdbval, cast_to=cls.get_gdb_type())
except RuntimeError:
# Handle any kind of error e.g. NULL ptrs by simply using the base