summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2012-06-27 18:15:34 (GMT)
committerDavid Malcolm <dmalcolm@redhat.com>2012-06-27 18:15:34 (GMT)
commit8d37ffa563cf552dd34990bfefd935eef8adfd11 (patch)
tree57f7147b9a540a984157a5d37777377ae21d7155 /Lib
parent5d2ecfb7809d6f21df431f3143834367aa27e634 (diff)
downloadcpython-8d37ffa563cf552dd34990bfefd935eef8adfd11.zip
cpython-8d37ffa563cf552dd34990bfefd935eef8adfd11.tar.gz
cpython-8d37ffa563cf552dd34990bfefd935eef8adfd11.tar.bz2
Issue #12605: Show information on more C frames within gdb backtraces
The gdb hooks for debugging CPython (within Tools/gdb) have been enhanced to show information on more C frames relevant to CPython within the "py-bt" and "py-bt-full" commands: * C frames that are waiting on the GIL * C frames that are garbage-collecting * C frames that are due to the invocation of a PyCFunction
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_gdb.py101
1 files changed, 99 insertions, 2 deletions
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index fd1275c..27fccd6 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -11,6 +11,12 @@ import sysconfig
import unittest
import locale
+# Is this Python configured to support threads?
+try:
+ import _thread
+except ImportError:
+ _thread = None
+
from test.support import run_unittest, findfile, python_is_optimized
try:
@@ -151,7 +157,6 @@ class DebuggerTests(unittest.TestCase):
# Ensure no unexpected error messages:
self.assertEqual(err, '')
-
return out
def get_gdb_repr(self, source,
@@ -172,7 +177,7 @@ class DebuggerTests(unittest.TestCase):
# gdb can insert additional '\n' and space characters in various places
# in its output, depending on the width of the terminal it's connected
# to (using its "wrap_here" function)
- m = re.match('.*#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)\)\s+at\s+Python/bltinmodule.c.*',
+ m = re.match('.*#0\s+builtin_id\s+\(self\=.*,\s+v=\s*(.*?)\)\s+at\s+\S*Python/bltinmodule.c.*',
gdb_output, re.DOTALL)
if not m:
self.fail('Unexpected gdb output: %r\n%s' % (gdb_output, gdb_output))
@@ -671,6 +676,98 @@ Traceback \(most recent call first\):
foo\(1, 2, 3\)
''')
+ @unittest.skipUnless(_thread,
+ "Python was compiled without thread support")
+ def test_threads(self):
+ 'Verify that "py-bt" indicates threads that are waiting for the GIL'
+ cmd = '''
+from threading import Thread
+
+class TestThread(Thread):
+ # These threads would run forever, but we'll interrupt things with the
+ # debugger
+ def run(self):
+ i = 0
+ while 1:
+ i += 1
+
+t = {}
+for i in range(4):
+ t[i] = TestThread()
+ t[i].start()
+
+# Trigger a breakpoint on the main thread
+id(42)
+
+'''
+ # Verify with "py-bt":
+ gdb_output = self.get_stack_trace(cmd,
+ cmds_after_breakpoint=['thread apply all py-bt'])
+ self.assertIn('Waiting for the GIL', gdb_output)
+
+ # Verify with "py-bt-full":
+ gdb_output = self.get_stack_trace(cmd,
+ cmds_after_breakpoint=['thread apply all py-bt-full'])
+ self.assertIn('Waiting for the GIL', gdb_output)
+
+ @unittest.skipIf(python_is_optimized(),
+ "Python was compiled with optimizations")
+ # Some older versions of gdb will fail with
+ # "Cannot find new threads: generic error"
+ # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
+ @unittest.skipUnless(_thread,
+ "Python was compiled without thread support")
+ def test_gc(self):
+ 'Verify that "py-bt" indicates if a thread is garbage-collecting'
+ cmd = ('from gc import collect\n'
+ 'id(42)\n'
+ 'def foo():\n'
+ ' collect()\n'
+ 'def bar():\n'
+ ' foo()\n'
+ 'bar()\n')
+ # Verify with "py-bt":
+ gdb_output = self.get_stack_trace(cmd,
+ cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt'],
+ )
+ self.assertIn('Garbage-collecting', gdb_output)
+
+ # Verify with "py-bt-full":
+ gdb_output = self.get_stack_trace(cmd,
+ cmds_after_breakpoint=['break update_refs', 'continue', 'py-bt-full'],
+ )
+ self.assertIn('Garbage-collecting', gdb_output)
+
+ @unittest.skipIf(python_is_optimized(),
+ "Python was compiled with optimizations")
+ # Some older versions of gdb will fail with
+ # "Cannot find new threads: generic error"
+ # unless we add LD_PRELOAD=PATH-TO-libpthread.so.1 as a workaround
+ @unittest.skipUnless(_thread,
+ "Python was compiled without thread support")
+ def test_pycfunction(self):
+ 'Verify that "py-bt" displays invocations of PyCFunction instances'
+ cmd = ('from time import sleep\n'
+ 'def foo():\n'
+ ' sleep(1)\n'
+ 'def bar():\n'
+ ' foo()\n'
+ 'bar()\n')
+ # Verify with "py-bt":
+ gdb_output = self.get_stack_trace(cmd,
+ breakpoint='time_sleep',
+ cmds_after_breakpoint=['bt', 'py-bt'],
+ )
+ self.assertIn('<built-in method sleep', gdb_output)
+
+ # Verify with "py-bt-full":
+ gdb_output = self.get_stack_trace(cmd,
+ breakpoint='time_sleep',
+ cmds_after_breakpoint=['py-bt-full'],
+ )
+ self.assertIn('#0 <built-in method sleep', gdb_output)
+
+
class PyPrintTests(DebuggerTests):
@unittest.skipIf(python_is_optimized(),
"Python was compiled with optimizations")