@@ -4378,6 +4378,198 @@ class DevtoolIdeSdkTests(DevtoolBase):
lambda magic_string: self._lldb_server_debugging_once(
tempdir, qemu, magic_string))
+ def _lldb_none_debugging_multi(self, tempdir, qemu, recipe_name, example_exe, magic_string):
+ """Verify lldb-server scripts generated by ide=none work end-to-end.
+
+ Mirrors _gdb_cross_debugging_multi but for the LLDB/clang path:
+ - uses the generated lldb_server_* start/stop script
+ - uses the generated lldb_* wrapper script with lldb --batch
+
+ Covers the executable, the library and a header-only inline function
+ (see _lldb_debug_cpp_example_batch_commands), since a single call-site
+ breakpoint would not exercise (and thus not catch a regression in) the
+ lldbinit source map / debug-file-search-paths setup for the library's
+ own debug info specifically.
+ """
+ sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
+ scripts_dir = self._workspace_scripts_dir(recipe_name)
+ binary_pretty = 'usr-bin-' + example_exe
+ lldb_server_script = os.path.join(
+ scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty)
+ lldb_script = os.path.join(scripts_dir, 'lldb_1234_%s' % binary_pretty)
+
+ self.assertExists(lldb_server_script)
+ self.assertExists(lldb_script)
+
+ # Start lldb-server (script exits once the port is ready)
+ r = runCmd(lldb_server_script, output_log=self._cmd_logger)
+ self.assertEqual(r.status, 0)
+
+ # Verify lldb-server is running on the target
+ r = runCmd('ssh %s root@%s ps' % (sshargs, qemu.ip),
+ output_log=self._cmd_logger)
+ self.assertEqual(r.status, 0)
+ self.assertIn('lldb-server', r.output)
+
+ # Verify the pid file points at the running lldb-server process
+ pid_file = '/tmp/lldb_server_1234_%s_multi/lldb_server.pid' % binary_pretty
+ test_cmd = "'cat /proc/$(cat %s)/cmdline'" % pid_file
+ r = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, test_cmd),
+ output_log=self._cmd_logger)
+ self.assertEqual(r.status, 0)
+ self.assertIn('lldb-server', r.output)
+
+ # Run an lldb batch session covering the executable, library and
+ # header breakpoints, then continue to completion
+ lldb_batch_args = self._lldb_debug_cpp_example_batch_commands(tempdir)
+ r = runCmd([lldb_script, '--batch'] + lldb_batch_args,
+ output_log=self._cmd_logger)
+ self.logger.debug("lldb batch output: %s", r.output)
+ self.assertEqual(r.status, 0)
+ self._lldb_debug_cpp_example_check(r.output, magic_string)
+
+ # Stop lldb-server
+ r = runCmd(lldb_server_script + ' stop', output_log=self._cmd_logger)
+ self.assertEqual(r.status, 0)
+
+ # Verify lldb-server is no longer running
+ r = runCmd('ssh %s root@%s ps' % (sshargs, qemu.ip),
+ output_log=self._cmd_logger)
+ self.assertEqual(r.status, 0)
+ self.assertNotIn('lldb-server', r.output)
+
+ @OETestTag("runqemu")
+ def test_devtool_ide_sdk_none_cmake_clang(self):
+ """Verify ide=none generates correct LLDB scripts for a clang cmake recipe.
+
+ Uses cmake-example-clang (TOOLCHAIN = "clang") which is built with the
+ clang toolchain. devtool ide-sdk with --ide=none should produce:
+ - lldb_server_<port>_<binary>_multi (start/stop script)
+ - lldbinit/lldbinit_<port>_<binary> (platform connect + source maps)
+ - lldb_<port>_<binary> (lldb wrapper)
+
+ The test verifies that lldb-server can be started via the generated
+ script, and that a basic lldb --batch debugging session reaches main.
+ """
+ recipe_name = 'cmake-example-clang'
+ example_exe = 'cmake-example-clang'
+ build_file = 'CMakeLists.txt'
+ testimage = 'oe-selftest-image'
+
+ self._check_workspace()
+ self._write_bb_config([recipe_name], extra_packages=['lldb-server'])
+ self._check_runqemu_prerequisites()
+ bitbake(testimage)
+ with runqemu(testimage, runqemuparams='nographic') as qemu:
+ tempdir = self._devtool_ide_sdk_recipe(recipe_name, build_file, testimage)
+ bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --ide=none' % (
+ recipe_name, testimage, qemu.ip)
+ runCmd(bitbake_sdk_cmd, output_log=self._cmd_logger)
+
+ # Verify cmake preset still works (build system unchanged)
+ compile_cmd = self._verify_cmake_preset(tempdir)
+
+ # Verify install && deploy script exists
+ # (_verify_install_script_code opens .vscode/tasks.json which is not
+ # generated for ide=none; check the script path directly instead)
+ recipe_id, _ = self._get_recipe_ids(recipe_name)
+ scripts_dir = self._workspace_scripts_dir(recipe_name)
+ self.assertExists(os.path.join(
+ scripts_dir, 'install_and_deploy_' + recipe_id))
+
+ # Verify LLDB scripts were generated (not GDB scripts)
+ binary_pretty = 'usr-bin-' + example_exe
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty))
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldbinit', 'lldbinit_1234_%s' % binary_pretty))
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldb_1234_%s' % binary_pretty))
+ # No GDB scripts should have been generated for a clang recipe
+ self.assertFalse(os.path.exists(os.path.join(
+ scripts_dir, 'gdbserver_1234_%s_multi' % binary_pretty)),
+ 'gdbserver script should not be generated for clang recipe')
+
+ # Verify the oe-scripts sym-link is valid
+ self.assertEqual(self._workspace_scripts_dir(recipe_name),
+ self._sources_scripts_dir(tempdir))
+
+ # Verify end-to-end lldb debugging, before and after a code
+ # change/recompile/redeploy cycle (see _lldb_cross_debugging_multi)
+ self._lldb_cross_debugging_multi(
+ tempdir, recipe_name, compile_cmd,
+ lambda magic_string: self._lldb_none_debugging_multi(
+ tempdir, qemu, recipe_name, example_exe, magic_string))
+
+ @OETestTag("runqemu")
+ def test_devtool_ide_sdk_none_meson_clang(self):
+ """Verify ide=none generates correct LLDB scripts for a clang meson recipe.
+
+ This is the meson/ninja counterpart of test_devtool_ide_sdk_none_cmake_clang.
+ It is required in addition to the cmake/clang test because meson/ninja
+ (unlike cmake here) invoke the compiler with source paths relative to
+ the build directory, which is what previously caused source-level
+ breakpoints to be left unresolved (pending) for devtool workspaces due
+ to -fdebug-prefix-map/-ffile-prefix-map underflow; see
+ _lldb_none_debugging_multi.
+
+ Uses meson-example-clang (TOOLCHAIN = "clang").
+ """
+ recipe_name = 'meson-example-clang'
+ example_exe = 'mesonex-clang'
+ build_file = 'meson.build'
+ testimage = 'oe-selftest-image'
+
+ self._check_workspace()
+ self._write_bb_config([recipe_name], extra_packages=['lldb-server'])
+ self._check_runqemu_prerequisites()
+
+ # Build image with debug settings (lldb-server for clang) before starting QEMU
+ tempdir = self._devtool_ide_sdk_recipe(recipe_name, build_file, testimage)
+ runCmd('devtool ide-sdk %s %s -c --ide=none' % (recipe_name, testimage),
+ output_log=self._cmd_logger)
+
+ with runqemu(testimage, runqemuparams='nographic') as qemu:
+ # Re-run with actual QEMU IP; image is already built
+ bitbake_sdk_cmd = 'devtool ide-sdk %s %s -t root@%s -c --skip-bitbake --ide=none' % (
+ recipe_name, testimage, qemu.ip)
+ runCmd(bitbake_sdk_cmd, output_log=self._cmd_logger)
+
+ # Verify the meson build system still works (unchanged by clang/lldb support)
+ compile_cmd = self._verify_meson_build(tempdir, recipe_name)
+
+ # Verify install && deploy script exists
+ # (_verify_install_script_code opens .vscode/tasks.json which is not
+ # generated for ide=none; check the script path directly instead)
+ recipe_id, _ = self._get_recipe_ids(recipe_name)
+ scripts_dir = self._workspace_scripts_dir(recipe_name)
+ self.assertExists(os.path.join(
+ scripts_dir, 'install_and_deploy_' + recipe_id))
+
+ # Verify LLDB scripts were generated (not GDB scripts)
+ binary_pretty = 'usr-bin-' + example_exe
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldb_server_1234_%s_multi' % binary_pretty))
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldbinit', 'lldbinit_1234_%s' % binary_pretty))
+ self.assertExists(os.path.join(
+ scripts_dir, 'lldb_1234_%s' % binary_pretty))
+ # No GDB scripts should have been generated for a clang recipe
+ self.assertFalse(os.path.exists(os.path.join(
+ scripts_dir, 'gdbserver_1234_%s_multi' % binary_pretty)),
+ 'gdbserver script should not be generated for clang recipe')
+
+ # Verify the oe-scripts sym-link is valid
+ self.assertEqual(self._workspace_scripts_dir(recipe_name),
+ self._sources_scripts_dir(tempdir))
+
+ # Verify end-to-end lldb debugging, before and after a code
+ # change/recompile/redeploy cycle (see _lldb_cross_debugging_multi)
+ self._lldb_cross_debugging_multi(
+ tempdir, recipe_name, compile_cmd,
+ lambda magic_string: self._lldb_none_debugging_multi(
+ tempdir, qemu, recipe_name, example_exe, magic_string))
+
def test_devtool_ide_sdk_plugins(self):
"""Test that devtool ide-sdk can use plugins from other layers."""