#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:
R David Murray 2012-10-27 13:22:41 -04:00
parent cad7b31467
commit f9333026f7
1 changed files with 46 additions and 38 deletions

View File

@ -19,39 +19,57 @@ 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'))
# 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, but we don't handle the case of the hooks file not existing if the
# tests are run from an installed Python (we'll produce failures in that case).
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()
@ -61,21 +79,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,
@ -132,7 +135,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, '')
@ -149,6 +152,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, '')