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