Commit 358da5b9 authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #19308: fix the gdb plugin on gdbs linked with Python 3

parent 9ec07227
......@@ -49,7 +49,7 @@ def run_gdb(*args, **env_vars):
return out, err
# Verify that "gdb" was built with the embedded python support enabled:
gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_info")
gdbpy_version, _ = run_gdb("--eval-command=python import sys; print(sys.version_info)")
if not gdbpy_version:
raise unittest.SkipTest("gdb not built with embedded python support")
......@@ -214,7 +214,7 @@ class PrettyPrintTests(DebuggerTests):
# matches repr(value) in this process:
gdb_repr, gdb_output = self.get_gdb_repr('print ' + repr(val),
cmds_after_breakpoint)
self.assertEqual(gdb_repr, repr(val), gdb_output)
self.assertEqual(gdb_repr, repr(val))
def test_int(self):
'Verify the pretty-printing of various "int" values'
......
......@@ -39,10 +39,20 @@ the type names are known to the debugger
The module also extends gdb with some python-specific commands.
'''
from __future__ import with_statement
# 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
import gdb
import os
import sys
if sys.version_info[0] >= 3:
unichr = chr
xrange = range
long = int
# Look up the gdb.Type for some standard types:
_type_char_ptr = gdb.lookup_type('char').pointer() # char*
_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
......@@ -51,17 +61,17 @@ _type_void_ptr = gdb.lookup_type('void').pointer() # void*
SIZEOF_VOID_P = _type_void_ptr.sizeof
Py_TPFLAGS_HEAPTYPE = (1L << 9)
Py_TPFLAGS_HEAPTYPE = (1 << 9)
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)
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_STRING_SUBCLASS = (1 << 27)
Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
Py_TPFLAGS_DICT_SUBCLASS = (1 << 29)
Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
MAX_OUTPUT_LEN=1024
......@@ -80,7 +90,7 @@ def safety_limit(val):
def safe_range(val):
# As per range, but don't trust the value too much: cap it to a safety
# threshold in case the data was corrupted
return xrange(safety_limit(val))
return xrange(safety_limit(int(val)))
class StringTruncated(RuntimeError):
......@@ -292,8 +302,8 @@ class PyObjectPtr(object):
# class
return cls
#print 'tp_flags = 0x%08x' % tp_flags
#print 'tp_name = %r' % tp_name
#print('tp_flags = 0x%08x' % tp_flags)
#print('tp_name = %r' % tp_name)
name_map = {'bool': PyBoolObjectPtr,
'classobj': PyClassObjectPtr,
......@@ -758,14 +768,14 @@ class PyLongObjectPtr(PyObjectPtr):
'''
ob_size = long(self.field('ob_size'))
if ob_size == 0:
return 0L
return 0
ob_digit = self.field('ob_digit')
if gdb.lookup_type('digit').sizeof == 2:
SHIFT = 15L
SHIFT = 15
else:
SHIFT = 30L
SHIFT = 30
digits = [long(ob_digit[i]) * 2**(SHIFT*i)
for i in safe_range(abs(ob_size))]
......@@ -774,6 +784,12 @@ class PyLongObjectPtr(PyObjectPtr):
result = -result
return result
def write_repr(self, out, visited):
# 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 PyNoneStructPtr(PyObjectPtr):
"""
......@@ -969,11 +985,19 @@ class PyStringObjectPtr(PyObjectPtr):
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):
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'
......@@ -1072,6 +1096,15 @@ class PyUnicodeObjectPtr(PyObjectPtr):
result = u''.join([_unichr(ucs) for ucs in Py_UNICODEs])
return result
def write_repr(self, out, visited):
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'))
def int_from_int(gdbval):
return int(str(gdbval))
......@@ -1295,12 +1328,12 @@ class PyList(gdb.Command):
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
print('Unable to locate python frame')
return
pyop = frame.get_pyop()
if not pyop or pyop.is_optimized_out():
print 'Unable to read information on python frame'
print('Unable to read information on python frame')
return
filename = pyop.filename()
......@@ -1350,9 +1383,9 @@ def move_in_stack(move_up):
frame = iter_frame
if move_up:
print 'Unable to find an older python frame'
print('Unable to find an older python frame')
else:
print 'Unable to find a newer python frame'
print('Unable to find a newer python frame')
class PyUp(gdb.Command):
'Select and print the python stack frame that called this one (if any)'
......@@ -1415,23 +1448,23 @@ class PyPrint(gdb.Command):
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
print('Unable to locate python frame')
return
pyop_frame = frame.get_pyop()
if not pyop_frame:
print 'Unable to read information on python frame'
print('Unable to read information on python frame')
return
pyop_var, scope = pyop_frame.get_var_by_name(name)
if pyop_var:
print ('%s %r = %s'
print('%s %r = %s'
% (scope,
name,
pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
else:
print '%r not found' % name
print('%r not found' % name)
PyPrint()
......@@ -1449,16 +1482,16 @@ class PyLocals(gdb.Command):
frame = Frame.get_selected_python_frame()
if not frame:
print 'Unable to locate python frame'
print('Unable to locate python frame')
return
pyop_frame = frame.get_pyop()
if not pyop_frame:
print 'Unable to read information on python frame'
print('Unable to read information on python frame')
return
for pyop_name, pyop_value in pyop_frame.iter_locals():
print ('%s = %s'
print('%s = %s'
% (pyop_name.proxyval(set()),
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment