Added 'cy exec' and 'py-exec' commands
[cython.git] / Cython / Debugger / libcython.py
1 """
2 GDB extension that adds Cython support.
3 """
4
5 from __future__ import with_statement
6
7 import os
8 import sys
9 import textwrap
10 import operator
11 import traceback
12 import functools
13 import itertools
14 import collections
15
16 import gdb
17
18 try:
19   from lxml import etree
20   have_lxml = True
21 except ImportError:
22     have_lxml = False
23     try:
24         # Python 2.5
25         from xml.etree import cElementTree as etree
26     except ImportError:
27         try:
28             # Python 2.5
29             from xml.etree import ElementTree as etree
30         except ImportError:
31             try:
32                 # normal cElementTree install
33                 import cElementTree as etree
34             except ImportError:
35                 # normal ElementTree install
36                 import elementtree.ElementTree as etree
37
38 try:
39     import pygments.lexers
40     import pygments.formatters
41 except ImportError:
42     pygments = None
43     sys.stderr.write("Install pygments for colorized source code.\n")
44
45 if hasattr(gdb, 'string_to_argv'):
46     from gdb import string_to_argv
47 else:
48     from shlex import split as string_to_argv
49
50 from Cython.Debugger import libpython
51
52 # C or Python type
53 CObject = 'CObject'
54 PythonObject = 'PythonObject'
55
56 _data_types = dict(CObject=CObject, PythonObject=PythonObject)
57 _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
58
59 # decorators
60
61 def dont_suppress_errors(function):
62     "*sigh*, readline"
63     @functools.wraps(function)
64     def wrapper(*args, **kwargs):
65         try:
66             return function(*args, **kwargs)
67         except Exception:
68             traceback.print_exc()
69             raise
70     
71     return wrapper
72
73 def default_selected_gdb_frame(err=True):
74     def decorator(function):
75         @functools.wraps(function)
76         def wrapper(self, frame=None, *args, **kwargs):
77             try:
78                 frame = frame or gdb.selected_frame()
79             except RuntimeError:
80                 raise gdb.GdbError("No frame is currently selected.")
81                 
82             if err and frame.name() is None:
83                 raise NoFunctionNameInFrameError()
84     
85             return function(self, frame, *args, **kwargs)
86         return wrapper
87     return decorator
88
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)
98     return wrapper 
99
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()
106             
107             if is_cy or (is_py and not python_command):
108                 function(self, *args, **kwargs)
109             elif is_py:
110                 gdb.execute(python_command)
111             elif self.is_relevant_function():
112                 gdb.execute(c_command)
113             else:
114                 raise gdb.GdbError("Not a function cygdb knows about. "
115                                    "Use the normal GDB commands instead.")
116         
117         return wrapper
118     return decorator
119
120 def require_running_program(function):
121     @functools.wraps(function)
122     def wrapper(*args, **kwargs):
123         try:
124             gdb.selected_frame()
125         except RuntimeError:
126             raise gdb.GdbError("No frame is currently selected.")
127         
128         return function(*args, **kwargs)
129     return wrapper
130     
131
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()
137
138         return function(self, string, *args, **kwargs)
139     return wrapper
140
141
142 # Classes that represent the debug information
143 # Don't rename the parameters of these classes, they come directly from the XML
144
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
150         self.globals = {}
151         # {cython_lineno: min(c_linenos)}
152         self.lineno_cy2c = {}
153         # {c_lineno: cython_lineno}
154         self.lineno_c2cy = {}
155         self.functions = {}
156         
157     def qualified_name(self, varname):
158         return '.'.join(self.name, varname)
159
160 class CythonVariable(object):
161
162     def __init__(self, name, cname, qualified_name, type):
163         self.name = name
164         self.cname = cname
165         self.qualified_name = qualified_name
166         self.type = type
167
168 class CythonFunction(CythonVariable):
169     def __init__(self, 
170                  module, 
171                  name, 
172                  cname, 
173                  pf_cname,
174                  qualified_name, 
175                  lineno, 
176                  type=CObject):
177         super(CythonFunction, self).__init__(name, 
178                                              cname, 
179                                              qualified_name, 
180                                              type)
181         self.module = module
182         self.pf_cname = pf_cname
183         self.lineno = int(lineno)
184         self.locals = {}
185         self.arguments = []
186         self.step_into_functions = set()
187
188
189 # General purpose classes
190
191 class CythonBase(object):
192     
193     @default_selected_gdb_frame(err=False)
194     def is_cython_function(self, frame):
195         return frame.name() in self.cy.functions_by_cname
196
197     @default_selected_gdb_frame(err=False)
198     def is_python_function(self, frame):
199         """
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.
202         """
203         if frame.name() == 'PyEval_EvalFrameEx':
204             pyframe = libpython.Frame(frame).get_pyop()
205             return pyframe and not pyframe.is_optimized_out()
206         return False
207         
208     @default_selected_gdb_frame()
209     def get_c_function_name(self, frame):
210         return frame.name()
211
212     @default_selected_gdb_frame()
213     def get_c_lineno(self, frame):
214         return frame.find_sal().line
215     
216     @default_selected_gdb_frame()
217     def get_cython_function(self, frame):
218         result = self.cy.functions_by_cname.get(frame.name())
219         if result is None:
220             raise NoCythonFunctionInFrameError()
221             
222         return result
223     
224     @default_selected_gdb_frame()
225     def get_cython_lineno(self, frame):
226         """
227         Get the current Cython line number. Returns 0 if there is no 
228         correspondence between the C and Cython code.
229         """
230         cyfunc = self.get_cython_function(frame)
231         return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0)
232     
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)
239             if pygments:
240                 lexer = pygments.lexers.CythonLexer(stripall=False)
241         elif self.is_python_function(frame):
242             pyframeobject = libpython.Frame(frame).get_pyop()
243
244             if not pyframeobject:
245                 raise gdb.GdbError('Unable to read information on python frame')
246
247             filename = pyframeobject.filename()
248             lineno = pyframeobject.current_line_num()
249             
250             if pygments:
251                 lexer = pygments.lexers.PythonLexer(stripall=False)
252         else:
253             symbol_and_line_obj = frame.find_sal()
254             if not symbol_and_line_obj or not symbol_and_line_obj.symtab:
255                 filename = None
256                 lineno = 0
257             else:
258                 filename = symbol_and_line_obj.symtab.filename
259                 lineno = symbol_and_line_obj.line
260                 if pygments:
261                     lexer = pygments.lexers.CLexer(stripall=False)
262             
263         return SourceFileDescriptor(filename, lexer), lineno
264
265     @default_selected_gdb_frame()
266     def get_source_line(self, frame):
267         source_desc, lineno = self.get_source_desc()
268         return source_desc.get_source(lineno)
269     
270     @default_selected_gdb_frame()
271     def is_relevant_function(self, frame):
272         """
273         returns whether we care about a frame on the user-level when debugging
274         Cython code
275         """
276         name = frame.name()
277         older_frame = frame.older()
278         if self.is_cython_function(frame) or self.is_python_function(frame):
279             return True
280         elif older_frame and self.is_cython_function(older_frame):
281             # direct C function call from a Cython function
282             cython_func = self.get_cython_function(older_frame)
283             return name in cython_func.step_into_functions
284
285         return False
286     
287     @default_selected_gdb_frame(err=False)
288     def print_stackframe(self, frame, index, is_c=False):
289         """
290         Print a C, Cython or Python stack frame and the line of source code
291         if available.
292         """
293         # do this to prevent the require_cython_frame decorator from
294         # raising GdbError when calling self.cy.cy_cvalue.invoke()
295         selected_frame = gdb.selected_frame()
296         frame.select()
297         
298         try:
299             source_desc, lineno = self.get_source_desc(frame)
300         except NoFunctionNameInFrameError:
301             print '#%-2d Unknown Frame (compile with -g)' % index
302             return
303
304         if not is_c and self.is_python_function(frame):
305             pyframe = libpython.Frame(frame).get_pyop()
306             if pyframe is None or pyframe.is_optimized_out():
307                 # print this python function as a C function
308                 return self.print_stackframe(frame, index, is_c=True)
309             
310             func_name = pyframe.co_name
311             func_cname = 'PyEval_EvalFrameEx'
312             func_args = []
313         elif self.is_cython_function(frame):
314             cyfunc = self.get_cython_function(frame)
315             f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame)
316             
317             func_name = cyfunc.name
318             func_cname = cyfunc.cname
319             func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments]
320         else:
321             source_desc, lineno = self.get_source_desc(frame)
322             func_name = frame.name()
323             func_cname = func_name
324             func_args = []
325         
326         try:
327             gdb_value = gdb.parse_and_eval(func_cname)
328         except RuntimeError:
329             func_address = 0
330         else:
331             # Seriously? Why is the address not an int?
332             func_address = int(str(gdb_value.address).split()[0], 0)
333         
334         a = ', '.join('%s=%s' % (name, val) for name, val in func_args)
335         print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a),
336             
337         if source_desc.filename is not None:
338             print 'at %s:%s' % (source_desc.filename, lineno),
339         
340         print
341             
342         try:
343             print '    ' + source_desc.get_source(lineno)
344         except gdb.GdbError:
345             pass
346         
347         selected_frame.select()
348     
349     def get_remote_cython_globals_dict(self):
350         m = gdb.parse_and_eval('__pyx_m')
351         
352         try:
353             PyModuleObject = gdb.lookup_type('PyModuleObject')
354         except RuntimeError:
355             raise gdb.GdbError(textwrap.dedent("""\
356                 Unable to lookup type PyModuleObject, did you compile python 
357                 with debugging support (-g)?"""))
358             
359         m = m.cast(PyModuleObject.pointer())
360         return m['md_dict']
361         
362     
363     def get_cython_globals_dict(self):
364         """
365         Get the Cython globals dict where the remote names are turned into
366         local strings.
367         """
368         remote_dict = self.get_remote_cython_globals_dict()
369         pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict)
370         
371         result = {}
372         seen = set()
373         for k, v in pyobject_dict.iteritems():
374             result[k.proxyval(seen)] = v
375             
376         return result
377
378     def print_gdb_value(self, name, value, max_name_length=None, prefix=''):
379         if libpython.pretty_printer_lookup(value):
380             typename = ''
381         else:
382             typename = '(%s) ' % (value.type,)
383                 
384         if max_name_length is None:
385             print '%s%s = %s%s' % (prefix, name, typename, value)
386         else:
387             print '%s%-*s = %s%s' % (prefix, max_name_length, name, typename, 
388                                      value)
389
390
391 class SourceFileDescriptor(object):
392     def __init__(self, filename, lexer, formatter=None):
393         self.filename = filename
394         self.lexer = lexer
395         self.formatter = formatter
396
397     def valid(self):
398         return self.filename is not None
399
400     def lex(self, code):
401         if pygments and self.lexer and parameters.colorize_code:
402             bg = parameters.terminal_background.value
403             if self.formatter is None:
404                 formatter = pygments.formatters.TerminalFormatter(bg=bg)
405             else:
406                 formatter = self.formatter
407
408             return pygments.highlight(code, self.lexer, formatter)
409
410         return code
411
412     def _get_source(self, start, stop, lex_source, mark_line, lex_entire):
413         with open(self.filename) as f:
414             # to provide "correct" colouring, the entire code needs to be
415             # lexed. However, this makes a lot of things terribly slow, so
416             # we decide not to. Besides, it's unlikely to matter.
417             
418             if lex_source and lex_entire:
419                 f = self.lex(f.read()).splitlines()
420             
421             slice = itertools.islice(f, start - 1, stop - 1)
422             
423             for idx, line in enumerate(slice):
424                 if start + idx == mark_line:
425                     prefix = '>'
426                 else:
427                     prefix = ' '
428                 
429                 if lex_source and not lex_entire:
430                     line = self.lex(line)
431
432                 yield '%s %4d    %s' % (prefix, start + idx, line.rstrip())
433
434     def get_source(self, start, stop=None, lex_source=True, mark_line=0, 
435                    lex_entire=False):
436         exc = gdb.GdbError('Unable to retrieve source code')
437         
438         if not self.filename:
439             raise exc
440         
441         start = max(start, 1)
442         if stop is None:
443             stop = start + 1
444
445         try:
446             return '\n'.join(
447                 self._get_source(start, stop, lex_source, mark_line, lex_entire))
448         except IOError:
449             raise exc
450
451
452 # Errors
453
454 class CyGDBError(gdb.GdbError):
455     """
456     Base class for Cython-command related erorrs
457     """
458     
459     def __init__(self, *args):
460         args = args or (self.msg,)
461         super(CyGDBError, self).__init__(*args)
462     
463 class NoCythonFunctionInFrameError(CyGDBError):
464     """
465     raised when the user requests the current cython function, which is 
466     unavailable
467     """
468     msg = "Current function is a function cygdb doesn't know about"
469
470 class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
471     """
472     raised when the name of the C function could not be determined 
473     in the current C stack frame
474     """
475     msg = ('C function name could not be determined in the current C stack '
476            'frame')
477
478
479 # Parameters
480
481 class CythonParameter(gdb.Parameter):
482     """
483     Base class for cython parameters
484     """
485     
486     def __init__(self, name, command_class, parameter_class, default=None):
487         self.show_doc = self.set_doc = self.__class__.__doc__
488         super(CythonParameter, self).__init__(name, command_class, 
489                                               parameter_class)
490         if default is not None:
491             self.value = default
492    
493     def __nonzero__(self):
494         return bool(self.value)
495     
496     __bool__ = __nonzero__ # python 3
497
498 class CompleteUnqualifiedFunctionNames(CythonParameter):
499     """
500     Have 'cy break' complete unqualified function or method names.
501     """ 
502
503 class ColorizeSourceCode(CythonParameter):
504     """
505     Tell cygdb whether to colorize source code.
506     """
507
508 class TerminalBackground(CythonParameter):
509     """
510     Tell cygdb about the user's terminal background (light or dark).
511     """
512
513 class CythonParameters(object):
514     """
515     Simple container class that might get more functionality in the distant
516     future (mostly to remind us that we're dealing with parameters).
517     """
518     
519     def __init__(self):
520         self.complete_unqualified = CompleteUnqualifiedFunctionNames(
521             'cy_complete_unqualified',
522             gdb.COMMAND_BREAKPOINTS,
523             gdb.PARAM_BOOLEAN,
524             True)
525         self.colorize_code = ColorizeSourceCode(
526             'cy_colorize_code',
527             gdb.COMMAND_FILES,
528             gdb.PARAM_BOOLEAN,
529             True)
530         self.terminal_background = TerminalBackground(
531             'cy_terminal_background_color',
532             gdb.COMMAND_FILES,
533             gdb.PARAM_STRING,
534             "dark")
535         
536 parameters = CythonParameters()
537
538
539 # Commands
540
541 class CythonCommand(gdb.Command, CythonBase):
542     """
543     Base class for Cython commands
544     """
545     
546     command_class = gdb.COMMAND_NONE
547     
548     @classmethod
549     def _register(cls, clsname, args, kwargs):
550         if not hasattr(cls, 'completer_class'):
551             return cls(clsname, cls.command_class, *args, **kwargs)
552         else:
553             return cls(clsname, cls.command_class, cls.completer_class, 
554                        *args, **kwargs)
555     
556     @classmethod
557     def register(cls, *args, **kwargs):
558         alias = getattr(cls, 'alias', None)
559         if alias:
560             cls._register(cls.alias, args, kwargs)
561             
562         return cls._register(cls.name, args, kwargs)
563
564
565 class CyCy(CythonCommand):
566     """
567     Invoke a Cython command. Available commands are:
568         
569         cy import
570         cy break
571         cy step
572         cy next
573         cy run
574         cy cont
575         cy up
576         cy down
577         cy bt / cy backtrace
578         cy print
579         cy list
580         cy locals
581         cy globals
582     """
583     
584     name = 'cy'
585     command_class = gdb.COMMAND_NONE
586     completer_class = gdb.COMPLETE_COMMAND
587     
588     def __init__(self, *args):
589         super(CythonCommand, self).__init__(*args, prefix=True)
590         
591         commands = dict(
592             import_ = CyImport.register(),
593             break_ = CyBreak.register(),
594             step = CyStep.register(),
595             next = CyNext.register(),
596             run = CyRun.register(),
597             cont = CyCont.register(),
598             finish = CyFinish.register(),
599             up = CyUp.register(),
600             down = CyDown.register(),
601             bt = CyBacktrace.register(),
602             list = CyList.register(),
603             print_ = CyPrint.register(),
604             locals = CyLocals.register(),
605             globals = CyGlobals.register(),
606             exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'),
607             _exec = CyExec.register(),
608             cy_cname = CyCName('cy_cname'),
609             cy_cvalue = CyCValue('cy_cvalue'),
610             cy_lineno = CyLine('cy_lineno'),
611         )
612             
613         for command_name, command in commands.iteritems():
614             command.cy = self
615             setattr(self, command_name, command)
616         
617         self.cy = self
618         
619         # Cython module namespace
620         self.cython_namespace = {}
621         
622         # maps (unique) qualified function names (e.g. 
623         # cythonmodule.ClassName.method_name) to the CythonFunction object
624         self.functions_by_qualified_name = {}
625         
626         # unique cnames of Cython functions
627         self.functions_by_cname = {}
628         
629         # map function names like method_name to a list of all such 
630         # CythonFunction objects
631         self.functions_by_name = collections.defaultdict(list)
632
633
634 class CyImport(CythonCommand):
635     """
636     Import debug information outputted by the Cython compiler
637     Example: cy import FILE...
638     """
639     
640     name = 'cy import'
641     command_class = gdb.COMMAND_STATUS
642     completer_class = gdb.COMPLETE_FILENAME
643     
644     def invoke(self, args, from_tty):
645         args = args.encode(_filesystemencoding)
646         for arg in string_to_argv(args):
647             try:
648                 f = open(arg)
649             except OSError, e:
650                 raise gdb.GdbError('Unable to open file %r: %s' % 
651                                                 (args, e.args[1]))
652             
653             t = etree.parse(f)
654             
655             for module in t.getroot():
656                 cython_module = CythonModule(**module.attrib)
657                 self.cy.cython_namespace[cython_module.name] = cython_module
658                 
659                 for variable in module.find('Globals'):
660                     d = variable.attrib
661                     cython_module.globals[d['name']] = CythonVariable(**d)
662                 
663                 for function in module.find('Functions'):
664                     cython_function = CythonFunction(module=cython_module, 
665                                                      **function.attrib)
666
667                     # update the global function mappings
668                     name = cython_function.name
669                     qname = cython_function.qualified_name
670                     
671                     self.cy.functions_by_name[name].append(cython_function)
672                     self.cy.functions_by_qualified_name[
673                         cython_function.qualified_name] = cython_function
674                     self.cy.functions_by_cname[
675                         cython_function.cname] = cython_function
676                     
677                     d = cython_module.functions[qname] = cython_function
678                     
679                     for local in function.find('Locals'):
680                         d = local.attrib
681                         cython_function.locals[d['name']] = CythonVariable(**d)
682
683                     for step_into_func in function.find('StepIntoFunctions'):
684                         d = step_into_func.attrib
685                         cython_function.step_into_functions.add(d['name'])
686                     
687                     cython_function.arguments.extend(
688                         funcarg.tag for funcarg in function.find('Arguments'))
689
690                 for marker in module.find('LineNumberMapping'):
691                     cython_lineno = int(marker.attrib['cython_lineno'])
692                     c_linenos = map(int, marker.attrib['c_linenos'].split())
693                     cython_module.lineno_cy2c[cython_lineno] = min(c_linenos)
694                     for c_lineno in c_linenos:
695                         cython_module.lineno_c2cy[c_lineno] = cython_lineno
696
697         self.cy.step.init_breakpoints()
698
699
700 class CyBreak(CythonCommand):
701     """
702     Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
703         
704         cy break cython_modulename.ClassName.method_name...
705     
706     or normal notation:
707         
708         cy break function_or_method_name...
709     
710     or for a line number:
711     
712         cy break cython_module:lineno...
713     
714     Set a Python breakpoint:
715         Break on any function or method named 'func' in module 'modname'
716             
717             cy break -p modname.func...
718         
719         Break on any function or method named 'func'
720             
721             cy break -p func...
722     """
723     
724     name = 'cy break'
725     command_class = gdb.COMMAND_BREAKPOINTS
726     
727     def _break_pyx(self, name):
728         modulename, _, lineno = name.partition(':')
729         lineno = int(lineno)
730         if modulename:
731             cython_module = self.cy.cython_namespace[modulename]
732         else:
733             cython_module = self.get_cython_function().module
734
735         if lineno in cython_module.lineno_cy2c:
736             c_lineno = cython_module.lineno_cy2c[lineno]
737             breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno)
738             gdb.execute('break ' + breakpoint)
739         else:
740             raise GdbError("Not a valid line number. "
741                            "Does it contain actual code?")
742     
743     def _break_funcname(self, funcname):
744         func = self.cy.functions_by_qualified_name.get(funcname)
745         break_funcs = [func]
746         
747         if not func:
748             funcs = self.cy.functions_by_name.get(funcname)
749             if not funcs:
750                 gdb.execute('break ' + funcname)
751                 return
752                 
753             if len(funcs) > 1:
754                 # multiple functions, let the user pick one
755                 print 'There are multiple such functions:'
756                 for idx, func in enumerate(funcs):
757                     print '%3d) %s' % (idx, func.qualified_name)
758                 
759                 while True:
760                     try:
761                         result = raw_input(
762                             "Select a function, press 'a' for all "
763                             "functions or press 'q' or '^D' to quit: ")
764                     except EOFError:
765                         return
766                     else:
767                         if result.lower() == 'q':
768                             return
769                         elif result.lower() == 'a':
770                             break_funcs = funcs
771                             break
772                         elif (result.isdigit() and 
773                             0 <= int(result) < len(funcs)):
774                             break_funcs = [funcs[int(result)]]
775                             break
776                         else:
777                             print 'Not understood...'
778             else:
779                 break_funcs = [funcs[0]]
780         
781         for func in break_funcs:
782             gdb.execute('break %s' % func.cname)
783             if func.pf_cname:
784                 gdb.execute('break %s' % func.pf_cname)
785     
786     def invoke(self, function_names, from_tty):
787         argv = string_to_argv(function_names.encode('UTF-8'))
788         if function_names.startswith('-p'):
789             argv = argv[1:]
790             python_breakpoints = True
791         else:
792             python_breakpoints = False
793         
794         for funcname in argv:
795             if python_breakpoints:
796                 gdb.execute('py-break %s' % funcname)
797             elif ':' in funcname:
798                 self._break_pyx(funcname)
799             else:
800                 self._break_funcname(funcname)
801     
802     @dont_suppress_errors
803     def complete(self, text, word):
804         names = self.cy.functions_by_qualified_name
805         if parameters.complete_unqualified:
806             names = itertools.chain(names, self.cy.functions_by_name)
807
808         words = text.strip().split()
809         if words and '.' in words[-1]:
810             lastword = words[-1]
811             compl = [n for n in self.cy.functions_by_qualified_name 
812                            if n.startswith(lastword)]
813         else:
814             seen = set(text[:-len(word)].split())
815             return [n for n in names if n.startswith(word) and n not in seen]
816         
817         if len(lastword) > len(word):
818             # readline sees something (e.g. a '.') as a word boundary, so don't
819             # "recomplete" this prefix
820             strip_prefix_length = len(lastword) - len(word)
821             compl = [n[strip_prefix_length:] for n in compl]
822             
823         return compl
824
825
826 class CythonCodeStepper(CythonCommand, libpython.GenericCodeStepper):
827     """
828     Base class for CyStep and CyNext. It implements the interface dictated by
829     libpython.GenericCodeStepper.
830     """
831     
832     def lineno(self, frame):
833         # Take care of the Python and Cython levels. We need to care for both
834         # as we can't simply dispath to 'py-step', since that would work for
835         # stepping through Python code, but it would not step back into Cython-
836         # related code. The C level should be dispatched to the 'step' command.
837         if self.is_cython_function(frame):
838             return self.get_cython_lineno(frame)
839         else:
840             return libpython.py_step.lineno(frame)
841     
842     def get_source_line(self, frame):
843         try:
844             line = super(CythonCodeStepper, self).get_source_line(frame)
845         except gdb.GdbError:
846             return None
847         else:
848             return line.strip() or None
849
850     @classmethod
851     def register(cls):
852         return cls(cls.name, stepinto=getattr(cls, 'stepinto', False))
853
854     def runtime_break_functions(self):
855         if self.is_cython_function():
856             return self.get_cython_function().step_into_functions
857     
858     def static_break_functions(self):
859         result = ['PyEval_EvalFrameEx']
860         result.extend(self.cy.functions_by_cname)
861         return result
862
863     def invoke(self, args, from_tty):
864         if not self.is_cython_function() and not self.is_python_function():
865             if self.stepinto:
866                 command = 'step'
867             else:
868                 command = 'next'
869                 
870             self.finish_executing(gdb.execute(command, to_string=True))
871         else:
872             self.step()
873
874
875 class CyStep(CythonCodeStepper):
876     "Step through Cython, Python or C code."
877     
878     name = 'cy step'
879     stepinto = True
880
881
882 class CyNext(CythonCodeStepper):
883     "Step-over Python code."
884
885     name = 'cy next'
886     stepinto = False
887
888
889 class CyRun(CythonCodeStepper):
890     """
891     Run a Cython program. This is like the 'run' command, except that it 
892     displays Cython or Python source lines as well
893     """
894     
895     name = 'cy run'
896     
897     invoke = CythonCodeStepper.run
898
899
900 class CyCont(CyRun):
901     """
902     Continue a Cython program. This is like the 'run' command, except that it 
903     displays Cython or Python source lines as well.
904     """
905     
906     name = 'cy cont'
907     invoke = CythonCodeStepper.cont
908
909
910 class CyFinish(CyRun):
911     """
912     Execute until the function returns.
913     """
914     name = 'cy finish'
915
916     invoke = CythonCodeStepper.finish
917
918
919 class CyUp(CythonCommand):
920     """
921     Go up a Cython, Python or relevant C frame.
922     """
923     name = 'cy up'
924     _command = 'up'
925     
926     def invoke(self, *args):
927         try:
928             gdb.execute(self._command, to_string=True)
929             while not self.is_relevant_function(gdb.selected_frame()):
930                 gdb.execute(self._command, to_string=True)
931         except RuntimeError, e:
932             raise gdb.GdbError(*e.args)
933         
934         frame = gdb.selected_frame()
935         index = 0
936         while frame:
937             frame = frame.older()
938             index += 1
939             
940         self.print_stackframe(index=index - 1)
941
942
943 class CyDown(CyUp):
944     """
945     Go down a Cython, Python or relevant C frame.
946     """
947     
948     name = 'cy down'
949     _command = 'down'
950
951
952 class CyBacktrace(CythonCommand):
953     'Print the Cython stack'
954     
955     name = 'cy bt'
956     alias = 'cy backtrace'
957     command_class = gdb.COMMAND_STACK
958     completer_class = gdb.COMPLETE_NONE
959     
960     @require_running_program
961     def invoke(self, args, from_tty):
962         # get the first frame
963         selected_frame = frame = gdb.selected_frame()
964         while frame.older():
965             frame = frame.older()
966         
967         print_all = args == '-a'
968         
969         index = 0
970         while frame:
971             is_c = False
972             
973             is_relevant = False
974             try:
975                 is_relevant = self.is_relevant_function(frame)
976             except CyGDBError:
977                 pass
978                 
979             if print_all or is_relevant:
980                 self.print_stackframe(frame, index)
981             
982             index += 1
983             frame = frame.newer()
984         
985         selected_frame.select()
986
987
988 class CyList(CythonCommand):
989     """
990     List Cython source code. To disable to customize colouring see the cy_*
991     parameters.
992     """
993     
994     name = 'cy list'
995     command_class = gdb.COMMAND_FILES
996     completer_class = gdb.COMPLETE_NONE
997     
998     @dispatch_on_frame(c_command='list')
999     def invoke(self, _, from_tty):
1000         sd, lineno = self.get_source_desc()
1001         source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno, 
1002                                lex_entire=True)
1003         print source
1004
1005
1006 class CyPrint(CythonCommand):
1007     """
1008     Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
1009     """
1010     
1011     name = 'cy print'
1012     command_class = gdb.COMMAND_DATA
1013     
1014     def invoke(self, name, from_tty, max_name_length=None):
1015         if self.is_python_function():
1016             return gdb.execute('py-print ' + name)
1017         elif self.is_cython_function():
1018             value = self.cy.cy_cvalue.invoke(name.lstrip('*'))
1019             for c in name:
1020                 if c == '*':
1021                     value = value.dereference()
1022                 else:
1023                     break
1024                 
1025             self.print_gdb_value(name, value, max_name_length)
1026         else:
1027             gdb.execute('print ' + name)
1028         
1029     def complete(self):
1030         if self.is_cython_function():
1031             f = self.get_cython_function()
1032             return list(itertools.chain(f.locals, f.globals))
1033         else:
1034             return []
1035
1036
1037 sortkey = lambda (name, value): name.lower()
1038
1039 class CyLocals(CythonCommand):
1040     """
1041     List the locals from the current Cython frame.
1042     """
1043     
1044     name = 'cy locals'
1045     command_class = gdb.COMMAND_STACK
1046     completer_class = gdb.COMPLETE_NONE
1047     
1048     def _print_if_initialized(self, cyvar, max_name_length, prefix=''):
1049         try:
1050             value = gdb.parse_and_eval(cyvar.cname)
1051         except RuntimeError:
1052             # variable not initialized yet
1053             pass
1054         else:
1055             self.print_gdb_value(cyvar.name, value, max_name_length, prefix)
1056     
1057     @dispatch_on_frame(c_command='info locals', python_command='py-locals')
1058     def invoke(self, args, from_tty):
1059         local_cython_vars = self.get_cython_function().locals
1060         max_name_length = len(max(local_cython_vars, key=len))
1061         for name, cyvar in sorted(local_cython_vars.iteritems(), key=sortkey):
1062             self._print_if_initialized(cyvar, max_name_length)
1063
1064
1065 class CyGlobals(CyLocals):
1066     """
1067     List the globals from the current Cython module.
1068     """
1069     
1070     name = 'cy globals'
1071     command_class = gdb.COMMAND_STACK
1072     completer_class = gdb.COMPLETE_NONE
1073     
1074     @dispatch_on_frame(c_command='info variables', python_command='py-globals')
1075     def invoke(self, args, from_tty):
1076         global_python_dict = self.get_cython_globals_dict()
1077         module_globals = self.get_cython_function().module.globals
1078         
1079         max_globals_len = 0
1080         max_globals_dict_len = 0
1081         if module_globals:
1082             max_globals_len = len(max(module_globals, key=len))
1083         if global_python_dict:
1084             max_globals_dict_len = len(max(global_python_dict))
1085             
1086         max_name_length = max(max_globals_len, max_globals_dict_len)
1087         
1088         seen = set()
1089         print 'Python globals:'
1090         for k, v in sorted(global_python_dict.iteritems(), key=sortkey):
1091             v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
1092             seen.add(k)
1093             print '    %-*s = %s' % (max_name_length, k, v)
1094         
1095         print 'C globals:'
1096         for name, cyvar in sorted(module_globals.iteritems(), key=sortkey):
1097             if name not in seen:
1098                 self._print_if_initialized(cyvar, max_name_length, 
1099                                            prefix='    ')
1100
1101
1102 class CyExec(CythonCommand):
1103     name = '-cy-exec'
1104     command_class = gdb.COMMAND_STACK
1105     completer_class = gdb.COMPLETE_NONE
1106     
1107     def _fill_locals_dict(self, executor, local_dict_pointer):
1108         "Fill a remotely allocated dict with values from the Cython C stack"
1109         cython_func = self.get_cython_function()
1110         
1111         for name, cyvar in cython_func.locals.iteritems():
1112             if cyvar.type == PythonObject:
1113                 # skip unitialized Cython variables 
1114                 try:
1115                     val = gdb.parse_and_eval(cyvar.cname)
1116                 except RuntimeError:
1117                     continue
1118                 else:
1119                     # Fortunately, Cython initializes all local (automatic)
1120                     # variables to NULL
1121                     if libpython.pointervalue(val) == 0:
1122                         continue
1123
1124                 pystringp = executor.alloc_pystring(name)
1125                 code = '''
1126                     PyDict_SetItem(
1127                         (PyObject *) %d, 
1128                         (PyObject *) %d, 
1129                         (PyObject *) %s)
1130                 ''' % (local_dict_pointer, pystringp, cyvar.cname)
1131                 
1132                 # PyDict_SetItem doesn't steal our reference
1133                 executor.decref(pystringp)
1134                 
1135                 if gdb.parse_and_eval(code) < 0:
1136                     gdb.parse_and_eval('PyErr_Print()')
1137                     raise gdb.GdbError("Unable to execute Python code.")
1138     
1139     def _find_first_cython_or_python_frame(self):
1140         frame = gdb.selected_frame()
1141         while frame:
1142             if (self.is_cython_function(frame) or 
1143                 self.is_python_function(frame)):
1144                 return frame
1145             
1146             frame = frame.older()
1147         
1148         raise gdb.GdbError("There is no Cython or Python frame on the stack.")
1149         
1150     def invoke(self, expr, from_tty):
1151         frame = self._find_first_cython_or_python_frame()
1152         if self.is_python_function(frame):
1153             libpython.py_exec.invoke(expr, from_tty)
1154             return
1155         
1156         executor = libpython.PythonCodeExecutor()
1157         
1158         # get the dict of Cython globals and construct a dict in the inferior
1159         # with Cython locals
1160         global_dict = gdb.parse_and_eval(
1161             '(PyObject *) PyModule_GetDict(__pyx_m)')
1162         local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
1163         
1164         try:
1165             self._fill_locals_dict(executor, libpython.pointervalue(local_dict))
1166             executor.evalcode(expr, global_dict, local_dict)
1167         finally:
1168             executor.decref(libpython.pointervalue(local_dict))
1169
1170
1171 # Functions
1172
1173 class CyCName(gdb.Function, CythonBase):
1174     """
1175     Get the C name of a Cython variable in the current context.
1176     Examples:
1177         
1178         print $cy_cname("function")
1179         print $cy_cname("Class.method")
1180         print $cy_cname("module.function")
1181     """
1182     
1183     @require_cython_frame
1184     @gdb_function_value_to_unicode
1185     def invoke(self, cyname, frame=None):
1186         frame = frame or gdb.selected_frame()
1187         cname = None
1188         
1189         if self.is_cython_function(frame):
1190             cython_function = self.get_cython_function(frame)
1191             if cyname in cython_function.locals:
1192                 cname = cython_function.locals[cyname].cname
1193             elif cyname in cython_function.module.globals:
1194                 cname = cython_function.module.globals[cyname].cname
1195             else:
1196                 qname = '%s.%s' % (cython_function.module.name, cyname)
1197                 if qname in cython_function.module.functions:
1198                     cname = cython_function.module.functions[qname].cname
1199             
1200         if not cname:
1201             cname = self.cy.functions_by_qualified_name.get(cyname)
1202             
1203         if not cname:
1204             raise gdb.GdbError('No such Cython variable: %s' % cyname)
1205         
1206         return cname
1207
1208
1209 class CyCValue(CyCName):
1210     """
1211     Get the value of a Cython variable.
1212     """
1213     
1214     @require_cython_frame
1215     @gdb_function_value_to_unicode
1216     def invoke(self, cyname, frame=None):
1217         try:
1218             cname = super(CyCValue, self).invoke(cyname, frame=frame)
1219             return gdb.parse_and_eval(cname)
1220         except (gdb.GdbError, RuntimeError):
1221             # variable exists but may not have been initialized yet, or may be
1222             # in the globals dict of the Cython module
1223             d = self.get_cython_globals_dict()
1224             if cyname in d:
1225                 return d[cyname]._gdbval
1226
1227             raise gdb.GdbError("Variable %s not initialized yet." % cyname)
1228
1229
1230 class CyLine(gdb.Function, CythonBase):
1231     """
1232     Get the current Cython line.
1233     """
1234     
1235     @require_cython_frame
1236     def invoke(self):
1237         return self.get_cython_lineno()
1238
1239
1240 cy = CyCy.register()