diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py index 17b44ea354d..d288d7944a8 100644 --- a/Lib/test/test_gdb.py +++ b/Lib/test/test_gdb.py @@ -611,12 +611,29 @@ $''') $''') class PyBtTests(DebuggerTests): - def test_basic_command(self): + def test_bt(self): 'Verify that the "py-bt" command works' bt = self.get_stack_trace(script=self.get_sample_script(), cmds_after_breakpoint=['py-bt']) self.assertMultilineMatches(bt, r'''^.* +Traceback \(most recent call first\): + File ".*gdb_sample.py", line 10, in baz + id\(42\) + File ".*gdb_sample.py", line 7, in bar + baz\(a, b, c\) + File ".*gdb_sample.py", line 4, in foo + bar\(a, b, c\) + File ".*gdb_sample.py", line 12, in + foo\(1, 2, 3\) +''') + + def test_bt_full(self): + 'Verify that the "py-bt-full" command works' + bt = self.get_stack_trace(script=self.get_sample_script(), + cmds_after_breakpoint=['py-bt-full']) + self.assertMultilineMatches(bt, + r'''^.* #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\) baz\(a, b, c\) #[0-9]+ Frame 0x[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\) diff --git a/Misc/NEWS b/Misc/NEWS index dfde0b2617a..5b014269e7f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -359,6 +359,9 @@ IDLE Tools/Demos ----------- +- Issue #11996: libpython (gdb), replace "py-bt" command by "py-bt-full" and + add a smarter "py-bt" command printing a classic Python traceback. + - Issue #11179: Make ccbench work under Python 3.1 and 2.7 again. Extension Modules diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 93b05283b7b..f3cb1b07c7c 100644 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -931,6 +931,15 @@ class PyFrameObjectPtr(PyObjectPtr): out.write(')') + def print_traceback(self): + if self.is_optimized_out(): + sys.stdout.write(' (frame information optimized out)\n') + visited = set() + sys.stdout.write(' File "%s", line %i, in %s\n' + % (self.co_filename.proxyval(visited), + self.current_line_num(), + self.co_name.proxyval(visited))) + class PySetObjectPtr(PyObjectPtr): _typename = 'PySetObject' @@ -1427,6 +1436,17 @@ class Frame(object): else: sys.stdout.write('#%i\n' % self.get_index()) + def print_traceback(self): + if self.is_evalframeex(): + pyop = self.get_pyop() + if pyop: + pyop.print_traceback() + sys.stdout.write(' %s\n' % pyop.current_line().strip()) + else: + sys.stdout.write(' (unable to read python frame information)\n') + else: + sys.stdout.write(' (not a python frame)\n') + class PyList(gdb.Command): '''List the current Python source code, if any @@ -1551,6 +1571,24 @@ if hasattr(gdb.Frame, 'select'): PyUp() PyDown() +class PyBacktraceFull(gdb.Command): + 'Display the current python frame and all the frames within its call stack (if any)' + def __init__(self): + gdb.Command.__init__ (self, + "py-bt-full", + gdb.COMMAND_STACK, + gdb.COMPLETE_NONE) + + + def invoke(self, args, from_tty): + frame = Frame.get_selected_python_frame() + while frame: + if frame.is_evalframeex(): + frame.print_summary() + frame = frame.older() + +PyBacktraceFull() + class PyBacktrace(gdb.Command): 'Display the current python frame and all the frames within its call stack (if any)' def __init__(self): @@ -1561,10 +1599,11 @@ class PyBacktrace(gdb.Command): def invoke(self, args, from_tty): + sys.stdout.write('Traceback (most recent call first):\n') frame = Frame.get_selected_python_frame() while frame: if frame.is_evalframeex(): - frame.print_summary() + frame.print_traceback() frame = frame.older() PyBacktrace()