summaryrefslogtreecommitdiffstats
path: root/Tools/gdb/libpython.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/gdb/libpython.py')
-rwxr-xr-xTools/gdb/libpython.py482
1 files changed, 148 insertions, 334 deletions
diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py
index 2ab7d3b..9def56e 100755
--- a/Tools/gdb/libpython.py
+++ b/Tools/gdb/libpython.py
@@ -19,10 +19,9 @@ giving file/line information and the state of local variables
In particular, given a gdb.Value corresponding to a PyObject* in the inferior
process, we can generate a "proxy value" within the gdb process. For example,
given a PyObject* in the inferior process that is in fact a PyListObject*
-holding three PyObject* that turn out to be PyBytesObject* instances, we can
-generate a proxy value within the gdb process that is a list of bytes
-instances:
- [b"foo", b"bar", b"baz"]
+holding three PyObject* that turn out to be PyStringObject* instances, we can
+generate a proxy value within the gdb process that is a list of strings:
+ ["foo", "bar", "baz"]
Doing so can be expensive for complicated graphs of objects, and could take
some time, so we also have a "write_repr" method that writes a representation
@@ -44,10 +43,10 @@ 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
+from __future__ import print_function, with_statement
import gdb
-import os
import locale
+import os
import sys
if sys.version_info[0] >= 3:
@@ -67,26 +66,17 @@ def _type_unsigned_char_ptr():
return gdb.lookup_type('unsigned char').pointer() # unsigned char*
-def _type_unsigned_short_ptr():
- return gdb.lookup_type('unsigned short').pointer()
-
-
-def _type_unsigned_int_ptr():
- return gdb.lookup_type('unsigned int').pointer()
-
-
def _sizeof_void_p():
return gdb.lookup_type('void').pointer().sizeof
-# value computed later, see PyUnicodeObjectPtr.proxy()
-_is_pep393 = None
-
Py_TPFLAGS_HEAPTYPE = (1 << 9)
+
+Py_TPFLAGS_INT_SUBCLASS = (1 << 23)
Py_TPFLAGS_LONG_SUBCLASS = (1 << 24)
Py_TPFLAGS_LIST_SUBCLASS = (1 << 25)
Py_TPFLAGS_TUPLE_SUBCLASS = (1 << 26)
-Py_TPFLAGS_BYTES_SUBCLASS = (1 << 27)
+Py_TPFLAGS_STRING_SUBCLASS = (1 << 27)
Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
Py_TPFLAGS_DICT_SUBCLASS = (1 << 29)
Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
@@ -95,12 +85,8 @@ Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
MAX_OUTPUT_LEN=1024
-hexdigits = "0123456789abcdef"
-
ENCODING = locale.getpreferredencoding()
-EVALFRAME = '_PyEval_EvalFrameDefault'
-
class NullPyObjectPtr(RuntimeError):
pass
@@ -129,31 +115,12 @@ else:
text = text.encode(ENCODING, 'backslashreplace')
file.write(text)
-try:
- os_fsencode = os.fsencode
-except AttributeError:
- def os_fsencode(filename):
- if not isinstance(filename, unicode):
- return filename
- encoding = sys.getfilesystemencoding()
- if encoding == 'mbcs':
- # mbcs doesn't support surrogateescape
- return filename.encode(encoding)
- encoded = []
- for char in filename:
- # surrogateescape error handler
- if 0xDC80 <= ord(char) <= 0xDCFF:
- byte = chr(ord(char) - 0xDC00)
- else:
- byte = char.encode(encoding)
- encoded.append(byte)
- return ''.join(encoded)
class StringTruncated(RuntimeError):
pass
class TruncatedStringIO(object):
- '''Similar to io.StringIO, but can truncate the output by raising a
+ '''Similar to cStringIO, but can truncate the output by raising a
StringTruncated exception'''
def __init__(self, maxlen=None):
self._val = ''
@@ -174,7 +141,7 @@ class TruncatedStringIO(object):
class PyObjectPtr(object):
"""
Class wrapping a gdb.Value that's either a (PyObject*) within the
- inferior process, or some subclass pointer e.g. (PyBytesObject*)
+ inferior process, or some subclass pointer e.g. (PyStringObject*)
There will be a subclass for every refined PyObject type that we care
about.
@@ -214,8 +181,12 @@ class PyObjectPtr(object):
return pyo_ptr.dereference()[name]
if name == 'ob_size':
- pyo_ptr = self._gdbval.cast(PyVarObjectPtr.get_gdb_type())
- return pyo_ptr.dereference()[name]
+ try:
+ # Python 2:
+ return self._gdbval.dereference()[name]
+ except RuntimeError:
+ # Python 3:
+ return self._gdbval.dereference()['ob_base'][name]
# General case: look it up inside the object:
return self._gdbval.dereference()[name]
@@ -362,6 +333,7 @@ class PyObjectPtr(object):
name_map = {'bool': PyBoolObjectPtr,
'classobj': PyClassObjectPtr,
+ 'instance': PyInstanceObjectPtr,
'NoneType': PyNoneStructPtr,
'frame': PyFrameObjectPtr,
'set' : PySetObjectPtr,
@@ -375,14 +347,16 @@ class PyObjectPtr(object):
if tp_flags & Py_TPFLAGS_HEAPTYPE:
return HeapTypeObjectPtr
+ 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_BYTES_SUBCLASS:
- return PyBytesObjectPtr
+ 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:
@@ -418,8 +392,6 @@ class PyObjectPtr(object):
def as_address(self):
return long(self._gdbval)
-class PyVarObjectPtr(PyObjectPtr):
- _typename = 'PyVarObject'
class ProxyAlreadyVisited(object):
'''
@@ -436,7 +408,7 @@ class ProxyAlreadyVisited(object):
def _write_instance_repr(out, visited, name, pyop_attrdict, address):
- '''Shared code for use by all classes:
+ '''Shared code for use by old-style and new-style classes:
write a representation to file-like object "out"'''
out.write('<')
out.write(name)
@@ -519,7 +491,7 @@ class HeapTypeObjectPtr(PyObjectPtr):
def proxyval(self, visited):
'''
- Support for classes.
+ Support for new-style classes.
Currently we just locate the dictionary using a transliteration to
python of _PyObject_GetDictPtr, ignoring descriptors
@@ -536,7 +508,7 @@ class HeapTypeObjectPtr(PyObjectPtr):
attr_dict = {}
tp_name = self.safe_tp_name()
- # Class:
+ # New-style class:
return InstanceProxy(tp_name, attr_dict, long(self._gdbval))
def write_repr(self, out, visited):
@@ -584,6 +556,20 @@ class PyBaseExceptionObjectPtr(PyObjectPtr):
out.write(self.safe_tp_name())
self.write_field_repr('args', out, visited)
+class PyBoolObjectPtr(PyObjectPtr):
+ """
+ Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
+ <bool> instances (Py_True/Py_False) within the process being debugged.
+ """
+ _typename = 'PyBoolObject'
+
+ def proxyval(self, visited):
+ if int_from_int(self.field('ob_ival')):
+ return True
+ else:
+ return False
+
+
class PyClassObjectPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyClassObject* i.e. a <classobj>
@@ -673,15 +659,9 @@ class PyDictObjectPtr(PyObjectPtr):
Yields a sequence of (PyObjectPtr key, PyObjectPtr value) pairs,
analogous to dict.iteritems()
'''
- keys = self.field('ma_keys')
- values = self.field('ma_values')
- 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:
- pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
+ for i in safe_range(self.field('ma_mask') + 1):
+ ep = self.field('ma_table') + i
+ pyop_value = PyObjectPtr.from_pyobject_ptr(ep['me_value'])
if not pyop_value.is_null():
pyop_key = PyObjectPtr.from_pyobject_ptr(ep['me_key'])
yield (pyop_key, pyop_value)
@@ -717,32 +697,50 @@ 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 RuntimeError:
- # >= Python 3.6
- pass
+class PyInstanceObjectPtr(PyObjectPtr):
+ _typename = 'PyInstanceObject'
- 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
+ def proxyval(self, visited):
+ # Guard against infinite loops:
+ if self.as_address() in visited:
+ return ProxyAlreadyVisited('<...>')
+ visited.add(self.as_address())
- ent_addr = keys['dk_indices'].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)
+ # Get name of class:
+ in_class = self.pyop_field('in_class')
+ cl_name = in_class.pyop_field('cl_name').proxyval(visited)
- return ent_addr, dk_nentries
+ # Get dictionary of instance attributes:
+ in_dict = self.pyop_field('in_dict').proxyval(visited)
+ # Old-style class:
+ return InstanceProxy(cl_name, in_dict, long(self._gdbval))
+
+ def write_repr(self, out, visited):
+ # Guard against infinite loops:
+ if self.as_address() in visited:
+ out.write('<...>')
+ return
+ visited.add(self.as_address())
+
+ # Old-style class:
+
+ # Get name of class:
+ in_class = self.pyop_field('in_class')
+ cl_name = in_class.pyop_field('cl_name').proxyval(visited)
+
+ # Get dictionary of instance attributes:
+ pyop_in_dict = self.pyop_field('in_dict')
+
+ _write_instance_repr(out, visited,
+ cl_name, pyop_in_dict, self.as_address())
+
+class PyIntObjectPtr(PyObjectPtr):
+ _typename = 'PyIntObject'
+
+ def proxyval(self, visited):
+ result = int_from_int(self.field('ob_ival'))
+ return result
class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject'
@@ -817,22 +815,12 @@ class PyLongObjectPtr(PyObjectPtr):
return result
def write_repr(self, out, visited):
- # Write this out as a Python 3 int literal, i.e. without the "L" suffix
- proxy = self.proxyval(visited)
- out.write("%s" % proxy)
+ # This ensures the trailing 'L' is printed when gdb is linked
+ # with a Python 3 interpreter.
+ out.write(repr(self.proxyval(visited)).rstrip('L'))
+ out.write('L')
-class PyBoolObjectPtr(PyLongObjectPtr):
- """
- Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two
- <bool> instances (Py_True/Py_False) within the process being debugged.
- """
- def proxyval(self, visited):
- if PyLongObjectPtr.proxyval(self, visited):
- return True
- else:
- return False
-
class PyNoneStructPtr(PyObjectPtr):
"""
Class wrapping a gdb.Value that's a PyObject* pointing to the
@@ -957,7 +945,7 @@ class PyFrameObjectPtr(PyObjectPtr):
filename = self.filename()
try:
- with open(os_fsencode(filename), 'r') as fp:
+ with open(filename, 'r') as fp:
lines = fp.readlines()
except IOError:
return None
@@ -1006,34 +994,28 @@ class PyFrameObjectPtr(PyObjectPtr):
class PySetObjectPtr(PyObjectPtr):
_typename = 'PySetObject'
- @classmethod
- def _dummy_key(self):
- return gdb.lookup_global_symbol('_PySet_Dummy').value()
-
- def __iter__(self):
- dummy_ptr = self._dummy_key()
- table = self.field('table')
- for i in safe_range(self.field('mask') + 1):
- setentry = table[i]
- key = setentry['key']
- if key != 0 and key != dummy_ptr:
- yield PyObjectPtr.from_pyobject_ptr(key)
-
def proxyval(self, visited):
# Guard against infinite loops:
if self.as_address() in visited:
return ProxyAlreadyVisited('%s(...)' % self.safe_tp_name())
visited.add(self.as_address())
- members = (key.proxyval(visited) for key in self)
+ members = []
+ table = self.field('table')
+ for i in safe_range(self.field('mask')+1):
+ setentry = table[i]
+ key = setentry['key']
+ if key != 0:
+ key_proxy = PyObjectPtr.from_pyobject_ptr(key).proxyval(visited)
+ if key_proxy != '<dummy key>':
+ members.append(key_proxy)
if self.safe_tp_name() == 'frozenset':
return frozenset(members)
else:
return set(members)
def write_repr(self, out, visited):
- # Emulate Python 3's set_repr
- tp_name = self.safe_tp_name()
+ out.write(self.safe_tp_name())
# Guard against infinite loops:
if self.as_address() in visited:
@@ -1041,72 +1023,42 @@ class PySetObjectPtr(PyObjectPtr):
return
visited.add(self.as_address())
- # Python 3's set_repr special-cases the empty set:
- if not self.field('used'):
- out.write(tp_name)
- out.write('()')
- return
-
- # Python 3 uses {} for set literals:
- if tp_name != 'set':
- out.write(tp_name)
- out.write('(')
-
- out.write('{')
+ out.write('([')
first = True
- for key in self:
- if not first:
- out.write(', ')
- first = False
- key.write_repr(out, visited)
- out.write('}')
-
- if tp_name != 'set':
- out.write(')')
+ table = self.field('table')
+ for i in safe_range(self.field('mask')+1):
+ setentry = table[i]
+ key = setentry['key']
+ if key != 0:
+ pyop_key = PyObjectPtr.from_pyobject_ptr(key)
+ key_proxy = pyop_key.proxyval(visited) # FIXME!
+ if key_proxy != '<dummy key>':
+ if not first:
+ out.write(', ')
+ first = False
+ pyop_key.write_repr(out, visited)
+ out.write('])')
-class PyBytesObjectPtr(PyObjectPtr):
- _typename = 'PyBytesObject'
+class PyStringObjectPtr(PyObjectPtr):
+ _typename = 'PyStringObject'
def __str__(self):
field_ob_size = self.field('ob_size')
field_ob_sval = self.field('ob_sval')
char_ptr = field_ob_sval.address.cast(_type_unsigned_char_ptr())
+ # When gdb is linked with a Python 3 interpreter, this is really
+ # a latin-1 mojibake decoding of the original string...
return ''.join([chr(char_ptr[i]) for i in safe_range(field_ob_size)])
def proxyval(self, visited):
return str(self)
def write_repr(self, out, visited):
- # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix
-
- # Get a PyStringObject* within the Python 2 gdb process:
- proxy = self.proxyval(visited)
-
- # Transliteration of Python 3's Objects/bytesobject.c:PyBytes_Repr
- # to Python 2 code:
- quote = "'"
- if "'" in proxy and not '"' in proxy:
- quote = '"'
- out.write('b')
- out.write(quote)
- for byte in proxy:
- if byte == quote or byte == '\\':
- out.write('\\')
- out.write(byte)
- elif byte == '\t':
- out.write('\\t')
- elif byte == '\n':
- out.write('\\n')
- elif byte == '\r':
- out.write('\\r')
- elif byte < ' ' or ord(byte) >= 0x7f:
- out.write('\\x')
- out.write(hexdigits[(ord(byte) & 0xf0) >> 4])
- out.write(hexdigits[ord(byte) & 0xf])
- else:
- out.write(byte)
- out.write(quote)
+ val = repr(self.proxyval(visited))
+ if sys.version_info[0] >= 3:
+ val = val.encode('ascii', 'backslashreplace').decode('ascii')
+ out.write(val)
class PyTupleObjectPtr(PyObjectPtr):
_typename = 'PyTupleObject'
@@ -1122,8 +1074,8 @@ class PyTupleObjectPtr(PyObjectPtr):
return ProxyAlreadyVisited('(...)')
visited.add(self.as_address())
- result = tuple(PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
- for i in safe_range(int_from_int(self.field('ob_size'))))
+ result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval(visited)
+ for i in safe_range(int_from_int(self.field('ob_size')))])
return result
def write_repr(self, out, visited):
@@ -1148,13 +1100,6 @@ class PyTypeObjectPtr(PyObjectPtr):
_typename = 'PyTypeObject'
-def _unichr_is_printable(char):
- # Logic adapted from Python 3's Tools/unicode/makeunicodedata.py
- if char == u" ":
- return True
- import unicodedata
- return unicodedata.category(char) not in ("C", "Z")
-
if sys.maxunicode >= 0x10000:
_unichr = unichr
else:
@@ -1167,7 +1112,6 @@ else:
ch2 = 0xDC00 | (x & 0x3FF)
return unichr(ch1) + unichr(ch2)
-
class PyUnicodeObjectPtr(PyObjectPtr):
_typename = 'PyUnicodeObject'
@@ -1176,46 +1120,15 @@ class PyUnicodeObjectPtr(PyObjectPtr):
return _type_Py_UNICODE.sizeof
def proxyval(self, visited):
- global _is_pep393
- if _is_pep393 is None:
- fields = gdb.lookup_type('PyUnicodeObject').fields()
- _is_pep393 = 'data' in [f.name for f in fields]
- if _is_pep393:
- # Python 3.3 and newer
- may_have_surrogates = False
- compact = self.field('_base')
- ascii = compact['_base']
- state = ascii['state']
- is_compact_ascii = (int(state['ascii']) and int(state['compact']))
- if not int(state['ready']):
- # string is not ready
- field_length = long(compact['wstr_length'])
- may_have_surrogates = True
- field_str = ascii['wstr']
- else:
- field_length = long(ascii['length'])
- if is_compact_ascii:
- field_str = ascii.address + 1
- elif int(state['compact']):
- field_str = compact.address + 1
- else:
- field_str = self.field('data')['any']
- repr_kind = int(state['kind'])
- if repr_kind == 1:
- field_str = field_str.cast(_type_unsigned_char_ptr())
- elif repr_kind == 2:
- field_str = field_str.cast(_type_unsigned_short_ptr())
- elif repr_kind == 4:
- field_str = field_str.cast(_type_unsigned_int_ptr())
- else:
- # Python 3.2 and earlier
- field_length = long(self.field('length'))
- field_str = self.field('str')
- may_have_surrogates = self.char_width() == 2
+ # From unicodeobject.h:
+ # Py_ssize_t length; /* Length of raw Unicode data in buffer */
+ # Py_UNICODE *str; /* Raw Unicode buffer */
+ field_length = long(self.field('length'))
+ field_str = self.field('str')
# Gather a list of ints from the Py_UNICODE array; these are either
- # UCS-1, UCS-2 or UCS-4 code points:
- if not may_have_surrogates:
+ # UCS-2 or UCS-4 code points:
+ if self.char_width() > 2:
Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)]
else:
# A more elaborate routine if sizeof(Py_UNICODE) is 2 in the
@@ -1248,112 +1161,13 @@ class PyUnicodeObjectPtr(PyObjectPtr):
return result
def write_repr(self, out, visited):
- # Write this out as a Python 3 str literal, i.e. without a "u" prefix
-
- # Get a PyUnicodeObject* within the Python 2 gdb process:
- proxy = self.proxyval(visited)
-
- # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr
- # to Python 2:
- if "'" in proxy and '"' not in proxy:
- quote = '"'
- else:
- quote = "'"
- out.write(quote)
-
- i = 0
- while i < len(proxy):
- ch = proxy[i]
- i += 1
-
- # Escape quotes and backslashes
- if ch == quote or ch == '\\':
- out.write('\\')
- out.write(ch)
-
- # Map special whitespace to '\t', \n', '\r'
- elif ch == '\t':
- out.write('\\t')
- elif ch == '\n':
- out.write('\\n')
- elif ch == '\r':
- out.write('\\r')
-
- # Map non-printable US ASCII to '\xhh' */
- elif ch < ' ' or ch == 0x7F:
- out.write('\\x')
- out.write(hexdigits[(ord(ch) >> 4) & 0x000F])
- out.write(hexdigits[ord(ch) & 0x000F])
-
- # Copy ASCII characters as-is
- elif ord(ch) < 0x7F:
- out.write(ch)
-
- # Non-ASCII characters
- else:
- ucs = ch
- ch2 = None
- if sys.maxunicode < 0x10000:
- # If sizeof(Py_UNICODE) is 2 here (in gdb), join
- # surrogate pairs before calling _unichr_is_printable.
- if (i < len(proxy)
- and 0xD800 <= ord(ch) < 0xDC00 \
- and 0xDC00 <= ord(proxy[i]) <= 0xDFFF):
- ch2 = proxy[i]
- ucs = ch + ch2
- i += 1
-
- # Unfortuately, Python 2's unicode type doesn't seem
- # to expose the "isprintable" method
- printable = _unichr_is_printable(ucs)
- if printable:
- try:
- ucs.encode(ENCODING)
- except UnicodeEncodeError:
- printable = False
-
- # Map Unicode whitespace and control characters
- # (categories Z* and C* except ASCII space)
- if not printable:
- if ch2 is not None:
- # Match Python 3's representation of non-printable
- # wide characters.
- code = (ord(ch) & 0x03FF) << 10
- code |= ord(ch2) & 0x03FF
- code += 0x00010000
- else:
- code = ord(ucs)
-
- # Map 8-bit characters to '\\xhh'
- if code <= 0xff:
- out.write('\\x')
- out.write(hexdigits[(code >> 4) & 0x000F])
- out.write(hexdigits[code & 0x000F])
- # Map 21-bit characters to '\U00xxxxxx'
- elif code >= 0x10000:
- out.write('\\U')
- out.write(hexdigits[(code >> 28) & 0x0000000F])
- out.write(hexdigits[(code >> 24) & 0x0000000F])
- out.write(hexdigits[(code >> 20) & 0x0000000F])
- out.write(hexdigits[(code >> 16) & 0x0000000F])
- out.write(hexdigits[(code >> 12) & 0x0000000F])
- out.write(hexdigits[(code >> 8) & 0x0000000F])
- out.write(hexdigits[(code >> 4) & 0x0000000F])
- out.write(hexdigits[code & 0x0000000F])
- # Map 16-bit characters to '\uxxxx'
- else:
- out.write('\\u')
- out.write(hexdigits[(code >> 12) & 0x000F])
- out.write(hexdigits[(code >> 8) & 0x000F])
- out.write(hexdigits[(code >> 4) & 0x000F])
- out.write(hexdigits[code & 0x000F])
- else:
- # Copy characters as-is
- out.write(ch)
- if ch2 is not None:
- out.write(ch2)
-
- out.write(quote)
+ val = repr(self.proxyval(visited))
+ if sys.version_info[0] >= 3:
+ val = val.encode('ascii', 'backslashreplace').decode('ascii')
+ # This ensures the 'u' prefix is printed when gdb is linked
+ # with a Python 3 interpreter.
+ out.write('u')
+ out.write(val.lstrip('u'))
class wrapperobject(PyObjectPtr):
@@ -1392,7 +1206,7 @@ class wrapperobject(PyObjectPtr):
def int_from_int(gdbval):
- return int(gdbval)
+ return int(str(gdbval))
def stringify(val):
@@ -1517,18 +1331,18 @@ class Frame(object):
# - everything else
def is_python_frame(self):
- '''Is this a _PyEval_EvalFrameDefault frame, or some other important
+ '''Is this a PyEval_EvalFrameEx frame, or some other important
frame? (see is_other_python_frame for what "important" means in this
context)'''
- if self.is_evalframe():
+ if self.is_evalframeex():
return True
if self.is_other_python_frame():
return True
return False
- def is_evalframe(self):
- '''Is this a _PyEval_EvalFrameDefault frame?'''
- if self._gdbframe.name() == EVALFRAME:
+ def is_evalframeex(self):
+ '''Is this a PyEval_EvalFrameEx frame?'''
+ if self._gdbframe.name() == 'PyEval_EvalFrameEx':
'''
I believe we also need to filter on the inline
struct frame_id.inline_depth, only regarding frames with
@@ -1537,7 +1351,7 @@ class Frame(object):
So we reject those with type gdb.INLINE_FRAME
'''
if self._gdbframe.type() == gdb.NORMAL_FRAME:
- # We have a _PyEval_EvalFrameDefault frame:
+ # We have a PyEval_EvalFrameEx frame:
return True
return False
@@ -1563,8 +1377,7 @@ class Frame(object):
if not caller:
return False
- if (caller.startswith('cfunction_vectorcall_') or
- caller == 'cfunction_call'):
+ if caller == 'PyCFunction_Call':
arg_name = 'func'
# Within that frame:
# "func" is the local containing the PyObject* of the
@@ -1600,7 +1413,8 @@ class Frame(object):
# This assumes the _POSIX_THREADS version of Python/ceval_gil.h:
name = self._gdbframe.name()
if name:
- return 'pthread_cond_timedwait' in name
+ return ('PyThread_acquire_lock' in name
+ and 'lock_PyThread_acquire_lock' not in name)
def is_gc_collect(self):
'''Is this frame "collect" within the garbage-collector?'''
@@ -1658,7 +1472,7 @@ class Frame(object):
frame = cls.get_selected_frame()
while frame:
- if frame.is_evalframe():
+ if frame.is_evalframeex():
return frame
frame = frame.older()
@@ -1666,7 +1480,7 @@ class Frame(object):
return None
def print_summary(self):
- if self.is_evalframe():
+ if self.is_evalframeex():
pyop = self.get_pyop()
if pyop:
line = pyop.get_truncated_repr(MAX_OUTPUT_LEN)
@@ -1685,7 +1499,7 @@ class Frame(object):
sys.stdout.write('#%i\n' % self.get_index())
def print_traceback(self):
- if self.is_evalframe():
+ if self.is_evalframeex():
pyop = self.get_pyop()
if pyop:
pyop.print_traceback()
@@ -1761,7 +1575,7 @@ class PyList(gdb.Command):
start = 1
try:
- f = open(os_fsencode(filename), 'r')
+ f = open(filename, 'r')
except IOError as err:
sys.stdout.write('Unable to open %s: %s\n'
% (filename, err))