diff options
Diffstat (limited to 'Lib/test/test_gdb.py')
| -rw-r--r-- | Lib/test/test_gdb.py | 108 |
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, |
