xref: /llvm-project/lldb/test/API/qemu/TestQemuLaunch.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
114086849SPavel Labathimport lldb
214086849SPavel Labathimport unittest
314086849SPavel Labathimport os
414086849SPavel Labathimport json
514086849SPavel Labathimport stat
614086849SPavel Labathimport sys
714086849SPavel Labathfrom textwrap import dedent
85c4cb323SPavel Labathimport lldbsuite.test.lldbutil
914086849SPavel Labathfrom lldbsuite.test.lldbtest import *
1014086849SPavel Labathfrom lldbsuite.test.decorators import *
1114086849SPavel Labathfrom lldbsuite.test.gdbclientutils import *
1214086849SPavel Labath
1314086849SPavel Labath
1414086849SPavel Labath@skipIfRemote
1514086849SPavel Labath@skipIfWindows
1614086849SPavel Labathclass TestQemuLaunch(TestBase):
1714086849SPavel Labath    NO_DEBUG_INFO_TESTCASE = True
1814086849SPavel Labath
1914086849SPavel Labath    def set_emulator_setting(self, name, value):
20*2238dcc3SJonas Devlieghere        self.runCmd("settings set -- platform.plugin.qemu-user.%s %s" % (name, value))
2114086849SPavel Labath
2214086849SPavel Labath    def setUp(self):
2314086849SPavel Labath        super().setUp()
2414086849SPavel Labath        emulator = self.getBuildArtifact("qemu.py")
25*2238dcc3SJonas Devlieghere        with os.fdopen(
26*2238dcc3SJonas Devlieghere            os.open(emulator, os.O_WRONLY | os.O_CREAT, stat.S_IRWXU), "w"
27*2238dcc3SJonas Devlieghere        ) as e:
28*2238dcc3SJonas Devlieghere            e.write(
29*2238dcc3SJonas Devlieghere                dedent(
30*2238dcc3SJonas Devlieghere                    """\
3114086849SPavel Labath                    #! {exec!s}
3214086849SPavel Labath
3314086849SPavel Labath                    import runpy
3414086849SPavel Labath                    import sys
3514086849SPavel Labath
3614086849SPavel Labath                    sys.path = {path!r}
3714086849SPavel Labath                    runpy.run_path({source!r}, run_name='__main__')
38*2238dcc3SJonas Devlieghere                    """
39*2238dcc3SJonas Devlieghere                ).format(
40*2238dcc3SJonas Devlieghere                    exec=sys.executable,
41*2238dcc3SJonas Devlieghere                    path=sys.path,
42*2238dcc3SJonas Devlieghere                    source=self.getSourcePath("qemu.py"),
43*2238dcc3SJonas Devlieghere                )
44*2238dcc3SJonas Devlieghere            )
4514086849SPavel Labath
4614086849SPavel Labath        self.set_emulator_setting("architecture", self.getArchitecture())
4714086849SPavel Labath        self.set_emulator_setting("emulator-path", emulator)
4814086849SPavel Labath
4945aa4356SPavel Labath    def _create_target(self):
5014086849SPavel Labath        self.build()
5114086849SPavel Labath        exe = self.getBuildArtifact()
5214086849SPavel Labath
535c4cb323SPavel Labath        # Create a target using our platform
5414086849SPavel Labath        error = lldb.SBError()
55*2238dcc3SJonas Devlieghere        target = self.dbg.CreateTarget(exe, "", "qemu-user", False, error)
5614086849SPavel Labath        self.assertSuccess(error)
5714086849SPavel Labath        self.assertEqual(target.GetPlatform().GetName(), "qemu-user")
5845aa4356SPavel Labath        return target
5945aa4356SPavel Labath
6045aa4356SPavel Labath    def _run_and_get_state(self, target=None, info=None):
6145aa4356SPavel Labath        if target is None:
6245aa4356SPavel Labath            target = self._create_target()
6345aa4356SPavel Labath
6445aa4356SPavel Labath        if info is None:
6545aa4356SPavel Labath            info = target.GetLaunchInfo()
6614086849SPavel Labath
6714086849SPavel Labath        # "Launch" the process. Our fake qemu implementation will pretend it
6814086849SPavel Labath        # immediately exited.
6945aa4356SPavel Labath        info.SetArguments(["dump:" + self.getBuildArtifact("state.log")], True)
7045aa4356SPavel Labath        error = lldb.SBError()
7145aa4356SPavel Labath        process = target.Launch(info, error)
7245aa4356SPavel Labath        self.assertSuccess(error)
7314086849SPavel Labath        self.assertIsNotNone(process)
741b8c7352SJonas Devlieghere        self.assertState(process.GetState(), lldb.eStateExited)
7514086849SPavel Labath        self.assertEqual(process.GetExitStatus(), 0x47)
7614086849SPavel Labath
7714086849SPavel Labath        # Verify the qemu invocation parameters.
7814086849SPavel Labath        with open(self.getBuildArtifact("state.log")) as s:
79611fdde4SPavel Labath            return json.load(s)
80611fdde4SPavel Labath
81611fdde4SPavel Labath    def test_basic_launch(self):
82611fdde4SPavel Labath        state = self._run_and_get_state()
83611fdde4SPavel Labath
8414086849SPavel Labath        self.assertEqual(state["program"], self.getBuildArtifact())
85*2238dcc3SJonas Devlieghere        self.assertEqual(state["args"], ["dump:" + self.getBuildArtifact("state.log")])
865c4cb323SPavel Labath
875c4cb323SPavel Labath    def test_stdio_pty(self):
8845aa4356SPavel Labath        target = self._create_target()
895c4cb323SPavel Labath
9045aa4356SPavel Labath        info = target.GetLaunchInfo()
91*2238dcc3SJonas Devlieghere        info.SetArguments(
92*2238dcc3SJonas Devlieghere            [
935c4cb323SPavel Labath                "stdin:stdin",
945c4cb323SPavel Labath                "stdout:STDOUT CONTENT\n",
955c4cb323SPavel Labath                "stderr:STDERR CONTENT\n",
965c4cb323SPavel Labath                "dump:" + self.getBuildArtifact("state.log"),
97*2238dcc3SJonas Devlieghere            ],
98*2238dcc3SJonas Devlieghere            False,
99*2238dcc3SJonas Devlieghere        )
1005c4cb323SPavel Labath
1015c4cb323SPavel Labath        listener = lldb.SBListener("test_stdio")
1025c4cb323SPavel Labath        info.SetListener(listener)
1035c4cb323SPavel Labath
1045c4cb323SPavel Labath        self.dbg.SetAsync(True)
10545aa4356SPavel Labath        error = lldb.SBError()
1065c4cb323SPavel Labath        process = target.Launch(info, error)
1075c4cb323SPavel Labath        self.assertSuccess(error)
108*2238dcc3SJonas Devlieghere        lldbutil.expect_state_changes(self, listener, process, [lldb.eStateRunning])
1095c4cb323SPavel Labath
1105c4cb323SPavel Labath        process.PutSTDIN("STDIN CONTENT\n")
1115c4cb323SPavel Labath
112*2238dcc3SJonas Devlieghere        lldbutil.expect_state_changes(self, listener, process, [lldb.eStateExited])
1135c4cb323SPavel Labath
1145c4cb323SPavel Labath        # Echoed stdin, stdout and stderr. With a pty we cannot split standard
1155c4cb323SPavel Labath        # output and error.
116*2238dcc3SJonas Devlieghere        self.assertEqual(
117*2238dcc3SJonas Devlieghere            process.GetSTDOUT(1000),
118*2238dcc3SJonas Devlieghere            "STDIN CONTENT\r\nSTDOUT CONTENT\r\nSTDERR CONTENT\r\n",
119*2238dcc3SJonas Devlieghere        )
1205c4cb323SPavel Labath        with open(self.getBuildArtifact("state.log")) as s:
1215c4cb323SPavel Labath            state = json.load(s)
1225c4cb323SPavel Labath        self.assertEqual(state["stdin"], "STDIN CONTENT\n")
1235c4cb323SPavel Labath
1245c4cb323SPavel Labath    def test_stdio_redirect(self):
1255c4cb323SPavel Labath        self.build()
1265c4cb323SPavel Labath        exe = self.getBuildArtifact()
1275c4cb323SPavel Labath
1285c4cb323SPavel Labath        # Create a target using our platform
1295c4cb323SPavel Labath        error = lldb.SBError()
130*2238dcc3SJonas Devlieghere        target = self.dbg.CreateTarget(exe, "", "qemu-user", False, error)
1315c4cb323SPavel Labath        self.assertSuccess(error)
1325c4cb323SPavel Labath
133*2238dcc3SJonas Devlieghere        info = lldb.SBLaunchInfo(
134*2238dcc3SJonas Devlieghere            [
1355c4cb323SPavel Labath                "stdin:stdin",
1365c4cb323SPavel Labath                "stdout:STDOUT CONTENT",
1375c4cb323SPavel Labath                "stderr:STDERR CONTENT",
1385c4cb323SPavel Labath                "dump:" + self.getBuildArtifact("state.log"),
139*2238dcc3SJonas Devlieghere            ]
140*2238dcc3SJonas Devlieghere        )
1415c4cb323SPavel Labath
142*2238dcc3SJonas Devlieghere        info.AddOpenFileAction(0, self.getBuildArtifact("stdin.txt"), True, False)
143*2238dcc3SJonas Devlieghere        info.AddOpenFileAction(1, self.getBuildArtifact("stdout.txt"), False, True)
144*2238dcc3SJonas Devlieghere        info.AddOpenFileAction(2, self.getBuildArtifact("stderr.txt"), False, True)
1455c4cb323SPavel Labath
1465c4cb323SPavel Labath        with open(self.getBuildArtifact("stdin.txt"), "w") as f:
1475c4cb323SPavel Labath            f.write("STDIN CONTENT")
1485c4cb323SPavel Labath
1495c4cb323SPavel Labath        process = target.Launch(info, error)
1505c4cb323SPavel Labath        self.assertSuccess(error)
1511b8c7352SJonas Devlieghere        self.assertState(process.GetState(), lldb.eStateExited)
1525c4cb323SPavel Labath
1535c4cb323SPavel Labath        with open(self.getBuildArtifact("stdout.txt")) as f:
1545c4cb323SPavel Labath            self.assertEqual(f.read(), "STDOUT CONTENT")
1555c4cb323SPavel Labath        with open(self.getBuildArtifact("stderr.txt")) as f:
1565c4cb323SPavel Labath            self.assertEqual(f.read(), "STDERR CONTENT")
1575c4cb323SPavel Labath        with open(self.getBuildArtifact("state.log")) as s:
1585c4cb323SPavel Labath            state = json.load(s)
1595c4cb323SPavel Labath        self.assertEqual(state["stdin"], "STDIN CONTENT")
16014086849SPavel Labath
1619b8f9d33SPavel Labath    def test_find_in_PATH(self):
1629b8f9d33SPavel Labath        emulator = self.getBuildArtifact("qemu-" + self.getArchitecture())
1639b8f9d33SPavel Labath        os.rename(self.getBuildArtifact("qemu.py"), emulator)
1649b8f9d33SPavel Labath        self.set_emulator_setting("emulator-path", "''")
1659b8f9d33SPavel Labath
1669b8f9d33SPavel Labath        original_path = os.environ["PATH"]
167*2238dcc3SJonas Devlieghere        os.environ["PATH"] = (
168*2238dcc3SJonas Devlieghere            self.getBuildDir()
169*2238dcc3SJonas Devlieghere            + self.platformContext.shlib_path_separator
170*2238dcc3SJonas Devlieghere            + original_path
171*2238dcc3SJonas Devlieghere        )
172*2238dcc3SJonas Devlieghere
1739b8f9d33SPavel Labath        def cleanup():
1749b8f9d33SPavel Labath            os.environ["PATH"] = original_path
1759b8f9d33SPavel Labath
1769b8f9d33SPavel Labath        self.addTearDownHook(cleanup)
1779b8f9d33SPavel Labath        state = self._run_and_get_state()
1789b8f9d33SPavel Labath
1799b8f9d33SPavel Labath        self.assertEqual(state["program"], self.getBuildArtifact())
180*2238dcc3SJonas Devlieghere        self.assertEqual(state["args"], ["dump:" + self.getBuildArtifact("state.log")])
1819b8f9d33SPavel Labath
18214086849SPavel Labath    def test_bad_emulator_path(self):
183*2238dcc3SJonas Devlieghere        self.set_emulator_setting(
184*2238dcc3SJonas Devlieghere            "emulator-path", self.getBuildArtifact("nonexistent.file")
185*2238dcc3SJonas Devlieghere        )
18614086849SPavel Labath
18745aa4356SPavel Labath        target = self._create_target()
18814086849SPavel Labath        info = lldb.SBLaunchInfo([])
18945aa4356SPavel Labath        error = lldb.SBError()
19014086849SPavel Labath        target.Launch(info, error)
19114086849SPavel Labath        self.assertTrue(error.Fail())
19214086849SPavel Labath        self.assertIn("doesn't exist", error.GetCString())
193611fdde4SPavel Labath
194611fdde4SPavel Labath    def test_extra_args(self):
195611fdde4SPavel Labath        self.set_emulator_setting("emulator-args", "-fake-arg fake-value")
196611fdde4SPavel Labath        state = self._run_and_get_state()
197611fdde4SPavel Labath
198611fdde4SPavel Labath        self.assertEqual(state["fake-arg"], "fake-value")
19945aa4356SPavel Labath
200586765c0SPavel Labath    def test_env_vars(self):
20145aa4356SPavel Labath        # First clear any global environment to have a clean slate for this test
20245aa4356SPavel Labath        self.runCmd("settings clear target.env-vars")
20345aa4356SPavel Labath        self.runCmd("settings clear target.unset-env-vars")
20445aa4356SPavel Labath
20545aa4356SPavel Labath        def var(i):
20645aa4356SPavel Labath            return "LLDB_TEST_QEMU_VAR%d" % i
20745aa4356SPavel Labath
20845aa4356SPavel Labath        # Set some variables in the host environment.
20945aa4356SPavel Labath        for i in range(4):
21045aa4356SPavel Labath            os.environ[var(i)] = "from host"
211*2238dcc3SJonas Devlieghere
21245aa4356SPavel Labath        def cleanup():
21345aa4356SPavel Labath            for i in range(4):
21445aa4356SPavel Labath                del os.environ[var(i)]
215*2238dcc3SJonas Devlieghere
21645aa4356SPavel Labath        self.addTearDownHook(cleanup)
21745aa4356SPavel Labath
218586765c0SPavel Labath        # Set some emulator-only variables.
219*2238dcc3SJonas Devlieghere        self.set_emulator_setting("emulator-env-vars", "%s='emulator only'" % var(4))
220586765c0SPavel Labath
22145aa4356SPavel Labath        # And through the platform setting.
222*2238dcc3SJonas Devlieghere        self.set_emulator_setting(
223*2238dcc3SJonas Devlieghere            "target-env-vars",
224*2238dcc3SJonas Devlieghere            "%s='from platform' %s='from platform'" % (var(1), var(2)),
225*2238dcc3SJonas Devlieghere        )
22645aa4356SPavel Labath
22745aa4356SPavel Labath        target = self._create_target()
22845aa4356SPavel Labath        info = target.GetLaunchInfo()
22945aa4356SPavel Labath        env = info.GetEnvironment()
23045aa4356SPavel Labath
231586765c0SPavel Labath        # Platform settings should trump host values. Emulator-only variables
232586765c0SPavel Labath        # should not be visible.
23345aa4356SPavel Labath        self.assertEqual(env.Get(var(0)), "from host")
23445aa4356SPavel Labath        self.assertEqual(env.Get(var(1)), "from platform")
23545aa4356SPavel Labath        self.assertEqual(env.Get(var(2)), "from platform")
23645aa4356SPavel Labath        self.assertEqual(env.Get(var(3)), "from host")
237586765c0SPavel Labath        self.assertIsNone(env.Get(var(4)))
23845aa4356SPavel Labath
23945aa4356SPavel Labath        # Finally, make some launch_info specific changes.
240529e03eaSPavel Labath        env.Set(var(2), "from target", True)
24145aa4356SPavel Labath        env.Unset(var(3))
242529e03eaSPavel Labath        info.SetEnvironment(env, False)
24345aa4356SPavel Labath
24445aa4356SPavel Labath        # Now check everything. Launch info changes should trump everything, but
24545aa4356SPavel Labath        # only for the target environment -- the emulator should still get the
24645aa4356SPavel Labath        # host values.
24745aa4356SPavel Labath        state = self._run_and_get_state(target, info)
24845aa4356SPavel Labath        for i in range(4):
24945aa4356SPavel Labath            self.assertEqual(state["environ"][var(i)], "from host")
250586765c0SPavel Labath        self.assertEqual(state["environ"][var(4)], "emulator only")
251*2238dcc3SJonas Devlieghere        self.assertEqual(
252*2238dcc3SJonas Devlieghere            state["environ"]["QEMU_SET_ENV"],
253*2238dcc3SJonas Devlieghere            "%s=from platform,%s=from target" % (var(1), var(2)),
254*2238dcc3SJonas Devlieghere        )
255*2238dcc3SJonas Devlieghere        self.assertEqual(
256*2238dcc3SJonas Devlieghere            state["environ"]["QEMU_UNSET_ENV"],
257*2238dcc3SJonas Devlieghere            "%s,%s,QEMU_SET_ENV,QEMU_UNSET_ENV" % (var(3), var(4)),
258*2238dcc3SJonas Devlieghere        )
259249a5fb0SPavel Labath
260249a5fb0SPavel Labath    def test_arg0(self):
261249a5fb0SPavel Labath        target = self._create_target()
262249a5fb0SPavel Labath        self.runCmd("settings set target.arg0 ARG0")
263249a5fb0SPavel Labath        state = self._run_and_get_state(target)
264249a5fb0SPavel Labath
265249a5fb0SPavel Labath        self.assertEqual(state["program"], self.getBuildArtifact())
266249a5fb0SPavel Labath        self.assertEqual(state["0"], "ARG0")
267862fffd8SPavel Labath
268862fffd8SPavel Labath    def test_sysroot(self):
269862fffd8SPavel Labath        sysroot = self.getBuildArtifact("sysroot")
270862fffd8SPavel Labath        self.runCmd("platform select qemu-user --sysroot %s" % sysroot)
271862fffd8SPavel Labath        state = self._run_and_get_state()
272862fffd8SPavel Labath        self.assertEqual(state["environ"]["QEMU_LD_PREFIX"], sysroot)
273*2238dcc3SJonas Devlieghere        self.assertIn("QEMU_LD_PREFIX", state["environ"]["QEMU_UNSET_ENV"].split(","))
274