Commit b17d2aa5 authored by Antoine Pitrou's avatar Antoine Pitrou

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

parent c17565e4
...@@ -59,7 +59,7 @@ def run_gdb(*args, **env_vars): ...@@ -59,7 +59,7 @@ def run_gdb(*args, **env_vars):
return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace') return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace')
# Verify that "gdb" was built with the embedded python support enabled: # 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: if not gdbpy_version:
raise unittest.SkipTest("gdb not built with embedded python support") raise unittest.SkipTest("gdb not built with embedded python support")
......
...@@ -40,11 +40,21 @@ the type names are known to the debugger ...@@ -40,11 +40,21 @@ the type names are known to the debugger
The module also extends gdb with some python-specific commands. 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 gdb
import os
import locale import locale
import sys import sys
if sys.version_info[0] >= 3:
unichr = chr
xrange = range
long = int
# Look up the gdb.Type for some standard types: # Look up the gdb.Type for some standard types:
_type_char_ptr = gdb.lookup_type('char').pointer() # char* _type_char_ptr = gdb.lookup_type('char').pointer() # char*
_type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char* _type_unsigned_char_ptr = gdb.lookup_type('unsigned char').pointer() # unsigned char*
...@@ -58,16 +68,16 @@ _is_pep393 = None ...@@ -58,16 +68,16 @@ _is_pep393 = None
SIZEOF_VOID_P = _type_void_ptr.sizeof SIZEOF_VOID_P = _type_void_ptr.sizeof
Py_TPFLAGS_HEAPTYPE = (1L << 9) Py_TPFLAGS_HEAPTYPE = (1 << 9)
Py_TPFLAGS_LONG_SUBCLASS = (1L << 24) Py_TPFLAGS_LONG_SUBCLASS = (1 << 24)
Py_TPFLAGS_LIST_SUBCLASS = (1L << 25) Py_TPFLAGS_LIST_SUBCLASS = (1 << 25)
Py_TPFLAGS_TUPLE_SUBCLASS = (1L << 26) Py_TPFLAGS_TUPLE_SUBCLASS = (1 << 26)
Py_TPFLAGS_BYTES_SUBCLASS = (1L << 27) Py_TPFLAGS_BYTES_SUBCLASS = (1 << 27)
Py_TPFLAGS_UNICODE_SUBCLASS = (1L << 28) Py_TPFLAGS_UNICODE_SUBCLASS = (1 << 28)
Py_TPFLAGS_DICT_SUBCLASS = (1L << 29) Py_TPFLAGS_DICT_SUBCLASS = (1 << 29)
Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30) Py_TPFLAGS_BASE_EXC_SUBCLASS = (1 << 30)
Py_TPFLAGS_TYPE_SUBCLASS = (1L << 31) Py_TPFLAGS_TYPE_SUBCLASS = (1 << 31)
MAX_OUTPUT_LEN=1024 MAX_OUTPUT_LEN=1024
...@@ -90,32 +100,39 @@ def safety_limit(val): ...@@ -90,32 +100,39 @@ def safety_limit(val):
def safe_range(val): def safe_range(val):
# As per range, but don't trust the value too much: cap it to a safety # As per range, but don't trust the value too much: cap it to a safety
# threshold in case the data was corrupted # threshold in case the data was corrupted
return xrange(safety_limit(val)) return xrange(safety_limit(int(val)))
def write_unicode(file, text): if sys.version_info[0] >= 3:
# Write a byte or unicode string to file. Unicode strings are encoded to def write_unicode(file, text):
# ENCODING encoding with 'backslashreplace' error handler to avoid file.write(text)
# UnicodeEncodeError. else:
if isinstance(text, unicode): def write_unicode(file, text):
text = text.encode(ENCODING, 'backslashreplace') # Write a byte or unicode string to file. Unicode strings are encoded to
file.write(text) # ENCODING encoding with 'backslashreplace' error handler to avoid
# UnicodeEncodeError.
def os_fsencode(filename): if isinstance(text, unicode):
if not isinstance(filename, unicode): text = text.encode(ENCODING, 'backslashreplace')
return filename file.write(text)
encoding = sys.getfilesystemencoding()
if encoding == 'mbcs': try:
# mbcs doesn't support surrogateescape os_fsencode = os.fsencode
return filename.encode(encoding) except ImportError:
encoded = [] def os_fsencode(filename):
for char in filename: if not isinstance(filename, unicode):
# surrogateescape error handler return filename
if 0xDC80 <= ord(char) <= 0xDCFF: encoding = sys.getfilesystemencoding()
byte = chr(ord(char) - 0xDC00) if encoding == 'mbcs':
else: # mbcs doesn't support surrogateescape
byte = char.encode(encoding) return filename.encode(encoding)
encoded.append(byte) encoded = []
return ''.join(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): class StringTruncated(RuntimeError):
pass pass
...@@ -322,8 +339,8 @@ class PyObjectPtr(object): ...@@ -322,8 +339,8 @@ class PyObjectPtr(object):
# class # class
return cls return cls
#print 'tp_flags = 0x%08x' % tp_flags #print('tp_flags = 0x%08x' % tp_flags)
#print 'tp_name = %r' % tp_name #print('tp_name = %r' % tp_name)
name_map = {'bool': PyBoolObjectPtr, name_map = {'bool': PyBoolObjectPtr,
'classobj': PyClassObjectPtr, 'classobj': PyClassObjectPtr,
...@@ -733,14 +750,14 @@ class PyLongObjectPtr(PyObjectPtr): ...@@ -733,14 +750,14 @@ class PyLongObjectPtr(PyObjectPtr):
''' '''
ob_size = long(self.field('ob_size')) ob_size = long(self.field('ob_size'))
if ob_size == 0: if ob_size == 0:
return 0L return 0
ob_digit = self.field('ob_digit') ob_digit = self.field('ob_digit')
if gdb.lookup_type('digit').sizeof == 2: if gdb.lookup_type('digit').sizeof == 2:
SHIFT = 15L SHIFT = 15
else: else:
SHIFT = 30L SHIFT = 30
digits = [long(ob_digit[i]) * 2**(SHIFT*i) digits = [long(ob_digit[i]) * 2**(SHIFT*i)
for i in safe_range(abs(ob_size))] for i in safe_range(abs(ob_size))]
...@@ -1595,12 +1612,12 @@ class PyList(gdb.Command): ...@@ -1595,12 +1612,12 @@ class PyList(gdb.Command):
# py-list requires an actual PyEval_EvalFrameEx frame: # py-list requires an actual PyEval_EvalFrameEx frame:
frame = Frame.get_selected_bytecode_frame() frame = Frame.get_selected_bytecode_frame()
if not frame: if not frame:
print 'Unable to locate gdb frame for python bytecode interpreter' print('Unable to locate gdb frame for python bytecode interpreter')
return return
pyop = frame.get_pyop() pyop = frame.get_pyop()
if not pyop or pyop.is_optimized_out(): 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 return
filename = pyop.filename() filename = pyop.filename()
...@@ -1656,9 +1673,9 @@ def move_in_stack(move_up): ...@@ -1656,9 +1673,9 @@ def move_in_stack(move_up):
frame = iter_frame frame = iter_frame
if move_up: if move_up:
print 'Unable to find an older python frame' print('Unable to find an older python frame')
else: else:
print 'Unable to find a newer python frame' print('Unable to find a newer python frame')
class PyUp(gdb.Command): class PyUp(gdb.Command):
'Select and print the python stack frame that called this one (if any)' 'Select and print the python stack frame that called this one (if any)'
...@@ -1740,23 +1757,23 @@ class PyPrint(gdb.Command): ...@@ -1740,23 +1757,23 @@ class PyPrint(gdb.Command):
frame = Frame.get_selected_python_frame() frame = Frame.get_selected_python_frame()
if not frame: if not frame:
print 'Unable to locate python frame' print('Unable to locate python frame')
return return
pyop_frame = frame.get_pyop() pyop_frame = frame.get_pyop()
if not pyop_frame: if not pyop_frame:
print 'Unable to read information on python frame' print('Unable to read information on python frame')
return return
pyop_var, scope = pyop_frame.get_var_by_name(name) pyop_var, scope = pyop_frame.get_var_by_name(name)
if pyop_var: if pyop_var:
print ('%s %r = %s' print('%s %r = %s'
% (scope, % (scope,
name, name,
pyop_var.get_truncated_repr(MAX_OUTPUT_LEN))) pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
else: else:
print '%r not found' % name print('%r not found' % name)
PyPrint() PyPrint()
...@@ -1774,16 +1791,16 @@ class PyLocals(gdb.Command): ...@@ -1774,16 +1791,16 @@ class PyLocals(gdb.Command):
frame = Frame.get_selected_python_frame() frame = Frame.get_selected_python_frame()
if not frame: if not frame:
print 'Unable to locate python frame' print('Unable to locate python frame')
return return
pyop_frame = frame.get_pyop() pyop_frame = frame.get_pyop()
if not pyop_frame: if not pyop_frame:
print 'Unable to read information on python frame' print('Unable to read information on python frame')
return return
for pyop_name, pyop_value in pyop_frame.iter_locals(): for pyop_name, pyop_value in pyop_frame.iter_locals():
print ('%s = %s' print('%s = %s'
% (pyop_name.proxyval(set()), % (pyop_name.proxyval(set()),
pyop_value.get_truncated_repr(MAX_OUTPUT_LEN))) 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