diff options
Diffstat (limited to 'Cython/Debugger/libcython.py')
-rw-r--r-- | Cython/Debugger/libcython.py | 99 |
1 files changed, 63 insertions, 36 deletions
diff --git a/Cython/Debugger/libcython.py b/Cython/Debugger/libcython.py index 23153789b..dd634cc35 100644 --- a/Cython/Debugger/libcython.py +++ b/Cython/Debugger/libcython.py @@ -11,7 +11,6 @@ except NameError: import sys import textwrap -import traceback import functools import itertools import collections @@ -69,19 +68,6 @@ _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8' # decorators -def dont_suppress_errors(function): - "*sigh*, readline" - @functools.wraps(function) - def wrapper(*args, **kwargs): - try: - return function(*args, **kwargs) - except Exception: - traceback.print_exc() - raise - - return wrapper - - def default_selected_gdb_frame(err=True): def decorator(function): @functools.wraps(function) @@ -252,7 +238,9 @@ class CythonBase(object): filename = lineno = lexer = None if self.is_cython_function(frame): filename = self.get_cython_function(frame).module.filename - lineno = self.get_cython_lineno(frame) + filename_and_lineno = self.get_cython_lineno(frame) + assert filename == filename_and_lineno[0] + lineno = filename_and_lineno[1] if pygments: lexer = pygments.lexers.CythonLexer(stripall=False) elif self.is_python_function(frame): @@ -334,7 +322,7 @@ class CythonBase(object): func_name = cyfunc.name func_cname = cyfunc.cname - func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments] + func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments] else: source_desc, lineno = self.get_source_desc(frame) func_name = frame.name() @@ -392,7 +380,7 @@ class CythonBase(object): result = {} seen = set() - for k, v in pyobject_dict.items(): + for k, v in pyobject_dict.iteritems(): result[k.proxyval(seen)] = v return result @@ -410,7 +398,7 @@ class CythonBase(object): def is_initialized(self, cython_func, local_name): cyvar = cython_func.locals[local_name] - cur_lineno = self.get_cython_lineno() + cur_lineno = self.get_cython_lineno()[1] if '->' in cyvar.cname: # Closed over free variable @@ -695,6 +683,7 @@ class CyImport(CythonCommand): command_class = gdb.COMMAND_STATUS completer_class = gdb.COMPLETE_FILENAME + @libpython.dont_suppress_errors def invoke(self, args, from_tty): if isinstance(args, BYTES): args = args.decode(_filesystemencoding) @@ -742,11 +731,12 @@ class CyImport(CythonCommand): funcarg.tag for funcarg in function.find('Arguments')) for marker in module.find('LineNumberMapping'): - cython_lineno = int(marker.attrib['cython_lineno']) + src_lineno = int(marker.attrib['src_lineno']) + src_path = marker.attrib['src_path'] c_linenos = list(map(int, marker.attrib['c_linenos'].split())) - cython_module.lineno_cy2c[cython_lineno] = min(c_linenos) + cython_module.lineno_cy2c[src_path, src_lineno] = min(c_linenos) for c_lineno in c_linenos: - cython_module.lineno_c2cy[c_lineno] = cython_lineno + cython_module.lineno_c2cy[c_lineno] = (src_path, src_lineno) class CyBreak(CythonCommand): @@ -784,8 +774,8 @@ class CyBreak(CythonCommand): else: cython_module = self.get_cython_function().module - if lineno in cython_module.lineno_cy2c: - c_lineno = cython_module.lineno_cy2c[lineno] + if (cython_module.filename, lineno) in cython_module.lineno_cy2c: + c_lineno = cython_module.lineno_cy2c[cython_module.filename, lineno] breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno) gdb.execute('break ' + breakpoint) else: @@ -841,6 +831,7 @@ class CyBreak(CythonCommand): if func.pf_cname: gdb.execute('break %s' % func.pf_cname) + @libpython.dont_suppress_errors def invoke(self, function_names, from_tty): if isinstance(function_names, BYTES): function_names = function_names.decode(_filesystemencoding) @@ -859,7 +850,7 @@ class CyBreak(CythonCommand): else: self._break_funcname(funcname) - @dont_suppress_errors + @libpython.dont_suppress_errors def complete(self, text, word): # Filter init-module functions (breakpoints can be set using # modulename:linenumber). @@ -904,7 +895,7 @@ class CythonInfo(CythonBase, libpython.PythonInfo): # stepping through Python code, but it would not step back into Cython- # related code. The C level should be dispatched to the 'step' command. if self.is_cython_function(frame): - return self.get_cython_lineno(frame) + return self.get_cython_lineno(frame)[1] return super(CythonInfo, self).lineno(frame) def get_source_line(self, frame): @@ -944,6 +935,7 @@ class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin): name = 'cy -step' stepinto = True + @libpython.dont_suppress_errors def invoke(self, args, from_tty): if self.is_python_function(): self.python_step(self.stepinto) @@ -973,7 +965,7 @@ class CyRun(CythonExecutionControlCommand): name = 'cy run' - invoke = CythonExecutionControlCommand.run + invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.run) class CyCont(CythonExecutionControlCommand): @@ -983,7 +975,7 @@ class CyCont(CythonExecutionControlCommand): """ name = 'cy cont' - invoke = CythonExecutionControlCommand.cont + invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.cont) class CyFinish(CythonExecutionControlCommand): @@ -992,7 +984,7 @@ class CyFinish(CythonExecutionControlCommand): """ name = 'cy finish' - invoke = CythonExecutionControlCommand.finish + invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.finish) class CyUp(CythonCommand): @@ -1002,6 +994,7 @@ class CyUp(CythonCommand): name = 'cy up' _command = 'up' + @libpython.dont_suppress_errors def invoke(self, *args): try: gdb.execute(self._command, to_string=True) @@ -1036,6 +1029,7 @@ class CySelect(CythonCommand): name = 'cy select' + @libpython.dont_suppress_errors def invoke(self, stackno, from_tty): try: stackno = int(stackno) @@ -1062,6 +1056,7 @@ class CyBacktrace(CythonCommand): command_class = gdb.COMMAND_STACK completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors @require_running_program def invoke(self, args, from_tty): # get the first frame @@ -1095,6 +1090,7 @@ class CyList(CythonCommand): command_class = gdb.COMMAND_FILES completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors # @dispatch_on_frame(c_command='list') def invoke(self, _, from_tty): sd, lineno = self.get_source_desc() @@ -1111,8 +1107,28 @@ class CyPrint(CythonCommand): name = 'cy print' command_class = gdb.COMMAND_DATA - def invoke(self, name, from_tty, max_name_length=None): - if self.is_python_function(): + @libpython.dont_suppress_errors + def invoke(self, name, from_tty): + global_python_dict = self.get_cython_globals_dict() + module_globals = self.get_cython_function().module.globals + + if name in global_python_dict: + value = global_python_dict[name].get_truncated_repr(libpython.MAX_OUTPUT_LEN) + print('%s = %s' % (name, value)) + #This also would work, but beacause the output of cy exec is not captured in gdb.execute, TestPrint would fail + #self.cy.exec_.invoke("print('"+name+"','=', type(" + name + "), "+name+", flush=True )", from_tty) + elif name in module_globals: + cname = module_globals[name].cname + try: + value = gdb.parse_and_eval(cname) + except RuntimeError: + print("unable to get value of %s" % name) + else: + if not value.is_optimized_out: + self.print_gdb_value(name, value) + else: + print("%s is optimized out" % name) + elif self.is_python_function(): return gdb.execute('py-print ' + name) elif self.is_cython_function(): value = self.cy.cy_cvalue.invoke(name.lstrip('*')) @@ -1122,7 +1138,7 @@ class CyPrint(CythonCommand): else: break - self.print_gdb_value(name, value, max_name_length) + self.print_gdb_value(name, value) else: gdb.execute('print ' + name) @@ -1146,6 +1162,7 @@ class CyLocals(CythonCommand): command_class = gdb.COMMAND_STACK completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors @dispatch_on_frame(c_command='info locals', python_command='py-locals') def invoke(self, args, from_tty): cython_function = self.get_cython_function() @@ -1173,6 +1190,7 @@ class CyGlobals(CyLocals): command_class = gdb.COMMAND_STACK completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors @dispatch_on_frame(c_command='info variables', python_command='py-globals') def invoke(self, args, from_tty): global_python_dict = self.get_cython_globals_dict() @@ -1189,6 +1207,7 @@ class CyGlobals(CyLocals): seen = set() print('Python globals:') + for k, v in sorted(global_python_dict.items(), key=sortkey): v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN) seen.add(k) @@ -1219,7 +1238,9 @@ class EvaluateOrExecuteCodeMixin(object): cython_func = self.get_cython_function() for name, cyvar in cython_func.locals.items(): - if cyvar.type == PythonObject and self.is_initialized(cython_func, name): + if (cyvar.type == PythonObject + and self.is_initialized(cython_func, name)): + try: val = gdb.parse_and_eval(cyvar.cname) except RuntimeError: @@ -1247,8 +1268,8 @@ class EvaluateOrExecuteCodeMixin(object): def _find_first_cython_or_python_frame(self): frame = gdb.selected_frame() while frame: - if (self.is_cython_function(frame) or - self.is_python_function(frame)): + if (self.is_cython_function(frame) + or self.is_python_function(frame)): frame.select() return frame @@ -1295,10 +1316,11 @@ class CyExec(CythonCommand, libpython.PyExec, EvaluateOrExecuteCodeMixin): command_class = gdb.COMMAND_STACK completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors def invoke(self, expr, from_tty): expr, input_type = self.readcode(expr) executor = libpython.PythonCodeExecutor() - executor.xdecref(self.evalcode(expr, executor.Py_single_input)) + executor.xdecref(self.evalcode(expr, executor.Py_file_input)) class CySet(CythonCommand): @@ -1317,6 +1339,7 @@ class CySet(CythonCommand): command_class = gdb.COMMAND_DATA completer_class = gdb.COMPLETE_NONE + @libpython.dont_suppress_errors @require_cython_frame def invoke(self, expr, from_tty): name_and_expr = expr.split('=', 1) @@ -1340,6 +1363,7 @@ class CyCName(gdb.Function, CythonBase): print $cy_cname("module.function") """ + @libpython.dont_suppress_errors @require_cython_frame @gdb_function_value_to_unicode def invoke(self, cyname, frame=None): @@ -1371,6 +1395,7 @@ class CyCValue(CyCName): Get the value of a Cython variable. """ + @libpython.dont_suppress_errors @require_cython_frame @gdb_function_value_to_unicode def invoke(self, cyname, frame=None): @@ -1391,9 +1416,10 @@ class CyLine(gdb.Function, CythonBase): Get the current Cython line. """ + @libpython.dont_suppress_errors @require_cython_frame def invoke(self): - return self.get_cython_lineno() + return self.get_cython_lineno()[1] class CyEval(gdb.Function, CythonBase, EvaluateOrExecuteCodeMixin): @@ -1401,6 +1427,7 @@ class CyEval(gdb.Function, CythonBase, EvaluateOrExecuteCodeMixin): Evaluate Python code in the nearest Python or Cython frame and return """ + @libpython.dont_suppress_errors @gdb_function_value_to_unicode def invoke(self, python_expression): input_type = libpython.PythonCodeExecutor.Py_eval_input |