summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/lib/oeqa/selftest/cases/gdbserver.py169
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 3124902543..3621d9c13e 100644
--- a/meta/lib/oeqa/selftest/cases/gdbserver.py
+++ b/meta/lib/oeqa/selftest/cases/gdbserver.py
@@ -4,122 +4,63 @@
4# SPDX-License-Identifier: MIT 4# SPDX-License-Identifier: MIT
5# 5#
6import os 6import os
7from subprocess import Popen, PIPE
8import threading
9import time 7import time
8import tempfile
9import shutil
10import concurrent.futures
10 11
11from oeqa.selftest.case import OESelftestTestCase 12from oeqa.selftest.case import OESelftestTestCase
12from oeqa.utils.commands import bitbake, get_bb_var, get_bb_vars, runqemu , runCmd 13from oeqa.utils.commands import bitbake, get_bb_var, runqemu, runCmd
13from oeqa.core.exception import OEQATimeoutError
14
15
16#The test runs gdbserver on qemu and connects the gdb client from host over TCP.
17#
18#It builds a cross gdb on the host and compiles the program to be debugged on the target,
19#launches the gdbserver and tries to connect cross gdb to it.
20
21
22class GdbTest(OESelftestTestCase):
23
24 def run_gdb(self, native_sysroot=None, **options):
25 # Add path to cross gdb to environment.
26 extra_paths = "%s/usr/bin/%s" % (self.recipe_sysroot_native, self.target_sys)
27 nenv = dict(options.get('env', os.environ))
28 nenv['PATH'] = extra_paths + ':' + nenv.get('PATH', '')
29 options['env'] = nenv
30
31 for count in range(5):
32 # Let the gdb server start before by putting client thread to sleep.
33 # Still, if gdb client happens to start before gdbserver, if will
34 # return "gdb connection timed out". In that case try
35 # connecting again
36 time.sleep(1)
37 cmd = "%s-gdb -ex 'set sysroot %s' -ex \"target remote %s:%s\" -ex continue -ex quit %s" \
38 %(self.target_sys, self.recipe_sysroot_native, self.qemu_ip, self.gdbserver_port, self.binary)
39 r = runCmd(cmd, native_sysroot=self.recipe_sysroot_native, **options)
40 if "Connection timed out" not in r.output:
41 break
42 if count == 4:
43 self.assertTrue(False, "gdb unable to connect to gdbserver")
44
45 def run_gdb_client(self):
46 self.run_gdb(native_sysroot=self.recipe_sysroot_native, ignore_status=False)
47 14
15class GdbServerTest(OESelftestTestCase):
48 def test_gdb_server(self): 16 def test_gdb_server(self):
49 self.target_dst = "/tmp/" 17 target_arch = self.td["TARGET_ARCH"]
50 self.source = "test.c" 18 target_sys = self.td["TARGET_SYS"]
51 self.binary = "test" 19 deploy_dir = get_bb_var("DEPLOY_DIR_IMAGE")
52 self.target_source = self.target_dst + self.source 20
53 self.target_binary = self.target_dst + self.binary 21 features = """
54 self.gdbserver_port = 2001 22IMAGE_GEN_DEBUGFS = "1"
55 23IMAGE_FSTYPES_DEBUGFS = "tar.bz2"
56 try: 24CORE_IMAGE_EXTRA_INSTALL = "gdbserver"
57 # These aren't the actual IP addresses but testexport class needs something defined 25 """
58 features = 'TEST_SERVER_IP = "192.168.7.1"\n' 26 self.write_config(features)
59 features += 'TEST_TARGET_IP = "192.168.7.2"\n' 27
60 features += 'EXTRA_IMAGE_FEATURES += "ssh-server-openssh"\n' 28 gdb_recipe = "gdb-cross-" + target_arch
61 features += 'CORE_IMAGE_EXTRA_INSTALL += "gdbserver packagegroup-core-buildessential"\n' 29 gdb_binary = target_sys + "-gdb"
62 self.write_config(features) 30
63 31 bitbake("core-image-minimal %s:do_addto_recipe_sysroot" % gdb_recipe)
64 self.target_arch = get_bb_var('TARGET_ARCH') 32
65 self.target_sys = get_bb_var('TARGET_SYS') 33 native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", gdb_recipe)
66 34 r = runCmd("%s --version" % gdb_binary, native_sysroot=native_sysroot, target_sys=target_sys)
67 recipe = "gdb-cross-%s" %self.target_arch 35 self.assertEqual(r.status, 0)
68 gdb_cross_bitbake_command = "%s -c addto_recipe_sysroot" %recipe 36 self.assertIn("GNU gdb", r.output)
69 37
70 bitbake(gdb_cross_bitbake_command) 38 with tempfile.TemporaryDirectory(prefix="debugfs-") as debugfs:
71 39 filename = os.path.join(deploy_dir, "core-image-minimal-%s-dbg.tar.bz2" % self.td["MACHINE"])
72 self.recipe_sysroot_native = get_bb_var('RECIPE_SYSROOT_NATIVE', recipe) 40 shutil.unpack_archive(filename, debugfs)
73 41 filename = os.path.join(deploy_dir, "core-image-minimal-%s.tar.bz2" % self.td["MACHINE"])
74 bitbake('core-image-minimal') 42 shutil.unpack_archive(filename, debugfs)
75 43
76 self.cross_gdb_name = "%s-gdb" %self.target_sys 44 with runqemu("core-image-minimal", runqemuparams="nographic") as qemu:
77 45 status, output = qemu.run_serial("kmod --help")
78 # wrap the execution with a qemu instance 46 self.assertIn("modprobe", output)
79 with runqemu("core-image-minimal", runqemuparams = "nographic") as qemu: 47
80 status, target_gcc = qemu.run_serial("which gcc") 48 with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
81 49 def run_gdb():
82 self.assertNotEqual(target_gcc, None, 'gcc not found on the target') 50 for _ in range(5):
83 51 time.sleep(2)
84 self.qemu_ip = qemu.ip 52 cmd = "%s --batch -ex 'set sysroot %s' -ex \"target extended-remote %s:9999\" -ex \"info line kmod_help\"" % (gdb_binary, debugfs, qemu.ip)
85 53 self.logger.warning("starting gdb %s" % cmd)
86 # self.tc.files_dir = meta/lib/oeqa/files 54 r = runCmd(cmd, native_sysroot=native_sysroot, target_sys=target_sys)
87 src = os.path.join(self.tc.files_dir, 'test.c') 55 self.assertEqual(0, r.status)
88 56 line_re = r"Line \d+ of \"/usr/src/debug/kmod/.*/tools/kmod.c\" starts at address 0x[0-9A-Fa-f]+ <kmod_help>"
89 self.logger.debug("src : %s qemu.ip : %s self.target_dst : %s" % (src , self.qemu_ip , self.target_dst)) 57 self.assertRegex(r.output, line_re)
90 cmd = "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR %s root@%s:%s" % (src, qemu.ip, self.target_dst) 58 break
91 result = runCmd(cmd) 59 else:
92 60 self.fail("Timed out connecting to gdb")
93 cmd = "cat %s" %(self.target_source) 61 future = executor.submit(run_gdb)
94 status, output = qemu.run_serial(cmd) 62
95 self.assertIn("1234", output, "Source file copied to target is different that what is expected") 63 status, output = qemu.run_serial("gdbserver --once :9999 kmod --help")
96 64 self.assertEqual(status, 1)
97 cmd = "%s %s -o %s -lm -g" % (target_gcc, self.target_source, self.target_binary) 65 # The future either returns None, or raises an exception
98 status, output = qemu.run_serial(cmd) 66 future.result()
99
100 cmd = "ls %s" %self.target_binary
101 status, output = qemu.run_serial(cmd)
102 self.assertNotIn("No such file or directory", output, "Test file compilation failed on target")
103
104 status, output = qemu.run_serial(self.target_binary)
105 self.assertIn("1234", output, "Test binary is different than what is expected")
106
107 cmd = "scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=ERROR root@%s:%s %s" % (qemu.ip, self.target_binary, os.getcwd())
108 result = runCmd(cmd)
109
110 cmd = "strip -s --strip-debug %s" %self.target_binary
111 status, output = qemu.run_serial(cmd)
112
113 gdb_client_thread = threading.Thread(target=self.run_gdb_client)
114 gdb_client_thread.start()
115
116 cmd = "gdbserver localhost:%s %s" %(self.gdbserver_port, self.target_binary)
117 status, output = qemu.run_serial(cmd)
118 self.logger.debug("gdbserver status : %s output : %s" % (status, output))
119
120 gdb_client_thread.join()
121 self.assertIn("1234", output, "Expected string (1234) not present in test output")
122
123 except OEQATimeoutError:
124 self.fail("gdbserver test timeout error")
125