mirror of https://github.com/python/cpython
merge #15043: Improve test_gdb support of gdb >= 7.4.
Instead of requiring the tester to manually add the path to the python-gdb.py file in the checkout to their .gdbinit file, add it automatically when invoking gdb in the test.
This commit is contained in:
commit
9617ce99a9
|
@ -26,42 +26,58 @@ except OSError:
|
||||||
# This is what "no gdb" looks like. There may, however, be other
|
# This is what "no gdb" looks like. There may, however, be other
|
||||||
# errors that manifest this way too.
|
# errors that manifest this way too.
|
||||||
raise unittest.SkipTest("Couldn't find gdb on the path")
|
raise unittest.SkipTest("Couldn't find gdb on the path")
|
||||||
gdb_version_number = re.search(b"^GNU gdb [^\d]*(\d+)\.", gdb_version)
|
gdb_version_number = re.search(b"^GNU gdb [^\d]*(\d+)\.(\d)", gdb_version)
|
||||||
if int(gdb_version_number.group(1)) < 7:
|
gdb_major_version = int(gdb_version_number.group(1))
|
||||||
|
gdb_minor_version = int(gdb_version_number.group(2))
|
||||||
|
if gdb_major_version < 7:
|
||||||
raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding"
|
raise unittest.SkipTest("gdb versions before 7.0 didn't support python embedding"
|
||||||
" Saw:\n" + gdb_version.decode('ascii', 'replace'))
|
" Saw:\n" + gdb_version.decode('ascii', 'replace'))
|
||||||
|
|
||||||
if not sysconfig.is_python_build():
|
if not sysconfig.is_python_build():
|
||||||
raise unittest.SkipTest("test_gdb only works on source builds at the moment.")
|
raise unittest.SkipTest("test_gdb only works on source builds at the moment.")
|
||||||
|
|
||||||
|
# Location of custom hooks file in a repository checkout.
|
||||||
|
checkout_hook_path = os.path.join(os.path.dirname(sys.executable),
|
||||||
|
'python-gdb.py')
|
||||||
|
|
||||||
|
def run_gdb(*args, **env_vars):
|
||||||
|
"""Runs gdb in --batch mode with the additional arguments given by *args.
|
||||||
|
|
||||||
|
Returns its (stdout, stderr) decoded from utf-8 using the replace handler.
|
||||||
|
"""
|
||||||
|
if env_vars:
|
||||||
|
env = os.environ.copy()
|
||||||
|
env.update(env_vars)
|
||||||
|
else:
|
||||||
|
env = None
|
||||||
|
base_cmd = ('gdb', '--batch')
|
||||||
|
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()
|
||||||
|
return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace')
|
||||||
|
|
||||||
# Verify that "gdb" was built with the embedded python support enabled:
|
# Verify that "gdb" was built with the embedded python support enabled:
|
||||||
cmd = "--eval-command=python import sys; print sys.version_info"
|
gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_info")
|
||||||
p = subprocess.Popen(["gdb", "--batch", cmd],
|
if not gdbpy_version:
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
gdbpy_version, _ = p.communicate()
|
|
||||||
if gdbpy_version == b'':
|
|
||||||
raise unittest.SkipTest("gdb not built with embedded python support")
|
raise unittest.SkipTest("gdb not built with embedded python support")
|
||||||
|
|
||||||
# Verify that "gdb" can load our custom hooks
|
# Verify that "gdb" can load our custom hooks. In theory this should never fail.
|
||||||
p = subprocess.Popen(["gdb", "--batch", cmd,
|
cmd = ['--args', sys.executable]
|
||||||
"--args", sys.executable],
|
_, gdbpy_errors = run_gdb('--args', sys.executable)
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
if "auto-loading has been declined" in gdbpy_errors:
|
||||||
__, gdbpy_errors = p.communicate()
|
msg = "gdb security settings prevent use of custom hooks: "
|
||||||
if b"auto-loading has been declined" in gdbpy_errors:
|
raise unittest.SkipTest(msg + gdbpy_errors.rstrip())
|
||||||
msg = "gdb security settings prevent use of custom hooks: %s"
|
|
||||||
raise unittest.SkipTest(msg % gdbpy_errors)
|
|
||||||
|
|
||||||
def gdb_has_frame_select():
|
def gdb_has_frame_select():
|
||||||
# Does this build of gdb have gdb.Frame.select ?
|
# Does this build of gdb have gdb.Frame.select ?
|
||||||
cmd = "--eval-command=python print(dir(gdb.Frame))"
|
stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))")
|
||||||
p = subprocess.Popen(["gdb", "--batch", cmd],
|
m = re.match(r'.*\[(.*)\].*', stdout)
|
||||||
stdout=subprocess.PIPE)
|
|
||||||
stdout, _ = p.communicate()
|
|
||||||
m = re.match(br'.*\[(.*)\].*', stdout)
|
|
||||||
if not m:
|
if not m:
|
||||||
raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test")
|
raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test")
|
||||||
gdb_frame_dir = m.group(1).split(b', ')
|
gdb_frame_dir = m.group(1).split(', ')
|
||||||
return b"'select'" in gdb_frame_dir
|
return "'select'" in gdb_frame_dir
|
||||||
|
|
||||||
HAS_PYUP_PYDOWN = gdb_has_frame_select()
|
HAS_PYUP_PYDOWN = gdb_has_frame_select()
|
||||||
|
|
||||||
|
@ -71,21 +87,6 @@ class DebuggerTests(unittest.TestCase):
|
||||||
|
|
||||||
"""Test that the debugger can debug Python."""
|
"""Test that the debugger can debug Python."""
|
||||||
|
|
||||||
def run_gdb(self, *args, **env_vars):
|
|
||||||
"""Runs gdb with the command line given by *args.
|
|
||||||
|
|
||||||
Returns its stdout, stderr
|
|
||||||
"""
|
|
||||||
if env_vars:
|
|
||||||
env = os.environ.copy()
|
|
||||||
env.update(env_vars)
|
|
||||||
else:
|
|
||||||
env = None
|
|
||||||
out, err = subprocess.Popen(
|
|
||||||
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
|
|
||||||
).communicate()
|
|
||||||
return out.decode('utf-8', 'replace'), err.decode('utf-8', 'replace')
|
|
||||||
|
|
||||||
def get_stack_trace(self, source=None, script=None,
|
def get_stack_trace(self, source=None, script=None,
|
||||||
breakpoint=BREAKPOINT_FN,
|
breakpoint=BREAKPOINT_FN,
|
||||||
cmds_after_breakpoint=None,
|
cmds_after_breakpoint=None,
|
||||||
|
@ -142,7 +143,7 @@ class DebuggerTests(unittest.TestCase):
|
||||||
# print ' '.join(args)
|
# print ' '.join(args)
|
||||||
|
|
||||||
# Use "args" to invoke gdb, capturing stdout, stderr:
|
# Use "args" to invoke gdb, capturing stdout, stderr:
|
||||||
out, err = self.run_gdb(*args, PYTHONHASHSEED='0')
|
out, err = run_gdb(*args, PYTHONHASHSEED='0')
|
||||||
|
|
||||||
# Ignore some noise on stderr due to the pending breakpoint:
|
# Ignore some noise on stderr due to the pending breakpoint:
|
||||||
err = err.replace('Function "%s" not defined.\n' % breakpoint, '')
|
err = err.replace('Function "%s" not defined.\n' % breakpoint, '')
|
||||||
|
@ -159,6 +160,11 @@ class DebuggerTests(unittest.TestCase):
|
||||||
'Do you need "set solib-search-path" or '
|
'Do you need "set solib-search-path" or '
|
||||||
'"set sysroot"?\n',
|
'"set sysroot"?\n',
|
||||||
'')
|
'')
|
||||||
|
err = err.replace('warning: Could not load shared library symbols for '
|
||||||
|
'linux-gate.so.1.\n'
|
||||||
|
'Do you need "set solib-search-path" or '
|
||||||
|
'"set sysroot"?\n',
|
||||||
|
'')
|
||||||
|
|
||||||
# Ensure no unexpected error messages:
|
# Ensure no unexpected error messages:
|
||||||
self.assertEqual(err, '')
|
self.assertEqual(err, '')
|
||||||
|
|
Loading…
Reference in New Issue