(root)/
Python-3.11.7/
Lib/
test/
test_gdb/
test_backtrace.py
       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 ")