1import textwrap 2import unittest 3from test import support 4from test.support import python_is_optimized 5 6from .util import setup_module, DebuggerTests, CET_PROTECTION, SAMPLE_SCRIPT 7 8 9def setUpModule(): 10 setup_module() 11 12 13class PyBtTests(DebuggerTests): 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'''^.* 22Traceback \(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_gil_enabled() 53 @support.requires_resource('cpu') 54 def test_threads(self): 55 'Verify that "py-bt" indicates threads that are waiting for the GIL' 56 cmd = ''' 57from threading import Thread 58 59class TestThread(Thread): 60 # These threads would run forever, but we'll interrupt things with the 61 # debugger 62 def run(self): 63 i = 0 64 while 1: 65 i += 1 66 67t = {} 68for i in range(4): 69 t[i] = TestThread() 70 t[i].start() 71 72# Trigger a breakpoint on the main thread 73id(42) 74 75''' 76 # Verify with "py-bt": 77 gdb_output = self.get_stack_trace(cmd, 78 cmds_after_breakpoint=['thread apply all py-bt']) 79 self.assertIn('Waiting for the GIL', gdb_output) 80 81 # Verify with "py-bt-full": 82 gdb_output = self.get_stack_trace(cmd, 83 cmds_after_breakpoint=['thread apply all py-bt-full']) 84 self.assertIn('Waiting for the GIL', gdb_output) 85 86 @unittest.skipIf(python_is_optimized(), 87 "Python was compiled with optimizations") 88 # Some older versions of gdb will fail with 89 # "Cannot find new threads: generic error" 90 # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround 91 def test_gc(self): 92 'Verify that "py-bt" indicates if a thread is garbage-collecting' 93 cmd = ('from gc import collect\n' 94 'id(42)\n' 95 'def foo():\n' 96 ' collect()\n' 97 'def bar():\n' 98 ' foo()\n' 99 'bar()\n') 100 # Verify with "py-bt": 101 gdb_output = self.get_stack_trace(cmd, 102 cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'], 103 ) 104 self.assertIn('Garbage-collecting', gdb_output) 105 106 # Verify with "py-bt-full": 107 gdb_output = self.get_stack_trace(cmd, 108 cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'], 109 ) 110 self.assertIn('Garbage-collecting', gdb_output) 111 112 @unittest.skipIf(python_is_optimized(), 113 "Python was compiled with optimizations") 114 def test_wrapper_call(self): 115 cmd = textwrap.dedent(''' 116 class MyList(list): 117 def __init__(self): 118 super(*[]).__init__() # wrapper_call() 119 120 id("first break point") 121 l = MyList() 122 ''') 123 cmds_after_breakpoint = ['break wrapper_call', 'continue'] 124 if CET_PROTECTION: 125 # bpo-32962: same case as in get_stack_trace(): 126 # we need an additional 'next' command in order to read 127 # arguments of the innermost function of the call stack. 128 cmds_after_breakpoint.append('next') 129 cmds_after_breakpoint.append('py-bt') 130 131 # Verify with "py-bt": 132 gdb_output = self.get_stack_trace(cmd, 133 cmds_after_breakpoint=cmds_after_breakpoint) 134 self.assertRegex(gdb_output, 135 r"<method-wrapper u?'__init__' of MyList object at ") 136