summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_gdb.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_gdb.py')
-rw-r--r--Lib/test/test_gdb.py108
1 files changed, 83 insertions, 25 deletions
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index 846422b..b5017b9 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -5,6 +5,7 @@
import os
import re
+import pprint
import subprocess
import sys
import sysconfig
@@ -17,21 +18,37 @@ try:
except ImportError:
_thread = None
+from test import support
from test.support import run_unittest, findfile, python_is_optimized
-try:
- gdb_version, _ = subprocess.Popen(["gdb", "--version"],
- stdout=subprocess.PIPE).communicate()
-except OSError:
- # This is what "no gdb" looks like. There may, however, be other
- # errors that manifest this way too.
- raise unittest.SkipTest("Couldn't find gdb on the path")
-gdb_version_number = re.search(b"^GNU gdb [^\d]*(\d+)\.(\d)", gdb_version)
-gdb_major_version = int(gdb_version_number.group(1))
-gdb_minor_version = int(gdb_version_number.group(2))
+def get_gdb_version():
+ try:
+ proc = subprocess.Popen(["gdb", "-nx", "--version"],
+ stdout=subprocess.PIPE,
+ universal_newlines=True)
+ with proc:
+ version = proc.communicate()[0]
+ except OSError:
+ # This is what "no gdb" looks like. There may, however, be other
+ # errors that manifest this way too.
+ raise unittest.SkipTest("Couldn't find gdb on the path")
+
+ # Regex to parse:
+ # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7
+ # 'GNU gdb (GDB) Fedora 7.9.1-17.fc22\n' -> 7.9
+ # 'GNU gdb 6.1.1 [FreeBSD]\n' -> 6.1
+ # 'GNU gdb (GDB) Fedora (7.5.1-37.fc18)\n' -> 7.5
+ match = re.search(r"^GNU gdb.*?\b(\d+)\.(\d+)", version)
+ if match is None:
+ raise Exception("unable to parse GDB version: %r" % version)
+ return (version, int(match.group(1)), int(match.group(2)))
+
+gdb_version, gdb_major_version, gdb_minor_version = get_gdb_version()
if gdb_major_version < 7:
- raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding"
- " Saw:\n" + gdb_version.decode('ascii', 'replace'))
+ raise unittest.SkipTest("gdb versions before 7.0 didn't support python "
+ "embedding. Saw %s.%s:\n%s"
+ % (gdb_major_version, gdb_minor_version,
+ gdb_version))
if not sysconfig.is_python_build():
raise unittest.SkipTest("test_gdb only works on source builds at the moment.")
@@ -40,6 +57,8 @@ if not sysconfig.is_python_build():
checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
'python-gdb.py')
+PYTHONHASHSEED = '123'
+
def run_gdb(*args, **env_vars):
"""Runs gdb in --batch mode with the additional arguments given by *args.
@@ -50,12 +69,17 @@ def run_gdb(*args, **env_vars):
env.update(env_vars)
else:
env = None
- base_cmd = ('gdb', '--batch')
+ # -nx: Do not execute commands from any .gdbinit initialization files
+ # (issue #22188)
+ base_cmd = ('gdb', '--batch', '-nx')
if (gdb_major_version, gdb_minor_version) >= (7, 4):
base_cmd += ('-iex', 'add-auto-load-safe-path ' + checkout_hook_path)
- out, err = subprocess.Popen(base_cmd + args,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
- ).communicate()
+ proc = subprocess.Popen(base_cmd + args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env=env)
+ with proc:
+ out, err = proc.communicate()
return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace')
# Verify that "gdb" was built with the embedded python support enabled:
@@ -117,7 +141,28 @@ class DebuggerTests(unittest.TestCase):
# Generate a list of commands in gdb's language:
commands = ['set breakpoint pending yes',
'break %s' % breakpoint,
+
+ # The tests assume that the first frame of printed
+ # backtrace will not contain program counter,
+ # that is however not guaranteed by gdb
+ # therefore we need to use 'set print address off' to
+ # make sure the counter is not there. For example:
+ # #0 in PyObject_Print ...
+ # is assumed, but sometimes this can be e.g.
+ # #0 0x00003fffb7dd1798 in PyObject_Print ...
+ 'set print address off',
+
'run']
+
+ # GDB as of 7.4 onwards can distinguish between the
+ # value of a variable at entry vs current value:
+ # http://sourceware.org/gdb/onlinedocs/gdb/Variables.html
+ # which leads to the selftests failing with errors like this:
+ # AssertionError: 'v@entry=()' != '()'
+ # Disable this:
+ if (gdb_major_version, gdb_minor_version) >= (7, 4):
+ commands += ['set print entry-values no']
+
if cmds_after_breakpoint:
commands += cmds_after_breakpoint
else:
@@ -126,7 +171,7 @@ class DebuggerTests(unittest.TestCase):
# print commands
# Use "commands" to generate the arguments with which to invoke "gdb":
- args = ["gdb", "--batch"]
+ args = ["gdb", "--batch", "-nx"]
args += ['--eval-command=%s' % cmd for cmd in commands]
args += ["--args",
sys.executable]
@@ -144,7 +189,7 @@ class DebuggerTests(unittest.TestCase):
# print (' '.join(args))
# Use "args" to invoke gdb, capturing stdout, stderr:
- out, err = run_gdb(*args, PYTHONHASHSEED='0')
+ out, err = run_gdb(*args, PYTHONHASHSEED=PYTHONHASHSEED)
errlines = err.splitlines()
unexpected_errlines = []
@@ -163,8 +208,14 @@ class DebuggerTests(unittest.TestCase):
'linux-vdso.so',
'warning: Could not load shared library symbols for '
'linux-gate.so',
+ 'warning: Could not load shared library symbols for '
+ 'linux-vdso64.so',
'Do you need "set solib-search-path" or '
'"set sysroot"?',
+ 'warning: Source file is more recent than executable.',
+ # Issue #19753: missing symbols on System Z
+ 'Missing separate debuginfo for ',
+ 'Try: zypper install -C ',
)
for line in errlines:
if not line.startswith(ignore_patterns):
@@ -248,9 +299,8 @@ class PrettyPrintTests(DebuggerTests):
def test_dicts(self):
'Verify the pretty-printing of dictionaries'
self.assertGdbRepr({})
- self.assertGdbRepr({'foo': 'bar'})
- self.assertGdbRepr({'foo': 'bar', 'douglas': 42},
- "{'foo': 'bar', 'douglas': 42}")
+ self.assertGdbRepr({'foo': 'bar'}, "{'foo': 'bar'}")
+ self.assertGdbRepr({'foo': 'bar', 'douglas': 42}, "{'douglas': 42, 'foo': 'bar'}")
def test_lists(self):
'Verify the pretty-printing of lists'
@@ -305,26 +355,30 @@ class PrettyPrintTests(DebuggerTests):
def test_tuples(self):
'Verify the pretty-printing of tuples'
- self.assertGdbRepr(tuple())
+ self.assertGdbRepr(tuple(), '()')
self.assertGdbRepr((1,), '(1,)')
self.assertGdbRepr(('foo', 'bar', 'baz'))
def test_sets(self):
'Verify the pretty-printing of sets'
- self.assertGdbRepr(set())
+ if (gdb_major_version, gdb_minor_version) < (7, 3):
+ self.skipTest("pretty-printing of sets needs gdb 7.3 or later")
+ self.assertGdbRepr(set(), 'set()')
self.assertGdbRepr(set(['a', 'b']), "{'a', 'b'}")
self.assertGdbRepr(set([4, 5, 6]), "{4, 5, 6}")
# Ensure that we handle sets containing the "dummy" key value,
# which happens on deletion:
gdb_repr, gdb_output = self.get_gdb_repr('''s = set(['a','b'])
-s.pop()
+s.remove('a')
id(s)''')
self.assertEqual(gdb_repr, "{'b'}")
def test_frozensets(self):
'Verify the pretty-printing of frozensets'
- self.assertGdbRepr(frozenset())
+ if (gdb_major_version, gdb_minor_version) < (7, 3):
+ self.skipTest("pretty-printing of frozensets needs gdb 7.3 or later")
+ self.assertGdbRepr(frozenset(), 'frozenset()')
self.assertGdbRepr(frozenset(['a', 'b']), "frozenset({'a', 'b'})")
self.assertGdbRepr(frozenset([4, 5, 6]), "frozenset({4, 5, 6})")
@@ -841,6 +895,10 @@ class PyLocalsTests(DebuggerTests):
r".*\na = 1\nb = 2\nc = 3\n.*")
def test_main():
+ if support.verbose:
+ print("GDB version %s.%s:" % (gdb_major_version, gdb_minor_version))
+ for line in gdb_version.splitlines():
+ print(" " * 4 + line)
run_unittest(PrettyPrintTests,
PyListTests,
StackNavigationTests,