2 GDB extension that adds Cython support.
5 from __future__
import with_statement
17 from lxml
import etree
23 from xml
.etree
import cElementTree
as etree
27 from xml
.etree
import ElementTree
as etree
30 # normal cElementTree install
31 import cElementTree
as etree
33 # normal ElementTree install
34 import elementtree
.ElementTree
as etree
37 import pygments
.lexers
38 import pygments
.formatters
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
46 from shlex
import split
as string_to_argv
48 from Cython
.Debugger
import libpython
52 PythonObject
= 'PythonObject'
54 _data_types
= dict(CObject
=CObject
, PythonObject
=PythonObject
)
55 _filesystemencoding
= sys
.getfilesystemencoding() or 'UTF-8'
59 def dont_suppress_errors(function
):
61 @functools.wraps(function
)
62 def wrapper(*args
, **kwargs
):
64 return function(*args
, **kwargs
)
71 def default_selected_gdb_frame(err
=True):
72 def decorator(function
):
73 @functools.wraps(function
)
74 def wrapper(self
, frame
=None, *args
, **kwargs
):
76 frame
= frame
or gdb
.selected_frame()
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
)
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
)
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
)
108 gdb
.execute(python_command
)
109 elif self
.is_relevant_function():
110 gdb
.execute(c_command
)
112 raise gdb
.GdbError("Not a function cygdb knows about. "
113 "Use the normal GDB commands instead.")
118 def require_running_program(function
):
119 @functools.wraps(function
)
120 def wrapper(*args
, **kwargs
):
124 raise gdb
.GdbError("No frame is currently selected.")
126 return function(*args
, **kwargs
)
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
)
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
149 # {cython_lineno: min(c_linenos)}
150 self
.lineno_cy2c
= {}
151 # {c_lineno: cython_lineno}
152 self
.lineno_c2cy
= {}
155 class CythonVariable(object):
157 def __init__(self
, name
, cname
, qualified_name
, type, lineno
):
160 self
.qualified_name
= qualified_name
162 self
.lineno
= int(lineno
)
164 class CythonFunction(CythonVariable
):
173 is_initmodule_function
="False"):
174 super(CythonFunction
, self
).__init
__(name
,
180 self
.pf_cname
= pf_cname
181 self
.is_initmodule_function
= is_initmodule_function
== "True"
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()
206 @default_selected_gdb_frame()
207 def get_c_function_name(self
, frame
):
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())
218 raise NoCythonFunctionInFrameError()
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
)
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
:
244 'Unable to read information on python frame')
246 filename
= pyframeobject
.filename()
247 lineno
= pyframeobject
.current_line_num()
250 lexer
= pygments
.lexers
.PythonLexer(stripall
=False)
252 symbol_and_line_obj
= frame
.find_sal()
253 if not symbol_and_line_obj
or not symbol_and_line_obj
.symtab
:
257 filename
= symbol_and_line_obj
.symtab
.fullname()
258 lineno
= symbol_and_line_obj
.line
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
276 older_frame
= frame
.older()
277 if self
.is_cython_function(frame
) or self
.is_python_function(frame
):
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
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
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()
298 source_desc
, lineno
= self
.get_source_desc(frame
)
299 except NoFunctionNameInFrameError
:
300 print '#%-2d Unknown Frame (compile with -g)' % index
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'
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]
320 source_desc
, lineno
= self
.get_source_desc(frame
)
321 func_name
= frame
.name()
322 func_cname
= func_name
326 gdb_value
= gdb
.parse_and_eval(func_cname
)
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
),
342 print ' ' + source_desc
.get_source(lineno
)
346 selected_frame
.select()
348 def get_remote_cython_globals_dict(self
):
349 m
= gdb
.parse_and_eval('__pyx_m')
352 PyModuleObject
= gdb
.lookup_type('PyModuleObject')
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())
362 def get_cython_globals_dict(self
):
364 Get the Cython globals dict where the remote names are turned into
367 remote_dict
= self
.get_remote_cython_globals_dict()
368 pyobject_dict
= libpython
.PyObjectPtr
.from_pyobject_ptr(remote_dict
)
372 for k
, v
in pyobject_dict
.iteritems():
373 result
[k
.proxyval(seen
)] = v
377 def print_gdb_value(self
, name
, value
, max_name_length
=None, prefix
=''):
378 if libpython
.pretty_printer_lookup(value
):
381 typename
= '(%s) ' % (value
.type,)
383 if max_name_length
is None:
384 print '%s%s = %s%s' % (prefix
, name
, typename
, value
)
386 print '%s%-*s = %s%s' % (prefix
, max_name_length
, name
, typename
,
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
))
401 return cur_lineno
> cyvar
.lineno
404 class SourceFileDescriptor(object):
405 def __init__(self
, filename
, lexer
, formatter
=None):
406 self
.filename
= filename
408 self
.formatter
= formatter
411 return self
.filename
is not None
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
)
419 formatter
= self
.formatter
421 return pygments
.highlight(code
, self
.lexer
, formatter
)
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
:
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,
449 exc
= gdb
.GdbError('Unable to retrieve source code')
451 if not self
.filename
:
454 start
= max(start
, 1)
460 self
._get
_source
(start
, stop
, lex_source
, mark_line
, lex_entire
))
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
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 '
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
,
503 if default
is not None:
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).
533 self
.complete_unqualified
= CompleteUnqualifiedFunctionNames(
534 'cy_complete_unqualified',
535 gdb
.COMMAND_BREAKPOINTS
,
538 self
.colorize_code
= ColorizeSourceCode(
543 self
.terminal_background
= TerminalBackground(
544 'cy_terminal_background_color',
549 parameters
= CythonParameters()
554 class CythonCommand(gdb
.Command
, CythonBase
):
556 Base class for Cython commands
559 command_class
= gdb
.COMMAND_NONE
562 def _register(cls
, clsname
, args
, kwargs
):
563 if not hasattr(cls
, 'completer_class'):
564 return cls(clsname
, cls
.command_class
, *args
, **kwargs
)
566 return cls(clsname
, cls
.command_class
, cls
.completer_class
,
570 def register(cls
, *args
, **kwargs
):
571 alias
= getattr(cls
, 'alias', None)
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:
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)
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(),
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():
640 setattr(self
, command_name
, command
)
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...
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
):
675 raise gdb
.GdbError('Unable to open file %r: %s' %
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'):
686 cython_module
.globals[d
['name']] = CythonVariable(**d
)
688 for function
in module
.find('Functions'):
689 cython_function
= CythonFunction(module
=cython_module
,
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'):
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...
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'
748 command_class
= gdb
.COMMAND_BREAKPOINTS
750 def _break_pyx(self
, name
):
751 modulename
, _
, lineno
= name
.partition(':')
754 cython_module
= self
.cy
.cython_namespace
[modulename
]
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
)
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
:
775 funcs
= self
.cy
.functions_by_name
.get(funcname
) or []
776 funcs
= [f
for f
in funcs
if not f
.is_initmodule_function
]
779 gdb
.execute('break ' + funcname
)
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
)
791 "Select a function, press 'a' for all "
792 "functions or press 'q' or '^D' to quit: ")
796 if result
.lower() == 'q':
798 elif result
.lower() == 'a':
801 elif (result
.isdigit() and
802 0 <= int(result
) < len(funcs
)):
803 break_funcs
= [funcs
[int(result
)]]
806 print 'Not understood...'
808 break_funcs
= [funcs
[0]]
810 for func
in break_funcs
:
811 gdb
.execute('break %s' % func
.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'):
819 python_breakpoints
= True
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
)
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
)
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
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
]
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
):
881 line
= super(CythonInfo
, self
).get_source_line(frame
)
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
896 def static_break_functions(self
):
897 result
= ['PyEval_EvalFrameEx']
898 result
.extend(self
.cy
.functions_by_cname
)
902 class CythonExecutionControlCommand(CythonCommand
,
903 libpython
.ExecutionControlCommandBase
):
907 return cls(cls
.name
, cython_info
)
910 class CyStep(CythonExecutionControlCommand
, libpython
.PythonStepperMixin
):
911 "Step through Cython, Python or C code."
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():
925 self
.finish_executing(gdb
.execute(command
, to_string
=True))
927 self
.step(stepinto
=self
.stepinto
)
930 class CyNext(CyStep
):
931 "Step-over Cython, Python or C code."
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
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.
955 invoke
= CythonExecutionControlCommand
.cont
958 class CyFinish(CythonExecutionControlCommand
):
960 Execute until the function returns.
964 invoke
= CythonExecutionControlCommand
.finish
967 class CyUp(CythonCommand
):
969 Go up a Cython, Python or relevant C frame.
974 def invoke(self
, *args
):
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()
985 frame
= frame
.older()
988 self
.print_stackframe(index
=index
- 1)
993 Go down a Cython, Python or relevant C frame.
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.
1008 def invoke(self
, stackno
, from_tty
):
1010 stackno
= int(stackno
)
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
)
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'
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'
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()
1057 class CyList(CythonCommand
):
1059 List Cython source code. To disable to customize colouring see the cy_*
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
,
1075 class CyPrint(CythonCommand
):
1077 Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
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('*'))
1090 value
= value
.dereference()
1094 self
.print_gdb_value(name
, value
, max_name_length
)
1096 gdb
.execute('print ' + name
)
1099 if self
.is_cython_function():
1100 f
= self
.get_cython_function()
1101 return list(itertools
.chain(f
.locals, f
.globals))
1106 sortkey
= lambda (name
, value
): name
.lower()
1108 class CyLocals(CythonCommand
):
1110 List the locals from the current Cython frame.
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
)
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.
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
1150 max_globals_dict_len
= 0
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
)
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
)
1163 print ' %-*s = %s' % (max_name_length
, k
, v
)
1166 for name
, cyvar
in sorted(module_globals
.iteritems(), key
=sortkey
):
1167 if name
not in seen
:
1169 value
= gdb
.parse_and_eval(cyvar
.cname
)
1170 except RuntimeError:
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
)):
1195 val
= gdb
.parse_and_eval(cyvar
.cname
)
1196 except RuntimeError:
1199 if val
.is_optimized_out
:
1202 pystringp
= executor
.alloc_pystring(name
)
1204 (PyObject *) PyDict_SetItem(
1208 ''' % (local_dict_pointer
, pystringp
, cyvar
.cname
)
1211 if gdb
.parse_and_eval(code
) < 0:
1212 gdb
.parse_and_eval('PyErr_Print()')
1213 raise gdb
.GdbError("Unable to execute Python code.")
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()
1221 if (self
.is_cython_function(frame
) or
1222 self
.is_python_function(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()')
1240 self
._fill
_locals
_dict
(executor
,
1241 libpython
.pointervalue(local_dict
))
1242 result
= executor
.evalcode(code
, input_type
, global_dict
,
1245 executor
.xdecref(libpython
.pointervalue(local_dict
))
1249 def evalcode(self
, code
, input_type
):
1251 Evaluate `code` in a Python or Cython stack frame using the given
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.
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
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
))
1305 class CyCName(gdb
.Function
, CythonBase
):
1307 Get the C name of a Cython variable in the current context.
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()
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
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
1333 cname
= self
.cy
.functions_by_qualified_name
.get(cyname
)
1336 raise gdb
.GdbError('No such Cython variable: %s' % cyname
)
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
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
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()
1386 def register_defines():
1387 libpython
.source_gdb_script(textwrap
.dedent("""\
1403 """) % (CyStep
.__doc
__, CyNext
.__doc
__))