1 import textwrap
2 import unittest
3 from test import support
4 from test.support import python_is_optimized
5
6 from .util import setup_module, DebuggerTests, CET_PROTECTION, SAMPLE_SCRIPT
7
8
9 def setUpModule():
10 setup_module()
11
12
13 class ESC[4;38;5;81mPyBtTests(ESC[4;38;5;149mDebuggerTests):
14 @unittest.skipIf(python_is_optimized(),
15 "Python was compiled with optimizations")
16 def test_bt(self):
17 'Verify that the "py-bt" command works'
18 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
19 cmds_after_breakpoint=['py-bt'])
20 self.assertMultilineMatches(bt,
21 r'''^.*
22 Traceback \(most recent call first\):
23 <built-in method id of module object .*>
24 File ".*gdb_sample.py", line 10, in baz
25 id\(42\)
26 File ".*gdb_sample.py", line 7, in bar
27 baz\(a, b, c\)
28 File ".*gdb_sample.py", line 4, in foo
29 bar\(a=a, b=b, c=c\)
30 File ".*gdb_sample.py", line 12, in <module>
31 foo\(1, 2, 3\)
32 ''')
33
34 @unittest.skipIf(python_is_optimized(),
35 "Python was compiled with optimizations")
36 def test_bt_full(self):
37 'Verify that the "py-bt-full" command works'
38 bt = self.get_stack_trace(script=SAMPLE_SCRIPT,
39 cmds_after_breakpoint=['py-bt-full'])
40 self.assertMultilineMatches(bt,
41 r'''^.*
42 #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 7, in bar \(a=1, b=2, c=3\)
43 baz\(a, b, c\)
44 #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 4, in foo \(a=1, b=2, c=3\)
45 bar\(a=a, b=b, c=c\)
46 #[0-9]+ Frame 0x-?[0-9a-f]+, for file .*gdb_sample.py, line 12, in <module> \(\)
47 foo\(1, 2, 3\)
48 ''')
49
50 @unittest.skipIf(python_is_optimized(),
51 "Python was compiled with optimizations")
52 @support.requires_resource('cpu')
53 def test_threads(self):
54 'Verify that "py-bt" indicates threads that are waiting for the GIL'
55 cmd = '''
56 from threading import Thread
57
58 class TestThread(Thread):
59 # These threads would run forever, but we'll interrupt things with the
60 # debugger
61 def run(self):
62 i = 0
63 while 1:
64 i += 1
65
66 t = {}
67 for i in range(4):
68 t[i] = TestThread()
69 t[i].start()
70
71 # Trigger a breakpoint on the main thread
72 id(42)
73
74 '''
75 # Verify with "py-bt":
76 gdb_output = self.get_stack_trace(cmd,
77 cmds_after_breakpoint=['thread apply all py-bt'])
78 self.assertIn('Waiting for the GIL', gdb_output)
79
80 # Verify with "py-bt-full":
81 gdb_output = self.get_stack_trace(cmd,
82 cmds_after_breakpoint=['thread apply all py-bt-full'])
83 self.assertIn('Waiting for the GIL', gdb_output)
84
85 @unittest.skipIf(python_is_optimized(),
86 "Python was compiled with optimizations")
87 # Some older versions of gdb will fail with
88 # "Cannot find new threads: generic error"
89 # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
90 def test_gc(self):
91 'Verify that "py-bt" indicates if a thread is garbage-collecting'
92 cmd = ('from gc import collect\n'
93 'id(42)\n'
94 'def foo():\n'
95 ' collect()\n'
96 'def bar():\n'
97 ' foo()\n'
98 'bar()\n')
99 # Verify with "py-bt":
100 gdb_output = self.get_stack_trace(cmd,
101 cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'],
102 )
103 self.assertIn('Garbage-collecting', gdb_output)
104
105 # Verify with "py-bt-full":
106 gdb_output = self.get_stack_trace(cmd,
107 cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'],
108 )
109 self.assertIn('Garbage-collecting', gdb_output)
110
111 @unittest.skipIf(python_is_optimized(),
112 "Python was compiled with optimizations")
113 def test_wrapper_call(self):
114 cmd = textwrap.dedent('''
115 class MyList(list):
116 def __init__(self):
117 super(*[]).__init__() # wrapper_call()
118
119 id("first break point")
120 l = MyList()
121 ''')
122 cmds_after_breakpoint = ['break wrapper_call', 'continue']
123 if CET_PROTECTION:
124 # bpo-32962: same case as in get_stack_trace():
125 # we need an additional 'next' command in order to read
126 # arguments of the innermost function of the call stack.
127 cmds_after_breakpoint.append('next')
128 cmds_after_breakpoint.append('py-bt')
129
130 # Verify with "py-bt":
131 gdb_output = self.get_stack_trace(cmd,
132 cmds_after_breakpoint=cmds_after_breakpoint)
133 self.assertRegex(gdb_output,
134 r"<method-wrapper u?'__init__' of MyList object at ")