| import re |
| import unittest |
| from test.support import python_is_optimized |
| |
| from .util import run_gdb, setup_module, DebuggerTests, SAMPLE_SCRIPT |
| |
| |
| def setUpModule(): |
| setup_module() |
| |
| |
| def gdb_has_frame_select(): |
| # Does this build of gdb have gdb.Frame.select ? |
| stdout, stderr = run_gdb("--eval-command=python print(dir(gdb.Frame))") |
| m = re.match(r'.*\[(.*)\].*', stdout) |
| if not m: |
| raise unittest.SkipTest( |
| f"Unable to parse output from gdb.Frame.select test\n" |
| f"stdout={stdout!r}\n" |
| f"stderr={stderr!r}\n") |
| gdb_frame_dir = m.group(1).split(', ') |
| return "'select'" in gdb_frame_dir |
| |
| HAS_PYUP_PYDOWN = gdb_has_frame_select() |
| |
| |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| class PyListTests(DebuggerTests): |
| def assertListing(self, expected, actual): |
| self.assertEndsWith(actual, expected) |
| |
| def test_basic_command(self): |
| 'Verify that the "py-list" command works' |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-list']) |
| |
| self.assertListing(' 5 \n' |
| ' 6 def bar(a, b, c):\n' |
| ' 7 baz(a, b, c)\n' |
| ' 8 \n' |
| ' 9 def baz(*args):\n' |
| ' >10 id(42)\n' |
| ' 11 \n' |
| ' 12 foo(1, 2, 3)\n', |
| bt) |
| |
| def test_one_abs_arg(self): |
| 'Verify the "py-list" command with one absolute argument' |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-list 9']) |
| |
| self.assertListing(' 9 def baz(*args):\n' |
| ' >10 id(42)\n' |
| ' 11 \n' |
| ' 12 foo(1, 2, 3)\n', |
| bt) |
| |
| def test_two_abs_args(self): |
| 'Verify the "py-list" command with two absolute arguments' |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-list 1,3']) |
| |
| self.assertListing(' 1 # Sample script for use by test_gdb\n' |
| ' 2 \n' |
| ' 3 def foo(a, b, c):\n', |
| bt) |
| |
| SAMPLE_WITH_C_CALL = """ |
| |
| from _testcapi import pyobject_vectorcall |
| |
| def foo(a, b, c): |
| bar(a, b, c) |
| |
| def bar(a, b, c): |
| pyobject_vectorcall(baz, (a, b, c), None) |
| |
| def baz(*args): |
| id(42) |
| |
| foo(1, 2, 3) |
| |
| """ |
| |
| |
| class StackNavigationTests(DebuggerTests): |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_pyup_command(self): |
| 'Verify that the "py-up" command works' |
| bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, |
| cmds_after_breakpoint=['py-up', 'py-up']) |
| self.assertMultilineMatches(bt, |
| r'''^.* |
| #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) |
| #[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+> |
| $''') |
| |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| def test_down_at_bottom(self): |
| 'Verify handling of "py-down" at the bottom of the stack' |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-down']) |
| self.assertEndsWith(bt, |
| 'Unable to find a newer python frame\n') |
| |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| def test_up_at_top(self): |
| 'Verify handling of "py-up" at the top of the stack' |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-up'] * 5) |
| self.assertEndsWith(bt, |
| 'Unable to find an older python frame\n') |
| |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_up_then_down(self): |
| 'Verify "py-up" followed by "py-down"' |
| bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, |
| cmds_after_breakpoint=['py-up', 'py-up', 'py-down']) |
| self.assertMultilineMatches(bt, |
| r'''^.* |
| #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) |
| #[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+> |
| #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\) |
| $''') |
| |
| class PyPrintTests(DebuggerTests): |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_basic_command(self): |
| 'Verify that the "py-print" command works' |
| bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, |
| cmds_after_breakpoint=['py-up', 'py-print args']) |
| self.assertMultilineMatches(bt, |
| r".*\nlocal 'args' = \(1, 2, 3\)\n.*") |
| |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| def test_print_after_up(self): |
| bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL, |
| cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a']) |
| self.assertMultilineMatches(bt, |
| r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*") |
| |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_printing_global(self): |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-up', 'py-print __name__']) |
| self.assertMultilineMatches(bt, |
| r".*\nglobal '__name__' = '__main__'\n.*") |
| |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_printing_builtin(self): |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-up', 'py-print len']) |
| self.assertMultilineMatches(bt, |
| r".*\nbuiltin 'len' = <built-in method len of module object at remote 0x-?[0-9a-f]+>\n.*") |
| |
| class PyLocalsTests(DebuggerTests): |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_basic_command(self): |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-up', 'py-locals']) |
| self.assertMultilineMatches(bt, |
| r".*\nargs = \(1, 2, 3\)\n.*") |
| |
| @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands") |
| @unittest.skipIf(python_is_optimized(), |
| "Python was compiled with optimizations") |
| def test_locals_after_up(self): |
| bt = self.get_stack_trace(script=SAMPLE_SCRIPT, |
| cmds_after_breakpoint=['py-up', 'py-up', 'py-locals']) |
| self.assertMultilineMatches(bt, |
| r'''^.* |
| Locals for foo |
| a = 1 |
| b = 2 |
| c = 3 |
| Locals for <module> |
| .*$''') |