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
|
||||
# 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+)\.", gdb_version)
|
||||
if int(gdb_version_number.group(1)) < 7:
|
||||
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))
|
||||
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'))
|
||||
|
||||
if not sysconfig.is_python_build():
|
||||
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:
|
||||
cmd = "--eval-command=python import sys; print sys.version_info"
|
||||
p = subprocess.Popen(["gdb", "--batch", cmd],
|
||||
stdout=subprocess.PIPE)
|
||||
gdbpy_version, _ = p.communicate()
|
||||
if gdbpy_version == b'':
|
||||
gdbpy_version, _ = run_gdb("--eval-command=python import sys; print sys.version_info")
|
||||
if not gdbpy_version:
|
||||
raise unittest.SkipTest("gdb not built with embedded python support")
|
||||
|
||||
# Verify that "gdb" can load our custom hooks
|
||||
p = subprocess.Popen(["gdb", "--batch", cmd,
|
||||
"--args", sys.executable],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
__, gdbpy_errors = p.communicate()
|
||||
if b"auto-loading has been declined" in gdbpy_errors:
|
||||
msg = "gdb security settings prevent use of custom hooks: %s"
|
||||
raise unittest.SkipTest(msg % gdbpy_errors)
|
||||
# Verify that "gdb" can load our custom hooks. In theory this should never fail.
|
||||
cmd = ['--args', sys.executable]
|
||||
_, gdbpy_errors = run_gdb('--args', sys.executable)
|
||||
if "auto-loading has been declined" in gdbpy_errors:
|
||||
msg = "gdb security settings prevent use of custom hooks: "
|
||||
raise unittest.SkipTest(msg + gdbpy_errors.rstrip())
|
||||
|
||||
def gdb_has_frame_select():
|
||||
# Does this build of gdb have gdb.Frame.select ?
|
||||
cmd = "--eval-command=python print(dir(gdb.Frame))"
|
||||
p = subprocess.Popen(["gdb", "--batch", cmd],
|
||||
stdout=subprocess.PIPE)
|
||||
stdout, _ = p.communicate()
|
||||
m = re.match(br'.*\[(.*)\].*', stdout)
|
||||
stdout, _ = run_gdb("--eval-command=python print(dir(gdb.Frame))")
|
||||
m = re.match(r'.*\[(.*)\].*', stdout)
|
||||
if not m:
|
||||
raise unittest.SkipTest("Unable to parse output from gdb.Frame.select test")
|
||||
gdb_frame_dir = m.group(1).split(b', ')
|
||||
return b"'select'" in gdb_frame_dir
|
||||
gdb_frame_dir = m.group(1).split(', ')
|
||||
return "'select'" in gdb_frame_dir
|
||||
|
||||
HAS_PYUP_PYDOWN = gdb_has_frame_select()
|
||||
|
||||
|
@ -71,21 +87,6 @@ class DebuggerTests(unittest.TestCase):
|
|||
|
||||
"""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,
|
||||
breakpoint=BREAKPOINT_FN,
|
||||
cmds_after_breakpoint=None,
|
||||
|
@ -142,7 +143,7 @@ class DebuggerTests(unittest.TestCase):
|
|||
# print ' '.join(args)
|
||||
|
||||
# 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:
|
||||
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 '
|
||||
'"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:
|
||||
self.assertEqual(err, '')
|
||||
|
|
Loading…
Reference in New Issue