diff options
Diffstat (limited to 'Tools/gdb/libpython.py')
-rwxr-xr-x | Tools/gdb/libpython.py | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index ed515c0017..cc1afbe16d 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -44,7 +44,7 @@ The module also extends gdb with some python-specific commands. # NOTE: some gdbs are linked with Python 3, so this file should be dual-syntax # compatible (2.6+ and 3.0+). See #19308. -from __future__ import print_function, with_statement +from __future__ import print_function import gdb import os import locale @@ -666,8 +666,9 @@ class PyDictObjectPtr(PyObjectPtr): ''' keys = self.field('ma_keys') values = self.field('ma_values') - for i in safe_range(keys['dk_size']): - ep = keys['dk_entries'].address + i + entries, nentries = self._get_entries(keys) + for i in safe_range(nentries): + ep = entries[i] if long(values): pyop_value = PyObjectPtr.from_pyobject_ptr(values[i]) else: @@ -707,6 +708,33 @@ class PyDictObjectPtr(PyObjectPtr): pyop_value.write_repr(out, visited) out.write('}') + def _get_entries(self, keys): + dk_nentries = int(keys['dk_nentries']) + dk_size = int(keys['dk_size']) + try: + # <= Python 3.5 + return keys['dk_entries'], dk_size + except gdb.error: + # >= Python 3.6 + pass + + if dk_size <= 0xFF: + offset = dk_size + elif dk_size <= 0xFFFF: + offset = 2 * dk_size + elif dk_size <= 0xFFFFFFFF: + offset = 4 * dk_size + else: + offset = 8 * dk_size + + ent_addr = keys['dk_indices']['as_1'].address + ent_addr = ent_addr.cast(_type_unsigned_char_ptr()) + offset + ent_ptr_t = gdb.lookup_type('PyDictKeyEntry').pointer() + ent_addr = ent_addr.cast(ent_ptr_t) + + return ent_addr, dk_nentries + + class PyListObjectPtr(PyObjectPtr): _typename = 'PyListObject' @@ -1464,23 +1492,38 @@ class Frame(object): ''' if self.is_waiting_for_gil(): return 'Waiting for the GIL' - elif self.is_gc_collect(): + + if self.is_gc_collect(): return 'Garbage-collecting' - else: - # Detect invocations of PyCFunction instances: - older = self.older() - if older and older._gdbframe.name() == 'PyCFunction_Call': - # Within that frame: - # "func" is the local containing the PyObject* of the - # PyCFunctionObject instance - # "f" is the same value, but cast to (PyCFunctionObject*) - # "self" is the (PyObject*) of the 'self' - try: - # Use the prettyprinter for the func: - func = older._gdbframe.read_var('func') - return str(func) - except RuntimeError: - return 'PyCFunction invocation (unable to read "func")' + + # Detect invocations of PyCFunction instances: + older = self.older() + if not older: + return False + + caller = older._gdbframe.name() + if not caller: + return False + + if caller == 'PyCFunction_Call': + # Within that frame: + # "func" is the local containing the PyObject* of the + # PyCFunctionObject instance + # "f" is the same value, but cast to (PyCFunctionObject*) + # "self" is the (PyObject*) of the 'self' + try: + # Use the prettyprinter for the func: + func = older._gdbframe.read_var('func') + return str(func) + except RuntimeError: + return 'PyCFunction invocation (unable to read "func")' + + elif caller == '_PyCFunction_FastCallDict': + try: + func = older._gdbframe.read_var('func_obj') + return str(func) + except RuntimeError: + return 'PyCFunction invocation (unable to read "func_obj")' # This frame isn't worth reporting: return False |