diff options
-rw-r--r-- | meta/lib/oeqa/selftest/cases/gdbserver.py | 169 |
1 files changed, 55 insertions, 114 deletions
diff --git a/meta/lib/oeqa/selftest/cases/gdbserver.py b/meta/lib/oeqa/selftest/cases/gdbserver.py index 3124902543c..3621d9c13eb 100644 --- a/meta/lib/oeqa/selftest/cases/gdbserver.py +++ b/meta/lib/oeqa/selftest/cases/gdbserver.py @@ -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 - - 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) - - self.target_arch = get_bb_var('TARGET_ARCH') - self.target_sys = get_bb_var('TARGET_SYS') - - recipe = "gdb-cross-%s" %self.target_arch - gdb_cross_bitbake_command = "%s -c addto_recipe_sysroot" %recipe - - bitbake(gdb_cross_bitbake_command) - - self.recipe_sysroot_native = get_bb_var('RECIPE_SYSROOT_NATIVE', recipe) - - bitbake('core-image-minimal') - - 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") - + target_arch = self.td["TARGET_ARCH"] + target_sys = self.td["TARGET_SYS"] + deploy_dir = get_bb_var("DEPLOY_DIR_IMAGE") + + features = """ +IMAGE_GEN_DEBUGFS = "1" +IMAGE_FSTYPES_DEBUGFS = "tar.bz2" +CORE_IMAGE_EXTRA_INSTALL = "gdbserver" + """ + self.write_config(features) + + gdb_recipe = "gdb-cross-" + target_arch + gdb_binary = target_sys + "-gdb" + + bitbake("core-image-minimal %s:do_addto_recipe_sysroot" % gdb_recipe) + + 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) + + 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) + + with runqemu("core-image-minimal", runqemuparams="nographic") as qemu: + status, output = qemu.run_serial("kmod --help") + self.assertIn("modprobe", output) + + 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() |