Commit 0d89c84c authored by Robert Bradshaw's avatar Robert Bradshaw

merge

parents 4dcea04a fd809921
...@@ -45,7 +45,7 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -45,7 +45,7 @@ class DebuggerTestCase(unittest.TestCase):
shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c') shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c')
compiler = ccompiler.new_compiler() compiler = ccompiler.new_compiler()
compiler.compile(['cfuncs.c'], debug=True) compiler.compile(['cfuncs.c'], debug=True, extra_postargs=['-fPIC'])
opts = dict( opts = dict(
test_directory=self.tempdir, test_directory=self.tempdir,
...@@ -122,14 +122,16 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -122,14 +122,16 @@ class GdbDebuggerTestCase(DebuggerTestCase):
python python
from Cython.Debugger.Tests import test_libcython_in_gdb from Cython.Debugger.Tests import test_libcython_in_gdb
test_libcython_in_gdb.main() test_libcython_in_gdb.main(version=%r)
end end
''') ''' % (sys.version_info[:2],))
self.gdb_command_file = cygdb.make_command_file(self.tempdir, self.gdb_command_file = cygdb.make_command_file(self.tempdir,
prefix_code) prefix_code)
open(self.gdb_command_file, 'a').write(code)
with open(self.gdb_command_file, 'a') as f:
f.write(code)
args = ['gdb', '-batch', '-x', self.gdb_command_file, '-n', '--args', args = ['gdb', '-batch', '-x', self.gdb_command_file, '-n', '--args',
sys.executable, '-c', 'import codefile'] sys.executable, '-c', 'import codefile']
...@@ -149,7 +151,7 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -149,7 +151,7 @@ class GdbDebuggerTestCase(DebuggerTestCase):
# gdb was not installed # gdb was not installed
have_gdb = False have_gdb = False
else: else:
gdb_version = p.stdout.read() gdb_version = p.stdout.read().decode('ascii')
p.wait() p.wait()
p.stdout.close() p.stdout.close()
...@@ -158,7 +160,8 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -158,7 +160,8 @@ class GdbDebuggerTestCase(DebuggerTestCase):
regex = "^GNU gdb [^\d]*(\d+)\.(\d+)" regex = "^GNU gdb [^\d]*(\d+)\.(\d+)"
gdb_version_number = re.search(regex, gdb_version).groups() gdb_version_number = re.search(regex, gdb_version).groups()
if not have_gdb or map(int, gdb_version_number) < [7, 2]: # Be Python 3 compatible
if not have_gdb or list(map(int, gdb_version_number)) < [7, 2]:
self.p = None self.p = None
warnings.warn('Skipping gdb tests, need gdb >= 7.2') warnings.warn('Skipping gdb tests, need gdb >= 7.2')
else: else:
...@@ -186,7 +189,7 @@ class TestAll(GdbDebuggerTestCase): ...@@ -186,7 +189,7 @@ class TestAll(GdbDebuggerTestCase):
border = '*' * 30 border = '*' * 30
start = '%s v INSIDE GDB v %s' % (border, border) start = '%s v INSIDE GDB v %s' % (border, border)
end = '%s ^ INSIDE GDB ^ %s' % (border, border) end = '%s ^ INSIDE GDB ^ %s' % (border, border)
errmsg = '\n%s\n%s%s' % (start, err, end) errmsg = '\n%s\n%s%s' % (start, err.decode('UTF-8'), end)
self.assertEquals(0, self.p.wait(), errmsg) self.assertEquals(0, self.p.wait(), errmsg)
sys.stderr.write(err) sys.stderr.write(err)
......
...@@ -24,7 +24,6 @@ from Cython.Debugger import libcython ...@@ -24,7 +24,6 @@ from Cython.Debugger import libcython
from Cython.Debugger import libpython from Cython.Debugger import libpython
from Cython.Debugger.Tests import TestLibCython as test_libcython from Cython.Debugger.Tests import TestLibCython as test_libcython
# for some reason sys.argv is missing in gdb # for some reason sys.argv is missing in gdb
sys.argv = ['gdb'] sys.argv = ['gdb']
...@@ -204,6 +203,7 @@ class TestStep(DebugStepperTestCase): ...@@ -204,6 +203,7 @@ class TestStep(DebugStepperTestCase):
self.assertEqual(str(pyframe.co_name), 'join') self.assertEqual(str(pyframe.co_name), 'join')
assert re.match(r'\d+ def join\(', result), result assert re.match(r'\d+ def join\(', result), result
class TestNext(DebugStepperTestCase): class TestNext(DebugStepperTestCase):
def test_cython_next(self): def test_cython_next(self):
...@@ -345,17 +345,18 @@ class TestExec(DebugTestCase): ...@@ -345,17 +345,18 @@ class TestExec(DebugTestCase):
self.assertEqual('14', self.eval_command('some_random_var')) self.assertEqual('14', self.eval_command('some_random_var'))
_do_debug = os.environ.get('CYTHON_GDB_DEBUG') _do_debug = os.environ.get('GDB_DEBUG')
if _do_debug: if _do_debug:
_debug_file = open('/dev/tty', 'w') _debug_file = open('/dev/tty', 'w')
def _debug(*messages): def _debug(*messages):
if _do_debug: if _do_debug:
messages = itertools.chain([sys._getframe(1).f_code.co_name], messages = itertools.chain([sys._getframe(1).f_code.co_name, ':'],
messages) messages)
_debug_file.write(' '.join(str(msg) for msg in messages) + '\n') _debug_file.write(' '.join(str(msg) for msg in messages) + '\n')
def _main():
def run_unittest_in_module(modulename):
try: try:
gdb.lookup_type('PyModuleObject') gdb.lookup_type('PyModuleObject')
except RuntimeError: except RuntimeError:
...@@ -365,7 +366,7 @@ def _main(): ...@@ -365,7 +366,7 @@ def _main():
warnings.warn(msg) warnings.warn(msg)
os._exit(1) os._exit(1)
else: else:
m = __import__(__name__, fromlist=['']) m = __import__(modulename, fromlist=[''])
tests = inspect.getmembers(m, inspect.isclass) tests = inspect.getmembers(m, inspect.isclass)
# test_support.run_unittest(tests) # test_support.run_unittest(tests)
...@@ -375,15 +376,29 @@ def _main(): ...@@ -375,15 +376,29 @@ def _main():
[test_loader.loadTestsFromTestCase(cls) for name, cls in tests]) [test_loader.loadTestsFromTestCase(cls) for name, cls in tests])
result = unittest.TextTestRunner(verbosity=1).run(suite) result = unittest.TextTestRunner(verbosity=1).run(suite)
if not result.wasSuccessful(): return result.wasSuccessful()
os._exit(1)
def main(trace_code=False): def runtests():
"""
Run the libcython and libpython tests. Ensure that an appropriate status is
returned to the parent test process.
"""
from Cython.Debugger.Tests import test_libpython_in_gdb
success_libcython = run_unittest_in_module(__name__)
success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__)
if not success_libcython or not success_libpython:
sys.exit(1)
def main(version, trace_code=False):
global inferior_python_version
inferior_python_version = version
if trace_code: if trace_code:
tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr, tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr,
ignoredirs=[sys.prefix, sys.exec_prefix]) ignoredirs=[sys.prefix, sys.exec_prefix])
tracer.runfunc(_main) tracer.runfunc(runtests)
else: else:
_main() runtests()
main()
# -*- coding: UTF-8 -*-
"""
Test libpython.py. This is already partly tested by test_libcython_in_gdb and
Lib/test/test_gdb.py in the Python source. These tests are run in gdb and
called from test_libcython_in_gdb.main()
"""
import os
import sys
import gdb
from Cython.Debugger import libcython
from Cython.Debugger import libpython
import test_libcython_in_gdb
from test_libcython_in_gdb import _debug, inferior_python_version
class TestPrettyPrinters(test_libcython_in_gdb.DebugTestCase):
"""
Test whether types of Python objects are correctly inferred and that
the right libpython.PySomeTypeObjectPtr classes are instantiated.
Also test whether values are appropriately formatted (don't be too
laborious as Lib/test/test_gdb.py already covers this extensively).
Don't take care of decreffing newly allocated objects as a new
interpreter is started for every test anyway.
"""
def setUp(self):
super(TestPrettyPrinters, self).setUp()
self.break_and_run('b = c = d = 0')
def get_pyobject(self, code):
value = gdb.parse_and_eval(code)
assert libpython.pointervalue(value) != 0
return value
def pyobject_fromcode(self, code, gdbvar=None):
if gdbvar is not None:
d = {'varname':gdbvar, 'code':code}
gdb.execute('set $%(varname)s = %(code)s' % d)
code = '$' + gdbvar
return libpython.PyObjectPtr.from_pyobject_ptr(self.get_pyobject(code))
def get_repr(self, pyobject):
return pyobject.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
def alloc_bytestring(self, string, gdbvar=None):
if inferior_python_version < (3, 0):
funcname = 'PyString_FromString'
else:
funcname = 'PyBytes_FromString'
assert '"' not in string
# ensure double quotes
code = '(PyObject *) %s("%s")' % (funcname, string)
return self.pyobject_fromcode(code, gdbvar=gdbvar)
def alloc_unicodestring(self, string, gdbvar=None):
self.alloc_bytestring(string.encode('UTF-8'), gdbvar='_temp')
postfix = libpython.get_inferior_unicode_postfix()
funcname = 'PyUnicode%s_FromEncodedObject' % (postfix,)
return self.pyobject_fromcode(
'(PyObject *) %s($_temp, "UTF-8", "strict")' % funcname,
gdbvar=gdbvar)
def test_bytestring(self):
bytestring = self.alloc_bytestring("spam")
if inferior_python_version < (3, 0):
bytestring_class = libpython.PyStringObjectPtr
expected = repr("spam")
else:
bytestring_class = libpython.PyBytesObjectPtr
expected = "b'spam'"
self.assertEqual(type(bytestring), bytestring_class)
self.assertEqual(self.get_repr(bytestring), expected)
def test_unicode(self):
unicode_string = self.alloc_unicodestring(u"spam ἄλφα")
expected = "'spam ἄλφα'"
if inferior_python_version < (3, 0):
expected = 'u' + expected
self.assertEqual(type(unicode_string), libpython.PyUnicodeObjectPtr)
self.assertEqual(self.get_repr(unicode_string), expected)
def test_int(self):
if inferior_python_version < (3, 0):
intval = self.pyobject_fromcode('PyInt_FromLong(100)')
self.assertEqual(type(intval), libpython.PyIntObjectPtr)
self.assertEqual(self.get_repr(intval), '100')
def test_long(self):
longval = self.pyobject_fromcode('PyLong_FromLong(200)',
gdbvar='longval')
assert gdb.parse_and_eval('$longval->ob_type == &PyLong_Type')
self.assertEqual(type(longval), libpython.PyLongObjectPtr)
self.assertEqual(self.get_repr(longval), '200')
def test_frame_type(self):
frame = self.pyobject_fromcode('PyEval_GetFrame()')
self.assertEqual(type(frame), libpython.PyFrameObjectPtr)
\ No newline at end of file
...@@ -55,6 +55,7 @@ import locale ...@@ -55,6 +55,7 @@ import locale
import atexit import atexit
import warnings import warnings
import tempfile import tempfile
import textwrap
import itertools import itertools
import gdb import gdb
...@@ -69,12 +70,11 @@ if sys.version_info[0] < 3: ...@@ -69,12 +70,11 @@ if sys.version_info[0] < 3:
# 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()
_type_void_ptr = gdb.lookup_type('void').pointer() # void* _type_void_ptr = gdb.lookup_type('void').pointer() # void*
SIZEOF_VOID_P = _type_void_ptr.sizeof SIZEOF_VOID_P = _type_void_ptr.sizeof
Py_TPFLAGS_HEAPTYPE = (1L << 9) Py_TPFLAGS_HEAPTYPE = (1L << 9)
Py_TPFLAGS_INT_SUBCLASS = (1L << 23) Py_TPFLAGS_INT_SUBCLASS = (1L << 23)
...@@ -88,8 +88,7 @@ Py_TPFLAGS_DICT_SUBCLASS = (1L << 29) ...@@ -88,8 +88,7 @@ Py_TPFLAGS_DICT_SUBCLASS = (1L << 29)
Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30) Py_TPFLAGS_BASE_EXC_SUBCLASS = (1L << 30)
Py_TPFLAGS_TYPE_SUBCLASS = (1L << 31) Py_TPFLAGS_TYPE_SUBCLASS = (1L << 31)
MAX_OUTPUT_LEN = 1024
MAX_OUTPUT_LEN=1024
hexdigits = "0123456789abcdef" hexdigits = "0123456789abcdef"
...@@ -158,6 +157,17 @@ class TruncatedStringIO(object): ...@@ -158,6 +157,17 @@ class TruncatedStringIO(object):
def getvalue(self): def getvalue(self):
return self._val return self._val
# pretty printer lookup
all_pretty_typenames = set()
class PrettyPrinterTrackerMeta(type):
def __init__(self, name, bases, dict):
super(PrettyPrinterTrackerMeta, self).__init__(name, bases, dict)
all_pretty_typenames.add(self._typename)
class PyObjectPtr(object): class PyObjectPtr(object):
""" """
Class wrapping a gdb.Value that's a either a (PyObject*) within the Class wrapping a gdb.Value that's a either a (PyObject*) within the
...@@ -169,8 +179,11 @@ class PyObjectPtr(object): ...@@ -169,8 +179,11 @@ class PyObjectPtr(object):
Note that at every stage the underlying pointer could be NULL, point Note that at every stage the underlying pointer could be NULL, point
to corrupt data, etc; this is the debugger, after all. to corrupt data, etc; this is the debugger, after all.
""" """
__metaclass__ = PrettyPrinterTrackerMeta
_typename = 'PyObject' _typename = 'PyObject'
def __init__(self, gdbval, cast_to=None): def __init__(self, gdbval, cast_to=None):
if cast_to: if cast_to:
self._gdbval = gdbval.cast(cast_to) self._gdbval = gdbval.cast(cast_to)
...@@ -355,7 +368,7 @@ class PyObjectPtr(object): ...@@ -355,7 +368,7 @@ class PyObjectPtr(object):
} }
if tp_name in name_map: if tp_name in name_map:
return name_map[tp_name] return name_map[tp_name]
if tp_flags & Py_TPFLAGS_HEAPTYPE: if tp_flags & Py_TPFLAGS_HEAPTYPE:
return HeapTypeObjectPtr return HeapTypeObjectPtr
...@@ -408,6 +421,7 @@ class PyObjectPtr(object): ...@@ -408,6 +421,7 @@ class PyObjectPtr(object):
def as_address(self): def as_address(self):
return long(self._gdbval) return long(self._gdbval)
class PyVarObjectPtr(PyObjectPtr): class PyVarObjectPtr(PyObjectPtr):
_typename = 'PyVarObject' _typename = 'PyVarObject'
...@@ -472,7 +486,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems): ...@@ -472,7 +486,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems):
class HeapTypeObjectPtr(PyObjectPtr): class HeapTypeObjectPtr(PyObjectPtr):
_typename = 'PyObject' _typename = 'PyObject'
def get_attr_dict(self): def get_attr_dict(self):
''' '''
Get the PyDictObject ptr representing the attribute dictionary Get the PyDictObject ptr representing the attribute dictionary
...@@ -550,7 +564,7 @@ class PyBaseExceptionObjectPtr(PyObjectPtr): ...@@ -550,7 +564,7 @@ class PyBaseExceptionObjectPtr(PyObjectPtr):
within the process being debugged. within the process being debugged.
""" """
_typename = 'PyBaseExceptionObject' _typename = 'PyBaseExceptionObject'
def proxyval(self, visited): def proxyval(self, visited):
# Guard against infinite loops: # Guard against infinite loops:
if self.as_address() in visited: if self.as_address() in visited:
...@@ -697,7 +711,7 @@ class PyDictObjectPtr(PyObjectPtr): ...@@ -697,7 +711,7 @@ class PyDictObjectPtr(PyObjectPtr):
class PyInstanceObjectPtr(PyObjectPtr): class PyInstanceObjectPtr(PyObjectPtr):
_typename = 'PyInstanceObject' _typename = 'PyInstanceObject'
def proxyval(self, visited): def proxyval(self, visited):
# Guard against infinite loops: # Guard against infinite loops:
if self.as_address() in visited: if self.as_address() in visited:
...@@ -742,7 +756,7 @@ class PyIntObjectPtr(PyObjectPtr): ...@@ -742,7 +756,7 @@ class PyIntObjectPtr(PyObjectPtr):
class PyListObjectPtr(PyObjectPtr): class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject' _typename = 'PyListObject'
def __getitem__(self, i): def __getitem__(self, i):
# Get the gdb.Value for the (PyObject*) with the given index: # Get the gdb.Value for the (PyObject*) with the given index:
field_ob_item = self.field('ob_item') field_ob_item = self.field('ob_item')
...@@ -775,7 +789,7 @@ class PyListObjectPtr(PyObjectPtr): ...@@ -775,7 +789,7 @@ class PyListObjectPtr(PyObjectPtr):
class PyLongObjectPtr(PyObjectPtr): class PyLongObjectPtr(PyObjectPtr):
_typename = 'PyLongObject' _typename = 'PyLongObject'
def proxyval(self, visited): def proxyval(self, visited):
''' '''
Python's Include/longobjrep.h has this declaration: Python's Include/longobjrep.h has this declaration:
...@@ -793,7 +807,7 @@ class PyLongObjectPtr(PyObjectPtr): ...@@ -793,7 +807,7 @@ class PyLongObjectPtr(PyObjectPtr):
where SHIFT can be either: where SHIFT can be either:
#define PyLong_SHIFT 30 #define PyLong_SHIFT 30
#define PyLong_SHIFT 15 #define PyLong_SHIFT 15
''' '''
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 0L
...@@ -823,9 +837,12 @@ class PyBoolObjectPtr(PyLongObjectPtr): ...@@ -823,9 +837,12 @@ class PyBoolObjectPtr(PyLongObjectPtr):
Class wrapping a gdb.Value that's a PyBoolObject* i.e. one of the two 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. <bool> instances (Py_True/Py_False) within the process being debugged.
""" """
_typename = 'PyBoolObject'
def proxyval(self, visited): def proxyval(self, visited):
return bool(PyLongObjectPtr.proxyval(self, visited)) castto = gdb.lookup_type('PyLongObject').pointer()
self._gdbval = self._gdbval.cast(castto)
return bool(PyLongObjectPtr(self._gdbval).proxyval(visited))
class PyNoneStructPtr(PyObjectPtr): class PyNoneStructPtr(PyObjectPtr):
...@@ -1033,7 +1050,7 @@ class PySetObjectPtr(PyObjectPtr): ...@@ -1033,7 +1050,7 @@ class PySetObjectPtr(PyObjectPtr):
class PyBytesObjectPtr(PyObjectPtr): class PyBytesObjectPtr(PyObjectPtr):
_typename = 'PyBytesObject' _typename = 'PyBytesObject'
def __str__(self): def __str__(self):
field_ob_size = self.field('ob_size') field_ob_size = self.field('ob_size')
field_ob_sval = self.field('ob_sval') field_ob_sval = self.field('ob_sval')
...@@ -1043,7 +1060,7 @@ class PyBytesObjectPtr(PyObjectPtr): ...@@ -1043,7 +1060,7 @@ class PyBytesObjectPtr(PyObjectPtr):
def proxyval(self, visited): def proxyval(self, visited):
return str(self) return str(self)
def write_repr(self, out, visited): def write_repr(self, out, visited, py3=True):
# Write this out as a Python 3 bytes literal, i.e. with a "b" prefix # Write this out as a Python 3 bytes literal, i.e. with a "b" prefix
# Get a PyStringObject* within the Python 2 gdb process: # Get a PyStringObject* within the Python 2 gdb process:
...@@ -1054,7 +1071,10 @@ class PyBytesObjectPtr(PyObjectPtr): ...@@ -1054,7 +1071,10 @@ class PyBytesObjectPtr(PyObjectPtr):
quote = "'" quote = "'"
if "'" in proxy and not '"' in proxy: if "'" in proxy and not '"' in proxy:
quote = '"' quote = '"'
out.write('b')
if py3:
out.write('b')
out.write(quote) out.write(quote)
for byte in proxy: for byte in proxy:
if byte == quote or byte == '\\': if byte == quote or byte == '\\':
...@@ -1077,6 +1097,8 @@ class PyBytesObjectPtr(PyObjectPtr): ...@@ -1077,6 +1097,8 @@ class PyBytesObjectPtr(PyObjectPtr):
class PyStringObjectPtr(PyBytesObjectPtr): class PyStringObjectPtr(PyBytesObjectPtr):
_typename = 'PyStringObject' _typename = 'PyStringObject'
def write_repr(self, out, visited):
return super(PyStringObjectPtr, self).write_repr(out, visited, py3=False)
class PyTupleObjectPtr(PyObjectPtr): class PyTupleObjectPtr(PyObjectPtr):
_typename = 'PyTupleObject' _typename = 'PyTupleObject'
...@@ -1184,13 +1206,20 @@ class PyUnicodeObjectPtr(PyObjectPtr): ...@@ -1184,13 +1206,20 @@ class PyUnicodeObjectPtr(PyObjectPtr):
return result return result
def write_repr(self, out, visited): 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: # Get a PyUnicodeObject* within the Python 2 gdb process:
proxy = self.proxyval(visited) proxy = self.proxyval(visited)
# Transliteration of Python 3's Object/unicodeobject.c:unicode_repr # Transliteration of Python 3's Object/unicodeobject.c:unicode_repr
# to Python 2: # to Python 2:
try:
gdb.parse_and_eval('PyString_Type')
except RuntimeError:
# Python 3, don't write 'u' as prefix
pass
else:
# Python 2, write the 'u'
out.write('u')
if "'" in proxy and '"' not in proxy: if "'" in proxy and '"' not in proxy:
quote = '"' quote = '"'
else: else:
...@@ -1292,8 +1321,6 @@ class PyUnicodeObjectPtr(PyObjectPtr): ...@@ -1292,8 +1321,6 @@ class PyUnicodeObjectPtr(PyObjectPtr):
out.write(quote) out.write(quote)
def int_from_int(gdbval): def int_from_int(gdbval):
return int(str(gdbval)) return int(str(gdbval))
...@@ -1324,16 +1351,11 @@ class PyObjectPtrPrinter: ...@@ -1324,16 +1351,11 @@ class PyObjectPtrPrinter:
proxyval = pyop.proxyval(set()) proxyval = pyop.proxyval(set())
return stringify(proxyval) return stringify(proxyval)
def pretty_printer_lookup(gdbval): def pretty_printer_lookup(gdbval):
type = gdbval.type.unqualified() type = gdbval.type.unqualified()
if type.code == gdb.TYPE_CODE_PTR: if type.code == gdb.TYPE_CODE_PTR:
type = type.target().unqualified() type = type.target().unqualified()
# do this every time to allow new subclasses to "register" if str(type) in all_pretty_typenames:
# alternatively, we could use a metaclass to register all the typenames
classes = [PyObjectPtr]
classes.extend(PyObjectPtr.__subclasses__())
if str(type) in [cls._typename for cls in classes]:
return PyObjectPtrPrinter(gdbval) return PyObjectPtrPrinter(gdbval)
""" """
...@@ -1364,8 +1386,6 @@ def register (obj): ...@@ -1364,8 +1386,6 @@ def register (obj):
register (gdb.current_objfile ()) register (gdb.current_objfile ())
# Unfortunately, the exact API exposed by the gdb module varies somewhat # Unfortunately, the exact API exposed by the gdb module varies somewhat
# from build to build # from build to build
# See http://bugs.python.org/issue8279?#msg102276 # See http://bugs.python.org/issue8279?#msg102276
...@@ -1868,11 +1888,8 @@ class GenericCodeStepper(gdb.Command): ...@@ -1868,11 +1888,8 @@ class GenericCodeStepper(gdb.Command):
Keep all breakpoints around and simply disable/enable them each time Keep all breakpoints around and simply disable/enable them each time
we are stepping. We need this because if you set and delete a we are stepping. We need this because if you set and delete a
breakpoint, gdb will not repeat your command (this is due to 'delete'). breakpoint, gdb will not repeat your command (this is due to 'delete').
Why? I'm buggered if I know. To further annoy us, we can't use the We also can't use the breakpoint API because there's no option to make
breakpoint API because there's no option to make breakpoint setting breakpoint setting silent.
silent.
So now! We may have an insane amount of breakpoints to list when the
user does 'info breakpoints' :(
This method must be called whenever the list of functions we should This method must be called whenever the list of functions we should
step into changes. It can be called on any GenericCodeStepper instance. step into changes. It can be called on any GenericCodeStepper instance.
...@@ -1890,10 +1907,11 @@ class GenericCodeStepper(gdb.Command): ...@@ -1890,10 +1907,11 @@ class GenericCodeStepper(gdb.Command):
except RuntimeError: except RuntimeError:
# gdb.Breakpoint does take an 'internal' argument, use it # gdb.Breakpoint does take an 'internal' argument, use it
# and hide output # and hide output
result = gdb.execute( result = gdb.execute(textwrap.dedent("""\
"python bp = gdb.Breakpoint(%r, gdb.BP_BREAKPOINT, internal=True); " python bp = gdb.Breakpoint(%r, gdb.BP_BREAKPOINT, \
"print bp.number", internal=True); \
to_string=True) print bp.number""",
to_string=True))
breakpoint = int(result) breakpoint = int(result)
...@@ -2177,6 +2195,19 @@ def pointervalue(gdbval): ...@@ -2177,6 +2195,19 @@ def pointervalue(gdbval):
return pointer return pointer
def get_inferior_unicode_postfix():
try:
gdb.parse_and_eval('PyUnicode_FromEncodedObject')
except RuntimeError:
try:
gdb.parse_and_eval('PyUnicodeUCS2_FromEncodedObject')
except RuntimeError:
return 'UCS4'
else:
return 'UCS2'
else:
return ''
class PythonCodeExecutor(object): class PythonCodeExecutor(object):
def malloc(self, size): def malloc(self, size):
...@@ -2197,16 +2228,14 @@ class PythonCodeExecutor(object): ...@@ -2197,16 +2228,14 @@ class PythonCodeExecutor(object):
def alloc_pystring(self, string): def alloc_pystring(self, string):
stringp = self.alloc_string(string) stringp = self.alloc_string(string)
PyString_FromStringAndSize = 'PyString_FromStringAndSize' PyString_FromStringAndSize = 'PyString_FromStringAndSize'
try: try:
gdb.parse_and_eval(PyString_FromStringAndSize) gdb.parse_and_eval(PyString_FromStringAndSize)
except RuntimeError: except RuntimeError:
try: # Python 3
gdb.parse_and_eval('PyUnicode_FromStringAndSize') PyString_FromStringAndSize = ('PyUnicode%s_FromStringAndSize' %
except RuntimeError: (get_inferior_unicode_postfix,))
PyString_FromStringAndSize = 'PyUnicodeUCS2_FromStringAndSize'
else:
PyString_FromStringAndSize = 'PyUnicode_FromStringAndSize'
try: try:
result = gdb.parse_and_eval( result = gdb.parse_and_eval(
'(PyObject *) %s((char *) %d, (size_t) %d)' % ( '(PyObject *) %s((char *) %d, (size_t) %d)' % (
...@@ -2259,7 +2288,7 @@ class PythonCodeExecutor(object): ...@@ -2259,7 +2288,7 @@ class PythonCodeExecutor(object):
code = """ code = """
PyRun_String( PyRun_String(
(PyObject *) %(code)d, (char *) %(code)d,
(int) %(start)d, (int) %(start)d,
(PyObject *) %(globals)s, (PyObject *) %(globals)s,
(PyObject *) %(locals)d) (PyObject *) %(locals)d)
......
...@@ -644,8 +644,8 @@ class CythonUnitTestCase(CythonCompileTestCase): ...@@ -644,8 +644,8 @@ class CythonUnitTestCase(CythonCompileTestCase):
except Exception: except Exception:
pass pass
# TODO: Re-enable once they're more robust.
include_debugger = sys.version_info[:2] >= (2, 5) and False include_debugger = sys.version_info[:2] > (2, 5)
def collect_unittests(path, module_prefix, suite, selectors): def collect_unittests(path, module_prefix, suite, selectors):
def file_matches(filename): def file_matches(filename):
......
...@@ -71,7 +71,7 @@ else: ...@@ -71,7 +71,7 @@ else:
setuptools_extra_args = {} setuptools_extra_args = {}
# tells whether to include cygdb (the script and the Cython.Debugger package # tells whether to include cygdb (the script and the Cython.Debugger package
include_debugger = sys.version_info[:2] >= (2, 5) include_debugger = sys.version_info[:2] > (2, 5)
if 'setuptools' in sys.modules: if 'setuptools' in sys.modules:
setuptools_extra_args['zip_safe'] = False setuptools_extra_args['zip_safe'] = False
......
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