def get_source_desc(self, frame): filename = lineno = lexer = None if self.is_cython_function(frame): filename = self.get_cython_function(frame).module.filename lineno = self.get_cython_lineno(frame) if pygments: lexer = pygments.lexers.CythonLexer(stripall=False) elif self.is_python_function(frame): pyframeobject = libpython.Frame(frame).get_pyop() if not pyframeobject: raise gdb.GdbError( 'Unable to read information on python frame') filename = pyframeobject.filename() lineno = pyframeobject.current_line_num() if pygments: lexer = pygments.lexers.PythonLexer(stripall=False) else: symbol_and_line_obj = frame.find_sal() if not symbol_and_line_obj or not symbol_and_line_obj.symtab: filename = None lineno = 0 else: filename = symbol_and_line_obj.symtab.fullname() lineno = symbol_and_line_obj.line if pygments: lexer = pygments.lexers.CLexer(stripall=False) return SourceFileDescriptor(filename, lexer), lineno
def print_stackframe(self, frame, index, is_c=False): """ Print a C, Cython or Python stack frame and the line of source code if available. """ # do this to prevent the require_cython_frame decorator from # raising GdbError when calling self.cy.cy_cvalue.invoke() selected_frame = gdb.selected_frame() frame.select() try: source_desc, lineno = self.get_source_desc(frame) except NoFunctionNameInFrameError: print '#%-2d Unknown Frame (compile with -g)' % index return if not is_c and self.is_python_function(frame): pyframe = libpython.Frame(frame).get_pyop() if pyframe is None or pyframe.is_optimized_out(): # print this python function as a C function return self.print_stackframe(frame, index, is_c=True) func_name = pyframe.co_name func_cname = 'PyEval_EvalFrameEx' func_args = [] elif self.is_cython_function(frame): cyfunc = self.get_cython_function(frame) f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame) func_name = cyfunc.name func_cname = cyfunc.cname func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments] else: source_desc, lineno = self.get_source_desc(frame) func_name = frame.name() func_cname = func_name func_args = [] try: gdb_value = gdb.parse_and_eval(func_cname) except RuntimeError: func_address = 0 else: # Seriously? Why is the address not an int? func_address = int(str(gdb_value.address).split()[0], 0) a = ', '.join('%s=%s' % (name, val) for name, val in func_args) print '#%-2d 0x%016x in %s(%s)' % (index, func_address, func_name, a), if source_desc.filename is not None: print 'at %s:%s' % (source_desc.filename, lineno), print try: print ' ' + source_desc.get_source(lineno) except gdb.GdbError: pass selected_frame.select()
def is_python_function(self, frame): """ Tells if a frame is associated with a Python function. If we can't read the Python frame information, don't regard it as such. """ if frame.name() == 'PyEval_EvalFrameEx': pyframe = libpython.Frame(frame).get_pyop() return pyframe and not pyframe.is_optimized_out() return False
def test_python_step(self): self.break_and_run('os.path.join("foo", "bar")') result = gdb.execute('cy step', to_string=True) curframe = gdb.selected_frame() self.assertEqual(curframe.name(), 'PyEval_EvalFrameEx') pyframe = libpython.Frame(curframe).get_pyop() # With Python 3 inferiors, pyframe.co_name will return a PyUnicodePtr, # be compatible frame_name = pyframe.co_name.proxyval(set()) self.assertEqual(frame_name, 'join') assert re.match(r'\d+ def join\(', result), result
def print_stackframe(self, frame, index, is_c=False): if not is_c and self.is_python_function(frame): pyframe = libpython.Frame(frame).get_pyop() if pyframe is None or pyframe.is_optimized_out(): # print this python function as a C function return self.print_stackframe(frame, index, is_c=True) func_name = pyframe.co_name func_cname = 'PyEval_EvalFrameEx' func_args = [] elif self.is_cython_function(frame): cyfunc = self.get_cython_function(frame) # f = lambda arg: self.cy.cy_cvalue.invoke(arg, frame=frame) func_name = cyfunc.name func_cname = cyfunc.cname func_args = [] # [(arg, f(arg)) for arg in cyfunc.arguments] else: func_name = frame.name() func_cname = func_name func_args = [] try: gdb_value = gdb.parse_and_eval(func_cname) except (RuntimeError, TypeError): func_address = 0 else: func_address = int(str(gdb_value.address).split()[0], 0) out = '#%-2d 0x%016x' % (index, func_address) try: a = ', '.join('%s=%s' % (name, val) for name, val in func_args) out += ' in %s (%s)' % (func_name or "??", a) source_desc, lineno = self.get_source_desc(frame) if source_desc.filename is not None: out += ' at %s:%s' % (source_desc.filename, lineno) except Exception: return finally: print(out) try: source = source_desc.get_source(lineno - 5, lineno + 5, mark_line=lineno, lex_entire=True) print(source) except gdb.GdbError: pass