1 import re
2 import unittest
3 from test.support import python_is_optimized
4
5 from .util import run_gdb, setup_module, DebuggerTests, SAMPLE_SCRIPT
6
7
8 def setUpModule():
9 setup_module()
10
11
12 def gdb_has_frame_select():
13 # Does this build of gdb have gdb.Frame.select ?
14 stdout, stderr = run_gdb("--eval-command=python print(dir(gdb.Frame))")
15 m = re.match(r'.*\[(.*)\].*', stdout)
16 if not m:
17 raise unittest.SkipTest(
18 f"Unable to parse output from gdb.Frame.select test\n"
19 f"stdout={stdout!r}\n"
20 f"stderr={stderr!r}\n")
21 gdb_frame_dir = m.group(1).split(', ')
22 return "'select'" in gdb_frame_dir
23
24 HAS_PYUP_PYDOWN = gdb_has_frame_select()
25
26
27 @unittest.skipIf(python_is_optimized(),
28 "Python was compiled with optimizations")
29 class ESC[4;38;5;81mPyListTests(ESC[4;38;5;149mDebuggerTests):
30 def assertListing(self, expected, actual):
31 self.assertEndsWith(actual, expected)
32
33 def test_basic_command(self):
34 'Verify that the "py-list" command works'
35 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
36 cmds_after_breakpoint=['py-list'])
37
38 self.assertListing(' 5 \n'
39 ' 6 def bar(a, b, c):\n'
40 ' 7 baz(a, b, c)\n'
41 ' 8 \n'
42 ' 9 def baz(*args):\n'
43 ' >10 id(42)\n'
44 ' 11 \n'
45 ' 12 foo(1, 2, 3)\n',
46 bt)
47
48 def test_one_abs_arg(self):
49 'Verify the "py-list" command with one absolute argument'
50 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
51 cmds_after_breakpoint=['py-list 9'])
52
53 self.assertListing(' 9 def baz(*args):\n'
54 ' >10 id(42)\n'
55 ' 11 \n'
56 ' 12 foo(1, 2, 3)\n',
57 bt)
58
59 def test_two_abs_args(self):
60 'Verify the "py-list" command with two absolute arguments'
61 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
62 cmds_after_breakpoint=['py-list 1,3'])
63
64 self.assertListing(' 1 # Sample script for use by test_gdb\n'
65 ' 2 \n'
66 ' 3 def foo(a, b, c):\n',
67 bt)
68
69 SAMPLE_WITH_C_CALL = """
70
71 from _testcapi import pyobject_vectorcall
72
73 def foo(a, b, c):
74 bar(a, b, c)
75
76 def bar(a, b, c):
77 pyobject_vectorcall(baz, (a, b, c), None)
78
79 def baz(*args):
80 id(42)
81
82 foo(1, 2, 3)
83
84 """
85
86
87 class ESC[4;38;5;81mStackNavigationTests(ESC[4;38;5;149mDebuggerTests):
88 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
89 @unittest.skipIf(python_is_optimized(),
90 "Python was compiled with optimizations")
91 def test_pyup_command(self):
92 'Verify that the "py-up" command works'
93 bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
94 cmds_after_breakpoint=['py-up', 'py-up'])
95 self.assertMultilineMatches(bt,
96 r'''^.*
97 #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
98 #[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
99 $''')
100
101 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
102 def test_down_at_bottom(self):
103 'Verify handling of "py-down" at the bottom of the stack'
104 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
105 cmds_after_breakpoint=['py-down'])
106 self.assertEndsWith(bt,
107 'Unable to find a newer python frame\n')
108
109 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
110 def test_up_at_top(self):
111 'Verify handling of "py-up" at the top of the stack'
112 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
113 cmds_after_breakpoint=['py-up'] * 5)
114 self.assertEndsWith(bt,
115 'Unable to find an older python frame\n')
116
117 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
118 @unittest.skipIf(python_is_optimized(),
119 "Python was compiled with optimizations")
120 def test_up_then_down(self):
121 'Verify "py-up" followed by "py-down"'
122 bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
123 cmds_after_breakpoint=['py-up', 'py-up', 'py-down'])
124 self.assertMultilineMatches(bt,
125 r'''^.*
126 #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
127 #[0-9]+ <built-in method pyobject_vectorcall of module object at remote 0x[0-9a-f]+>
128 #[0-9]+ Frame 0x-?[0-9a-f]+, for file <string>, line 12, in baz \(args=\(1, 2, 3\)\)
129 $''')
130
131 class ESC[4;38;5;81mPyPrintTests(ESC[4;38;5;149mDebuggerTests):
132 @unittest.skipIf(python_is_optimized(),
133 "Python was compiled with optimizations")
134 def test_basic_command(self):
135 'Verify that the "py-print" command works'
136 bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
137 cmds_after_breakpoint=['py-up', 'py-print args'])
138 self.assertMultilineMatches(bt,
139 r".*\nlocal 'args' = \(1, 2, 3\)\n.*")
140
141 @unittest.skipIf(python_is_optimized(),
142 "Python was compiled with optimizations")
143 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
144 def test_print_after_up(self):
145 bt = self.get_stack_trace(source=SAMPLE_WITH_C_CALL,
146 cmds_after_breakpoint=['py-up', 'py-up', 'py-print c', 'py-print b', 'py-print a'])
147 self.assertMultilineMatches(bt,
148 r".*\nlocal 'c' = 3\nlocal 'b' = 2\nlocal 'a' = 1\n.*")
149
150 @unittest.skipIf(python_is_optimized(),
151 "Python was compiled with optimizations")
152 def test_printing_global(self):
153 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
154 cmds_after_breakpoint=['py-up', 'py-print __name__'])
155 self.assertMultilineMatches(bt,
156 r".*\nglobal '__name__' = '__main__'\n.*")
157
158 @unittest.skipIf(python_is_optimized(),
159 "Python was compiled with optimizations")
160 def test_printing_builtin(self):
161 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
162 cmds_after_breakpoint=['py-up', 'py-print len'])
163 self.assertMultilineMatches(bt,
164 r".*\nbuiltin 'len' = <built-in method len of module object at remote 0x-?[0-9a-f]+>\n.*")
165
166 class ESC[4;38;5;81mPyLocalsTests(ESC[4;38;5;149mDebuggerTests):
167 @unittest.skipIf(python_is_optimized(),
168 "Python was compiled with optimizations")
169 def test_basic_command(self):
170 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
171 cmds_after_breakpoint=['py-up', 'py-locals'])
172 self.assertMultilineMatches(bt,
173 r".*\nargs = \(1, 2, 3\)\n.*")
174
175 @unittest.skipUnless(HAS_PYUP_PYDOWN, "test requires py-up/py-down commands")
176 @unittest.skipIf(python_is_optimized(),
177 "Python was compiled with optimizations")
178 def test_locals_after_up(self):
179 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
180 cmds_after_breakpoint=['py-up', 'py-up', 'py-locals'])
181 self.assertMultilineMatches(bt,
182 r'''^.*
183 Locals for foo
184 a = 1
185 b = 2
186 c = 3
187 Locals for <module>
188 .*$''')