2023-09-28 08:24:15 -03:00
|
|
|
import re
|
|
|
|
import unittest
|
|
|
|
from test.support import python_is_optimized
|
|
|
|
|
2023-09-28 14:04:01 -03:00
|
|
|
from .util import run_gdb, setup_module, DebuggerTests, SAMPLE_SCRIPT
|
2023-09-28 08:24:15 -03:00
|
|
|
|
|
|
|
|
|
|
|
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'
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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'
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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'
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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'
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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'
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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):
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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):
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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):
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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):
|
2023-09-28 14:04:01 -03:00
|
|
|
bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
|
2023-09-28 08:24:15 -03:00
|
|
|
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>
|
|
|
|
.*$''')
|