Cython 3.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. Cython/Build/BuildExecutable.py +169 -0
  2. Cython/Build/Cache.py +199 -0
  3. Cython/Build/Cythonize.py +250 -0
  4. Cython/Build/Dependencies.py +1275 -0
  5. Cython/Build/Distutils.py +1 -0
  6. Cython/Build/Inline.py +342 -0
  7. Cython/Build/IpythonMagic.py +560 -0
  8. Cython/Build/Tests/TestCyCache.py +119 -0
  9. Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
  10. Cython/Build/Tests/TestDependencies.py +133 -0
  11. Cython/Build/Tests/TestInline.py +112 -0
  12. Cython/Build/Tests/TestIpythonMagic.py +287 -0
  13. Cython/Build/Tests/TestRecythonize.py +212 -0
  14. Cython/Build/Tests/TestStripLiterals.py +155 -0
  15. Cython/Build/Tests/__init__.py +1 -0
  16. Cython/Build/__init__.py +8 -0
  17. Cython/CodeWriter.py +811 -0
  18. Cython/Compiler/AnalysedTreeTransforms.py +97 -0
  19. Cython/Compiler/Annotate.py +326 -0
  20. Cython/Compiler/AutoDocTransforms.py +314 -0
  21. Cython/Compiler/Buffer.py +680 -0
  22. Cython/Compiler/Builtin.py +862 -0
  23. Cython/Compiler/CmdLine.py +243 -0
  24. Cython/Compiler/Code.pxd +145 -0
  25. Cython/Compiler/Code.py +3328 -0
  26. Cython/Compiler/CodeGeneration.py +33 -0
  27. Cython/Compiler/CythonScope.py +179 -0
  28. Cython/Compiler/Dataclass.py +868 -0
  29. Cython/Compiler/DebugFlags.py +21 -0
  30. Cython/Compiler/Errors.py +295 -0
  31. Cython/Compiler/ExprNodes.py +15051 -0
  32. Cython/Compiler/FlowControl.pxd +97 -0
  33. Cython/Compiler/FlowControl.py +1438 -0
  34. Cython/Compiler/FusedNode.py +998 -0
  35. Cython/Compiler/Future.py +16 -0
  36. Cython/Compiler/Interpreter.py +57 -0
  37. Cython/Compiler/Lexicon.py +340 -0
  38. Cython/Compiler/LineTable.py +114 -0
  39. Cython/Compiler/Main.py +779 -0
  40. Cython/Compiler/MatchCaseNodes.py +259 -0
  41. Cython/Compiler/MemoryView.py +860 -0
  42. Cython/Compiler/ModuleNode.py +4065 -0
  43. Cython/Compiler/Naming.py +369 -0
  44. Cython/Compiler/Nodes.py +10557 -0
  45. Cython/Compiler/Optimize.py +5269 -0
  46. Cython/Compiler/Options.py +828 -0
  47. Cython/Compiler/ParseTreeTransforms.pxd +78 -0
  48. Cython/Compiler/ParseTreeTransforms.py +4441 -0
  49. Cython/Compiler/Parsing.pxd +9 -0
  50. Cython/Compiler/Parsing.py +4797 -0
  51. Cython/Compiler/Pipeline.py +425 -0
  52. Cython/Compiler/PyrexTypes.py +5572 -0
  53. Cython/Compiler/Pythran.py +223 -0
  54. Cython/Compiler/Scanning.pxd +40 -0
  55. Cython/Compiler/Scanning.py +574 -0
  56. Cython/Compiler/StringEncoding.py +347 -0
  57. Cython/Compiler/Symtab.py +2998 -0
  58. Cython/Compiler/Tests/TestBuffer.py +105 -0
  59. Cython/Compiler/Tests/TestBuiltin.py +72 -0
  60. Cython/Compiler/Tests/TestCmdLine.py +573 -0
  61. Cython/Compiler/Tests/TestCode.py +86 -0
  62. Cython/Compiler/Tests/TestFlowControl.py +65 -0
  63. Cython/Compiler/Tests/TestGrammar.py +202 -0
  64. Cython/Compiler/Tests/TestMemView.py +71 -0
  65. Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
  66. Cython/Compiler/Tests/TestScanning.py +134 -0
  67. Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
  68. Cython/Compiler/Tests/TestStringEncoding.py +33 -0
  69. Cython/Compiler/Tests/TestTreeFragment.py +63 -0
  70. Cython/Compiler/Tests/TestTreePath.py +93 -0
  71. Cython/Compiler/Tests/TestTypes.py +75 -0
  72. Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
  73. Cython/Compiler/Tests/TestVisitor.py +61 -0
  74. Cython/Compiler/Tests/Utils.py +36 -0
  75. Cython/Compiler/Tests/__init__.py +1 -0
  76. Cython/Compiler/TreeFragment.py +278 -0
  77. Cython/Compiler/TreePath.py +290 -0
  78. Cython/Compiler/TypeInference.py +584 -0
  79. Cython/Compiler/TypeSlots.py +1181 -0
  80. Cython/Compiler/UFuncs.py +311 -0
  81. Cython/Compiler/UtilNodes.py +387 -0
  82. Cython/Compiler/UtilityCode.py +274 -0
  83. Cython/Compiler/Version.py +8 -0
  84. Cython/Compiler/Visitor.pxd +53 -0
  85. Cython/Compiler/Visitor.py +861 -0
  86. Cython/Compiler/__init__.py +1 -0
  87. Cython/Coverage.py +443 -0
  88. Cython/Debugger/Cygdb.py +179 -0
  89. Cython/Debugger/DebugWriter.py +82 -0
  90. Cython/Debugger/Tests/TestLibCython.py +275 -0
  91. Cython/Debugger/Tests/__init__.py +1 -0
  92. Cython/Debugger/Tests/cfuncs.c +8 -0
  93. Cython/Debugger/Tests/codefile +49 -0
  94. Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
  95. Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
  96. Cython/Debugger/__init__.py +1 -0
  97. Cython/Debugger/libcython.py +1549 -0
  98. Cython/Debugger/libpython.py +2821 -0
  99. Cython/Debugging.py +20 -0
  100. Cython/Distutils/__init__.py +2 -0
  101. Cython/Distutils/build_ext.py +137 -0
  102. Cython/Distutils/extension.py +96 -0
  103. Cython/Distutils/old_build_ext.py +351 -0
  104. Cython/Includes/cpython/__init__.pxd +173 -0
  105. Cython/Includes/cpython/array.pxd +174 -0
  106. Cython/Includes/cpython/bool.pxd +37 -0
  107. Cython/Includes/cpython/buffer.pxd +112 -0
  108. Cython/Includes/cpython/bytearray.pxd +33 -0
  109. Cython/Includes/cpython/bytes.pxd +200 -0
  110. Cython/Includes/cpython/cellobject.pxd +35 -0
  111. Cython/Includes/cpython/ceval.pxd +8 -0
  112. Cython/Includes/cpython/codecs.pxd +121 -0
  113. Cython/Includes/cpython/complex.pxd +55 -0
  114. Cython/Includes/cpython/contextvars.pxd +141 -0
  115. Cython/Includes/cpython/conversion.pxd +36 -0
  116. Cython/Includes/cpython/datetime.pxd +384 -0
  117. Cython/Includes/cpython/descr.pxd +26 -0
  118. Cython/Includes/cpython/dict.pxd +187 -0
  119. Cython/Includes/cpython/exc.pxd +263 -0
  120. Cython/Includes/cpython/fileobject.pxd +57 -0
  121. Cython/Includes/cpython/float.pxd +47 -0
  122. Cython/Includes/cpython/function.pxd +65 -0
  123. Cython/Includes/cpython/genobject.pxd +25 -0
  124. Cython/Includes/cpython/getargs.pxd +12 -0
  125. Cython/Includes/cpython/instance.pxd +25 -0
  126. Cython/Includes/cpython/iterator.pxd +36 -0
  127. Cython/Includes/cpython/iterobject.pxd +24 -0
  128. Cython/Includes/cpython/list.pxd +92 -0
  129. Cython/Includes/cpython/long.pxd +149 -0
  130. Cython/Includes/cpython/longintrepr.pxd +19 -0
  131. Cython/Includes/cpython/mapping.pxd +63 -0
  132. Cython/Includes/cpython/marshal.pxd +66 -0
  133. Cython/Includes/cpython/mem.pxd +120 -0
  134. Cython/Includes/cpython/memoryview.pxd +50 -0
  135. Cython/Includes/cpython/method.pxd +49 -0
  136. Cython/Includes/cpython/module.pxd +208 -0
  137. Cython/Includes/cpython/number.pxd +258 -0
  138. Cython/Includes/cpython/object.pxd +433 -0
  139. Cython/Includes/cpython/pycapsule.pxd +143 -0
  140. Cython/Includes/cpython/pylifecycle.pxd +68 -0
  141. Cython/Includes/cpython/pyport.pxd +8 -0
  142. Cython/Includes/cpython/pystate.pxd +95 -0
  143. Cython/Includes/cpython/pythread.pxd +53 -0
  144. Cython/Includes/cpython/ref.pxd +67 -0
  145. Cython/Includes/cpython/sequence.pxd +134 -0
  146. Cython/Includes/cpython/set.pxd +119 -0
  147. Cython/Includes/cpython/slice.pxd +70 -0
  148. Cython/Includes/cpython/time.pxd +129 -0
  149. Cython/Includes/cpython/tuple.pxd +72 -0
  150. Cython/Includes/cpython/type.pxd +53 -0
  151. Cython/Includes/cpython/unicode.pxd +639 -0
  152. Cython/Includes/cpython/version.pxd +32 -0
  153. Cython/Includes/cpython/weakref.pxd +42 -0
  154. Cython/Includes/libc/__init__.pxd +1 -0
  155. Cython/Includes/libc/complex.pxd +35 -0
  156. Cython/Includes/libc/errno.pxd +127 -0
  157. Cython/Includes/libc/float.pxd +43 -0
  158. Cython/Includes/libc/limits.pxd +28 -0
  159. Cython/Includes/libc/locale.pxd +46 -0
  160. Cython/Includes/libc/math.pxd +209 -0
  161. Cython/Includes/libc/setjmp.pxd +10 -0
  162. Cython/Includes/libc/signal.pxd +64 -0
  163. Cython/Includes/libc/stddef.pxd +9 -0
  164. Cython/Includes/libc/stdint.pxd +105 -0
  165. Cython/Includes/libc/stdio.pxd +80 -0
  166. Cython/Includes/libc/stdlib.pxd +72 -0
  167. Cython/Includes/libc/string.pxd +50 -0
  168. Cython/Includes/libc/time.pxd +47 -0
  169. Cython/Includes/libcpp/__init__.pxd +4 -0
  170. Cython/Includes/libcpp/algorithm.pxd +320 -0
  171. Cython/Includes/libcpp/any.pxd +16 -0
  172. Cython/Includes/libcpp/atomic.pxd +59 -0
  173. Cython/Includes/libcpp/bit.pxd +29 -0
  174. Cython/Includes/libcpp/cast.pxd +12 -0
  175. Cython/Includes/libcpp/cmath.pxd +518 -0
  176. Cython/Includes/libcpp/complex.pxd +106 -0
  177. Cython/Includes/libcpp/deque.pxd +165 -0
  178. Cython/Includes/libcpp/execution.pxd +15 -0
  179. Cython/Includes/libcpp/forward_list.pxd +63 -0
  180. Cython/Includes/libcpp/functional.pxd +26 -0
  181. Cython/Includes/libcpp/iterator.pxd +34 -0
  182. Cython/Includes/libcpp/limits.pxd +61 -0
  183. Cython/Includes/libcpp/list.pxd +117 -0
  184. Cython/Includes/libcpp/map.pxd +252 -0
  185. Cython/Includes/libcpp/memory.pxd +115 -0
  186. Cython/Includes/libcpp/numbers.pxd +15 -0
  187. Cython/Includes/libcpp/numeric.pxd +131 -0
  188. Cython/Includes/libcpp/optional.pxd +34 -0
  189. Cython/Includes/libcpp/pair.pxd +1 -0
  190. Cython/Includes/libcpp/queue.pxd +25 -0
  191. Cython/Includes/libcpp/random.pxd +166 -0
  192. Cython/Includes/libcpp/set.pxd +228 -0
  193. Cython/Includes/libcpp/stack.pxd +11 -0
  194. Cython/Includes/libcpp/string.pxd +333 -0
  195. Cython/Includes/libcpp/typeindex.pxd +15 -0
  196. Cython/Includes/libcpp/typeinfo.pxd +10 -0
  197. Cython/Includes/libcpp/unordered_map.pxd +193 -0
  198. Cython/Includes/libcpp/unordered_set.pxd +152 -0
  199. Cython/Includes/libcpp/utility.pxd +30 -0
  200. Cython/Includes/libcpp/vector.pxd +167 -0
  201. Cython/Includes/openmp.pxd +50 -0
  202. Cython/Includes/posix/__init__.pxd +1 -0
  203. Cython/Includes/posix/dlfcn.pxd +14 -0
  204. Cython/Includes/posix/fcntl.pxd +86 -0
  205. Cython/Includes/posix/ioctl.pxd +4 -0
  206. Cython/Includes/posix/mman.pxd +101 -0
  207. Cython/Includes/posix/resource.pxd +57 -0
  208. Cython/Includes/posix/select.pxd +21 -0
  209. Cython/Includes/posix/signal.pxd +73 -0
  210. Cython/Includes/posix/stat.pxd +98 -0
  211. Cython/Includes/posix/stdio.pxd +37 -0
  212. Cython/Includes/posix/stdlib.pxd +29 -0
  213. Cython/Includes/posix/strings.pxd +9 -0
  214. Cython/Includes/posix/time.pxd +71 -0
  215. Cython/Includes/posix/types.pxd +30 -0
  216. Cython/Includes/posix/uio.pxd +26 -0
  217. Cython/Includes/posix/unistd.pxd +271 -0
  218. Cython/Includes/posix/wait.pxd +38 -0
  219. Cython/Plex/Actions.pxd +24 -0
  220. Cython/Plex/Actions.py +119 -0
  221. Cython/Plex/DFA.pxd +14 -0
  222. Cython/Plex/DFA.py +164 -0
  223. Cython/Plex/Errors.py +48 -0
  224. Cython/Plex/Lexicons.py +178 -0
  225. Cython/Plex/Machines.pxd +36 -0
  226. Cython/Plex/Machines.py +238 -0
  227. Cython/Plex/Regexps.py +539 -0
  228. Cython/Plex/Scanners.pxd +47 -0
  229. Cython/Plex/Scanners.py +360 -0
  230. Cython/Plex/Transitions.pxd +14 -0
  231. Cython/Plex/Transitions.py +239 -0
  232. Cython/Plex/__init__.py +34 -0
  233. Cython/Runtime/__init__.py +1 -0
  234. Cython/Runtime/refnanny.pyx +261 -0
  235. Cython/Shadow.py +656 -0
  236. Cython/Shadow.pyi +521 -0
  237. Cython/StringIOTree.py +170 -0
  238. Cython/Tempita/__init__.py +4 -0
  239. Cython/Tempita/_looper.py +154 -0
  240. Cython/Tempita/_tempita.py +1091 -0
  241. Cython/TestUtils.py +417 -0
  242. Cython/Tests/TestCodeWriter.py +128 -0
  243. Cython/Tests/TestCythonUtils.py +202 -0
  244. Cython/Tests/TestJediTyper.py +223 -0
  245. Cython/Tests/TestShadow.py +114 -0
  246. Cython/Tests/TestStringIOTree.py +67 -0
  247. Cython/Tests/TestTestUtils.py +90 -0
  248. Cython/Tests/__init__.py +1 -0
  249. Cython/Tests/xmlrunner.py +390 -0
  250. Cython/Utility/AsyncGen.c +1263 -0
  251. Cython/Utility/Buffer.c +875 -0
  252. Cython/Utility/Builtins.c +660 -0
  253. Cython/Utility/CConvert.pyx +134 -0
  254. Cython/Utility/CMath.c +95 -0
  255. Cython/Utility/CommonStructures.c +139 -0
  256. Cython/Utility/Complex.c +378 -0
  257. Cython/Utility/Coroutine.c +2413 -0
  258. Cython/Utility/CpdefEnums.pyx +108 -0
  259. Cython/Utility/CppConvert.pyx +279 -0
  260. Cython/Utility/CppSupport.cpp +133 -0
  261. Cython/Utility/CythonFunction.c +1851 -0
  262. Cython/Utility/Dataclasses.c +185 -0
  263. Cython/Utility/Dataclasses.py +112 -0
  264. Cython/Utility/Embed.c +125 -0
  265. Cython/Utility/Exceptions.c +1017 -0
  266. Cython/Utility/ExtensionTypes.c +797 -0
  267. Cython/Utility/FunctionArguments.c +573 -0
  268. Cython/Utility/ImportExport.c +912 -0
  269. Cython/Utility/MemoryView.pyx +1478 -0
  270. Cython/Utility/MemoryView_C.c +992 -0
  271. Cython/Utility/ModuleSetupCode.c +2501 -0
  272. Cython/Utility/NumpyImportArray.c +46 -0
  273. Cython/Utility/ObjectHandling.c +3054 -0
  274. Cython/Utility/Optimize.c +1533 -0
  275. Cython/Utility/Overflow.c +404 -0
  276. Cython/Utility/Printing.c +86 -0
  277. Cython/Utility/Profile.c +660 -0
  278. Cython/Utility/StringTools.c +1206 -0
  279. Cython/Utility/TestCyUtilityLoader.pyx +8 -0
  280. Cython/Utility/TestCythonScope.pyx +75 -0
  281. Cython/Utility/TestUtilityLoader.c +12 -0
  282. Cython/Utility/TypeConversion.c +1329 -0
  283. Cython/Utility/UFuncs.pyx +50 -0
  284. Cython/Utility/UFuncs_C.c +89 -0
  285. Cython/Utility/__init__.py +28 -0
  286. Cython/Utility/arrayarray.h +143 -0
  287. Cython/Utils.py +687 -0
  288. Cython/__init__.py +10 -0
  289. Cython/__init__.pyi +7 -0
  290. Cython/py.typed +0 -0
  291. Cython-3.1.0a1.dist-info/COPYING.txt +19 -0
  292. Cython-3.1.0a1.dist-info/LICENSE.txt +176 -0
  293. Cython-3.1.0a1.dist-info/METADATA +67 -0
  294. Cython-3.1.0a1.dist-info/RECORD +301 -0
  295. Cython-3.1.0a1.dist-info/WHEEL +5 -0
  296. Cython-3.1.0a1.dist-info/entry_points.txt +4 -0
  297. Cython-3.1.0a1.dist-info/top_level.txt +3 -0
  298. cython.py +29 -0
  299. pyximport/__init__.py +4 -0
  300. pyximport/pyxbuild.py +160 -0
  301. pyximport/pyximport.py +482 -0
@@ -0,0 +1,1549 @@
1
+ """
2
+ GDB extension that adds Cython support.
3
+ """
4
+
5
+
6
+ import sys
7
+ import textwrap
8
+ import functools
9
+ import itertools
10
+ import collections
11
+
12
+ import gdb
13
+
14
+ try:
15
+ from lxml import etree
16
+ have_lxml = True
17
+ except ImportError:
18
+ from xml.etree import ElementTree as etree
19
+ have_lxml = False
20
+
21
+ try:
22
+ import pygments.lexers
23
+ import pygments.formatters
24
+ except ImportError:
25
+ pygments = None
26
+ sys.stderr.write("Install pygments for colorized source code.\n")
27
+
28
+ if hasattr(gdb, 'string_to_argv'):
29
+ from gdb import string_to_argv
30
+ else:
31
+ from shlex import split as string_to_argv
32
+
33
+ from Cython.Debugger import libpython
34
+
35
+ # C or Python type
36
+ CObject = 'CObject'
37
+ PythonObject = 'PythonObject'
38
+
39
+ _data_types = dict(CObject=CObject, PythonObject=PythonObject)
40
+ _filesystemencoding = sys.getfilesystemencoding() or 'UTF-8'
41
+
42
+
43
+ # decorators
44
+
45
+ def default_selected_gdb_frame(err=True):
46
+ def decorator(function):
47
+ @functools.wraps(function)
48
+ def wrapper(self, frame=None, *args, **kwargs):
49
+ try:
50
+ frame = frame or gdb.selected_frame()
51
+ except RuntimeError:
52
+ raise gdb.GdbError("No frame is currently selected.")
53
+
54
+ if err and frame.name() is None:
55
+ raise NoFunctionNameInFrameError()
56
+
57
+ return function(self, frame, *args, **kwargs)
58
+ return wrapper
59
+ return decorator
60
+
61
+
62
+ def require_cython_frame(function):
63
+ @functools.wraps(function)
64
+ @require_running_program
65
+ def wrapper(self, *args, **kwargs):
66
+ frame = kwargs.get('frame') or gdb.selected_frame()
67
+ if not self.is_cython_function(frame):
68
+ raise gdb.GdbError('Selected frame does not correspond with a '
69
+ 'Cython function we know about.')
70
+ return function(self, *args, **kwargs)
71
+ return wrapper
72
+
73
+
74
+ def dispatch_on_frame(c_command, python_command=None):
75
+ def decorator(function):
76
+ @functools.wraps(function)
77
+ def wrapper(self, *args, **kwargs):
78
+ is_cy = self.is_cython_function()
79
+ is_py = self.is_python_function()
80
+
81
+ if is_cy or (is_py and not python_command):
82
+ function(self, *args, **kwargs)
83
+ elif is_py:
84
+ gdb.execute(python_command)
85
+ elif self.is_relevant_function():
86
+ gdb.execute(c_command)
87
+ else:
88
+ raise gdb.GdbError("Not a function cygdb knows about. "
89
+ "Use the normal GDB commands instead.")
90
+
91
+ return wrapper
92
+ return decorator
93
+
94
+
95
+ def require_running_program(function):
96
+ @functools.wraps(function)
97
+ def wrapper(*args, **kwargs):
98
+ try:
99
+ gdb.selected_frame()
100
+ except RuntimeError:
101
+ raise gdb.GdbError("No frame is currently selected.")
102
+
103
+ return function(*args, **kwargs)
104
+ return wrapper
105
+
106
+
107
+ def gdb_function_value_to_unicode(function):
108
+ @functools.wraps(function)
109
+ def wrapper(self, string, *args, **kwargs):
110
+ if isinstance(string, gdb.Value):
111
+ string = string.string()
112
+
113
+ return function(self, string, *args, **kwargs)
114
+ return wrapper
115
+
116
+
117
+ # Classes that represent the debug information
118
+ # Don't rename the parameters of these classes, they come directly from the XML
119
+
120
+ def simple_repr(self, renamed=None, state=True):
121
+ """Prints out all instance variables needed to recreate an object.
122
+
123
+ Following the python convention for __repr__, this function prints all the
124
+ information stored in an instance as opposed to its class. The working
125
+ assumption is that most initialization arguments are stored as a property
126
+ using the same name.
127
+
128
+ The object contents are displayed as the initialization call followed by,
129
+ optionally, the value of each of the instance's properties in the form:
130
+ ```
131
+ ClassName(
132
+ init_arg_1 = "repr of some example str",
133
+ ...
134
+ )
135
+ self.state_based_property = ...
136
+ ```
137
+
138
+ Function arguments:
139
+ self Instance to be represented
140
+
141
+ renamed Dictionary of initialization arguments that are stored under a
142
+ different property name in the form { argument: property }
143
+
144
+ state Boolean representing whether properties outside the
145
+ initialization parameters should be printed (self.prop = ...).
146
+ Using `False` may make the class more amenable to recursive repr
147
+ """
148
+ import inspect
149
+ init_arg_names = tuple(inspect.signature(self.__init__).parameters)
150
+ init_attrs = [renamed.get(arg, arg) for arg in init_arg_names] \
151
+ if renamed else init_arg_names
152
+ state_repr = ()
153
+ if state:
154
+ instance_attrs = sorted(vars(self).keys())
155
+ state_repr = [attr for attr in instance_attrs if attr not in init_attrs]
156
+
157
+ def names_and_values(prefix, attrs, args=None):
158
+ for attr, arg in zip(attrs, args or attrs):
159
+ param = repr(getattr(self, attr)).replace("\n", "\n\t\t")
160
+ yield f'{prefix}{arg} = {param}'
161
+
162
+ return "".join([
163
+ self.__class__.__qualname__, "(",
164
+ ",".join(names_and_values("\n\t\t", init_attrs, init_arg_names)),
165
+ "\n\t)", *names_and_values("\nself.", state_repr)
166
+ ])
167
+
168
+
169
+ class CythonModule:
170
+ def __init__(self, module_name, filename, c_filename):
171
+ self.name = module_name
172
+ self.filename = filename
173
+ self.c_filename = c_filename
174
+ self.globals = {}
175
+ # {cython_lineno: min(c_linenos)}
176
+ self.lineno_cy2c = {}
177
+ # {c_lineno: cython_lineno}
178
+ self.lineno_c2cy = {}
179
+ self.functions = {}
180
+
181
+ def __repr__(self):
182
+ return simple_repr(self, renamed={"module_name": "name"}, state=False)
183
+
184
+
185
+ class CythonVariable:
186
+
187
+ def __init__(self, name, cname, qualified_name, type, lineno):
188
+ self.name = name
189
+ self.cname = cname
190
+ self.qualified_name = qualified_name
191
+ self.type = type
192
+ self.lineno = int(lineno)
193
+
194
+ def __repr__(self):
195
+ return simple_repr(self)
196
+
197
+
198
+ class CythonFunction(CythonVariable):
199
+ def __init__(self,
200
+ module,
201
+ name,
202
+ cname,
203
+ pf_cname,
204
+ qualified_name,
205
+ lineno,
206
+ type=CObject,
207
+ is_initmodule_function="False"):
208
+ super().__init__(name,
209
+ cname,
210
+ qualified_name,
211
+ type,
212
+ lineno)
213
+ self.module = module
214
+ self.pf_cname = pf_cname
215
+ self.is_initmodule_function = is_initmodule_function == "True"
216
+ self.locals = {}
217
+ self.arguments = []
218
+ self.step_into_functions = set()
219
+
220
+
221
+ # General purpose classes
222
+
223
+ # fail fast if the API changes
224
+ frame_repr_whitelist = set(f.__qualname__ for f in [
225
+ gdb.Frame.is_valid,
226
+ gdb.Frame.name,
227
+ gdb.Frame.architecture,
228
+ gdb.Frame.type,
229
+ gdb.Frame.pc,
230
+ gdb.Frame.block,
231
+ gdb.Frame.function,
232
+ gdb.Frame.older,
233
+ gdb.Frame.newer,
234
+ gdb.Frame.find_sal,
235
+ gdb.Frame.select,
236
+ gdb.Frame.static_link,
237
+ gdb.Frame.level,
238
+ gdb.Frame.language,
239
+ gdb.Symbol.is_valid,
240
+ gdb.Symbol.value,
241
+ gdb.Symtab_and_line.is_valid,
242
+ gdb.Symtab.is_valid,
243
+ gdb.Symtab.fullname,
244
+ gdb.Symtab.global_block,
245
+ gdb.Symtab.static_block,
246
+ gdb.Symtab.linetable,
247
+ ])
248
+
249
+ def frame_repr(frame):
250
+ """Returns a string representing the internal state of a provided GDB frame
251
+ https://sourceware.org/gdb/current/onlinedocs/gdb.html/Frames-In-Python.html
252
+
253
+ Created to serve as GDB.Frame.__repr__ for debugging purposes. GDB has many
254
+ layers of abstraction separating the state of the debugger from the
255
+ corresponding source code. This prints a tree of instance properties,
256
+ expanding the values for Symtab_and_line, Symbol, and Symtab.
257
+
258
+ Most of these properties require computation to determine, meaning much of
259
+ relevant info is behind a monad, a subset of which are evaluated.
260
+
261
+ Arguments
262
+ frame The GDB.Frame instance to be represented as a string
263
+ """
264
+ res = f"{frame}\n"
265
+ for attribute in sorted(dir(frame)):
266
+ if attribute.startswith("__"):
267
+ continue
268
+ value = getattr(frame, attribute)
269
+ if callable(value) and value.__qualname__ in frame_repr_whitelist:
270
+ value = value()
271
+
272
+ if type(value) in [gdb.Symtab_and_line, gdb.Symbol, gdb.Symtab]:
273
+ # strip last line since it will get added on at the end of the loop
274
+ value = frame_repr(value).rstrip("\n").replace("\n", "\n\t")
275
+ res += f"{attribute}: " + (
276
+ f"{value:x}\n" if isinstance(value, int) and attribute != "line"
277
+ else f"{value}\n")
278
+ return res
279
+
280
+ class CythonBase:
281
+
282
+ @default_selected_gdb_frame(err=False)
283
+ def is_cython_function(self, frame):
284
+ return frame.name() in self.cy.functions_by_cname
285
+
286
+ @default_selected_gdb_frame(err=False)
287
+ def is_python_function(self, frame):
288
+ """
289
+ Tells if a frame is associated with a Python function.
290
+ If we can't read the Python frame information, don't regard it as such.
291
+ """
292
+ if frame.name() == 'PyEval_EvalFrameEx':
293
+ pyframe = libpython.Frame(frame).get_pyop()
294
+ return pyframe and not pyframe.is_optimized_out()
295
+ return False
296
+
297
+ @default_selected_gdb_frame()
298
+ def get_c_function_name(self, frame):
299
+ return frame.name()
300
+
301
+ @default_selected_gdb_frame()
302
+ def get_c_lineno(self, frame):
303
+ return frame.find_sal().line
304
+
305
+ @default_selected_gdb_frame()
306
+ def get_cython_function(self, frame):
307
+ result = self.cy.functions_by_cname.get(frame.name())
308
+ if result is None:
309
+ raise NoCythonFunctionInFrameError()
310
+
311
+ return result
312
+
313
+ @default_selected_gdb_frame()
314
+ def get_cython_lineno(self, frame):
315
+ """
316
+ Get the current Cython line number. Returns 0 if there is no
317
+ correspondence between the C and Cython code.
318
+ """
319
+ cyfunc = self.get_cython_function(frame)
320
+ return cyfunc.module.lineno_c2cy.get(self.get_c_lineno(frame), 0)
321
+
322
+ @default_selected_gdb_frame()
323
+ def get_source_desc(self, frame):
324
+ filename = lineno = lexer = None
325
+ if self.is_cython_function(frame):
326
+ filename = self.get_cython_function(frame).module.filename
327
+ filename_and_lineno = self.get_cython_lineno(frame)
328
+ assert filename == filename_and_lineno[0]
329
+ lineno = filename_and_lineno[1]
330
+ if pygments:
331
+ lexer = pygments.lexers.CythonLexer(stripall=False)
332
+ elif self.is_python_function(frame):
333
+ pyframeobject = libpython.Frame(frame).get_pyop()
334
+
335
+ if not pyframeobject:
336
+ raise gdb.GdbError(
337
+ 'Unable to read information on python frame')
338
+
339
+ filename = pyframeobject.filename()
340
+ lineno = pyframeobject.current_line_num()
341
+
342
+ if pygments:
343
+ lexer = pygments.lexers.PythonLexer(stripall=False)
344
+ else:
345
+ symbol_and_line_obj = frame.find_sal()
346
+ if not symbol_and_line_obj or not symbol_and_line_obj.symtab:
347
+ filename = None
348
+ lineno = 0
349
+ else:
350
+ filename = symbol_and_line_obj.symtab.fullname()
351
+ lineno = symbol_and_line_obj.line
352
+ if pygments:
353
+ lexer = pygments.lexers.CLexer(stripall=False)
354
+
355
+ return SourceFileDescriptor(filename, lexer), lineno
356
+
357
+ @default_selected_gdb_frame()
358
+ def get_source_line(self, frame):
359
+ source_desc, lineno = self.get_source_desc()
360
+ return source_desc.get_source(lineno)
361
+
362
+ @default_selected_gdb_frame()
363
+ def is_relevant_function(self, frame):
364
+ """
365
+ returns whether we care about a frame on the user-level when debugging
366
+ Cython code
367
+ """
368
+ name = frame.name()
369
+ older_frame = frame.older()
370
+ if self.is_cython_function(frame) or self.is_python_function(frame):
371
+ return True
372
+ elif older_frame and self.is_cython_function(older_frame):
373
+ # check for direct C function call from a Cython function
374
+ cython_func = self.get_cython_function(older_frame)
375
+ return name in cython_func.step_into_functions
376
+
377
+ return False
378
+
379
+ @default_selected_gdb_frame(err=False)
380
+ def print_stackframe(self, frame, index, is_c=False):
381
+ """
382
+ Print a C, Cython or Python stack frame and the line of source code
383
+ if available.
384
+ """
385
+ # do this to prevent the require_cython_frame decorator from
386
+ # raising GdbError when calling self.cy.cy_cvalue.invoke()
387
+ selected_frame = gdb.selected_frame()
388
+ frame.select()
389
+
390
+ try:
391
+ source_desc, lineno = self.get_source_desc(frame)
392
+ except NoFunctionNameInFrameError:
393
+ print('#%-2d Unknown Frame (compile with -g)' % index)
394
+ return
395
+
396
+ if not is_c and self.is_python_function(frame):
397
+ pyframe = libpython.Frame(frame).get_pyop()
398
+ if pyframe is None or pyframe.is_optimized_out():
399
+ # print this python function as a C function
400
+ return self.print_stackframe(frame, index, is_c=True)
401
+
402
+ func_name = pyframe.co_name
403
+ func_cname = 'PyEval_EvalFrameEx'
404
+ func_args = []
405
+ elif self.is_cython_function(frame):
406
+ cyfunc = self.get_cython_function(frame)
407
+ f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame)
408
+
409
+ func_name = cyfunc.name
410
+ func_cname = cyfunc.cname
411
+ func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments]
412
+ else:
413
+ source_desc, lineno = self.get_source_desc(frame)
414
+ func_name = frame.name()
415
+ func_cname = func_name
416
+ func_args = []
417
+
418
+ try:
419
+ gdb_value = gdb.parse_and_eval(func_cname)
420
+ except RuntimeError:
421
+ func_address = 0
422
+ else:
423
+ func_address = gdb_value.address
424
+ if not isinstance(func_address, int):
425
+ # Seriously? Why is the address not an int?
426
+ if not isinstance(func_address, (str, bytes)):
427
+ func_address = str(func_address)
428
+ func_address = int(func_address.split()[0], 0)
429
+
430
+ a = ', '.join('%s=%s' % (name, val) for name, val in func_args)
431
+ sys.stdout.write('#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a))
432
+
433
+ if source_desc.filename is not None:
434
+ sys.stdout.write(' at %s:%s' % (source_desc.filename, lineno))
435
+
436
+ sys.stdout.write('\n')
437
+
438
+ try:
439
+ sys.stdout.write(f' {source_desc.get_source(lineno)}\n')
440
+ except gdb.GdbError:
441
+ pass
442
+
443
+ selected_frame.select()
444
+
445
+ def get_remote_cython_globals_dict(self):
446
+ m = gdb.parse_and_eval('__pyx_m')
447
+
448
+ try:
449
+ PyModuleObject = gdb.lookup_type('PyModuleObject')
450
+ except RuntimeError:
451
+ raise gdb.GdbError(textwrap.dedent("""\
452
+ Unable to lookup type PyModuleObject, did you compile python
453
+ with debugging support (-g)?"""))
454
+
455
+ m = m.cast(PyModuleObject.pointer())
456
+ return m['md_dict']
457
+
458
+
459
+ def get_cython_globals_dict(self):
460
+ """
461
+ Get the Cython globals dict where the remote names are turned into
462
+ local strings.
463
+ """
464
+ remote_dict = self.get_remote_cython_globals_dict()
465
+ pyobject_dict = libpython.PyObjectPtr.from_pyobject_ptr(remote_dict)
466
+
467
+ result = {}
468
+ seen = set()
469
+ for k, v in pyobject_dict.iteritems():
470
+ result[k.proxyval(seen)] = v
471
+
472
+ return result
473
+
474
+ def print_gdb_value(self, name, value, max_name_length=None, prefix=''):
475
+ if libpython.pretty_printer_lookup(value):
476
+ typename = ''
477
+ else:
478
+ typename = '(%s) ' % (value.type,)
479
+
480
+ if max_name_length is None:
481
+ print('%s%s = %s%s' % (prefix, name, typename, value))
482
+ else:
483
+ print('%s%-*s = %s%s' % (prefix, max_name_length, name, typename, value))
484
+
485
+ def is_initialized(self, cython_func, local_name):
486
+ cyvar = cython_func.locals[local_name]
487
+ cur_lineno = self.get_cython_lineno()[1]
488
+
489
+ if '->' in cyvar.cname:
490
+ # Closed over free variable
491
+ if cur_lineno > cython_func.lineno:
492
+ if cyvar.type == PythonObject:
493
+ return int(gdb.parse_and_eval(cyvar.cname))
494
+ return True
495
+ return False
496
+
497
+ return cur_lineno > cyvar.lineno
498
+
499
+
500
+ class SourceFileDescriptor:
501
+ def __init__(self, filename, lexer, formatter=None):
502
+ self.filename = filename
503
+ self.lexer = lexer
504
+ self.formatter = formatter
505
+
506
+ def valid(self):
507
+ return self.filename is not None
508
+
509
+ def lex(self, code):
510
+ if pygments and self.lexer and parameters.colorize_code:
511
+ bg = parameters.terminal_background.value
512
+ if self.formatter is None:
513
+ formatter = pygments.formatters.TerminalFormatter(bg=bg)
514
+ else:
515
+ formatter = self.formatter
516
+
517
+ return pygments.highlight(code, self.lexer, formatter)
518
+
519
+ return code
520
+
521
+ def _get_source(self, start, stop, lex_source, mark_line, lex_entire):
522
+ with open(self.filename) as f:
523
+ # to provide "correct" colouring, the entire code needs to be
524
+ # lexed. However, this makes a lot of things terribly slow, so
525
+ # we decide not to. Besides, it's unlikely to matter.
526
+
527
+ if lex_source and lex_entire:
528
+ f = self.lex(f.read()).splitlines()
529
+
530
+ slice = itertools.islice(f, start - 1, stop - 1)
531
+
532
+ for idx, line in enumerate(slice):
533
+ if start + idx == mark_line:
534
+ prefix = '>'
535
+ else:
536
+ prefix = ' '
537
+
538
+ if lex_source and not lex_entire:
539
+ line = self.lex(line)
540
+
541
+ yield '%s %4d %s' % (prefix, start + idx, line.rstrip())
542
+
543
+ def get_source(self, start, stop=None, lex_source=True, mark_line=0,
544
+ lex_entire=False):
545
+ exc = gdb.GdbError('Unable to retrieve source code')
546
+
547
+ if not self.filename:
548
+ raise exc
549
+
550
+ start = max(start, 1)
551
+ if stop is None:
552
+ stop = start + 1
553
+
554
+ try:
555
+ return '\n'.join(
556
+ self._get_source(start, stop, lex_source, mark_line, lex_entire))
557
+ except OSError:
558
+ raise exc
559
+
560
+
561
+ # Errors
562
+
563
+ class CyGDBError(gdb.GdbError):
564
+ """
565
+ Base class for Cython-command related errors
566
+ """
567
+
568
+ def __init__(self, *args):
569
+ args = args or (self.msg,)
570
+ super().__init__(*args)
571
+
572
+
573
+ class NoCythonFunctionInFrameError(CyGDBError):
574
+ """
575
+ raised when the user requests the current cython function, which is
576
+ unavailable
577
+ """
578
+ msg = "Current function is a function cygdb doesn't know about"
579
+
580
+
581
+ class NoFunctionNameInFrameError(NoCythonFunctionInFrameError):
582
+ """
583
+ raised when the name of the C function could not be determined
584
+ in the current C stack frame
585
+ """
586
+ msg = ('C function name could not be determined in the current C stack '
587
+ 'frame')
588
+
589
+
590
+ # Parameters
591
+
592
+ class CythonParameter(gdb.Parameter):
593
+ """
594
+ Base class for cython parameters
595
+ """
596
+
597
+ def __init__(self, name, command_class, parameter_class, default=None):
598
+ self.show_doc = self.set_doc = self.__class__.__doc__
599
+ super().__init__(name, command_class,
600
+ parameter_class)
601
+ if default is not None:
602
+ self.value = default
603
+
604
+ def __bool__(self):
605
+ return bool(self.value)
606
+
607
+ __nonzero__ = __bool__ # Python 2
608
+
609
+
610
+
611
+ class CompleteUnqualifiedFunctionNames(CythonParameter):
612
+ """
613
+ Have 'cy break' complete unqualified function or method names.
614
+ """
615
+
616
+
617
+ class ColorizeSourceCode(CythonParameter):
618
+ """
619
+ Tell cygdb whether to colorize source code.
620
+ """
621
+
622
+
623
+ class TerminalBackground(CythonParameter):
624
+ """
625
+ Tell cygdb about the user's terminal background (light or dark).
626
+ """
627
+
628
+
629
+ class CythonParameters:
630
+ """
631
+ Simple container class that might get more functionality in the distant
632
+ future (mostly to remind us that we're dealing with parameters).
633
+ """
634
+
635
+ def __init__(self):
636
+ self.complete_unqualified = CompleteUnqualifiedFunctionNames(
637
+ 'cy_complete_unqualified',
638
+ gdb.COMMAND_BREAKPOINTS,
639
+ gdb.PARAM_BOOLEAN,
640
+ True)
641
+ self.colorize_code = ColorizeSourceCode(
642
+ 'cy_colorize_code',
643
+ gdb.COMMAND_FILES,
644
+ gdb.PARAM_BOOLEAN,
645
+ True)
646
+ self.terminal_background = TerminalBackground(
647
+ 'cy_terminal_background_color',
648
+ gdb.COMMAND_FILES,
649
+ gdb.PARAM_STRING,
650
+ "dark")
651
+
652
+ parameters = CythonParameters()
653
+
654
+
655
+ # Commands
656
+
657
+ class CythonCommand(gdb.Command, CythonBase):
658
+ """
659
+ Base class for Cython commands
660
+ """
661
+
662
+ command_class = gdb.COMMAND_NONE
663
+
664
+ @classmethod
665
+ def _register(cls, clsname, args, kwargs):
666
+ if not hasattr(cls, 'completer_class'):
667
+ return cls(clsname, cls.command_class, *args, **kwargs)
668
+ else:
669
+ return cls(clsname, cls.command_class, cls.completer_class,
670
+ *args, **kwargs)
671
+
672
+ @classmethod
673
+ def register(cls, *args, **kwargs):
674
+ alias = getattr(cls, 'alias', None)
675
+ if alias:
676
+ cls._register(cls.alias, args, kwargs)
677
+
678
+ return cls._register(cls.name, args, kwargs)
679
+
680
+
681
+ class CyCy(CythonCommand):
682
+ """
683
+ Invoke a Cython command. Available commands are:
684
+
685
+ cy import
686
+ cy break
687
+ cy step
688
+ cy next
689
+ cy run
690
+ cy cont
691
+ cy finish
692
+ cy up
693
+ cy down
694
+ cy select
695
+ cy bt / cy backtrace
696
+ cy list
697
+ cy print
698
+ cy set
699
+ cy locals
700
+ cy globals
701
+ cy exec
702
+ """
703
+
704
+ name = 'cy'
705
+ command_class = gdb.COMMAND_NONE
706
+ completer_class = gdb.COMPLETE_COMMAND
707
+
708
+ def __init__(self, name, command_class, completer_class):
709
+ # keep the signature 2.5 compatible (i.e. do not use f(*a, k=v)
710
+ super(CythonCommand, self).__init__(name, command_class,
711
+ completer_class, prefix=True)
712
+
713
+ commands = dict(
714
+ # GDB commands
715
+ import_ = CyImport.register(),
716
+ break_ = CyBreak.register(),
717
+ step = CyStep.register(),
718
+ next = CyNext.register(),
719
+ run = CyRun.register(),
720
+ cont = CyCont.register(),
721
+ finish = CyFinish.register(),
722
+ up = CyUp.register(),
723
+ down = CyDown.register(),
724
+ select = CySelect.register(),
725
+ bt = CyBacktrace.register(),
726
+ list = CyList.register(),
727
+ print_ = CyPrint.register(),
728
+ locals = CyLocals.register(),
729
+ globals = CyGlobals.register(),
730
+ exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'),
731
+ _exec = CyExec.register(),
732
+ set = CySet.register(),
733
+
734
+ # GDB functions
735
+ cy_cname = CyCName('cy_cname'),
736
+ cy_cvalue = CyCValue('cy_cvalue'),
737
+ cy_lineno = CyLine('cy_lineno'),
738
+ cy_eval = CyEval('cy_eval'),
739
+ )
740
+
741
+ for command_name, command in commands.items():
742
+ command.cy = self
743
+ setattr(self, command_name, command)
744
+
745
+ self.cy = self
746
+
747
+ # Cython module namespace
748
+ self.cython_namespace = {}
749
+
750
+ # maps (unique) qualified function names (e.g.
751
+ # cythonmodule.ClassName.method_name) to the CythonFunction object
752
+ self.functions_by_qualified_name = {}
753
+
754
+ # unique cnames of Cython functions
755
+ self.functions_by_cname = {}
756
+
757
+ # map function names like method_name to a list of all such
758
+ # CythonFunction objects
759
+ self.functions_by_name = collections.defaultdict(list)
760
+
761
+
762
+ class CyImport(CythonCommand):
763
+ """
764
+ Import debug information outputted by the Cython compiler
765
+ Example: cy import FILE...
766
+ """
767
+
768
+ name = 'cy import'
769
+ command_class = gdb.COMMAND_STATUS
770
+ completer_class = gdb.COMPLETE_FILENAME
771
+
772
+ @libpython.dont_suppress_errors
773
+ def invoke(self, args, from_tty):
774
+ if isinstance(args, bytes):
775
+ args = args.decode(_filesystemencoding)
776
+ for arg in string_to_argv(args):
777
+ try:
778
+ f = open(arg)
779
+ except OSError as e:
780
+ raise gdb.GdbError('Unable to open file %r: %s' % (args, e.args[1]))
781
+
782
+ t = etree.parse(f)
783
+
784
+ for module in t.getroot():
785
+ cython_module = CythonModule(**module.attrib)
786
+ self.cy.cython_namespace[cython_module.name] = cython_module
787
+
788
+ for variable in module.find('Globals'):
789
+ d = variable.attrib
790
+ cython_module.globals[d['name']] = CythonVariable(**d)
791
+
792
+ for function in module.find('Functions'):
793
+ cython_function = CythonFunction(module=cython_module,
794
+ **function.attrib)
795
+
796
+ # update the global function mappings
797
+ name = cython_function.name
798
+ qname = cython_function.qualified_name
799
+
800
+ self.cy.functions_by_name[name].append(cython_function)
801
+ self.cy.functions_by_qualified_name[
802
+ cython_function.qualified_name] = cython_function
803
+ self.cy.functions_by_cname[
804
+ cython_function.cname] = cython_function
805
+
806
+ d = cython_module.functions[qname] = cython_function
807
+
808
+ for local in function.find('Locals'):
809
+ d = local.attrib
810
+ cython_function.locals[d['name']] = CythonVariable(**d)
811
+
812
+ for step_into_func in function.find('StepIntoFunctions'):
813
+ d = step_into_func.attrib
814
+ cython_function.step_into_functions.add(d['name'])
815
+
816
+ cython_function.arguments.extend(
817
+ funcarg.tag for funcarg in function.find('Arguments'))
818
+
819
+ for marker in module.find('LineNumberMapping'):
820
+ src_lineno = int(marker.attrib['src_lineno'])
821
+ src_path = marker.attrib['src_path']
822
+ c_linenos = list(map(int, marker.attrib['c_linenos'].split()))
823
+ cython_module.lineno_cy2c[src_path, src_lineno] = min(c_linenos)
824
+ for c_lineno in c_linenos:
825
+ cython_module.lineno_c2cy[c_lineno] = (src_path, src_lineno)
826
+
827
+
828
+ class CyBreak(CythonCommand):
829
+ """
830
+ Set a breakpoint for Cython code using Cython qualified name notation, e.g.:
831
+
832
+ cy break cython_modulename.ClassName.method_name...
833
+
834
+ or normal notation:
835
+
836
+ cy break function_or_method_name...
837
+
838
+ or for a line number:
839
+
840
+ cy break cython_module:lineno...
841
+
842
+ Set a Python breakpoint:
843
+ Break on any function or method named 'func' in module 'modname'
844
+
845
+ cy break -p modname.func...
846
+
847
+ Break on any function or method named 'func'
848
+
849
+ cy break -p func...
850
+ """
851
+
852
+ name = 'cy break'
853
+ command_class = gdb.COMMAND_BREAKPOINTS
854
+
855
+ def _break_pyx(self, name):
856
+ modulename, _, lineno = name.partition(':')
857
+ lineno = int(lineno)
858
+ if modulename:
859
+ cython_module = self.cy.cython_namespace[modulename]
860
+ else:
861
+ cython_module = self.get_cython_function().module
862
+
863
+ if (cython_module.filename, lineno) in cython_module.lineno_cy2c:
864
+ c_lineno = cython_module.lineno_cy2c[cython_module.filename, lineno]
865
+ breakpoint = '%s:%s' % (cython_module.c_filename, c_lineno)
866
+ gdb.execute('break ' + breakpoint)
867
+ else:
868
+ raise gdb.GdbError("Not a valid line number. "
869
+ "Does it contain actual code?")
870
+
871
+ def _break_funcname(self, funcname):
872
+ func = self.cy.functions_by_qualified_name.get(funcname)
873
+
874
+ if func and func.is_initmodule_function:
875
+ func = None
876
+
877
+ break_funcs = [func]
878
+
879
+ if not func:
880
+ funcs = self.cy.functions_by_name.get(funcname) or []
881
+ funcs = [f for f in funcs if not f.is_initmodule_function]
882
+
883
+ if not funcs:
884
+ gdb.execute('break ' + funcname)
885
+ return
886
+
887
+ if len(funcs) > 1:
888
+ # multiple functions, let the user pick one
889
+ print('There are multiple such functions:')
890
+ for idx, func in enumerate(funcs):
891
+ print('%3d) %s' % (idx, func.qualified_name))
892
+
893
+ while True:
894
+ try:
895
+ result = input(
896
+ "Select a function, press 'a' for all "
897
+ "functions or press 'q' or '^D' to quit: ")
898
+ except EOFError:
899
+ return
900
+ else:
901
+ if result.lower() == 'q':
902
+ return
903
+ elif result.lower() == 'a':
904
+ break_funcs = funcs
905
+ break
906
+ elif (result.isdigit() and
907
+ 0 <= int(result) < len(funcs)):
908
+ break_funcs = [funcs[int(result)]]
909
+ break
910
+ else:
911
+ print('Not understood...')
912
+ else:
913
+ break_funcs = [funcs[0]]
914
+
915
+ for func in break_funcs:
916
+ gdb.execute('break %s' % func.cname)
917
+ if func.pf_cname:
918
+ gdb.execute('break %s' % func.pf_cname)
919
+
920
+ @libpython.dont_suppress_errors
921
+ def invoke(self, function_names, from_tty):
922
+ if isinstance(function_names, bytes):
923
+ function_names = function_names.decode(_filesystemencoding)
924
+ argv = string_to_argv(function_names)
925
+ if function_names.startswith('-p'):
926
+ argv = argv[1:]
927
+ python_breakpoints = True
928
+ else:
929
+ python_breakpoints = False
930
+
931
+ for funcname in argv:
932
+ if python_breakpoints:
933
+ gdb.execute('py-break %s' % funcname)
934
+ elif ':' in funcname:
935
+ self._break_pyx(funcname)
936
+ else:
937
+ self._break_funcname(funcname)
938
+
939
+ @libpython.dont_suppress_errors
940
+ def complete(self, text, word):
941
+ # https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/python/py-cmd.c;h=7143c1c5f7fdce9316a8c41fc2246bc6a07630d4;hb=HEAD#l140
942
+ word = word or ""
943
+ # Filter init-module functions (breakpoints can be set using
944
+ # modulename:linenumber).
945
+ names = [n for n, L in self.cy.functions_by_name.items()
946
+ if any(not f.is_initmodule_function for f in L)]
947
+ qnames = [n for n, f in self.cy.functions_by_qualified_name.items()
948
+ if not f.is_initmodule_function]
949
+
950
+ if parameters.complete_unqualified:
951
+ all_names = itertools.chain(qnames, names)
952
+ else:
953
+ all_names = qnames
954
+
955
+ words = text.strip().split()
956
+ if not words or '.' not in words[-1]:
957
+ # complete unqualified
958
+ seen = set(text[:-len(word)].split())
959
+ return [n for n in all_names
960
+ if n.startswith(word) and n not in seen]
961
+
962
+ # complete qualified name
963
+ lastword = words[-1]
964
+ compl = [n for n in qnames if n.startswith(lastword)]
965
+
966
+ if len(lastword) > len(word):
967
+ # readline sees something (e.g. a '.') as a word boundary, so don't
968
+ # "recomplete" this prefix
969
+ strip_prefix_length = len(lastword) - len(word)
970
+ compl = [n[strip_prefix_length:] for n in compl]
971
+
972
+ return compl
973
+
974
+
975
+ class CythonInfo(CythonBase, libpython.PythonInfo):
976
+ """
977
+ Implementation of the interface dictated by libpython.LanguageInfo.
978
+ """
979
+
980
+ def lineno(self, frame):
981
+ # Take care of the Python and Cython levels. We need to care for both
982
+ # as we can't simply dispatch to 'py-step', since that would work for
983
+ # stepping through Python code, but it would not step back into Cython-
984
+ # related code. The C level should be dispatched to the 'step' command.
985
+ if self.is_cython_function(frame):
986
+ return self.get_cython_lineno(frame)[1]
987
+ return super().lineno(frame)
988
+
989
+ def get_source_line(self, frame):
990
+ try:
991
+ line = super().get_source_line(frame)
992
+ except gdb.GdbError:
993
+ return None
994
+ else:
995
+ return line.strip() or None
996
+
997
+ def exc_info(self, frame):
998
+ if self.is_python_function:
999
+ return super().exc_info(frame)
1000
+
1001
+ def runtime_break_functions(self):
1002
+ if self.is_cython_function():
1003
+ return self.get_cython_function().step_into_functions
1004
+ return ()
1005
+
1006
+ def static_break_functions(self):
1007
+ result = ['PyEval_EvalFrameEx']
1008
+ result.extend(self.cy.functions_by_cname)
1009
+ return result
1010
+
1011
+
1012
+ class CythonExecutionControlCommand(CythonCommand,
1013
+ libpython.ExecutionControlCommandBase):
1014
+
1015
+ @classmethod
1016
+ def register(cls):
1017
+ return cls(cls.name, cython_info)
1018
+
1019
+
1020
+ class CyStep(CythonExecutionControlCommand, libpython.PythonStepperMixin):
1021
+ "Step through Cython, Python or C code."
1022
+
1023
+ name = 'cy -step'
1024
+ stepinto = True
1025
+
1026
+ @libpython.dont_suppress_errors
1027
+ def invoke(self, args, from_tty):
1028
+ if self.is_python_function():
1029
+ self.python_step(self.stepinto)
1030
+ elif not self.is_cython_function():
1031
+ if self.stepinto:
1032
+ command = 'step'
1033
+ else:
1034
+ command = 'next'
1035
+
1036
+ self.finish_executing(gdb.execute(command, to_string=True))
1037
+ else:
1038
+ self.step(stepinto=self.stepinto)
1039
+
1040
+
1041
+ class CyNext(CyStep):
1042
+ "Step-over Cython, Python or C code."
1043
+
1044
+ name = 'cy -next'
1045
+ stepinto = False
1046
+
1047
+
1048
+ class CyRun(CythonExecutionControlCommand):
1049
+ """
1050
+ Run a Cython program. This is like the 'run' command, except that it
1051
+ displays Cython or Python source lines as well
1052
+ """
1053
+
1054
+ name = 'cy run'
1055
+
1056
+ invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.run)
1057
+
1058
+
1059
+ class CyCont(CythonExecutionControlCommand):
1060
+ """
1061
+ Continue a Cython program. This is like the 'run' command, except that it
1062
+ displays Cython or Python source lines as well.
1063
+ """
1064
+
1065
+ name = 'cy cont'
1066
+ invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.cont)
1067
+
1068
+
1069
+ class CyFinish(CythonExecutionControlCommand):
1070
+ """
1071
+ Execute until the function returns.
1072
+ """
1073
+ name = 'cy finish'
1074
+
1075
+ invoke = libpython.dont_suppress_errors(CythonExecutionControlCommand.finish)
1076
+
1077
+
1078
+ class CyUp(CythonCommand):
1079
+ """
1080
+ Go up a Cython, Python or relevant C frame.
1081
+ """
1082
+ name = 'cy up'
1083
+ _command = 'up'
1084
+
1085
+ @libpython.dont_suppress_errors
1086
+ def invoke(self, *args):
1087
+ try:
1088
+ gdb.execute(self._command, to_string=True)
1089
+ while not self.is_relevant_function(gdb.selected_frame()):
1090
+ gdb.execute(self._command, to_string=True)
1091
+ except RuntimeError as e:
1092
+ raise gdb.GdbError(*e.args)
1093
+
1094
+ frame = gdb.selected_frame()
1095
+ index = 0
1096
+ while frame:
1097
+ frame = frame.older()
1098
+ index += 1
1099
+
1100
+ self.print_stackframe(index=index - 1)
1101
+
1102
+
1103
+ class CyDown(CyUp):
1104
+ """
1105
+ Go down a Cython, Python or relevant C frame.
1106
+ """
1107
+
1108
+ name = 'cy down'
1109
+ _command = 'down'
1110
+
1111
+
1112
+ class CySelect(CythonCommand):
1113
+ """
1114
+ Select a frame. Use frame numbers as listed in `cy backtrace`.
1115
+ This command is useful because `cy backtrace` prints a reversed backtrace.
1116
+ """
1117
+
1118
+ name = 'cy select'
1119
+
1120
+ @libpython.dont_suppress_errors
1121
+ def invoke(self, stackno, from_tty):
1122
+ try:
1123
+ stackno = int(stackno)
1124
+ except ValueError:
1125
+ raise gdb.GdbError("Not a valid number: %r" % (stackno,))
1126
+
1127
+ frame = gdb.selected_frame()
1128
+ while frame.newer():
1129
+ frame = frame.newer()
1130
+
1131
+ stackdepth = libpython.stackdepth(frame)
1132
+
1133
+ try:
1134
+ gdb.execute('select %d' % (stackdepth - stackno - 1,))
1135
+ except RuntimeError as e:
1136
+ raise gdb.GdbError(*e.args)
1137
+
1138
+
1139
+ class CyBacktrace(CythonCommand):
1140
+ 'Print the Cython stack'
1141
+
1142
+ name = 'cy bt'
1143
+ alias = 'cy backtrace'
1144
+ command_class = gdb.COMMAND_STACK
1145
+ completer_class = gdb.COMPLETE_NONE
1146
+
1147
+ @libpython.dont_suppress_errors
1148
+ @require_running_program
1149
+ def invoke(self, args, from_tty):
1150
+ # get the first frame
1151
+ frame = gdb.selected_frame()
1152
+ while frame.older():
1153
+ frame = frame.older()
1154
+
1155
+ print_all = args == '-a'
1156
+
1157
+ index = 0
1158
+ while frame:
1159
+ try:
1160
+ is_relevant = self.is_relevant_function(frame)
1161
+ except CyGDBError:
1162
+ is_relevant = False
1163
+
1164
+ if print_all or is_relevant:
1165
+ self.print_stackframe(frame, index)
1166
+
1167
+ index += 1
1168
+ frame = frame.newer()
1169
+
1170
+
1171
+ class CyList(CythonCommand):
1172
+ """
1173
+ List Cython source code. To disable to customize colouring see the cy_*
1174
+ parameters.
1175
+ """
1176
+
1177
+ name = 'cy list'
1178
+ command_class = gdb.COMMAND_FILES
1179
+ completer_class = gdb.COMPLETE_NONE
1180
+
1181
+ @libpython.dont_suppress_errors
1182
+ # @dispatch_on_frame(c_command='list')
1183
+ def invoke(self, _, from_tty):
1184
+ sd, lineno = self.get_source_desc()
1185
+ source = sd.get_source(lineno - 5, lineno + 5, mark_line=lineno,
1186
+ lex_entire=True)
1187
+ print(source)
1188
+
1189
+
1190
+ class CyPrint(CythonCommand):
1191
+ """
1192
+ Print a Cython variable using 'cy-print x' or 'cy-print module.function.x'
1193
+ """
1194
+
1195
+ name = 'cy print'
1196
+ command_class = gdb.COMMAND_DATA
1197
+
1198
+ @libpython.dont_suppress_errors
1199
+ def invoke(self, name, from_tty):
1200
+ global_python_dict = self.get_cython_globals_dict()
1201
+ module_globals = self.get_cython_function().module.globals
1202
+
1203
+ if name in global_python_dict:
1204
+ value = global_python_dict[name].get_truncated_repr(libpython.MAX_OUTPUT_LEN)
1205
+ print('%s = %s' % (name, value))
1206
+ #This also would work, but because the output of cy exec is not captured in gdb.execute, TestPrint would fail
1207
+ #self.cy.exec_.invoke("print('"+name+"','=', type(" + name + "), "+name+", flush=True )", from_tty)
1208
+ elif name in module_globals:
1209
+ cname = module_globals[name].cname
1210
+ try:
1211
+ value = gdb.parse_and_eval(cname)
1212
+ except RuntimeError:
1213
+ print("unable to get value of %s" % name)
1214
+ else:
1215
+ if not value.is_optimized_out:
1216
+ self.print_gdb_value(name, value)
1217
+ else:
1218
+ print("%s is optimized out" % name)
1219
+ elif self.is_python_function():
1220
+ return gdb.execute('py-print ' + name)
1221
+ elif self.is_cython_function():
1222
+ value = self.cy.cy_cvalue.invoke(name.lstrip('*'))
1223
+ for c in name:
1224
+ if c == '*':
1225
+ value = value.dereference()
1226
+ else:
1227
+ break
1228
+
1229
+ self.print_gdb_value(name, value)
1230
+ else:
1231
+ gdb.execute('print ' + name)
1232
+
1233
+ def complete(self):
1234
+ if self.is_cython_function():
1235
+ f = self.get_cython_function()
1236
+ return list(itertools.chain(f.locals, f.globals))
1237
+ else:
1238
+ return []
1239
+
1240
+
1241
+ sortkey = lambda item: item[0].lower()
1242
+
1243
+
1244
+ class CyLocals(CythonCommand):
1245
+ """
1246
+ List the locals from the current Cython frame.
1247
+ """
1248
+
1249
+ name = 'cy locals'
1250
+ command_class = gdb.COMMAND_STACK
1251
+ completer_class = gdb.COMPLETE_NONE
1252
+
1253
+ @libpython.dont_suppress_errors
1254
+ @dispatch_on_frame(c_command='info locals', python_command='py-locals')
1255
+ def invoke(self, args, from_tty):
1256
+ cython_function = self.get_cython_function()
1257
+
1258
+ if cython_function.is_initmodule_function:
1259
+ self.cy.globals.invoke(args, from_tty)
1260
+ return
1261
+
1262
+ local_cython_vars = cython_function.locals
1263
+ max_name_length = len(max(local_cython_vars, key=len))
1264
+ for name, cyvar in sorted(local_cython_vars.items(), key=sortkey):
1265
+ if self.is_initialized(self.get_cython_function(), cyvar.name):
1266
+ value = gdb.parse_and_eval(cyvar.cname)
1267
+ if not value.is_optimized_out:
1268
+ self.print_gdb_value(cyvar.name, value,
1269
+ max_name_length, '')
1270
+
1271
+
1272
+ class CyGlobals(CyLocals):
1273
+ """
1274
+ List the globals from the current Cython module.
1275
+ """
1276
+
1277
+ name = 'cy globals'
1278
+ command_class = gdb.COMMAND_STACK
1279
+ completer_class = gdb.COMPLETE_NONE
1280
+
1281
+ @libpython.dont_suppress_errors
1282
+ @dispatch_on_frame(c_command='info variables', python_command='py-globals')
1283
+ def invoke(self, args, from_tty):
1284
+ global_python_dict = self.get_cython_globals_dict()
1285
+ module_globals = self.get_cython_function().module.globals
1286
+
1287
+ max_globals_len = 0
1288
+ max_globals_dict_len = 0
1289
+ if module_globals:
1290
+ max_globals_len = len(max(module_globals, key=len))
1291
+ if global_python_dict:
1292
+ max_globals_dict_len = len(max(global_python_dict))
1293
+
1294
+ max_name_length = max(max_globals_len, max_globals_dict_len)
1295
+
1296
+ seen = set()
1297
+ print('Python globals:')
1298
+
1299
+ for k, v in sorted(global_python_dict.items(), key=sortkey):
1300
+ v = v.get_truncated_repr(libpython.MAX_OUTPUT_LEN)
1301
+ seen.add(k)
1302
+ print(' %-*s = %s' % (max_name_length, k, v))
1303
+
1304
+ print('C globals:')
1305
+ for name, cyvar in sorted(module_globals.items(), key=sortkey):
1306
+ if name not in seen:
1307
+ try:
1308
+ value = gdb.parse_and_eval(cyvar.cname)
1309
+ except RuntimeError:
1310
+ pass
1311
+ else:
1312
+ if not value.is_optimized_out:
1313
+ self.print_gdb_value(cyvar.name, value,
1314
+ max_name_length, ' ')
1315
+
1316
+
1317
+ class EvaluateOrExecuteCodeMixin:
1318
+ """
1319
+ Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
1320
+ method evaluations Python code, prints a traceback if an exception went
1321
+ uncaught, and returns any return value as a gdb.Value (NULL on exception).
1322
+ """
1323
+
1324
+ def _fill_locals_dict(self, executor, local_dict_pointer):
1325
+ "Fill a remotely allocated dict with values from the Cython C stack"
1326
+ cython_func = self.get_cython_function()
1327
+
1328
+ for name, cyvar in cython_func.locals.items():
1329
+ if (cyvar.type == PythonObject
1330
+ and self.is_initialized(cython_func, name)):
1331
+
1332
+ try:
1333
+ val = gdb.parse_and_eval(cyvar.cname)
1334
+ except RuntimeError:
1335
+ continue
1336
+ else:
1337
+ if val.is_optimized_out:
1338
+ continue
1339
+
1340
+ pystringp = executor.alloc_pystring(name)
1341
+ code = '''
1342
+ (PyObject *) PyDict_SetItem(
1343
+ (PyObject *) %d,
1344
+ (PyObject *) %d,
1345
+ (PyObject *) %s)
1346
+ ''' % (local_dict_pointer, pystringp, cyvar.cname)
1347
+
1348
+ try:
1349
+ if gdb.parse_and_eval(code) < 0:
1350
+ gdb.parse_and_eval('PyErr_Print()')
1351
+ raise gdb.GdbError("Unable to execute Python code.")
1352
+ finally:
1353
+ # PyDict_SetItem doesn't steal our reference
1354
+ executor.xdecref(pystringp)
1355
+
1356
+ def _find_first_cython_or_python_frame(self):
1357
+ frame = gdb.selected_frame()
1358
+ while frame:
1359
+ if (self.is_cython_function(frame)
1360
+ or self.is_python_function(frame)):
1361
+ frame.select()
1362
+ return frame
1363
+
1364
+ frame = frame.older()
1365
+
1366
+ raise gdb.GdbError("There is no Cython or Python frame on the stack.")
1367
+
1368
+ def _evalcode_cython(self, executor, code, input_type):
1369
+ with libpython.FetchAndRestoreError():
1370
+ # get the dict of Cython globals and construct a dict in the
1371
+ # inferior with Cython locals
1372
+ global_dict = gdb.parse_and_eval(
1373
+ '(PyObject *) PyModule_GetDict(__pyx_m)')
1374
+ local_dict = gdb.parse_and_eval('(PyObject *) PyDict_New()')
1375
+
1376
+ try:
1377
+ self._fill_locals_dict(executor,
1378
+ libpython.pointervalue(local_dict))
1379
+ result = executor.evalcode(code, input_type, global_dict,
1380
+ local_dict)
1381
+ finally:
1382
+ executor.xdecref(libpython.pointervalue(local_dict))
1383
+
1384
+ return result
1385
+
1386
+ def evalcode(self, code, input_type):
1387
+ """
1388
+ Evaluate `code` in a Python or Cython stack frame using the given
1389
+ `input_type`.
1390
+ """
1391
+ frame = self._find_first_cython_or_python_frame()
1392
+ executor = libpython.PythonCodeExecutor()
1393
+ if self.is_python_function(frame):
1394
+ return libpython._evalcode_python(executor, code, input_type)
1395
+ return self._evalcode_cython(executor, code, input_type)
1396
+
1397
+
1398
+ class CyExec(CythonCommand, libpython.PyExec, EvaluateOrExecuteCodeMixin):
1399
+ """
1400
+ Execute Python code in the nearest Python or Cython frame.
1401
+ """
1402
+
1403
+ name = '-cy-exec'
1404
+ command_class = gdb.COMMAND_STACK
1405
+ completer_class = gdb.COMPLETE_NONE
1406
+
1407
+ @libpython.dont_suppress_errors
1408
+ def invoke(self, expr, from_tty):
1409
+ expr, input_type = self.readcode(expr)
1410
+ executor = libpython.PythonCodeExecutor()
1411
+ executor.xdecref(self.evalcode(expr, executor.Py_file_input))
1412
+
1413
+
1414
+ class CySet(CythonCommand):
1415
+ """
1416
+ Set a Cython variable to a certain value
1417
+
1418
+ cy set my_cython_c_variable = 10
1419
+ cy set my_cython_py_variable = $cy_eval("{'doner': 'kebab'}")
1420
+
1421
+ This is equivalent to
1422
+
1423
+ set $cy_value("my_cython_variable") = 10
1424
+ """
1425
+
1426
+ name = 'cy set'
1427
+ command_class = gdb.COMMAND_DATA
1428
+ completer_class = gdb.COMPLETE_NONE
1429
+
1430
+ @libpython.dont_suppress_errors
1431
+ @require_cython_frame
1432
+ def invoke(self, expr, from_tty):
1433
+ name_and_expr = expr.split('=', 1)
1434
+ if len(name_and_expr) != 2:
1435
+ raise gdb.GdbError("Invalid expression. Use 'cy set var = expr'.")
1436
+
1437
+ varname, expr = name_and_expr
1438
+ cname = self.cy.cy_cname.invoke(varname.strip())
1439
+ gdb.execute("set %s = %s" % (cname, expr))
1440
+
1441
+
1442
+ # Functions
1443
+
1444
+ class CyCName(gdb.Function, CythonBase):
1445
+ """
1446
+ Get the C name of a Cython variable in the current context.
1447
+ Examples:
1448
+
1449
+ print $cy_cname("function")
1450
+ print $cy_cname("Class.method")
1451
+ print $cy_cname("module.function")
1452
+ """
1453
+
1454
+ @libpython.dont_suppress_errors
1455
+ @require_cython_frame
1456
+ @gdb_function_value_to_unicode
1457
+ def invoke(self, cyname, frame=None):
1458
+ frame = frame or gdb.selected_frame()
1459
+ cname = None
1460
+
1461
+ if self.is_cython_function(frame):
1462
+ cython_function = self.get_cython_function(frame)
1463
+ if cyname in cython_function.locals:
1464
+ cname = cython_function.locals[cyname].cname
1465
+ elif cyname in cython_function.module.globals:
1466
+ cname = cython_function.module.globals[cyname].cname
1467
+ else:
1468
+ qname = '%s.%s' % (cython_function.module.name, cyname)
1469
+ if qname in cython_function.module.functions:
1470
+ cname = cython_function.module.functions[qname].cname
1471
+
1472
+ if not cname:
1473
+ cname = self.cy.functions_by_qualified_name.get(cyname)
1474
+
1475
+ if not cname:
1476
+ raise gdb.GdbError('No such Cython variable: %s' % cyname)
1477
+
1478
+ return cname
1479
+
1480
+
1481
+ class CyCValue(CyCName):
1482
+ """
1483
+ Get the value of a Cython variable.
1484
+ """
1485
+
1486
+ @libpython.dont_suppress_errors
1487
+ @require_cython_frame
1488
+ @gdb_function_value_to_unicode
1489
+ def invoke(self, cyname, frame=None):
1490
+ globals_dict = self.get_cython_globals_dict()
1491
+ cython_function = self.get_cython_function(frame)
1492
+
1493
+ if self.is_initialized(cython_function, cyname):
1494
+ cname = super().invoke(cyname, frame=frame)
1495
+ return gdb.parse_and_eval(cname)
1496
+ elif cyname in globals_dict:
1497
+ return globals_dict[cyname]._gdbval
1498
+ else:
1499
+ raise gdb.GdbError("Variable %s is not initialized." % cyname)
1500
+
1501
+
1502
+ class CyLine(gdb.Function, CythonBase):
1503
+ """
1504
+ Get the current Cython line.
1505
+ """
1506
+
1507
+ @libpython.dont_suppress_errors
1508
+ @require_cython_frame
1509
+ def invoke(self):
1510
+ return self.get_cython_lineno()[1]
1511
+
1512
+
1513
+ class CyEval(gdb.Function, CythonBase, EvaluateOrExecuteCodeMixin):
1514
+ """
1515
+ Evaluate Python code in the nearest Python or Cython frame and return
1516
+ """
1517
+
1518
+ @libpython.dont_suppress_errors
1519
+ @gdb_function_value_to_unicode
1520
+ def invoke(self, python_expression):
1521
+ input_type = libpython.PythonCodeExecutor.Py_eval_input
1522
+ return self.evalcode(python_expression, input_type)
1523
+
1524
+
1525
+ cython_info = CythonInfo()
1526
+ cy = CyCy.register()
1527
+ cython_info.cy = cy
1528
+
1529
+
1530
+ def register_defines():
1531
+ libpython.source_gdb_script(textwrap.dedent("""\
1532
+ define cy step
1533
+ cy -step
1534
+ end
1535
+
1536
+ define cy next
1537
+ cy -next
1538
+ end
1539
+
1540
+ document cy step
1541
+ %s
1542
+ end
1543
+
1544
+ document cy next
1545
+ %s
1546
+ end
1547
+ """) % (CyStep.__doc__, CyNext.__doc__))
1548
+
1549
+ register_defines()