@@ -4472,6 +4472,133 @@ class DevtoolIdeSdkRustTests(DevtoolIdeSdkTests):
if task['label'].startswith('install && deploy-target '))
self.assertEqual(install_task['dependsOn'], [build_task['label']])
+ @OETestTag("runqemu")
+ def test_code_cargo_qemu_slirp(self):
+ recipe_name = 'cargo-example'
+ testimage = 'oe-selftest-image'
+ self._check_workspace()
+ self._write_bb_config()
+ tempdir = self._devtool_ide_sdk_recipe(
+ recipe_name, 'Cargo.toml', testimage)
+ port_start = self._reserve_slirp_port_block()
+ port_opts = ' -G %d' % port_start
+ runCmd(
+ 'devtool ide-sdk %s %s --ide=code --target root@localhost '
+ '--port 2222 --no-host-check%s' % (
+ recipe_name, testimage, port_opts),
+ output_log=self._cmd_logger)
+ source_remap = '--remap-path-prefix=%s=%s' % (
+ os.path.realpath(tempdir),
+ get_bb_var('TARGET_DBGSRC_DIR', recipe_name))
+ rustflags = shlex.split(get_bb_var('RUSTFLAGS', recipe_name))
+ self.assertIn(
+ source_remap, rustflags,
+ 'Cargo BitBake builds must remap the external source tree for DWARF')
+ self._verify_slirp_bbappend(testimage)
+
+ with runqemu(
+ testimage, runqemuparams='nographic slirp snapshot') as qemu:
+ self.assertIsNotNone(qemu.port, 'No SSH port for the slirp target')
+ runCmd(
+ 'devtool ide-sdk %s %s %s --skip-bitbake --ide=code%s' % (
+ recipe_name, testimage,
+ '-t root@%s -P %s --no-host-check' % (qemu.ip, qemu.port),
+ port_opts),
+ output_log=self._cmd_logger)
+ rustflags = shlex.split(get_bb_var('RUSTFLAGS', recipe_name))
+ self.assertIn(
+ source_remap, rustflags,
+ 'Repeated ide-sdk runs must preserve the Cargo source remap')
+ self._verify_rust_lldb_debugging(tempdir, expected_input=4)
+
+ def _verify_rust_lldb_debugging(self, tempdir, expected_input):
+ with open(os.path.join(tempdir, '.vscode', 'launch.json')) as launch_file:
+ launch = json.load(launch_file)['configurations'][0]
+ with open(os.path.join(tempdir, '.vscode', 'tasks.json')) as tasks_file:
+ tasks = json.load(tasks_file)['tasks']
+
+ self.assertEqual(launch['type'], 'lldb')
+ target_dbgsrc_dir = get_bb_var('TARGET_DBGSRC_DIR', 'cargo-example')
+ self.assertEqual(
+ launch['sourceMap'][target_dbgsrc_dir], os.path.realpath(tempdir))
+ self._run_vscode_task_with_dependencies(
+ tempdir, launch['preLaunchTask'], run_main_task=False)
+ server_task = next(
+ task for task in tasks if task['label'] == launch['preLaunchTask'])
+ self.assertEqual(server_task['command'], 'ssh')
+ ssh_args = [server_task['command']] + server_task['args']
+ if ssh_args[-1].startswith('"') and ssh_args[-1].endswith('"'):
+ ssh_args[-1] = ssh_args[-1][1:-1].replace('\\$', '$')
+ runCmd(ssh_args, output_log=self._cmd_logger)
+
+ source_line = self._find_source_break_line(
+ tempdir, 'src/main.rs', ' match n {')
+ println_line = self._find_source_break_line(
+ tempdir, 'src/main.rs', 'println!')
+ lldb_batch = [
+ os.path.join(
+ get_bb_var('RECIPE_SYSROOT_NATIVE', 'lldb-native'),
+ 'usr', 'bin', 'lldb'),
+ '--batch',
+ ]
+ for command in launch['initCommands'] + launch['targetCreateCommands']:
+ lldb_batch += ['-o', command]
+ source_map_args = []
+ for source, destination in launch.get('sourceMap', {}).items():
+ source_map_args += [source, destination]
+ if source_map_args:
+ lldb_batch += [
+ '-o', 'settings set target.source-map %s' %
+ ' '.join(source_map_args)]
+ lldb_batch += [
+ '-o', 'breakpoint set --file main.rs --line %d' % source_line,
+ '-o', 'breakpoint set --file main.rs --line %d' % println_line,
+ '-o', 'breakpoint disable 2',
+ '-o', 'breakpoint list',
+ '-o', 'run',
+ '-o', 'frame variable n',
+ '-o', 'thread backtrace',
+ '-o', 'breakpoint disable 1',
+ '-o', 'breakpoint enable 2',
+ '-o', 'continue',
+ '-o', 'frame info',
+ '-o', 'frame select 1',
+ '-o', 'frame info',
+ '-o', 'frame select 3',
+ '-o', "image lookup -v -r -n 'std::rt::lang_start.*'",
+ '-o', 'thread backtrace',
+ '-o', 'exit',
+ ]
+ result = runCmd(lldb_batch, timeout=60, output_log=self._cmd_logger)
+ self.assertNotIn('(pending)', result.output)
+ self.assertIn('cargo_example::fibonacci', result.output)
+ self.assertIn('cargo_example::main', result.output)
+ self.assertIn('std::rt::lang_start', result.output)
+ self.assertIn('__libc_start', result.output)
+ self.assertRegex(result.output, r'n\s*=\s*%d' % expected_input)
+ libstd_rustsrc = get_bb_var('RUSTSRC', 'libstd-rs')
+ libstd_work_shared = os.path.join(
+ get_bb_var('TMPDIR', 'libstd-rs'), 'work-shared')
+ rust_std_target_root = os.path.join(
+ get_bb_var('TARGET_DBGSRC_DIR', 'libstd-rs'),
+ os.path.relpath(libstd_rustsrc, libstd_work_shared),
+ 'library')
+ rust_std_sdk_root = os.path.join(
+ get_bb_var('RECIPE_SYSROOT_NATIVE', 'cargo-example'),
+ 'usr', 'lib', 'rustlib', 'src', 'rust', 'library')
+ rust_std_source = os.path.join(
+ rust_std_target_root, 'std', 'src', 'rt.rs')
+ self.assertEqual(
+ launch['sourceMap'][rust_std_target_root], rust_std_sdk_root)
+ self.assertIn(
+ rust_std_source, result.output,
+ 'Rust runtime backtrace did not resolve to the SDK debug path:\n%s' %
+ result.output)
+ self.assertNotIn(libstd_rustsrc, result.output)
+ self.assertTrue(
+ os.path.isfile(os.path.join(rust_std_sdk_root, 'std', 'src', 'rt.rs')),
+ 'Rust standard-library source is missing from the recipe SDK sysroot')
+
class DevtoolIdeSdkKernelTests(DevtoolIdeSdkTests):
Exercise Cargo deploy and CodeLLDB launch against oe-selftest-image over slirp. Verify source breakpoints, Rust and runtime backtrace frames, and that BitBake's RUST_DEBUG_REMAP includes the devtool external source tree so package QA does not reject host paths in DWARF. AI-Generated: Uses GitHub Copilot Signed-off-by: Enguerrand de Ribaucourt <enguerrand.de-ribaucourt@savoirfairelinux.com> --- meta/lib/oeqa/selftest/cases/devtool.py | 127 ++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+)