2 GDB extension that adds Cython support.
5 from __future__ import with_statement
19 from lxml import etree
25 from xml.etree import cElementTree as etree
29 from xml.etree import ElementTree as etree
32 # normal cElementTree install
33 import cElementTree as etree
35 # normal ElementTree install
36 import elementtree.ElementTree as etree
39 import pygments.lexers
40 import pygments.formatters
43 sys.stderr.write("Install pygments for colorized source code.\n")
45 if hasattr(gdb, 'string_to_argv'):
46 from gdb import string_to_argv
48 from shlex import split as string_to_argv
50 from Cython.Debugger import libpython
54 PythonObject = 'PythonObject'
56 _data_types = dict(CObject=CObject, PythonObject=PythonObject)
57 _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
61 def dont_suppress_errors(function):
63 @functools.wraps(function)
64 def wrapper(*args, **kwargs):
66 return function(*args, **kwargs)
73 def default_selected_gdb_frame(err=True):
74 def decorator(function):
75 @functools.wraps(function)
76 def wrapper(self, frame=None, *args, **kwargs):
78 frame = frame or gdb.selected_frame()
80 raise gdb.GdbError("No frame is currently selected.")
82 if err and frame.name() is None:
83 raise NoFunctionNameInFrameError()
85 return function(self, frame, *args, **kwargs)
89 def require_cython_frame(function):
90 @functools.wraps(function)
91 @require_running_program
92 def wrapper(self, *args, **kwargs):
93 frame = kwargs.get('frame') or gdb.selected_frame()
94 if not self.is_cython_function(frame):
95 raise gdb.GdbError('Selected frame does not correspond with a '
96 'Cython function we know about.')
97 return function(self, *args, **kwargs)
100 def dispatch_on_frame(c_command, python_command=None):
101 def decorator(function):
102 @functools.wraps(function)
103 def wrapper(self, *args, **kwargs):
104 is_cy = self.is_cython_function()
105 is_py = self.is_python_function()
107 if is_cy or (is_py and not python_command):
108 function(self, *args, **kwargs)
110 gdb.execute(python_command)
111 elif self.is_relevant_function():
112 gdb.execute(c_command)
114 raise gdb.GdbError("Not a function cygdb knows about. "
115 "Use the normal GDB commands instead.")
120 def require_running_program(function):
121 @functools.wraps(function)
122 def wrapper(*args, **kwargs):
126 raise gdb.GdbError("No frame is currently selected.")
128 return function(*args, **kwargs)
132 def gdb_function_value_to_unicode(function):
133 @functools.wraps(function)
134 def wrapper(self, string, *args, **kwargs):
135 if isinstance(string, gdb.Value):
136 string = string.string()
138 return function(self, string, *args, **kwargs)
142 # Classes that represent the debug information
143 # Don't rename the parameters of these classes, they come directly from the XML
145 class CythonModule(object):
146 def __init__(self, module_name, filename, c_filename):
147 self.name = module_name
148 self.filename = filename
149 self.c_filename = c_filename
151 # {cython_lineno: min(c_linenos)}
152 self.lineno_cy2c = {}
153 # {c_lineno: cython_lineno}
154 self.lineno_c2cy = {}
157 class CythonVariable(object):
159 def __init__(self, name, cname, qualified_name, type, lineno):
162 self.qualified_name = qualified_name
164 self.lineno = int(lineno)
166 class CythonFunction(CythonVariable):
175 is_initmodule_function="False"):
176 super(CythonFunction, self).__init__(name,
182 self.pf_cname = pf_cname
183 self.is_initmodule_function = is_initmodule_function == "True"
186 self.step_into_functions = set()
189 # General purpose classes
191 class CythonBase(object):
193 @default_selected_gdb_frame(err=False)
194 def is_cython_function(self, frame):
195 return frame.name() in self.cy.functions_by_cname
197 @default_selected_gdb_frame(err=False)
198 def is_python_function(self, frame):
200 Tells if a frame is associated with a Python function.
201 If we can't read the Python frame information, don't regard it as such.
203 if frame.name() == 'PyEval_EvalFrameEx':
204 pyframe = libpython.Frame(frame).get_pyop()
205 return pyframe and not pyframe.is_optimized_out()
208 @default_selected_gdb_frame()
209 def get_c_function_name(self, frame):
212 @default_selected_gdb_frame()
213 def get_c_lineno(self, frame):
214 return frame.find_sal().line
216 @default_selected_gdb_frame()
217 def get_cython_function(self, frame):
218 result = self.cy.functions_by_cname.get(frame.name())
220 raise NoCythonFunctionInFrameError()
224 @default_selected_gdb_frame()
225 def get_cython_lineno(self, frame):
227 Get the current Cython line number. Returns 0 if there is no
228 correspondence between the C and Cython code.
230 cyfunc = self.get_cython_function(frame)
231 return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0)
233 @default_selected_gdb_frame()
234 def get_source_desc(self, frame):
235 filename = lineno = lexer = None
236 if self.is_cython_function(frame):
237 filename = self.get_cython_function(frame).module.filename
238 lineno = self.get_cython_lineno(frame)
240 lexer = pygments.lexers.CythonLexer(stripall=False)
241 elif self.is_python_function(frame):
242 pyframeobject = libpython.Frame(frame).get_pyop()
244 if not pyframeobject:
246 'Unable to read information on python frame')
248 filename = pyframeobject.filename()
249 lineno = pyframeobject.current_line_num()
252 lexer = pygments.lexers.PythonLexer(stripall=False)
254 symbol_and_line_obj = frame.find_sal()
255 if not symbol_and_line_obj or not symbol_and_line_obj.symtab:
259 filename = symbol_and_line_obj.symtab.fullname()
260 lineno = symbol_and_line_obj.line
262 lexer = pygments.lexers.CLexer(stripall=False)
264 return SourceFileDescriptor(filename, lexer), lineno
266 @default_selected_gdb_frame()
267 def get_source_line(self, frame):
268 source_desc, lineno = self.get_source_desc()
269 return source_desc.get_source(lineno)
271 @default_selected_gdb_frame()
272 def is_relevant_function(self, frame):
274 returns whether we care about a frame on the user-level when debugging
278 older_frame = frame.older()
279 if self.is_cython_function(frame) or self.is_python_function(frame):
281 elif older_frame and self.is_cython_function(older_frame):
282 # direct C function call from a Cython function
283 cython_func = self.get_cython_function(older_frame)
284 return name in cython_func.step_into_functions
288 @default_selected_gdb_frame(err=False)
289 def print_stackframe(self, frame, index, is_c=False):
291 Print a C, Cython or Python stack frame and the line of source code
294 # do this to prevent the require_cython_frame decorator from
295 # raising GdbError when calling self.cy.cy_cvalue.invoke()
296 selected_frame = gdb.selected_frame()
300 source_desc, lineno = self.get_source_desc(frame)
301 except NoFunctionNameInFrameError:
302 print '#%-2d Unknown Frame (compile with -g)' % index
305 if not is_c and self.is_python_function(frame):
306 pyframe = libpython.Frame(frame).get_pyop()
307 if pyframe is None or pyframe.is_optimized_out():
308 # print this python function as a C function
309 return self.print_stackframe(frame, index, is_c=True)
311 func_name = pyframe.co_name
312 func_cname = 'PyEval_EvalFrameEx'
314 elif self.is_cython_function(frame):
315 cyfunc = self.get_cython_function(frame)
316 f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame)
318 func_name = cyfunc.name
319 func_cname = cyfunc.cname
320 func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments]
322 source_desc, lineno = self.get_source_desc(frame)
323 func_name = frame.name()
324 func_cname = func_name
328 gdb_value = gdb.parse_and_eval(func_cname)
332 # Seriously? Why is the address not an int?
333 func_address = int(str(gdb_value.address).split()[0], 0)
335 a = ', '.join('%s=%s' % (name, val) for name, val in func_args)
336 print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a),
338 if source_desc.filename is not None:
339 print 'at %s:%s' % (source_desc.filename, lineno),
344 print ' ' + source_desc.get_source(lineno)
348 selected_frame.select()
350 def get_remote_cython_globals_dict(self):
351 m = gdb.parse_and_eval('__pyx_m')
354 PyModuleObject = gdb.lookup_type('PyModuleObject')
356 raise gdb.GdbError(textwrap.dedent("""\
357 Unable to lookup type PyModuleObject, did you compile python
358 with debugging support (-g)?"""))
360 m = m.cast(PyModuleObject.pointer())
364 def get_cython_globals_dict(self):
366 Get the Cython globals dict where the remote names are turned into
369 remote_dict = self.get_remote_cython_globals_dict()
370 pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict)
374 for k, v in pyobject_dict.iteritems():
375 result[k.proxyval(seen)] = v
379 def print_gdb_value(self, name, value, max_name_length=None, prefix=''):
380 if libpython.pretty_printer_lookup(value):
383 typename = '(%s) ' % (value.type,)
385 if max_name_length is None:
386 print '%s%s = %s%s' % (prefix, name, typename, value)
388 print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename,
391 def is_initialized(self, cython_func, local_name):
392 islocal = local_name in cython_func.locals
394 cyvar = cython_func.locals[local_name]
395 if '->' in cyvar.cname:
396 # Closed over free variable
398 gdb.parse_and_eval(cyvar.cname)
403 cur_lineno = self.get_cython_lineno()
404 return (local_name in cython_func.arguments or
405 (islocal and cur_lineno > cyvar.lineno))
407 class SourceFileDescriptor(object):
408 def __init__(self, filename, lexer, formatter=None):
409 self.filename = filename
411 self.formatter = formatter
414 return self.filename is not None
417 if pygments and self.lexer and parameters.colorize_code:
418 bg = parameters.terminal_background.value
419 if self.formatter is None:
420 formatter = pygments.formatters.TerminalFormatter(bg=bg)
422 formatter = self.formatter
424 return pygments.highlight(code, self.lexer, formatter)
428 def _get_source(self, start, stop, lex_source, mark_line, lex_entire):
429 with open(self.filename) as f:
430 # to provide "correct" colouring, the entire code needs to be
431 # lexed. However, this makes a lot of things terribly slow, so
432 # we decide not to. Besides, it's unlikely to matter.
434 if lex_source and lex_entire:
435 f = self.lex(f.read()).splitlines()
437 slice = itertools.islice(f, start - 1, stop - 1)
439 for idx, line in enumerate(slice):
440 if start + idx == mark_line:
445 if lex_source and not lex_entire:
446 line = self.lex(line)
448 yield '%s %4d %s' % (prefix, start + idx, line.rstrip())
450 def get_source(self, start, stop=None, lex_source=True, mark_line=0,
452 exc = gdb.GdbError('Unable to retrieve source code')
454 if not self.filename:
457 start = max(start, 1)
463 self._get_source(start, stop, lex_source, mark_line, lex_entire))
470 class CyGDBError(gdb.GdbError):
472 Base class for Cython-command related erorrs
475 def __init__(self, *args):
476 args = args or (self.msg,)
477 super(CyGDBError, self).__init__(*args)
479 class NoCythonFunctionInFrameError(CyGDBError):
481 raised when the user requests the current cython function, which is
484 msg = "Current function is a function cygdb doesn't know about"
486 class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
488 raised when the name of the C function could not be determined
489 in the current C stack frame
491 msg = ('C function name could not be determined in the current C stack '
497 class CythonParameter(gdb.Parameter):
499 Base class for cython parameters
502 def __init__(self, name, command_class, parameter_class, default=None):
503 self.show_doc = self.set_doc = self.__class__.__doc__
504 super(CythonParameter, self).__init__(name, command_class,
506 if default is not None:
509 def __nonzero__(self):
510 return bool(self.value)
512 __bool__ = __nonzero__ # python 3
514 class CompleteUnqualifiedFunctionNames(CythonParameter):
516 Have 'cy break' complete unqualified function or method names.
519 class ColorizeSourceCode(CythonParameter):
521 Tell cygdb whether to colorize source code.
524 class TerminalBackground(CythonParameter):
526 Tell cygdb about the user's terminal background (light or dark).
529 class CythonParameters(object):
531 Simple container class that might get more functionality in the distant
532 future (mostly to remind us that we're dealing with parameters).
536 self.complete_unqualified = CompleteUnqualifiedFunctionNames(
537 'cy_complete_unqualified',
538 gdb.COMMAND_BREAKPOINTS,
541 self.colorize_code = ColorizeSourceCode(
546 self.terminal_background = TerminalBackground(
547 'cy_terminal_background_color',
552 parameters = CythonParameters()
557 class CythonCommand(gdb.Command, CythonBase):
559 Base class for Cython commands
562 command_class = gdb.COMMAND_NONE
565 def _register(cls, clsname, args, kwargs):
566 if not hasattr(cls, 'completer_class'):
567 return cls(clsname, cls.command_class, *args, **kwargs)
569 return cls(clsname, cls.command_class, cls.completer_class,
573 def register(cls, *args, **kwargs):
574 alias = getattr(cls, 'alias', None)
576 cls._register(cls.alias, args, kwargs)
578 return cls._register(cls.name, args, kwargs)
581 class CyCy(CythonCommand):
583 Invoke a Cython command. Available commands are:
604 command_class = gdb.COMMAND_NONE
605 completer_class = gdb.COMPLETE_COMMAND
607 def __init__(self, name, command_class, completer_class):
608 # keep the signature 2.5 compatible (i.e. do not use f(*a, k=v)
609 super(CythonCommand, self).__init__(name, command_class,
610 completer_class, prefix=True)
613 import_ = CyImport.register(),
614 break_ = CyBreak.register(),
615 step = CyStep.register(),
616 next = CyNext.register(),
617 run = CyRun.register(),
618 cont = CyCont.register(),
619 finish = CyFinish.register(),
620 up = CyUp.register(),
621 down = CyDown.register(),
622 select = CySelect.register(),
623 bt = CyBacktrace.register(),
624 list = CyList.register(),
625 print_ = CyPrint.register(),
626 locals = CyLocals.register(),
627 globals = CyGlobals.register(),
628 exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'),
629 _exec = CyExec.register(),
630 cy_cname = CyCName('cy_cname'),
631 cy_cvalue = CyCValue('cy_cvalue'),
632 cy_lineno = CyLine('cy_lineno'),
635 for command_name, command in commands.iteritems():
637 setattr(self, command_name, command)
641 # Cython module namespace
642 self.cython_namespace = {}
644 # maps (unique) qualified function names (e.g.
645 # cythonmodule.ClassName.method_name) to the CythonFunction object
646 self.functions_by_qualified_name = {}
648 # unique cnames of Cython functions
649 self.functions_by_cname = {}
651 # map function names like method_name to a list of all such
652 # CythonFunction objects
653 self.functions_by_name = collections.defaultdict(list)
656 class CyImport(CythonCommand):
658 Import debug information outputted by the Cython compiler
659 Example: cy import FILE...
663 command_class = gdb.COMMAND_STATUS
664 completer_class = gdb.COMPLETE_FILENAME
666 def invoke(self, args, from_tty):
667 args = args.encode(_filesystemencoding)
668 for arg in string_to_argv(args):
672 raise gdb.GdbError('Unable to open file %r: %s' %
677 for module in t.getroot():
678 cython_module = CythonModule(**module.attrib)
679 self.cy.cython_namespace[cython_module.name] = cython_module
681 for variable in module.find('Globals'):
683 cython_module.globals[d['name']] = CythonVariable(**d)
685 for function in module.find('Functions'):
686 cython_function = CythonFunction(module=cython_module,
689 # update the global function mappings
690 name = cython_function.name
691 qname = cython_function.qualified_name
693 self.cy.functions_by_name[name].append(cython_function)
694 self.cy.functions_by_qualified_name[
695 cython_function.qualified_name] = cython_function
696 self.cy.functions_by_cname[
697 cython_function.cname] = cython_function
699 d = cython_module.functions[qname] = cython_function
701 for local in function.find('Locals'):
703 cython_function.locals[d['name']] = CythonVariable(**d)
705 for step_into_func in function.find('StepIntoFunctions'):
706 d = step_into_func.attrib
707 cython_function.step_into_functions.add(d['name'])
709 cython_function.arguments.extend(
710 funcarg.tag for funcarg in function.find('Arguments'))
712 for marker in module.find('LineNumberMapping'):
713 cython_lineno = int(marker.attrib['cython_lineno'])
714 c_linenos = map(int, marker.attrib['c_linenos'].split())
715 cython_module.lineno_cy2c[cython_lineno] = min(c_linenos)
716 for c_lineno in c_linenos:
717 cython_module.lineno_c2cy[c_lineno] = cython_lineno
720 class CyBreak(CythonCommand):
722 Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
724 cy break cython_modulename.ClassName.method_name...
728 cy break function_or_method_name...
730 or for a line number:
732 cy break cython_module:lineno...
734 Set a Python breakpoint:
735 Break on any function or method named 'func' in module 'modname'
737 cy break -p modname.func...
739 Break on any function or method named 'func'
745 command_class = gdb.COMMAND_BREAKPOINTS
747 def _break_pyx(self, name):
748 modulename, _, lineno = name.partition(':')
751 cython_module = self.cy.cython_namespace[modulename]
753 cython_module = self.get_cython_function().module
755 if lineno in cython_module.lineno_cy2c:
756 c_lineno = cython_module.lineno_cy2c[lineno]
757 breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno)
758 gdb.execute('break ' + breakpoint)
760 raise GdbError("Not a valid line number. "
761 "Does it contain actual code?")
763 def _break_funcname(self, funcname):
764 func = self.cy.functions_by_qualified_name.get(funcname)
766 if func and func.is_initmodule_function:
772 funcs = self.cy.functions_by_name.get(funcname) or []
773 funcs = [f for f in funcs if not f.is_initmodule_function]
776 gdb.execute('break ' + funcname)
780 # multiple functions, let the user pick one
781 print 'There are multiple such functions:'
782 for idx, func in enumerate(funcs):
783 print '%3d) %s' % (idx, func.qualified_name)
788 "Select a function, press 'a' for all "
789 "functions or press 'q' or '^D' to quit: ")
793 if result.lower() == 'q':
795 elif result.lower() == 'a':
798 elif (result.isdigit() and
799 0 <= int(result) < len(funcs)):
800 break_funcs = [funcs[int(result)]]
803 print 'Not understood...'
805 break_funcs = [funcs[0]]
807 for func in break_funcs:
808 gdb.execute('break %s' % func.cname)
810 gdb.execute('break %s' % func.pf_cname)
812 def invoke(self, function_names, from_tty):
813 argv = string_to_argv(function_names.encode('UTF-8'))
814 if function_names.startswith('-p'):
816 python_breakpoints = True
818 python_breakpoints = False
820 for funcname in argv:
821 if python_breakpoints:
822 gdb.execute('py-break %s' % funcname)
823 elif ':' in funcname:
824 self._break_pyx(funcname)
826 self._break_funcname(funcname)
828 @dont_suppress_errors
829 def complete(self, text, word):
830 # Filter init-module functions (breakpoints can be set using
831 # modulename:linenumber).
832 names = [n for n, L in self.cy.functions_by_name.iteritems()
833 if any(not f.is_initmodule_function for f in L)]
834 qnames = [n for n, f in self.cy.functions_by_qualified_name.iteritems()
835 if not f.is_initmodule_function]
837 if parameters.complete_unqualified:
838 all_names = itertools.chain(qnames, names)
842 words = text.strip().split()
843 if not words or '.' not in words[-1]:
844 # complete unqualified
845 seen = set(text[:-len(word)].split())
846 return [n for n in all_names
847 if n.startswith(word) and n not in seen]
849 # complete qualified name
851 compl = [n for n in qnames if n.startswith(lastword)]
853 if len(lastword) > len(word):
854 # readline sees something (e.g. a '.') as a word boundary, so don't
855 # "recomplete" this prefix
856 strip_prefix_length = len(lastword) - len(word)
857 compl = [n[strip_prefix_length:] for n in compl]
862 class CythonInfo(CythonBase, libpython.PythonInfo):
864 Implementation of the interface dictated by libpython.LanguageInfo.
867 def lineno(self, frame):
868 # Take care of the Python and Cython levels. We need to care for both
869 # as we can't simply dispath to 'py-step', since that would work for
870 # stepping through Python code, but it would not step back into Cython-
871 # related code. The C level should be dispatched to the 'step' command.
872 if self.is_cython_function(frame):
873 return self.get_cython_lineno(frame)
874 return super(CythonInfo, self).lineno(frame)
876 def get_source_line(self, frame):
878 line = super(CythonInfo, self).get_source_line(frame)
882 return line.strip() or None
884 def exc_info(self, frame):
885 if self.is_python_function:
886 return super(CythonInfo, self).exc_info(frame)
888 def runtime_break_functions(self):
889 if self.is_cython_function():
890 return self.get_cython_function().step_into_functions
893 def static_break_functions(self):
894 result = ['PyEval_EvalFrameEx']
895 result.extend(self.cy.functions_by_cname)
899 class CythonExecutionControlCommand(CythonCommand,
900 libpython.ExecutionControlCommandBase):
904 return cls(cls.name, cython_info)
907 class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
908 "Step through Cython, Python or C code."
913 def invoke(self, args, from_tty):
914 if self.is_python_function():
915 self.python_step(self.stepinto)
916 elif not self.is_cython_function():
922 self.finish_executing(gdb.execute(command, to_string=True))
924 self.step(stepinto=self.stepinto)
927 class CyNext(CyStep):
928 "Step-over Cython, Python or C code."
934 class CyRun(CythonExecutionControlCommand):
936 Run a Cython program. This is like the 'run' command, except that it
937 displays Cython or Python source lines as well
942 invoke = CythonExecutionControlCommand.run
945 class CyCont(CythonExecutionControlCommand):
947 Continue a Cython program. This is like the 'run' command, except that it
948 displays Cython or Python source lines as well.
952 invoke = CythonExecutionControlCommand.cont
955 class CyFinish(CythonExecutionControlCommand):
957 Execute until the function returns.
961 invoke = CythonExecutionControlCommand.finish
964 class CyUp(CythonCommand):
966 Go up a Cython, Python or relevant C frame.
971 def invoke(self, *args):
973 gdb.execute(self._command, to_string=True)
974 while not self.is_relevant_function(gdb.selected_frame()):
975 gdb.execute(self._command, to_string=True)
976 except RuntimeError, e:
977 raise gdb.GdbError(*e.args)
979 frame = gdb.selected_frame()
982 frame = frame.older()
985 self.print_stackframe(index=index - 1)
990 Go down a Cython, Python or relevant C frame.
997 class CySelect(CythonCommand):
999 Select a frame. Use frame numbers as listed in `cy backtrace`.
1000 This command is useful because `cy backtrace` prints a reversed backtrace.
1005 def invoke(self, stackno, from_tty):
1007 stackno = int(stackno)
1009 raise gdb.GdbError("Not a valid number: %r" % (stackno,))
1011 frame = gdb.selected_frame()
1012 while frame.newer():
1013 frame = frame.newer()
1015 stackdepth = libpython.stackdepth(frame)
1018 gdb.execute('select %d' % (stackdepth - stackno - 1,))
1019 except RuntimeError, e:
1020 raise gdb.GdbError(*e.args)
1023 class CyBacktrace(CythonCommand):
1024 'Print the Cython stack'
1027 alias = 'cy backtrace'
1028 command_class = gdb.COMMAND_STACK
1029 completer_class = gdb.COMPLETE_NONE
1031 @require_running_program
1032 def invoke(self, args, from_tty):
1033 # get the first frame
1034 selected_frame = frame = gdb.selected_frame()
1035 while frame.older():
1036 frame = frame.older()
1038 print_all = args == '-a'
1046 is_relevant = self.is_relevant_function(frame)
1050 if print_all or is_relevant:
1051 self.print_stackframe(frame, index)
1054 frame = frame.newer()
1056 selected_frame.select()
1059 class CyList(CythonCommand):
1061 List Cython source code. To disable to customize colouring see the cy_*
1066 command_class = gdb.COMMAND_FILES
1067 completer_class = gdb.COMPLETE_NONE
1069 # @dispatch_on_frame(c_command='list')
1070 def invoke(self, _, from_tty):
1071 sd, lineno = self.get_source_desc()
1072 source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno,
1077 class CyPrint(CythonCommand):
1079 Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
1083 command_class = gdb.COMMAND_DATA
1085 def invoke(self, name, from_tty, max_name_length=None):
1086 if self.is_python_function():
1087 return gdb.execute('py-print ' + name)
1088 elif self.is_cython_function():
1089 value = self.cy.cy_cvalue.invoke(name.lstrip('*'))
1092 value = value.dereference()
1096 self.print_gdb_value(name, value, max_name_length)
1098 gdb.execute('print ' + name)
1101 if self.is_cython_function():
1102 f = self.get_cython_function()
1103 return list(itertools.chain(f.locals, f.globals))
1108 sortkey = lambda (name, value): name.lower()
1110 class CyLocals(CythonCommand):
1112 List the locals from the current Cython frame.
1116 command_class = gdb.COMMAND_STACK
1117 completer_class = gdb.COMPLETE_NONE
1119 @dispatch_on_frame(c_command='info locals', python_command='py-locals')
1120 def invoke(self, args, from_tty):
1121 cython_function = self.get_cython_function()
1123 if cython_function.is_initmodule_function:
1124 self.cy.globals.invoke(args, from_tty)
1127 local_cython_vars = cython_function.locals
1128 max_name_length = len(max(local_cython_vars, key=len))
1129 for name, cyvar in sorted(local_cython_vars.iteritems(), key=sortkey):
1130 if self.is_initialized(self.get_cython_function(), cyvar.name):
1131 value = gdb.parse_and_eval(cyvar.cname)
1132 if not value.is_optimized_out:
1133 self.print_gdb_value(cyvar.name, value,
1134 max_name_length, '')
1137 class CyGlobals(CyLocals):
1139 List the globals from the current Cython module.
1143 command_class = gdb.COMMAND_STACK
1144 completer_class = gdb.COMPLETE_NONE
1146 @dispatch_on_frame(c_command='info variables', python_command='py-globals')
1147 def invoke(self, args, from_tty):
1148 global_python_dict = self.get_cython_globals_dict()
1149 module_globals = self.get_cython_function().module.globals
1152 max_globals_dict_len = 0
1154 max_globals_len = len(max(module_globals, key=len))
1155 if global_python_dict:
1156 max_globals_dict_len = len(max(global_python_dict))
1158 max_name_length = max(max_globals_len, max_globals_dict_len)
1161 print 'Python globals:'
1162 for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
1163 v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
1165 print ' %-*s = %s' % (max_name_length, k, v)
1168 for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
1169 if name not in seen:
1171 value = gdb.parse_and_eval(cyvar.cname)
1172 except RuntimeError:
1175 if not value.is_optimized_out:
1176 self.print_gdb_value(cyvar.name, value,
1177 max_name_length, ' ')
1180 class CyExec(CythonCommand, libpython.PyExec):
1182 Execute Python code in the nearest Python or Cython frame.
1186 command_class = gdb.COMMAND_STACK
1187 completer_class = gdb.COMPLETE_NONE
1189 def _fill_locals_dict(self, executor, local_dict_pointer):
1190 "Fill a remotely allocated dict with values from the Cython C stack"
1191 cython_func = self.get_cython_function()
1192 current_lineno = self.get_cython_lineno()
1194 for name, cyvar in cython_func.locals.iteritems():
1195 if (cyvar.type == PythonObject and
1196 self.is_initialized(cython_func, name)):
1199 val = gdb.parse_and_eval(cyvar.cname)
1200 except RuntimeError:
1203 if val.is_optimized_out:
1206 pystringp = executor.alloc_pystring(name)
1208 (PyObject *) PyDict_SetItem(
1212 ''' % (local_dict_pointer, pystringp, cyvar.cname)
1215 if gdb.parse_and_eval(code) < 0:
1216 gdb.parse_and_eval('PyErr_Print()')
1217 raise gdb.GdbError("Unable to execute Python code.")
1219 # PyDict_SetItem doesn't steal our reference
1220 executor.decref(pystringp)
1222 def _find_first_cython_or_python_frame(self):
1223 frame = gdb.selected_frame()
1225 if (self.is_cython_function(frame) or
1226 self.is_python_function(frame)):
1229 frame = frame.older()
1231 raise gdb.GdbError("There is no Cython or Python frame on the stack.")
1233 def invoke(self, expr, from_tty):
1234 frame = self._find_first_cython_or_python_frame()
1235 if self.is_python_function(frame):
1236 libpython.py_exec.invoke(expr, from_tty)
1239 expr, input_type = self.readcode(expr)
1240 executor = libpython.PythonCodeExecutor()
1242 with libpython.FetchAndRestoreError():
1243 # get the dict of Cython globals and construct a dict in the
1244 # inferior with Cython locals
1245 global_dict = gdb.parse_and_eval(
1246 '(PyObject *) PyModule_GetDict(__pyx_m)')
1247 local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
1249 cython_function = self.get_cython_function()
1252 self._fill_locals_dict(executor,
1253 libpython.pointervalue(local_dict))
1254 executor.evalcode(expr, input_type, global_dict, local_dict)
1256 executor.decref(libpython.pointervalue(local_dict))
1261 class CyCName(gdb.Function, CythonBase):
1263 Get the C name of a Cython variable in the current context.
1266 print $cy_cname("function")
1267 print $cy_cname("Class.method")
1268 print $cy_cname("module.function")
1271 @require_cython_frame
1272 @gdb_function_value_to_unicode
1273 def invoke(self, cyname, frame=None):
1274 frame = frame or gdb.selected_frame()
1277 if self.is_cython_function(frame):
1278 cython_function = self.get_cython_function(frame)
1279 if cyname in cython_function.locals:
1280 cname = cython_function.locals[cyname].cname
1281 elif cyname in cython_function.module.globals:
1282 cname = cython_function.module.globals[cyname].cname
1284 qname = '%s.%s' % (cython_function.module.name, cyname)
1285 if qname in cython_function.module.functions:
1286 cname = cython_function.module.functions[qname].cname
1289 cname = self.cy.functions_by_qualified_name.get(cyname)
1292 raise gdb.GdbError('No such Cython variable: %s' % cyname)
1297 class CyCValue(CyCName):
1299 Get the value of a Cython variable.
1302 @require_cython_frame
1303 @gdb_function_value_to_unicode
1304 def invoke(self, cyname, frame=None):
1306 cname = super(CyCValue, self).invoke(cyname, frame=frame)
1307 return gdb.parse_and_eval(cname)
1308 except (gdb.GdbError, RuntimeError), e:
1309 # variable exists but may not have been initialized yet, or may be
1310 # in the globals dict of the Cython module
1311 d = self.get_cython_globals_dict()
1313 return d[cyname]._gdbval
1315 raise gdb.GdbError(str(e))
1318 class CyLine(gdb.Function, CythonBase):
1320 Get the current Cython line.
1323 @require_cython_frame
1325 return self.get_cython_lineno()
1327 cython_info = CythonInfo()
1328 cy = CyCy.register()
1331 def register_defines():
1332 libpython.source_gdb_script(textwrap.dedent("""\
1348 """) % (CyStep.__doc__, CyNext.__doc__))