Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / cython / src / Cython / Debugger / libcython.py
bloba1d4221e4d5c2b8ab66065a5fac77b9618b8a361
1 """
2 GDB extension that adds Cython support.
3 """
5 from __future__ import with_statement
7 import sys
8 import textwrap
9 import traceback
10 import functools
11 import itertools
12 import collections
14 import gdb
16 try:
17 from lxml import etree
18 have_lxml = True
19 except ImportError:
20 have_lxml = False
21 try:
22 # Python 2.5
23 from xml.etree import cElementTree as etree
24 except ImportError:
25 try:
26 # Python 2.5
27 from xml.etree import ElementTree as etree
28 except ImportError:
29 try:
30 # normal cElementTree install
31 import cElementTree as etree
32 except ImportError:
33 # normal ElementTree install
34 import elementtree.ElementTree as etree
36 try:
37 import pygments.lexers
38 import pygments.formatters
39 except ImportError:
40 pygments = None
41 sys.stderr.write("Install pygments for colorized source code.\n")
43 if hasattr(gdb, 'string_to_argv'):
44 from gdb import string_to_argv
45 else:
46 from shlex import split as string_to_argv
48 from Cython.Debugger import libpython
50 # C or Python type
51 CObject = 'CObject'
52 PythonObject = 'PythonObject'
54 _data_types = dict(CObject=CObject, PythonObject=PythonObject)
55 _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
57 # decorators
59 def dont_suppress_errors(function):
60 "*sigh*, readline"
61 @functools.wraps(function)
62 def wrapper(*args, **kwargs):
63 try:
64 return function(*args, **kwargs)
65 except Exception:
66 traceback.print_exc()
67 raise
69 return wrapper
71 def default_selected_gdb_frame(err=True):
72 def decorator(function):
73 @functools.wraps(function)
74 def wrapper(self, frame=None, *args, **kwargs):
75 try:
76 frame = frame or gdb.selected_frame()
77 except RuntimeError:
78 raise gdb.GdbError("No frame is currently selected.")
80 if err and frame.name() is None:
81 raise NoFunctionNameInFrameError()
83 return function(self, frame, *args, **kwargs)
84 return wrapper
85 return decorator
87 def require_cython_frame(function):
88 @functools.wraps(function)
89 @require_running_program
90 def wrapper(self, *args, **kwargs):
91 frame = kwargs.get('frame') or gdb.selected_frame()
92 if not self.is_cython_function(frame):
93 raise gdb.GdbError('Selected frame does not correspond with a '
94 'Cython function we know about.')
95 return function(self, *args, **kwargs)
96 return wrapper
98 def dispatch_on_frame(c_command, python_command=None):
99 def decorator(function):
100 @functools.wraps(function)
101 def wrapper(self, *args, **kwargs):
102 is_cy = self.is_cython_function()
103 is_py = self.is_python_function()
105 if is_cy or (is_py and not python_command):
106 function(self, *args, **kwargs)
107 elif is_py:
108 gdb.execute(python_command)
109 elif self.is_relevant_function():
110 gdb.execute(c_command)
111 else:
112 raise gdb.GdbError("Not a function cygdb knows about. "
113 "Use the normal GDB commands instead.")
115 return wrapper
116 return decorator
118 def require_running_program(function):
119 @functools.wraps(function)
120 def wrapper(*args, **kwargs):
121 try:
122 gdb.selected_frame()
123 except RuntimeError:
124 raise gdb.GdbError("No frame is currently selected.")
126 return function(*args, **kwargs)
127 return wrapper
130 def gdb_function_value_to_unicode(function):
131 @functools.wraps(function)
132 def wrapper(self, string, *args, **kwargs):
133 if isinstance(string, gdb.Value):
134 string = string.string()
136 return function(self, string, *args, **kwargs)
137 return wrapper
140 # Classes that represent the debug information
141 # Don't rename the parameters of these classes, they come directly from the XML
143 class CythonModule(object):
144 def __init__(self, module_name, filename, c_filename):
145 self.name = module_name
146 self.filename = filename
147 self.c_filename = c_filename
148 self.globals = {}
149 # {cython_lineno: min(c_linenos)}
150 self.lineno_cy2c = {}
151 # {c_lineno: cython_lineno}
152 self.lineno_c2cy = {}
153 self.functions = {}
155 class CythonVariable(object):
157 def __init__(self, name, cname, qualified_name, type, lineno):
158 self.name = name
159 self.cname = cname
160 self.qualified_name = qualified_name
161 self.type = type
162 self.lineno = int(lineno)
164 class CythonFunction(CythonVariable):
165 def __init__(self,
166 module,
167 name,
168 cname,
169 pf_cname,
170 qualified_name,
171 lineno,
172 type=CObject,
173 is_initmodule_function="False"):
174 super(CythonFunction, self).__init__(name,
175 cname,
176 qualified_name,
177 type,
178 lineno)
179 self.module = module
180 self.pf_cname = pf_cname
181 self.is_initmodule_function = is_initmodule_function == "True"
182 self.locals = {}
183 self.arguments = []
184 self.step_into_functions = set()
187 # General purpose classes
189 class CythonBase(object):
191 @default_selected_gdb_frame(err=False)
192 def is_cython_function(self, frame):
193 return frame.name() in self.cy.functions_by_cname
195 @default_selected_gdb_frame(err=False)
196 def is_python_function(self, frame):
198 Tells if a frame is associated with a Python function.
199 If we can't read the Python frame information, don't regard it as such.
201 if frame.name() == 'PyEval_EvalFrameEx':
202 pyframe = libpython.Frame(frame).get_pyop()
203 return pyframe and not pyframe.is_optimized_out()
204 return False
206 @default_selected_gdb_frame()
207 def get_c_function_name(self, frame):
208 return frame.name()
210 @default_selected_gdb_frame()
211 def get_c_lineno(self, frame):
212 return frame.find_sal().line
214 @default_selected_gdb_frame()
215 def get_cython_function(self, frame):
216 result = self.cy.functions_by_cname.get(frame.name())
217 if result is None:
218 raise NoCythonFunctionInFrameError()
220 return result
222 @default_selected_gdb_frame()
223 def get_cython_lineno(self, frame):
225 Get the current Cython line number. Returns 0 if there is no
226 correspondence between the C and Cython code.
228 cyfunc = self.get_cython_function(frame)
229 return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0)
231 @default_selected_gdb_frame()
232 def get_source_desc(self, frame):
233 filename = lineno = lexer = None
234 if self.is_cython_function(frame):
235 filename = self.get_cython_function(frame).module.filename
236 lineno = self.get_cython_lineno(frame)
237 if pygments:
238 lexer = pygments.lexers.CythonLexer(stripall=False)
239 elif self.is_python_function(frame):
240 pyframeobject = libpython.Frame(frame).get_pyop()
242 if not pyframeobject:
243 raise gdb.GdbError(
244 'Unable to read information on python frame')
246 filename = pyframeobject.filename()
247 lineno = pyframeobject.current_line_num()
249 if pygments:
250 lexer = pygments.lexers.PythonLexer(stripall=False)
251 else:
252 symbol_and_line_obj = frame.find_sal()
253 if not symbol_and_line_obj or not symbol_and_line_obj.symtab:
254 filename = None
255 lineno = 0
256 else:
257 filename = symbol_and_line_obj.symtab.fullname()
258 lineno = symbol_and_line_obj.line
259 if pygments:
260 lexer = pygments.lexers.CLexer(stripall=False)
262 return SourceFileDescriptor(filename, lexer), lineno
264 @default_selected_gdb_frame()
265 def get_source_line(self, frame):
266 source_desc, lineno = self.get_source_desc()
267 return source_desc.get_source(lineno)
269 @default_selected_gdb_frame()
270 def is_relevant_function(self, frame):
272 returns whether we care about a frame on the user-level when debugging
273 Cython code
275 name = frame.name()
276 older_frame = frame.older()
277 if self.is_cython_function(frame) or self.is_python_function(frame):
278 return True
279 elif older_frame and self.is_cython_function(older_frame):
280 # check for direct C function call from a Cython function
281 cython_func = self.get_cython_function(older_frame)
282 return name in cython_func.step_into_functions
284 return False
286 @default_selected_gdb_frame(err=False)
287 def print_stackframe(self, frame, index, is_c=False):
289 Print a C, Cython or Python stack frame and the line of source code
290 if available.
292 # do this to prevent the require_cython_frame decorator from
293 # raising GdbError when calling self.cy.cy_cvalue.invoke()
294 selected_frame = gdb.selected_frame()
295 frame.select()
297 try:
298 source_desc, lineno = self.get_source_desc(frame)
299 except NoFunctionNameInFrameError:
300 print '#%-2d Unknown Frame (compile with -g)' % index
301 return
303 if not is_c and self.is_python_function(frame):
304 pyframe = libpython.Frame(frame).get_pyop()
305 if pyframe is None or pyframe.is_optimized_out():
306 # print this python function as a C function
307 return self.print_stackframe(frame, index, is_c=True)
309 func_name = pyframe.co_name
310 func_cname = 'PyEval_EvalFrameEx'
311 func_args = []
312 elif self.is_cython_function(frame):
313 cyfunc = self.get_cython_function(frame)
314 f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame)
316 func_name = cyfunc.name
317 func_cname = cyfunc.cname
318 func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments]
319 else:
320 source_desc, lineno = self.get_source_desc(frame)
321 func_name = frame.name()
322 func_cname = func_name
323 func_args = []
325 try:
326 gdb_value = gdb.parse_and_eval(func_cname)
327 except RuntimeError:
328 func_address = 0
329 else:
330 # Seriously? Why is the address not an int?
331 func_address = int(str(gdb_value.address).split()[0], 0)
333 a = ', '.join('%s=%s' % (name, val) for name, val in func_args)
334 print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a),
336 if source_desc.filename is not None:
337 print 'at %s:%s' % (source_desc.filename, lineno),
339 print
341 try:
342 print ' ' + source_desc.get_source(lineno)
343 except gdb.GdbError:
344 pass
346 selected_frame.select()
348 def get_remote_cython_globals_dict(self):
349 m = gdb.parse_and_eval('__pyx_m')
351 try:
352 PyModuleObject = gdb.lookup_type('PyModuleObject')
353 except RuntimeError:
354 raise gdb.GdbError(textwrap.dedent("""\
355 Unable to lookup type PyModuleObject, did you compile python
356 with debugging support (-g)?"""))
358 m = m.cast(PyModuleObject.pointer())
359 return m['md_dict']
362 def get_cython_globals_dict(self):
364 Get the Cython globals dict where the remote names are turned into
365 local strings.
367 remote_dict = self.get_remote_cython_globals_dict()
368 pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict)
370 result = {}
371 seen = set()
372 for k, v in pyobject_dict.iteritems():
373 result[k.proxyval(seen)] = v
375 return result
377 def print_gdb_value(self, name, value, max_name_length=None, prefix=''):
378 if libpython.pretty_printer_lookup(value):
379 typename = ''
380 else:
381 typename = '(%s) ' % (value.type,)
383 if max_name_length is None:
384 print '%s%s = %s%s' % (prefix, name, typename, value)
385 else:
386 print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename,
387 value)
389 def is_initialized(self, cython_func, local_name):
390 cyvar = cython_func.locals[local_name]
391 cur_lineno = self.get_cython_lineno()
393 if '->' in cyvar.cname:
394 # Closed over free variable
395 if cur_lineno > cython_func.lineno:
396 if cyvar.type == PythonObject:
397 return long(gdb.parse_and_eval(cyvar.cname))
398 return True
399 return False
401 return cur_lineno > cyvar.lineno
404 class SourceFileDescriptor(object):
405 def __init__(self, filename, lexer, formatter=None):
406 self.filename = filename
407 self.lexer = lexer
408 self.formatter = formatter
410 def valid(self):
411 return self.filename is not None
413 def lex(self, code):
414 if pygments and self.lexer and parameters.colorize_code:
415 bg = parameters.terminal_background.value
416 if self.formatter is None:
417 formatter = pygments.formatters.TerminalFormatter(bg=bg)
418 else:
419 formatter = self.formatter
421 return pygments.highlight(code, self.lexer, formatter)
423 return code
425 def _get_source(self, start, stop, lex_source, mark_line, lex_entire):
426 with open(self.filename) as f:
427 # to provide "correct" colouring, the entire code needs to be
428 # lexed. However, this makes a lot of things terribly slow, so
429 # we decide not to. Besides, it's unlikely to matter.
431 if lex_source and lex_entire:
432 f = self.lex(f.read()).splitlines()
434 slice = itertools.islice(f, start - 1, stop - 1)
436 for idx, line in enumerate(slice):
437 if start + idx == mark_line:
438 prefix = '>'
439 else:
440 prefix = ' '
442 if lex_source and not lex_entire:
443 line = self.lex(line)
445 yield '%s %4d %s' % (prefix, start + idx, line.rstrip())
447 def get_source(self, start, stop=None, lex_source=True, mark_line=0,
448 lex_entire=False):
449 exc = gdb.GdbError('Unable to retrieve source code')
451 if not self.filename:
452 raise exc
454 start = max(start, 1)
455 if stop is None:
456 stop = start + 1
458 try:
459 return '\n'.join(
460 self._get_source(start, stop, lex_source, mark_line, lex_entire))
461 except IOError:
462 raise exc
465 # Errors
467 class CyGDBError(gdb.GdbError):
469 Base class for Cython-command related erorrs
472 def __init__(self, *args):
473 args = args or (self.msg,)
474 super(CyGDBError, self).__init__(*args)
476 class NoCythonFunctionInFrameError(CyGDBError):
478 raised when the user requests the current cython function, which is
479 unavailable
481 msg = "Current function is a function cygdb doesn't know about"
483 class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
485 raised when the name of the C function could not be determined
486 in the current C stack frame
488 msg = ('C function name could not be determined in the current C stack '
489 'frame')
492 # Parameters
494 class CythonParameter(gdb.Parameter):
496 Base class for cython parameters
499 def __init__(self, name, command_class, parameter_class, default=None):
500 self.show_doc = self.set_doc = self.__class__.__doc__
501 super(CythonParameter, self).__init__(name, command_class,
502 parameter_class)
503 if default is not None:
504 self.value = default
506 def __nonzero__(self):
507 return bool(self.value)
509 __bool__ = __nonzero__ # python 3
511 class CompleteUnqualifiedFunctionNames(CythonParameter):
513 Have 'cy break' complete unqualified function or method names.
516 class ColorizeSourceCode(CythonParameter):
518 Tell cygdb whether to colorize source code.
521 class TerminalBackground(CythonParameter):
523 Tell cygdb about the user's terminal background (light or dark).
526 class CythonParameters(object):
528 Simple container class that might get more functionality in the distant
529 future (mostly to remind us that we're dealing with parameters).
532 def __init__(self):
533 self.complete_unqualified = CompleteUnqualifiedFunctionNames(
534 'cy_complete_unqualified',
535 gdb.COMMAND_BREAKPOINTS,
536 gdb.PARAM_BOOLEAN,
537 True)
538 self.colorize_code = ColorizeSourceCode(
539 'cy_colorize_code',
540 gdb.COMMAND_FILES,
541 gdb.PARAM_BOOLEAN,
542 True)
543 self.terminal_background = TerminalBackground(
544 'cy_terminal_background_color',
545 gdb.COMMAND_FILES,
546 gdb.PARAM_STRING,
547 "dark")
549 parameters = CythonParameters()
552 # Commands
554 class CythonCommand(gdb.Command, CythonBase):
556 Base class for Cython commands
559 command_class = gdb.COMMAND_NONE
561 @classmethod
562 def _register(cls, clsname, args, kwargs):
563 if not hasattr(cls, 'completer_class'):
564 return cls(clsname, cls.command_class, *args, **kwargs)
565 else:
566 return cls(clsname, cls.command_class, cls.completer_class,
567 *args, **kwargs)
569 @classmethod
570 def register(cls, *args, **kwargs):
571 alias = getattr(cls, 'alias', None)
572 if alias:
573 cls._register(cls.alias, args, kwargs)
575 return cls._register(cls.name, args, kwargs)
578 class CyCy(CythonCommand):
580 Invoke a Cython command. Available commands are:
582 cy import
583 cy break
584 cy step
585 cy next
586 cy run
587 cy cont
588 cy finish
589 cy up
590 cy down
591 cy select
592 cy bt / cy backtrace
593 cy list
594 cy print
595 cy set
596 cy locals
597 cy globals
598 cy exec
601 name = 'cy'
602 command_class = gdb.COMMAND_NONE
603 completer_class = gdb.COMPLETE_COMMAND
605 def __init__(self, name, command_class, completer_class):
606 # keep the signature 2.5 compatible (i.e. do not use f(*a, k=v)
607 super(CythonCommand, self).__init__(name, command_class,
608 completer_class, prefix=True)
610 commands = dict(
611 # GDB commands
612 import_ = CyImport.register(),
613 break_ = CyBreak.register(),
614 step = CyStep.register(),
615 next = CyNext.register(),
616 run = CyRun.register(),
617 cont = CyCont.register(),
618 finish = CyFinish.register(),
619 up = CyUp.register(),
620 down = CyDown.register(),
621 select = CySelect.register(),
622 bt = CyBacktrace.register(),
623 list = CyList.register(),
624 print_ = CyPrint.register(),
625 locals = CyLocals.register(),
626 globals = CyGlobals.register(),
627 exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'),
628 _exec = CyExec.register(),
629 set = CySet.register(),
631 # GDB functions
632 cy_cname = CyCName('cy_cname'),
633 cy_cvalue = CyCValue('cy_cvalue'),
634 cy_lineno = CyLine('cy_lineno'),
635 cy_eval = CyEval('cy_eval'),
638 for command_name, command in commands.iteritems():
639 command.cy = self
640 setattr(self, command_name, command)
642 self.cy = self
644 # Cython module namespace
645 self.cython_namespace = {}
647 # maps (unique) qualified function names (e.g.
648 # cythonmodule.ClassName.method_name) to the CythonFunction object
649 self.functions_by_qualified_name = {}
651 # unique cnames of Cython functions
652 self.functions_by_cname = {}
654 # map function names like method_name to a list of all such
655 # CythonFunction objects
656 self.functions_by_name = collections.defaultdict(list)
659 class CyImport(CythonCommand):
661 Import debug information outputted by the Cython compiler
662 Example: cy import FILE...
665 name = 'cy import'
666 command_class = gdb.COMMAND_STATUS
667 completer_class = gdb.COMPLETE_FILENAME
669 def invoke(self, args, from_tty):
670 args = args.encode(_filesystemencoding)
671 for arg in string_to_argv(args):
672 try:
673 f = open(arg)
674 except OSError, e:
675 raise gdb.GdbError('Unable to open file %r: %s' %
676 (args, e.args[1]))
678 t = etree.parse(f)
680 for module in t.getroot():
681 cython_module = CythonModule(**module.attrib)
682 self.cy.cython_namespace[cython_module.name] = cython_module
684 for variable in module.find('Globals'):
685 d = variable.attrib
686 cython_module.globals[d['name']] = CythonVariable(**d)
688 for function in module.find('Functions'):
689 cython_function = CythonFunction(module=cython_module,
690 **function.attrib)
692 # update the global function mappings
693 name = cython_function.name
694 qname = cython_function.qualified_name
696 self.cy.functions_by_name[name].append(cython_function)
697 self.cy.functions_by_qualified_name[
698 cython_function.qualified_name] = cython_function
699 self.cy.functions_by_cname[
700 cython_function.cname] = cython_function
702 d = cython_module.functions[qname] = cython_function
704 for local in function.find('Locals'):
705 d = local.attrib
706 cython_function.locals[d['name']] = CythonVariable(**d)
708 for step_into_func in function.find('StepIntoFunctions'):
709 d = step_into_func.attrib
710 cython_function.step_into_functions.add(d['name'])
712 cython_function.arguments.extend(
713 funcarg.tag for funcarg in function.find('Arguments'))
715 for marker in module.find('LineNumberMapping'):
716 cython_lineno = int(marker.attrib['cython_lineno'])
717 c_linenos = map(int, marker.attrib['c_linenos'].split())
718 cython_module.lineno_cy2c[cython_lineno] = min(c_linenos)
719 for c_lineno in c_linenos:
720 cython_module.lineno_c2cy[c_lineno] = cython_lineno
723 class CyBreak(CythonCommand):
725 Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
727 cy break cython_modulename.ClassName.method_name...
729 or normal notation:
731 cy break function_or_method_name...
733 or for a line number:
735 cy break cython_module:lineno...
737 Set a Python breakpoint:
738 Break on any function or method named 'func' in module 'modname'
740 cy break -p modname.func...
742 Break on any function or method named 'func'
744 cy break -p func...
747 name = 'cy break'
748 command_class = gdb.COMMAND_BREAKPOINTS
750 def _break_pyx(self, name):
751 modulename, _, lineno = name.partition(':')
752 lineno = int(lineno)
753 if modulename:
754 cython_module = self.cy.cython_namespace[modulename]
755 else:
756 cython_module = self.get_cython_function().module
758 if lineno in cython_module.lineno_cy2c:
759 c_lineno = cython_module.lineno_cy2c[lineno]
760 breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno)
761 gdb.execute('break ' + breakpoint)
762 else:
763 raise gdb.GdbError("Not a valid line number. "
764 "Does it contain actual code?")
766 def _break_funcname(self, funcname):
767 func = self.cy.functions_by_qualified_name.get(funcname)
769 if func and func.is_initmodule_function:
770 func = None
772 break_funcs = [func]
774 if not func:
775 funcs = self.cy.functions_by_name.get(funcname) or []
776 funcs = [f for f in funcs if not f.is_initmodule_function]
778 if not funcs:
779 gdb.execute('break ' + funcname)
780 return
782 if len(funcs) > 1:
783 # multiple functions, let the user pick one
784 print 'There are multiple such functions:'
785 for idx, func in enumerate(funcs):
786 print '%3d) %s' % (idx, func.qualified_name)
788 while True:
789 try:
790 result = raw_input(
791 "Select a function, press 'a' for all "
792 "functions or press 'q' or '^D' to quit: ")
793 except EOFError:
794 return
795 else:
796 if result.lower() == 'q':
797 return
798 elif result.lower() == 'a':
799 break_funcs = funcs
800 break
801 elif (result.isdigit() and
802 0 <= int(result) < len(funcs)):
803 break_funcs = [funcs[int(result)]]
804 break
805 else:
806 print 'Not understood...'
807 else:
808 break_funcs = [funcs[0]]
810 for func in break_funcs:
811 gdb.execute('break %s' % func.cname)
812 if func.pf_cname:
813 gdb.execute('break %s' % func.pf_cname)
815 def invoke(self, function_names, from_tty):
816 argv = string_to_argv(function_names.encode('UTF-8'))
817 if function_names.startswith('-p'):
818 argv = argv[1:]
819 python_breakpoints = True
820 else:
821 python_breakpoints = False
823 for funcname in argv:
824 if python_breakpoints:
825 gdb.execute('py-break %s' % funcname)
826 elif ':' in funcname:
827 self._break_pyx(funcname)
828 else:
829 self._break_funcname(funcname)
831 @dont_suppress_errors
832 def complete(self, text, word):
833 # Filter init-module functions (breakpoints can be set using
834 # modulename:linenumber).
835 names = [n for n, L in self.cy.functions_by_name.iteritems()
836 if any(not f.is_initmodule_function for f in L)]
837 qnames = [n for n, f in self.cy.functions_by_qualified_name.iteritems()
838 if not f.is_initmodule_function]
840 if parameters.complete_unqualified:
841 all_names = itertools.chain(qnames, names)
842 else:
843 all_names = qnames
845 words = text.strip().split()
846 if not words or '.' not in words[-1]:
847 # complete unqualified
848 seen = set(text[:-len(word)].split())
849 return [n for n in all_names
850 if n.startswith(word) and n not in seen]
852 # complete qualified name
853 lastword = words[-1]
854 compl = [n for n in qnames if n.startswith(lastword)]
856 if len(lastword) > len(word):
857 # readline sees something (e.g. a '.') as a word boundary, so don't
858 # "recomplete" this prefix
859 strip_prefix_length = len(lastword) - len(word)
860 compl = [n[strip_prefix_length:] for n in compl]
862 return compl
865 class CythonInfo(CythonBase, libpython.PythonInfo):
867 Implementation of the interface dictated by libpython.LanguageInfo.
870 def lineno(self, frame):
871 # Take care of the Python and Cython levels. We need to care for both
872 # as we can't simply dispath to 'py-step', since that would work for
873 # stepping through Python code, but it would not step back into Cython-
874 # related code. The C level should be dispatched to the 'step' command.
875 if self.is_cython_function(frame):
876 return self.get_cython_lineno(frame)
877 return super(CythonInfo, self).lineno(frame)
879 def get_source_line(self, frame):
880 try:
881 line = super(CythonInfo, self).get_source_line(frame)
882 except gdb.GdbError:
883 return None
884 else:
885 return line.strip() or None
887 def exc_info(self, frame):
888 if self.is_python_function:
889 return super(CythonInfo, self).exc_info(frame)
891 def runtime_break_functions(self):
892 if self.is_cython_function():
893 return self.get_cython_function().step_into_functions
894 return ()
896 def static_break_functions(self):
897 result = ['PyEval_EvalFrameEx']
898 result.extend(self.cy.functions_by_cname)
899 return result
902 class CythonExecutionControlCommand(CythonCommand,
903 libpython.ExecutionControlCommandBase):
905 @classmethod
906 def register(cls):
907 return cls(cls.name, cython_info)
910 class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
911 "Step through Cython, Python or C code."
913 name = 'cy -step'
914 stepinto = True
916 def invoke(self, args, from_tty):
917 if self.is_python_function():
918 self.python_step(self.stepinto)
919 elif not self.is_cython_function():
920 if self.stepinto:
921 command = 'step'
922 else:
923 command = 'next'
925 self.finish_executing(gdb.execute(command, to_string=True))
926 else:
927 self.step(stepinto=self.stepinto)
930 class CyNext(CyStep):
931 "Step-over Cython, Python or C code."
933 name = 'cy -next'
934 stepinto = False
937 class CyRun(CythonExecutionControlCommand):
939 Run a Cython program. This is like the 'run' command, except that it
940 displays Cython or Python source lines as well
943 name = 'cy run'
945 invoke = CythonExecutionControlCommand.run
948 class CyCont(CythonExecutionControlCommand):
950 Continue a Cython program. This is like the 'run' command, except that it
951 displays Cython or Python source lines as well.
954 name = 'cy cont'
955 invoke = CythonExecutionControlCommand.cont
958 class CyFinish(CythonExecutionControlCommand):
960 Execute until the function returns.
962 name = 'cy finish'
964 invoke = CythonExecutionControlCommand.finish
967 class CyUp(CythonCommand):
969 Go up a Cython, Python or relevant C frame.
971 name = 'cy up'
972 _command = 'up'
974 def invoke(self, *args):
975 try:
976 gdb.execute(self._command, to_string=True)
977 while not self.is_relevant_function(gdb.selected_frame()):
978 gdb.execute(self._command, to_string=True)
979 except RuntimeError, e:
980 raise gdb.GdbError(*e.args)
982 frame = gdb.selected_frame()
983 index = 0
984 while frame:
985 frame = frame.older()
986 index += 1
988 self.print_stackframe(index=index - 1)
991 class CyDown(CyUp):
993 Go down a Cython, Python or relevant C frame.
996 name = 'cy down'
997 _command = 'down'
1000 class CySelect(CythonCommand):
1002 Select a frame. Use frame numbers as listed in `cy backtrace`.
1003 This command is useful because `cy backtrace` prints a reversed backtrace.
1006 name = 'cy select'
1008 def invoke(self, stackno, from_tty):
1009 try:
1010 stackno = int(stackno)
1011 except ValueError:
1012 raise gdb.GdbError("Not a valid number: %r" % (stackno,))
1014 frame = gdb.selected_frame()
1015 while frame.newer():
1016 frame = frame.newer()
1018 stackdepth = libpython.stackdepth(frame)
1020 try:
1021 gdb.execute('select %d' % (stackdepth - stackno - 1,))
1022 except RuntimeError, e:
1023 raise gdb.GdbError(*e.args)
1026 class CyBacktrace(CythonCommand):
1027 'Print the Cython stack'
1029 name = 'cy bt'
1030 alias = 'cy backtrace'
1031 command_class = gdb.COMMAND_STACK
1032 completer_class = gdb.COMPLETE_NONE
1034 @require_running_program
1035 def invoke(self, args, from_tty):
1036 # get the first frame
1037 frame = gdb.selected_frame()
1038 while frame.older():
1039 frame = frame.older()
1041 print_all = args == '-a'
1043 index = 0
1044 while frame:
1045 try:
1046 is_relevant = self.is_relevant_function(frame)
1047 except CyGDBError:
1048 is_relevant = False
1050 if print_all or is_relevant:
1051 self.print_stackframe(frame, index)
1053 index += 1
1054 frame = frame.newer()
1057 class CyList(CythonCommand):
1059 List Cython source code. To disable to customize colouring see the cy_*
1060 parameters.
1063 name = 'cy list'
1064 command_class = gdb.COMMAND_FILES
1065 completer_class = gdb.COMPLETE_NONE
1067 # @dispatch_on_frame(c_command='list')
1068 def invoke(self, _, from_tty):
1069 sd, lineno = self.get_source_desc()
1070 source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno,
1071 lex_entire=True)
1072 print source
1075 class CyPrint(CythonCommand):
1077 Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
1080 name = 'cy print'
1081 command_class = gdb.COMMAND_DATA
1083 def invoke(self, name, from_tty, max_name_length=None):
1084 if self.is_python_function():
1085 return gdb.execute('py-print ' + name)
1086 elif self.is_cython_function():
1087 value = self.cy.cy_cvalue.invoke(name.lstrip('*'))
1088 for c in name:
1089 if c == '*':
1090 value = value.dereference()
1091 else:
1092 break
1094 self.print_gdb_value(name, value, max_name_length)
1095 else:
1096 gdb.execute('print ' + name)
1098 def complete(self):
1099 if self.is_cython_function():
1100 f = self.get_cython_function()
1101 return list(itertools.chain(f.locals, f.globals))
1102 else:
1103 return []
1106 sortkey = lambda (name, value): name.lower()
1108 class CyLocals(CythonCommand):
1110 List the locals from the current Cython frame.
1113 name = 'cy locals'
1114 command_class = gdb.COMMAND_STACK
1115 completer_class = gdb.COMPLETE_NONE
1117 @dispatch_on_frame(c_command='info locals', python_command='py-locals')
1118 def invoke(self, args, from_tty):
1119 cython_function = self.get_cython_function()
1121 if cython_function.is_initmodule_function:
1122 self.cy.globals.invoke(args, from_tty)
1123 return
1125 local_cython_vars = cython_function.locals
1126 max_name_length = len(max(local_cython_vars, key=len))
1127 for name, cyvar in sorted(local_cython_vars.iteritems(), key=sortkey):
1128 if self.is_initialized(self.get_cython_function(), cyvar.name):
1129 value = gdb.parse_and_eval(cyvar.cname)
1130 if not value.is_optimized_out:
1131 self.print_gdb_value(cyvar.name, value,
1132 max_name_length, '')
1135 class CyGlobals(CyLocals):
1137 List the globals from the current Cython module.
1140 name = 'cy globals'
1141 command_class = gdb.COMMAND_STACK
1142 completer_class = gdb.COMPLETE_NONE
1144 @dispatch_on_frame(c_command='info variables', python_command='py-globals')
1145 def invoke(self, args, from_tty):
1146 global_python_dict = self.get_cython_globals_dict()
1147 module_globals = self.get_cython_function().module.globals
1149 max_globals_len = 0
1150 max_globals_dict_len = 0
1151 if module_globals:
1152 max_globals_len = len(max(module_globals, key=len))
1153 if global_python_dict:
1154 max_globals_dict_len = len(max(global_python_dict))
1156 max_name_length = max(max_globals_len, max_globals_dict_len)
1158 seen = set()
1159 print 'Python globals:'
1160 for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
1161 v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
1162 seen.add(k)
1163 print ' %-*s = %s' % (max_name_length, k, v)
1165 print 'C globals:'
1166 for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
1167 if name not in seen:
1168 try:
1169 value = gdb.parse_and_eval(cyvar.cname)
1170 except RuntimeError:
1171 pass
1172 else:
1173 if not value.is_optimized_out:
1174 self.print_gdb_value(cyvar.name, value,
1175 max_name_length, ' ')
1179 class EvaluateOrExecuteCodeMixin(object):
1181 Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
1182 method evaluations Python code, prints a traceback if an exception went
1183 uncaught, and returns any return value as a gdb.Value (NULL on exception).
1186 def _fill_locals_dict(self, executor, local_dict_pointer):
1187 "Fill a remotely allocated dict with values from the Cython C stack"
1188 cython_func = self.get_cython_function()
1190 for name, cyvar in cython_func.locals.iteritems():
1191 if (cyvar.type == PythonObject and
1192 self.is_initialized(cython_func, name)):
1194 try:
1195 val = gdb.parse_and_eval(cyvar.cname)
1196 except RuntimeError:
1197 continue
1198 else:
1199 if val.is_optimized_out:
1200 continue
1202 pystringp = executor.alloc_pystring(name)
1203 code = '''
1204 (PyObject *) PyDict_SetItem(
1205 (PyObject *) %d,
1206 (PyObject *) %d,
1207 (PyObject *) %s)
1208 ''' % (local_dict_pointer, pystringp, cyvar.cname)
1210 try:
1211 if gdb.parse_and_eval(code) < 0:
1212 gdb.parse_and_eval('PyErr_Print()')
1213 raise gdb.GdbError("Unable to execute Python code.")
1214 finally:
1215 # PyDict_SetItem doesn't steal our reference
1216 executor.xdecref(pystringp)
1218 def _find_first_cython_or_python_frame(self):
1219 frame = gdb.selected_frame()
1220 while frame:
1221 if (self.is_cython_function(frame) or
1222 self.is_python_function(frame)):
1223 frame.select()
1224 return frame
1226 frame = frame.older()
1228 raise gdb.GdbError("There is no Cython or Python frame on the stack.")
1231 def _evalcode_cython(self, executor, code, input_type):
1232 with libpython.FetchAndRestoreError():
1233 # get the dict of Cython globals and construct a dict in the
1234 # inferior with Cython locals
1235 global_dict = gdb.parse_and_eval(
1236 '(PyObject *) PyModule_GetDict(__pyx_m)')
1237 local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
1239 try:
1240 self._fill_locals_dict(executor,
1241 libpython.pointervalue(local_dict))
1242 result = executor.evalcode(code, input_type, global_dict,
1243 local_dict)
1244 finally:
1245 executor.xdecref(libpython.pointervalue(local_dict))
1247 return result
1249 def evalcode(self, code, input_type):
1251 Evaluate `code` in a Python or Cython stack frame using the given
1252 `input_type`.
1254 frame = self._find_first_cython_or_python_frame()
1255 executor = libpython.PythonCodeExecutor()
1256 if self.is_python_function(frame):
1257 return libpython._evalcode_python(executor, code, input_type)
1258 return self._evalcode_cython(executor, code, input_type)
1261 class CyExec(CythonCommand, libpython.PyExec, EvaluateOrExecuteCodeMixin):
1263 Execute Python code in the nearest Python or Cython frame.
1266 name = '-cy-exec'
1267 command_class = gdb.COMMAND_STACK
1268 completer_class = gdb.COMPLETE_NONE
1270 def invoke(self, expr, from_tty):
1271 expr, input_type = self.readcode(expr)
1272 executor = libpython.PythonCodeExecutor()
1273 executor.xdecref(self.evalcode(expr, executor.Py_single_input))
1276 class CySet(CythonCommand):
1278 Set a Cython variable to a certain value
1280 cy set my_cython_c_variable = 10
1281 cy set my_cython_py_variable = $cy_eval("{'doner': 'kebab'}")
1283 This is equivalent to
1285 set $cy_value("my_cython_variable") = 10
1288 name = 'cy set'
1289 command_class = gdb.COMMAND_DATA
1290 completer_class = gdb.COMPLETE_NONE
1292 @require_cython_frame
1293 def invoke(self, expr, from_tty):
1294 name_and_expr = expr.split('=', 1)
1295 if len(name_and_expr) != 2:
1296 raise gdb.GdbError("Invalid expression. Use 'cy set var = expr'.")
1298 varname, expr = name_and_expr
1299 cname = self.cy.cy_cname.invoke(varname.strip())
1300 gdb.execute("set %s = %s" % (cname, expr))
1303 # Functions
1305 class CyCName(gdb.Function, CythonBase):
1307 Get the C name of a Cython variable in the current context.
1308 Examples:
1310 print $cy_cname("function")
1311 print $cy_cname("Class.method")
1312 print $cy_cname("module.function")
1315 @require_cython_frame
1316 @gdb_function_value_to_unicode
1317 def invoke(self, cyname, frame=None):
1318 frame = frame or gdb.selected_frame()
1319 cname = None
1321 if self.is_cython_function(frame):
1322 cython_function = self.get_cython_function(frame)
1323 if cyname in cython_function.locals:
1324 cname = cython_function.locals[cyname].cname
1325 elif cyname in cython_function.module.globals:
1326 cname = cython_function.module.globals[cyname].cname
1327 else:
1328 qname = '%s.%s' % (cython_function.module.name, cyname)
1329 if qname in cython_function.module.functions:
1330 cname = cython_function.module.functions[qname].cname
1332 if not cname:
1333 cname = self.cy.functions_by_qualified_name.get(cyname)
1335 if not cname:
1336 raise gdb.GdbError('No such Cython variable: %s' % cyname)
1338 return cname
1341 class CyCValue(CyCName):
1343 Get the value of a Cython variable.
1346 @require_cython_frame
1347 @gdb_function_value_to_unicode
1348 def invoke(self, cyname, frame=None):
1349 globals_dict = self.get_cython_globals_dict()
1350 cython_function = self.get_cython_function(frame)
1352 if self.is_initialized(cython_function, cyname):
1353 cname = super(CyCValue, self).invoke(cyname, frame=frame)
1354 return gdb.parse_and_eval(cname)
1355 elif cyname in globals_dict:
1356 return globals_dict[cyname]._gdbval
1357 else:
1358 raise gdb.GdbError("Variable %s is not initialized." % cyname)
1361 class CyLine(gdb.Function, CythonBase):
1363 Get the current Cython line.
1366 @require_cython_frame
1367 def invoke(self):
1368 return self.get_cython_lineno()
1371 class CyEval(gdb.Function, CythonBase, EvaluateOrExecuteCodeMixin):
1373 Evaluate Python code in the nearest Python or Cython frame and return
1376 @gdb_function_value_to_unicode
1377 def invoke(self, python_expression):
1378 input_type = libpython.PythonCodeExecutor.Py_eval_input
1379 return self.evalcode(python_expression, input_type)
1382 cython_info = CythonInfo()
1383 cy = CyCy.register()
1384 cython_info.cy = cy
1386 def register_defines():
1387 libpython.source_gdb_script(textwrap.dedent("""\
1388 define cy step
1389 cy -step
1392 define cy next
1393 cy -next
1396 document cy step
1400 document cy next
1403 """) % (CyStep.__doc__, CyNext.__doc__))
1405 register_defines()