libcython.py 44 KB

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