mirror of
https://git.yoctoproject.org/poky
synced 2026-01-29 21:08:42 +01:00
oeqa/selftest: rewrite gdbserver test
The gdbserver test case didn't actually work and doesn't follow the documentation for how to use gdbserver in Yocto. Rewrite the test case to follow the documented process so if that breaks then we're aware. (From OE-Core rev: a8eddb71b16a2b958cde54d0dbd35f7a9467ddd2) Signed-off-by: Ross Burton <ross.burton@arm.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
e015c6cf32
commit
238660fcca
@@ -4,122 +4,63 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
import os
|
||||
from subprocess import Popen, PIPE
|
||||
import threading
|
||||
import time
|
||||
import tempfile
|
||||
import shutil
|
||||
import concurrent.futures
|
||||
|
||||
from oeqa.selftest.case import OESelftestTestCase
|
||||
from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runqemu , runCmd
|
||||
from oeqa.core.exception import OEQATimeoutError
|
||||
|
||||
|
||||
#The test runs gdbserver on qemu and connects the gdb client from host over TCP.
|
||||
#
|
||||
#It builds a cross gdb on the host and compiles the program to be debugged on the target,
|
||||
#launches the gdbserver and tries to connect cross gdb to it.
|
||||
|
||||
|
||||
class GdbTest(OESelftestTestCase):
|
||||
|
||||
def run_gdb(self, native_sysroot=None, **options):
|
||||
# Add path to cross gdb to environment.
|
||||
extra_paths = "%s/usr/bin/%s" % (self.recipe_sysroot_native, self.target_sys)
|
||||
nenv = dict(options.get('env', os.environ))
|
||||
nenv['PATH'] = extra_paths + ':' + nenv.get('PATH', '')
|
||||
options['env'] = nenv
|
||||
|
||||
for count in range(5):
|
||||
# Let the gdb server start before by putting client thread to sleep.
|
||||
# Still, if gdb client happens to start before gdbserver, if will
|
||||
# return "gdb connection timed out". In that case try
|
||||
# connecting again
|
||||
time.sleep(1)
|
||||
cmd = "%s-gdb -ex 'set sysroot %s' -ex \"target remote %s:%s\" -ex continue -ex quit %s" \
|
||||
%(self.target_sys, self.recipe_sysroot_native, self.qemu_ip, self.gdbserver_port, self.binary)
|
||||
r = runCmd(cmd, native_sysroot=self.recipe_sysroot_native, **options)
|
||||
if "Connection timed out" not in r.output:
|
||||
break
|
||||
if count == 4:
|
||||
self.assertTrue(False, "gdb unable to connect to gdbserver")
|
||||
|
||||
def run_gdb_client(self):
|
||||
self.run_gdb(native_sysroot=self.recipe_sysroot_native, ignore_status=False)
|
||||
from oeqa.utils.commands import bitbake, get_bb_var, runqemu, runCmd
|
||||
|
||||
class GdbServerTest(OESelftestTestCase):
|
||||
def test_gdb_server(self):
|
||||
self.target_dst = "/tmp/"
|
||||
self.source = "test.c"
|
||||
self.binary = "test"
|
||||
self.target_source = self.target_dst + self.source
|
||||
self.target_binary = self.target_dst + self.binary
|
||||
self.gdbserver_port = 2001
|
||||
target_arch = self.td["TARGET_ARCH"]
|
||||
target_sys = self.td["TARGET_SYS"]
|
||||
deploy_dir = get_bb_var("DEPLOY_DIR_IMAGE")
|
||||
|
||||
try:
|
||||
# These aren't the actual IP addresses but testexport class needs something defined
|
||||
features = 'TEST_SERVER_IP = "192.168.7.1"\n'
|
||||
features += 'TEST_TARGET_IP = "192.168.7.2"\n'
|
||||
features += 'EXTRA_IMAGE_FEATURES += "ssh-server-openssh"\n'
|
||||
features += 'CORE_IMAGE_EXTRA_INSTALL += "gdbserver packagegroup-core-buildessential"\n'
|
||||
self.write_config(features)
|
||||
features = """
|
||||
IMAGE_GEN_DEBUGFS = "1"
|
||||
IMAGE_FSTYPES_DEBUGFS = "tar.bz2"
|
||||
CORE_IMAGE_EXTRA_INSTALL = "gdbserver"
|
||||
"""
|
||||
self.write_config(features)
|
||||
|
||||
self.target_arch = get_bb_var('TARGET_ARCH')
|
||||
self.target_sys = get_bb_var('TARGET_SYS')
|
||||
gdb_recipe = "gdb-cross-" + target_arch
|
||||
gdb_binary = target_sys + "-gdb"
|
||||
|
||||
recipe = "gdb-cross-%s" %self.target_arch
|
||||
gdb_cross_bitbake_command = "%s -c addto_recipe_sysroot" %recipe
|
||||
bitbake("core-image-minimal %s:do_addto_recipe_sysroot" % gdb_recipe)
|
||||
|
||||
bitbake(gdb_cross_bitbake_command)
|
||||
native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", gdb_recipe)
|
||||
r = runCmd("%s --version" % gdb_binary, native_sysroot=native_sysroot, target_sys=target_sys)
|
||||
self.assertEqual(r.status, 0)
|
||||
self.assertIn("GNU gdb", r.output)
|
||||
|
||||
self.recipe_sysroot_native = get_bb_var('RECIPE_SYSROOT_NATIVE', recipe)
|
||||
with tempfile.TemporaryDirectory(prefix="debugfs-") as debugfs:
|
||||
filename = os.path.join(deploy_dir, "core-image-minimal-%s-dbg.tar.bz2" % self.td["MACHINE"])
|
||||
shutil.unpack_archive(filename, debugfs)
|
||||
filename = os.path.join(deploy_dir, "core-image-minimal-%s.tar.bz2" % self.td["MACHINE"])
|
||||
shutil.unpack_archive(filename, debugfs)
|
||||
|
||||
bitbake('core-image-minimal')
|
||||
with runqemu("core-image-minimal", runqemuparams="nographic") as qemu:
|
||||
status, output = qemu.run_serial("kmod --help")
|
||||
self.assertIn("modprobe", output)
|
||||
|
||||
self.cross_gdb_name = "%s-gdb" %self.target_sys
|
||||
|
||||
# wrap the execution with a qemu instance
|
||||
with runqemu("core-image-minimal", runqemuparams = "nographic") as qemu:
|
||||
status, target_gcc = qemu.run_serial("which gcc")
|
||||
|
||||
self.assertNotEqual(target_gcc, None, 'gcc not found on the target')
|
||||
|
||||
self.qemu_ip = qemu.ip
|
||||
|
||||
# self.tc.files_dir = meta/lib/oeqa/files
|
||||
src = os.path.join(self.tc.files_dir, 'test.c')
|
||||
|
||||
self.logger.debug("src : %s qemu.ip : %s self.target_dst : %s" % (src , self.qemu_ip , self.target_dst))
|
||||
cmd = "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR %s root@%s:%s" % (src, qemu.ip, self.target_dst)
|
||||
result = runCmd(cmd)
|
||||
|
||||
cmd = "cat %s" %(self.target_source)
|
||||
status, output = qemu.run_serial(cmd)
|
||||
self.assertIn("1234", output, "Source file copied to target is different that what is expected")
|
||||
|
||||
cmd = "%s %s -o %s -lm -g" % (target_gcc, self.target_source, self.target_binary)
|
||||
status, output = qemu.run_serial(cmd)
|
||||
|
||||
cmd = "ls %s" %self.target_binary
|
||||
status, output = qemu.run_serial(cmd)
|
||||
self.assertNotIn("No such file or directory", output, "Test file compilation failed on target")
|
||||
|
||||
status, output = qemu.run_serial(self.target_binary)
|
||||
self.assertIn("1234", output, "Test binary is different than what is expected")
|
||||
|
||||
cmd = "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR root@%s:%s %s" % (qemu.ip, self.target_binary, os.getcwd())
|
||||
result = runCmd(cmd)
|
||||
|
||||
cmd = "strip -s --strip-debug %s" %self.target_binary
|
||||
status, output = qemu.run_serial(cmd)
|
||||
|
||||
gdb_client_thread = threading.Thread(target=self.run_gdb_client)
|
||||
gdb_client_thread.start()
|
||||
|
||||
cmd = "gdbserver localhost:%s %s" %(self.gdbserver_port, self.target_binary)
|
||||
status, output = qemu.run_serial(cmd)
|
||||
self.logger.debug("gdbserver status : %s output : %s" % (status, output))
|
||||
|
||||
gdb_client_thread.join()
|
||||
self.assertIn("1234", output, "Expected string (1234) not present in test output")
|
||||
|
||||
except OEQATimeoutError:
|
||||
self.fail("gdbserver test timeout error")
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
||||
def run_gdb():
|
||||
for _ in range(5):
|
||||
time.sleep(2)
|
||||
cmd = "%s --batch -ex 'set sysroot %s' -ex \"target extended-remote %s:9999\" -ex \"info line kmod_help\"" % (gdb_binary, debugfs, qemu.ip)
|
||||
self.logger.warning("starting gdb %s" % cmd)
|
||||
r = runCmd(cmd, native_sysroot=native_sysroot, target_sys=target_sys)
|
||||
self.assertEqual(0, r.status)
|
||||
line_re = r"Line \d+ of \"/usr/src/debug/kmod/.*/tools/kmod.c\" starts at address 0x[0-9A-Fa-f]+ <kmod_help>"
|
||||
self.assertRegex(r.output, line_re)
|
||||
break
|
||||
else:
|
||||
self.fail("Timed out connecting to gdb")
|
||||
future = executor.submit(run_gdb)
|
||||
|
||||
status, output = qemu.run_serial("gdbserver --once :9999 kmod --help")
|
||||
self.assertEqual(status, 1)
|
||||
# The future either returns None, or raises an exception
|
||||
future.result()
|
||||
|
||||
Reference in New Issue
Block a user