Commit 8bb090b0 authored by Stefan Behnel's avatar Stefan Behnel

make libcython.py Py2/3 compatible to allows its immediate usage from both...

make libcython.py Py2/3 compatible to allows its immediate usage from both versions (and clean it up a little)
parent f4a2df85
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
GDB extension that adds Cython support. GDB extension that adds Cython support.
""" """
from __future__ import with_statement from __future__ import print_function
import sys import sys
import textwrap import textwrap
...@@ -54,6 +54,7 @@ PythonObject = 'PythonObject' ...@@ -54,6 +54,7 @@ PythonObject = 'PythonObject'
_data_types = dict(CObject=CObject, PythonObject=PythonObject) _data_types = dict(CObject=CObject, PythonObject=PythonObject)
_filesystemencoding = sys.getfilesystemencoding() or 'UTF-8' _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
# decorators # decorators
def dont_suppress_errors(function): def dont_suppress_errors(function):
...@@ -68,6 +69,7 @@ def dont_suppress_errors(function): ...@@ -68,6 +69,7 @@ def dont_suppress_errors(function):
return wrapper return wrapper
def default_selected_gdb_frame(err=True): def default_selected_gdb_frame(err=True):
def decorator(function): def decorator(function):
@functools.wraps(function) @functools.wraps(function)
...@@ -84,6 +86,7 @@ def default_selected_gdb_frame(err=True): ...@@ -84,6 +86,7 @@ def default_selected_gdb_frame(err=True):
return wrapper return wrapper
return decorator return decorator
def require_cython_frame(function): def require_cython_frame(function):
@functools.wraps(function) @functools.wraps(function)
@require_running_program @require_running_program
...@@ -95,6 +98,7 @@ def require_cython_frame(function): ...@@ -95,6 +98,7 @@ def require_cython_frame(function):
return function(self, *args, **kwargs) return function(self, *args, **kwargs)
return wrapper return wrapper
def dispatch_on_frame(c_command, python_command=None): def dispatch_on_frame(c_command, python_command=None):
def decorator(function): def decorator(function):
@functools.wraps(function) @functools.wraps(function)
...@@ -115,6 +119,7 @@ def dispatch_on_frame(c_command, python_command=None): ...@@ -115,6 +119,7 @@ def dispatch_on_frame(c_command, python_command=None):
return wrapper return wrapper
return decorator return decorator
def require_running_program(function): def require_running_program(function):
@functools.wraps(function) @functools.wraps(function)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
...@@ -152,6 +157,7 @@ class CythonModule(object): ...@@ -152,6 +157,7 @@ class CythonModule(object):
self.lineno_c2cy = {} self.lineno_c2cy = {}
self.functions = {} self.functions = {}
class CythonVariable(object): class CythonVariable(object):
def __init__(self, name, cname, qualified_name, type, lineno): def __init__(self, name, cname, qualified_name, type, lineno):
...@@ -161,6 +167,7 @@ class CythonVariable(object): ...@@ -161,6 +167,7 @@ class CythonVariable(object):
self.type = type self.type = type
self.lineno = int(lineno) self.lineno = int(lineno)
class CythonFunction(CythonVariable): class CythonFunction(CythonVariable):
def __init__(self, def __init__(self,
module, module,
...@@ -297,7 +304,7 @@ class CythonBase(object): ...@@ -297,7 +304,7 @@ class CythonBase(object):
try: try:
source_desc, lineno = self.get_source_desc(frame) source_desc, lineno = self.get_source_desc(frame)
except NoFunctionNameInFrameError: except NoFunctionNameInFrameError:
print '#%-2d Unknown Frame (compile with -g)' % index print('#%-2d Unknown Frame (compile with -g)' % index)
return return
if not is_c and self.is_python_function(frame): if not is_c and self.is_python_function(frame):
...@@ -381,10 +388,9 @@ class CythonBase(object): ...@@ -381,10 +388,9 @@ class CythonBase(object):
typename = '(%s) ' % (value.type,) typename = '(%s) ' % (value.type,)
if max_name_length is None: if max_name_length is None:
print '%s%s = %s%s' % (prefix, name, typename, value) print('%s%s = %s%s' % (prefix, name, typename, value))
else: else:
print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename, print('%s%-*s = %s%s' % (prefix, max_name_length, name, typename, value))
value)
def is_initialized(self, cython_func, local_name): def is_initialized(self, cython_func, local_name):
cyvar = cython_func.locals[local_name] cyvar = cython_func.locals[local_name]
...@@ -473,6 +479,7 @@ class CyGDBError(gdb.GdbError): ...@@ -473,6 +479,7 @@ class CyGDBError(gdb.GdbError):
args = args or (self.msg,) args = args or (self.msg,)
super(CyGDBError, self).__init__(*args) super(CyGDBError, self).__init__(*args)
class NoCythonFunctionInFrameError(CyGDBError): class NoCythonFunctionInFrameError(CyGDBError):
""" """
raised when the user requests the current cython function, which is raised when the user requests the current cython function, which is
...@@ -480,6 +487,7 @@ class NoCythonFunctionInFrameError(CyGDBError): ...@@ -480,6 +487,7 @@ class NoCythonFunctionInFrameError(CyGDBError):
""" """
msg = "Current function is a function cygdb doesn't know about" msg = "Current function is a function cygdb doesn't know about"
class NoFunctionNameInFrameError(NoCythonFunctionInFrameError): class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
""" """
raised when the name of the C function could not be determined raised when the name of the C function could not be determined
...@@ -509,21 +517,25 @@ class CythonParameter(gdb.Parameter): ...@@ -509,21 +517,25 @@ class CythonParameter(gdb.Parameter):
__nonzero__ = __bool__ # Python 2 __nonzero__ = __bool__ # Python 2
class CompleteUnqualifiedFunctionNames(CythonParameter): class CompleteUnqualifiedFunctionNames(CythonParameter):
""" """
Have 'cy break' complete unqualified function or method names. Have 'cy break' complete unqualified function or method names.
""" """
class ColorizeSourceCode(CythonParameter): class ColorizeSourceCode(CythonParameter):
""" """
Tell cygdb whether to colorize source code. Tell cygdb whether to colorize source code.
""" """
class TerminalBackground(CythonParameter): class TerminalBackground(CythonParameter):
""" """
Tell cygdb about the user's terminal background (light or dark). Tell cygdb about the user's terminal background (light or dark).
""" """
class CythonParameters(object): class CythonParameters(object):
""" """
Simple container class that might get more functionality in the distant Simple container class that might get more functionality in the distant
...@@ -636,7 +648,7 @@ class CyCy(CythonCommand): ...@@ -636,7 +648,7 @@ class CyCy(CythonCommand):
cy_eval = CyEval('cy_eval'), cy_eval = CyEval('cy_eval'),
) )
for command_name, command in commands.iteritems(): for command_name, command in commands.items():
command.cy = self command.cy = self
setattr(self, command_name, command) setattr(self, command_name, command)
...@@ -672,9 +684,8 @@ class CyImport(CythonCommand): ...@@ -672,9 +684,8 @@ class CyImport(CythonCommand):
for arg in string_to_argv(args): for arg in string_to_argv(args):
try: try:
f = open(arg) f = open(arg)
except OSError, e: except OSError as e:
raise gdb.GdbError('Unable to open file %r: %s' % raise gdb.GdbError('Unable to open file %r: %s' % (args, e.args[1]))
(args, e.args[1]))
t = etree.parse(f) t = etree.parse(f)
...@@ -782,9 +793,9 @@ class CyBreak(CythonCommand): ...@@ -782,9 +793,9 @@ class CyBreak(CythonCommand):
if len(funcs) > 1: if len(funcs) > 1:
# multiple functions, let the user pick one # multiple functions, let the user pick one
print 'There are multiple such functions:' print('There are multiple such functions:')
for idx, func in enumerate(funcs): for idx, func in enumerate(funcs):
print '%3d) %s' % (idx, func.qualified_name) print('%3d) %s' % (idx, func.qualified_name))
while True: while True:
try: try:
...@@ -804,7 +815,7 @@ class CyBreak(CythonCommand): ...@@ -804,7 +815,7 @@ class CyBreak(CythonCommand):
break_funcs = [funcs[int(result)]] break_funcs = [funcs[int(result)]]
break break
else: else:
print 'Not understood...' print('Not understood...')
else: else:
break_funcs = [funcs[0]] break_funcs = [funcs[0]]
...@@ -977,7 +988,7 @@ class CyUp(CythonCommand): ...@@ -977,7 +988,7 @@ class CyUp(CythonCommand):
gdb.execute(self._command, to_string=True) gdb.execute(self._command, to_string=True)
while not self.is_relevant_function(gdb.selected_frame()): while not self.is_relevant_function(gdb.selected_frame()):
gdb.execute(self._command, to_string=True) gdb.execute(self._command, to_string=True)
except RuntimeError, e: except RuntimeError as e:
raise gdb.GdbError(*e.args) raise gdb.GdbError(*e.args)
frame = gdb.selected_frame() frame = gdb.selected_frame()
...@@ -1020,7 +1031,7 @@ class CySelect(CythonCommand): ...@@ -1020,7 +1031,7 @@ class CySelect(CythonCommand):
try: try:
gdb.execute('select %d' % (stackdepth - stackno - 1,)) gdb.execute('select %d' % (stackdepth - stackno - 1,))
except RuntimeError, e: except RuntimeError as e:
raise gdb.GdbError(*e.args) raise gdb.GdbError(*e.args)
...@@ -1070,7 +1081,7 @@ class CyList(CythonCommand): ...@@ -1070,7 +1081,7 @@ class CyList(CythonCommand):
sd, lineno = self.get_source_desc() sd, lineno = self.get_source_desc()
source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno, source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno,
lex_entire=True) lex_entire=True)
print source print(source)
class CyPrint(CythonCommand): class CyPrint(CythonCommand):
...@@ -1104,7 +1115,8 @@ class CyPrint(CythonCommand): ...@@ -1104,7 +1115,8 @@ class CyPrint(CythonCommand):
return [] return []
sortkey = lambda (name, value): name.lower() sortkey = lambda item: item[0].lower()
class CyLocals(CythonCommand): class CyLocals(CythonCommand):
""" """
...@@ -1157,13 +1169,13 @@ class CyGlobals(CyLocals): ...@@ -1157,13 +1169,13 @@ class CyGlobals(CyLocals):
max_name_length = max(max_globals_len, max_globals_dict_len) max_name_length = max(max_globals_len, max_globals_dict_len)
seen = set() seen = set()
print 'Python globals:' print('Python globals:')
for k, v in sorted(global_python_dict.iteritems(), key=sortkey): for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN) v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
seen.add(k) seen.add(k)
print ' %-*s = %s' % (max_name_length, k, v) print(' %-*s = %s' % (max_name_length, k, v))
print 'C globals:' print('C globals:')
for name, cyvar in sorted(module_globals.iteritems(), key=sortkey): for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
if name not in seen: if name not in seen:
try: try:
...@@ -1176,7 +1188,6 @@ class CyGlobals(CyLocals): ...@@ -1176,7 +1188,6 @@ class CyGlobals(CyLocals):
max_name_length, ' ') max_name_length, ' ')
class EvaluateOrExecuteCodeMixin(object): class EvaluateOrExecuteCodeMixin(object):
""" """
Evaluate or execute Python code in a Cython or Python frame. The 'evalcode' Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
...@@ -1228,7 +1239,6 @@ class EvaluateOrExecuteCodeMixin(object): ...@@ -1228,7 +1239,6 @@ class EvaluateOrExecuteCodeMixin(object):
raise gdb.GdbError("There is no Cython or Python frame on the stack.") raise gdb.GdbError("There is no Cython or Python frame on the stack.")
def _evalcode_cython(self, executor, code, input_type): def _evalcode_cython(self, executor, code, input_type):
with libpython.FetchAndRestoreError(): with libpython.FetchAndRestoreError():
# get the dict of Cython globals and construct a dict in the # get the dict of Cython globals and construct a dict in the
...@@ -1384,6 +1394,7 @@ cython_info = CythonInfo() ...@@ -1384,6 +1394,7 @@ cython_info = CythonInfo()
cy = CyCy.register() cy = CyCy.register()
cython_info.cy = cy cython_info.cy = cy
def register_defines(): def register_defines():
libpython.source_gdb_script(textwrap.dedent("""\ libpython.source_gdb_script(textwrap.dedent("""\
define cy step define cy step
......
...@@ -45,8 +45,6 @@ the type names are known to the debugger ...@@ -45,8 +45,6 @@ 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
import os import os
import re import re
import sys import sys
...@@ -60,6 +58,11 @@ import itertools ...@@ -60,6 +58,11 @@ import itertools
import gdb import gdb
try:
xrange
except NameError:
xrange = range
if sys.version_info[0] < 3: if sys.version_info[0] < 3:
# I think this is the only way to fix this bug :'( # I think this is the only way to fix this bug :'(
# http://sourceware.org/bugzilla/show_bug.cgi?id=12285 # http://sourceware.org/bugzilla/show_bug.cgi?id=12285
...@@ -75,18 +78,18 @@ _type_void_ptr = gdb.lookup_type('void').pointer() # void* ...@@ -75,18 +78,18 @@ _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 = (1 << 9)
Py_TPFLAGS_INT_SUBCLASS = (1L << 23) Py_TPFLAGS_INT_SUBCLASS = (1 << 23)
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_STRING_SUBCLASS = (1L << 27) Py_TPFLAGS_STRING_SUBCLASS = (1 << 27)
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
...@@ -94,6 +97,7 @@ hexdigits = "0123456789abcdef" ...@@ -94,6 +97,7 @@ hexdigits = "0123456789abcdef"
ENCODING = locale.getpreferredencoding() ENCODING = locale.getpreferredencoding()
class NullPyObjectPtr(RuntimeError): class NullPyObjectPtr(RuntimeError):
pass pass
...@@ -110,16 +114,18 @@ def safe_range(val): ...@@ -110,16 +114,18 @@ def safe_range(val):
# threshold in case the data was corrupted # threshold in case the data was corrupted
return xrange(safety_limit(val)) return xrange(safety_limit(val))
def write_unicode(file, text): def write_unicode(file, text):
# Write a byte or unicode string to file. Unicode strings are encoded to # Write a byte or unicode string to file. Unicode strings are encoded to
# ENCODING encoding with 'backslashreplace' error handler to avoid # ENCODING encoding with 'backslashreplace' error handler to avoid
# UnicodeEncodeError. # UnicodeEncodeError.
if isinstance(text, unicode): if not isinstance(text, str):
text = text.encode(ENCODING, 'backslashreplace') text = text.encode(ENCODING, 'backslashreplace')
file.write(text) file.write(text)
def os_fsencode(filename): def os_fsencode(filename):
if not isinstance(filename, unicode): if isinstance(filename, str): # only encode in Py2
return filename return filename
encoding = sys.getfilesystemencoding() encoding = sys.getfilesystemencoding()
if encoding == 'mbcs': if encoding == 'mbcs':
...@@ -135,9 +141,11 @@ def os_fsencode(filename): ...@@ -135,9 +141,11 @@ def os_fsencode(filename):
encoded.append(byte) encoded.append(byte)
return ''.join(encoded) return ''.join(encoded)
class StringTruncated(RuntimeError): class StringTruncated(RuntimeError):
pass pass
class TruncatedStringIO(object): class TruncatedStringIO(object):
'''Similar to cStringIO, but can truncate the output by raising a '''Similar to cStringIO, but can truncate the output by raising a
StringTruncated exception''' StringTruncated exception'''
...@@ -161,6 +169,7 @@ class TruncatedStringIO(object): ...@@ -161,6 +169,7 @@ class TruncatedStringIO(object):
# pretty printer lookup # pretty printer lookup
all_pretty_typenames = set() all_pretty_typenames = set()
class PrettyPrinterTrackerMeta(type): class PrettyPrinterTrackerMeta(type):
def __init__(self, name, bases, dict): def __init__(self, name, bases, dict):
...@@ -406,7 +415,7 @@ class PyObjectPtr(object): ...@@ -406,7 +415,7 @@ class PyObjectPtr(object):
p = PyObjectPtr(gdbval) p = PyObjectPtr(gdbval)
cls = cls.subclass_from_type(p.type()) cls = cls.subclass_from_type(p.type())
return cls(gdbval, cast_to=cls.get_gdb_type()) return cls(gdbval, cast_to=cls.get_gdb_type())
except RuntimeError, exc: except RuntimeError as exc:
# Handle any kind of error e.g. NULL ptrs by simply using the base # Handle any kind of error e.g. NULL ptrs by simply using the base
# class # class
pass pass
...@@ -423,6 +432,7 @@ class PyObjectPtr(object): ...@@ -423,6 +432,7 @@ class PyObjectPtr(object):
class PyVarObjectPtr(PyObjectPtr): class PyVarObjectPtr(PyObjectPtr):
_typename = 'PyVarObject' _typename = 'PyVarObject'
class ProxyAlreadyVisited(object): class ProxyAlreadyVisited(object):
''' '''
Placeholder proxy to use when protecting against infinite recursion due to Placeholder proxy to use when protecting against infinite recursion due to
...@@ -467,13 +477,14 @@ class InstanceProxy(object): ...@@ -467,13 +477,14 @@ class InstanceProxy(object):
def __repr__(self): def __repr__(self):
if isinstance(self.attrdict, dict): if isinstance(self.attrdict, dict):
kwargs = ', '.join(["%s=%r" % (arg, val) kwargs = ', '.join("%s=%r" % (arg, val)
for arg, val in self.attrdict.iteritems()]) for arg, val in self.attrdict.iteritems())
return '<%s(%s) at remote 0x%x>' % (self.cl_name, return '<%s(%s) at remote 0x%x>' % (
kwargs, self.address) self.cl_name, kwargs, self.address)
else: else:
return '<%s at remote 0x%x>' % (self.cl_name, return '<%s at remote 0x%x>' % (
self.address) self.cl_name, self.address)
def _PyObject_VAR_SIZE(typeobj, nitems): def _PyObject_VAR_SIZE(typeobj, nitems):
return ( ( typeobj.field('tp_basicsize') + return ( ( typeobj.field('tp_basicsize') +
...@@ -482,6 +493,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems): ...@@ -482,6 +493,7 @@ def _PyObject_VAR_SIZE(typeobj, nitems):
) & ~(SIZEOF_VOID_P - 1) ) & ~(SIZEOF_VOID_P - 1)
).cast(gdb.lookup_type('size_t')) ).cast(gdb.lookup_type('size_t'))
class PyTypeObjectPtr(PyObjectPtr): class PyTypeObjectPtr(PyObjectPtr):
_typename = 'PyTypeObject' _typename = 'PyTypeObject'
...@@ -549,12 +561,12 @@ class PyTypeObjectPtr(PyObjectPtr): ...@@ -549,12 +561,12 @@ class PyTypeObjectPtr(PyObjectPtr):
except RuntimeError: except RuntimeError:
tp_name = 'unknown' tp_name = 'unknown'
out.write('<type %s at remote 0x%x>' % (tp_name, out.write('<type %s at remote 0x%x>' % (tp_name, self.as_address()))
self.as_address()))
# pyop_attrdict = self.get_attr_dict() # pyop_attrdict = self.get_attr_dict()
# _write_instance_repr(out, visited, # _write_instance_repr(out, visited,
# self.safe_tp_name(), pyop_attrdict, self.as_address()) # self.safe_tp_name(), pyop_attrdict, self.as_address())
class ProxyException(Exception): class ProxyException(Exception):
def __init__(self, tp_name, args): def __init__(self, tp_name, args):
self.tp_name = tp_name self.tp_name = tp_name
...@@ -563,6 +575,7 @@ class ProxyException(Exception): ...@@ -563,6 +575,7 @@ class ProxyException(Exception):
def __repr__(self): def __repr__(self):
return '%s%r' % (self.tp_name, self.args) return '%s%r' % (self.tp_name, self.args)
class PyBaseExceptionObjectPtr(PyObjectPtr): class PyBaseExceptionObjectPtr(PyObjectPtr):
""" """
Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception Class wrapping a gdb.Value that's a PyBaseExceptionObject* i.e. an exception
...@@ -605,17 +618,17 @@ class BuiltInFunctionProxy(object): ...@@ -605,17 +618,17 @@ class BuiltInFunctionProxy(object):
def __repr__(self): def __repr__(self):
return "<built-in function %s>" % self.ml_name return "<built-in function %s>" % self.ml_name
class BuiltInMethodProxy(object): class BuiltInMethodProxy(object):
def __init__(self, ml_name, pyop_m_self): def __init__(self, ml_name, pyop_m_self):
self.ml_name = ml_name self.ml_name = ml_name
self.pyop_m_self = pyop_m_self self.pyop_m_self = pyop_m_self
def __repr__(self): def __repr__(self):
return ('<built-in method %s of %s object at remote 0x%x>' return '<built-in method %s of %s object at remote 0x%x>' % (
% (self.ml_name, self.ml_name, self.pyop_m_self.safe_tp_name(),
self.pyop_m_self.safe_tp_name(),
self.pyop_m_self.as_address()) self.pyop_m_self.as_address())
)
class PyCFunctionObjectPtr(PyObjectPtr): class PyCFunctionObjectPtr(PyObjectPtr):
""" """
...@@ -714,6 +727,7 @@ class PyDictObjectPtr(PyObjectPtr): ...@@ -714,6 +727,7 @@ class PyDictObjectPtr(PyObjectPtr):
pyop_value.write_repr(out, visited) pyop_value.write_repr(out, visited)
out.write('}') out.write('}')
class PyInstanceObjectPtr(PyObjectPtr): class PyInstanceObjectPtr(PyObjectPtr):
_typename = 'PyInstanceObject' _typename = 'PyInstanceObject'
...@@ -752,6 +766,7 @@ class PyInstanceObjectPtr(PyObjectPtr): ...@@ -752,6 +766,7 @@ class PyInstanceObjectPtr(PyObjectPtr):
_write_instance_repr(out, visited, _write_instance_repr(out, visited,
cl_name, pyop_in_dict, self.as_address()) cl_name, pyop_in_dict, self.as_address())
class PyIntObjectPtr(PyObjectPtr): class PyIntObjectPtr(PyObjectPtr):
_typename = 'PyIntObject' _typename = 'PyIntObject'
...@@ -759,6 +774,7 @@ class PyIntObjectPtr(PyObjectPtr): ...@@ -759,6 +774,7 @@ class PyIntObjectPtr(PyObjectPtr):
result = int_from_int(self.field('ob_ival')) result = int_from_int(self.field('ob_ival'))
return result return result
class PyListObjectPtr(PyObjectPtr): class PyListObjectPtr(PyObjectPtr):
_typename = 'PyListObject' _typename = 'PyListObject'
...@@ -792,6 +808,7 @@ class PyListObjectPtr(PyObjectPtr): ...@@ -792,6 +808,7 @@ class PyListObjectPtr(PyObjectPtr):
element.write_repr(out, visited) element.write_repr(out, visited)
out.write(']') out.write(']')
class PyLongObjectPtr(PyObjectPtr): class PyLongObjectPtr(PyObjectPtr):
_typename = 'PyLongObject' _typename = 'PyLongObject'
...@@ -815,16 +832,16 @@ class PyLongObjectPtr(PyObjectPtr): ...@@ -815,16 +832,16 @@ 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 long(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 = [ob_digit[i] * (1 << (SHIFT*i))
for i in safe_range(abs(ob_size))] for i in safe_range(abs(ob_size))]
result = sum(digits) result = sum(digits)
if ob_size < 0: if ob_size < 0:
...@@ -989,6 +1006,7 @@ class PyFrameObjectPtr(PyObjectPtr): ...@@ -989,6 +1006,7 @@ class PyFrameObjectPtr(PyObjectPtr):
out.write(')') out.write(')')
class PySetObjectPtr(PyObjectPtr): class PySetObjectPtr(PyObjectPtr):
_typename = 'PySetObject' _typename = 'PySetObject'
...@@ -1099,12 +1117,14 @@ class PyBytesObjectPtr(PyObjectPtr): ...@@ -1099,12 +1117,14 @@ class PyBytesObjectPtr(PyObjectPtr):
out.write(byte) out.write(byte)
out.write(quote) out.write(quote)
class PyStringObjectPtr(PyBytesObjectPtr): class PyStringObjectPtr(PyBytesObjectPtr):
_typename = 'PyStringObject' _typename = 'PyStringObject'
def write_repr(self, out, visited): def write_repr(self, out, visited):
return super(PyStringObjectPtr, self).write_repr(out, visited, py3=False) return super(PyStringObjectPtr, self).write_repr(out, visited, py3=False)
class PyTupleObjectPtr(PyObjectPtr): class PyTupleObjectPtr(PyObjectPtr):
_typename = 'PyTupleObject' _typename = 'PyTupleObject'
...@@ -1149,8 +1169,12 @@ def _unichr_is_printable(char): ...@@ -1149,8 +1169,12 @@ def _unichr_is_printable(char):
import unicodedata import unicodedata
return unicodedata.category(char) not in ("C", "Z") return unicodedata.category(char) not in ("C", "Z")
if sys.maxunicode >= 0x10000: if sys.maxunicode >= 0x10000:
try:
_unichr = unichr _unichr = unichr
except NameError:
_unichr = chr
else: else:
# Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb # Needed for proper surrogate support if sizeof(Py_UNICODE) is 2 in gdb
def _unichr(x): def _unichr(x):
...@@ -1161,6 +1185,7 @@ else: ...@@ -1161,6 +1185,7 @@ else:
ch2 = 0xDC00 | (x & 0x3FF) ch2 = 0xDC00 | (x & 0x3FF)
return unichr(ch1) + unichr(ch2) return unichr(ch1) + unichr(ch2)
class PyUnicodeObjectPtr(PyObjectPtr): class PyUnicodeObjectPtr(PyObjectPtr):
_typename = 'PyUnicodeObject' _typename = 'PyUnicodeObject'
...@@ -1333,6 +1358,7 @@ class PyUnicodeObjectPtr(PyObjectPtr): ...@@ -1333,6 +1358,7 @@ class PyUnicodeObjectPtr(PyObjectPtr):
# Be compatible with that. # Be compatible with that.
return unicode(self).encode('UTF-8') return unicode(self).encode('UTF-8')
def int_from_int(gdbval): def int_from_int(gdbval):
return int(str(gdbval)) return int(str(gdbval))
...@@ -1363,6 +1389,7 @@ class PyObjectPtrPrinter: ...@@ -1363,6 +1389,7 @@ 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:
...@@ -1389,19 +1416,22 @@ that this python file is installed to the same path as the library (or its ...@@ -1389,19 +1416,22 @@ that this python file is installed to the same path as the library (or its
/usr/lib/libpython2.6.so.1.0-gdb.py /usr/lib/libpython2.6.so.1.0-gdb.py
/usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py /usr/lib/debug/usr/lib/libpython2.6.so.1.0.debug-gdb.py
""" """
def register (obj):
if obj == None:
def register(obj):
if obj is None:
obj = gdb obj = gdb
# Wire up the pretty-printer # Wire up the pretty-printer
obj.pretty_printers.append(pretty_printer_lookup) obj.pretty_printers.append(pretty_printer_lookup)
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
class Frame(object): class Frame(object):
''' '''
Wrapper for gdb.Frame, adding various methods Wrapper for gdb.Frame, adding various methods
...@@ -1529,6 +1559,7 @@ class Frame(object): ...@@ -1529,6 +1559,7 @@ class Frame(object):
else: else:
sys.stdout.write('#%i\n' % self.get_index()) sys.stdout.write('#%i\n' % self.get_index())
class PyList(gdb.Command): class PyList(gdb.Command):
'''List the current Python source code, if any '''List the current Python source code, if any
...@@ -1547,7 +1578,6 @@ class PyList(gdb.Command): ...@@ -1547,7 +1578,6 @@ class PyList(gdb.Command):
gdb.COMMAND_FILES, gdb.COMMAND_FILES,
gdb.COMPLETE_NONE) gdb.COMPLETE_NONE)
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
import re import re
...@@ -1565,12 +1595,12 @@ class PyList(gdb.Command): ...@@ -1565,12 +1595,12 @@ class PyList(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.get_pyop() pyop = frame.get_pyop()
if not pyop: if not pyop:
print 'Unable to read information on python frame' print('Unable to read information on python frame')
return return
filename = pyop.filename() filename = pyop.filename()
...@@ -1595,10 +1625,10 @@ class PyList(gdb.Command): ...@@ -1595,10 +1625,10 @@ class PyList(gdb.Command):
linestr = '>' + linestr linestr = '>' + linestr
sys.stdout.write('%4s %s' % (linestr, line)) sys.stdout.write('%4s %s' % (linestr, line))
# ...and register the command: # ...and register the command:
PyList() PyList()
def move_in_stack(move_up): def move_in_stack(move_up):
'''Move up or down the stack (for the py-up/py-down command)''' '''Move up or down the stack (for the py-up/py-down command)'''
frame = Frame.get_selected_python_frame() frame = Frame.get_selected_python_frame()
...@@ -1620,9 +1650,10 @@ def move_in_stack(move_up): ...@@ -1620,9 +1650,10 @@ 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)'
...@@ -1632,10 +1663,10 @@ class PyUp(gdb.Command): ...@@ -1632,10 +1663,10 @@ class PyUp(gdb.Command):
gdb.COMMAND_STACK, gdb.COMMAND_STACK,
gdb.COMPLETE_NONE) gdb.COMPLETE_NONE)
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
move_in_stack(move_up=True) move_in_stack(move_up=True)
class PyDown(gdb.Command): class PyDown(gdb.Command):
'Select and print the python stack frame called by this one (if any)' 'Select and print the python stack frame called by this one (if any)'
def __init__(self): def __init__(self):
...@@ -1644,15 +1675,16 @@ class PyDown(gdb.Command): ...@@ -1644,15 +1675,16 @@ class PyDown(gdb.Command):
gdb.COMMAND_STACK, gdb.COMMAND_STACK,
gdb.COMPLETE_NONE) gdb.COMPLETE_NONE)
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
move_in_stack(move_up=False) move_in_stack(move_up=False)
# Not all builds of gdb have gdb.Frame.select # Not all builds of gdb have gdb.Frame.select
if hasattr(gdb.Frame, 'select'): if hasattr(gdb.Frame, 'select'):
PyUp() PyUp()
PyDown() PyDown()
class PyBacktrace(gdb.Command): class PyBacktrace(gdb.Command):
'Display the current python frame and all the frames within its call stack (if any)' 'Display the current python frame and all the frames within its call stack (if any)'
def __init__(self): def __init__(self):
...@@ -1671,6 +1703,7 @@ class PyBacktrace(gdb.Command): ...@@ -1671,6 +1703,7 @@ class PyBacktrace(gdb.Command):
PyBacktrace() PyBacktrace()
class PyPrint(gdb.Command): class PyPrint(gdb.Command):
'Look up the given python variable name, and print it' 'Look up the given python variable name, and print it'
def __init__(self): def __init__(self):
...@@ -1679,32 +1712,30 @@ class PyPrint(gdb.Command): ...@@ -1679,32 +1712,30 @@ class PyPrint(gdb.Command):
gdb.COMMAND_DATA, gdb.COMMAND_DATA,
gdb.COMPLETE_NONE) gdb.COMPLETE_NONE)
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
name = str(args) name = str(args)
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, pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
name,
pyop_var.get_truncated_repr(MAX_OUTPUT_LEN)))
else: else:
print '%r not found' % name print('%r not found' % name)
PyPrint() PyPrint()
class PyLocals(gdb.Command): class PyLocals(gdb.Command):
'Look up the given python variable name, and print it' 'Look up the given python variable name, and print it'
...@@ -1713,24 +1744,24 @@ class PyLocals(gdb.Command): ...@@ -1713,24 +1744,24 @@ 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
namespace = self.get_namespace(pyop_frame) namespace = self.get_namespace(pyop_frame)
namespace = [(name.proxyval(set()), val) for name, val in namespace] namespace = [(name.proxyval(set()), val) for name, val in namespace]
if namespace: if namespace:
name, val = max(namespace, key=lambda (name, val): len(name)) name, val = max(namespace, key=lambda item: len(item[0]))
max_name_length = len(name) max_name_length = len(name)
for name, pyop_value in namespace: for name, pyop_value in namespace:
value = pyop_value.get_truncated_repr(MAX_OUTPUT_LEN) value = pyop_value.get_truncated_repr(MAX_OUTPUT_LEN)
print ('%-*s = %s' % (max_name_length, name, value)) print('%-*s = %s' % (max_name_length, name, value))
def get_namespace(self, pyop_frame): def get_namespace(self, pyop_frame):
return pyop_frame.iter_locals() return pyop_frame.iter_locals()
...@@ -1880,6 +1911,7 @@ def get_selected_inferior(): ...@@ -1880,6 +1911,7 @@ def get_selected_inferior():
if thread == selected_thread: if thread == selected_thread:
return inferior return inferior
def source_gdb_script(script_contents, to_string=False): def source_gdb_script(script_contents, to_string=False):
""" """
Source a gdb script with script_contents passed as a string. This is useful Source a gdb script with script_contents passed as a string. This is useful
...@@ -1894,6 +1926,7 @@ def source_gdb_script(script_contents, to_string=False): ...@@ -1894,6 +1926,7 @@ def source_gdb_script(script_contents, to_string=False):
gdb.execute("source %s" % filename, to_string=to_string) gdb.execute("source %s" % filename, to_string=to_string)
os.remove(filename) os.remove(filename)
def register_defines(): def register_defines():
source_gdb_script(textwrap.dedent("""\ source_gdb_script(textwrap.dedent("""\
define py-step define py-step
...@@ -1923,6 +1956,7 @@ def stackdepth(frame): ...@@ -1923,6 +1956,7 @@ def stackdepth(frame):
return depth return depth
class ExecutionControlCommandBase(gdb.Command): class ExecutionControlCommandBase(gdb.Command):
""" """
Superclass for language specific execution control. Language specific Superclass for language specific execution control. Language specific
...@@ -1983,7 +2017,6 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1983,7 +2017,6 @@ class ExecutionControlCommandBase(gdb.Command):
return (filter_output(output_on_halt), return (filter_output(output_on_halt),
finish_output + filter_output(output_always)) finish_output + filter_output(output_always))
def stopped(self): def stopped(self):
return get_selected_inferior().pid == 0 return get_selected_inferior().pid == 0
...@@ -1996,22 +2029,22 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1996,22 +2029,22 @@ class ExecutionControlCommandBase(gdb.Command):
output_on_halt, output_always = self.filter_output(result) output_on_halt, output_always = self.filter_output(result)
if self.stopped(): if self.stopped():
print output_always print(output_always)
print output_on_halt print(output_on_halt)
else: else:
frame = gdb.selected_frame() frame = gdb.selected_frame()
source_line = self.lang_info.get_source_line(frame) source_line = self.lang_info.get_source_line(frame)
if self.lang_info.is_relevant_function(frame): if self.lang_info.is_relevant_function(frame):
raised_exception = self.lang_info.exc_info(frame) raised_exception = self.lang_info.exc_info(frame)
if raised_exception: if raised_exception:
print raised_exception print(raised_exception)
if source_line: if source_line:
if output_always.rstrip(): if output_always.rstrip():
print output_always.rstrip() print(output_always.rstrip())
print source_line print(source_line)
else: else:
print result print(result)
def _finish(self): def _finish(self):
""" """
...@@ -2181,6 +2214,7 @@ class LanguageInfo(object): ...@@ -2181,6 +2214,7 @@ class LanguageInfo(object):
""" """
return () return ()
class PythonInfo(LanguageInfo): class PythonInfo(LanguageInfo):
def pyframe(self, frame): def pyframe(self, frame):
...@@ -2203,7 +2237,7 @@ class PythonInfo(LanguageInfo): ...@@ -2203,7 +2237,7 @@ class PythonInfo(LanguageInfo):
pyframe = self.pyframe(frame) pyframe = self.pyframe(frame)
return '%4d %s' % (pyframe.current_line_num(), return '%4d %s' % (pyframe.current_line_num(),
pyframe.current_line().rstrip()) pyframe.current_line().rstrip())
except IOError, e: except IOError:
return None return None
def exc_info(self, frame): def exc_info(self, frame):
...@@ -2216,7 +2250,7 @@ class PythonInfo(LanguageInfo): ...@@ -2216,7 +2250,7 @@ class PythonInfo(LanguageInfo):
if inf_type: if inf_type:
return 'An exception was raised: %s' % (inf_value,) return 'An exception was raised: %s' % (inf_value,)
except (ValueError, RuntimeError), e: except (ValueError, RuntimeError):
# Could not read the variable tstate or it's memory, it's ok # Could not read the variable tstate or it's memory, it's ok
pass pass
...@@ -2249,21 +2283,25 @@ class PyStep(ExecutionControlCommandBase, PythonStepperMixin): ...@@ -2249,21 +2283,25 @@ class PyStep(ExecutionControlCommandBase, PythonStepperMixin):
def invoke(self, args, from_tty): def invoke(self, args, from_tty):
self.python_step(stepinto=self.stepinto) self.python_step(stepinto=self.stepinto)
class PyNext(PyStep): class PyNext(PyStep):
"Step-over Python code." "Step-over Python code."
stepinto = False stepinto = False
class PyFinish(ExecutionControlCommandBase): class PyFinish(ExecutionControlCommandBase):
"Execute until function returns to a caller." "Execute until function returns to a caller."
invoke = ExecutionControlCommandBase.finish invoke = ExecutionControlCommandBase.finish
class PyRun(ExecutionControlCommandBase): class PyRun(ExecutionControlCommandBase):
"Run the program." "Run the program."
invoke = ExecutionControlCommandBase.run invoke = ExecutionControlCommandBase.run
class PyCont(ExecutionControlCommandBase): class PyCont(ExecutionControlCommandBase):
invoke = ExecutionControlCommandBase.cont invoke = ExecutionControlCommandBase.cont
...@@ -2283,6 +2321,7 @@ def _pointervalue(gdbval): ...@@ -2283,6 +2321,7 @@ def _pointervalue(gdbval):
# still convert the pointer to an int # still convert the pointer to an int
return long(gdbval) return long(gdbval)
def pointervalue(gdbval): def pointervalue(gdbval):
pointer = _pointervalue(gdbval) pointer = _pointervalue(gdbval)
try: try:
...@@ -2296,6 +2335,7 @@ def pointervalue(gdbval): ...@@ -2296,6 +2335,7 @@ def pointervalue(gdbval):
return pointer return pointer
def get_inferior_unicode_postfix(): def get_inferior_unicode_postfix():
try: try:
gdb.parse_and_eval('PyUnicode_FromEncodedObject') gdb.parse_and_eval('PyUnicode_FromEncodedObject')
...@@ -2309,6 +2349,7 @@ def get_inferior_unicode_postfix(): ...@@ -2309,6 +2349,7 @@ def get_inferior_unicode_postfix():
else: else:
return '' return ''
class PythonCodeExecutor(object): class PythonCodeExecutor(object):
Py_single_input = 256 Py_single_input = 256
...@@ -2408,6 +2449,7 @@ class PythonCodeExecutor(object): ...@@ -2408,6 +2449,7 @@ class PythonCodeExecutor(object):
return pyobject_return_value return pyobject_return_value
class FetchAndRestoreError(PythonCodeExecutor): class FetchAndRestoreError(PythonCodeExecutor):
""" """
Context manager that fetches the error indicator in the inferior and Context manager that fetches the error indicator in the inferior and
...@@ -2478,7 +2520,7 @@ class FixGdbCommand(gdb.Command): ...@@ -2478,7 +2520,7 @@ class FixGdbCommand(gdb.Command):
self.fix_gdb() self.fix_gdb()
try: try:
gdb.execute('%s %s' % (self.actual_command, args)) gdb.execute('%s %s' % (self.actual_command, args))
except RuntimeError, e: except RuntimeError as e:
raise gdb.GdbError(str(e)) raise gdb.GdbError(str(e))
self.fix_gdb() self.fix_gdb()
...@@ -2497,6 +2539,7 @@ def _evalcode_python(executor, code, input_type): ...@@ -2497,6 +2539,7 @@ def _evalcode_python(executor, code, input_type):
return executor.evalcode(code, input_type, global_dict, local_dict) return executor.evalcode(code, input_type, global_dict, local_dict)
class PyExec(gdb.Command): class PyExec(gdb.Command):
def readcode(self, expr): def readcode(self, expr):
...@@ -2520,8 +2563,7 @@ class PyExec(gdb.Command): ...@@ -2520,8 +2563,7 @@ class PyExec(gdb.Command):
def invoke(self, expr, from_tty): def invoke(self, expr, from_tty):
expr, input_type = self.readcode(expr) expr, input_type = self.readcode(expr)
executor = PythonCodeExecutor() executor = PythonCodeExecutor()
executor.xdecref(_evalcode_python(executor, input_type, global_dict, executor.xdecref(_evalcode_python(executor, input_type, global_dict, local_dict))
local_dict))
gdb.execute('set breakpoint pending on') gdb.execute('set breakpoint pending on')
......
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