xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision b3a835e129ed8a67cf393f9ee26989b36a3eff1c)
1f3176f5fSMed Ismail Bennani"""
2f3176f5fSMed Ismail BennaniTest python scripted process in lldb
3f3176f5fSMed Ismail Bennani"""
4f3176f5fSMed Ismail Bennani
56aa48034SMed Ismail Bennaniimport os, shutil
6f3176f5fSMed Ismail Bennani
7f3176f5fSMed Ismail Bennaniimport lldb
8f3176f5fSMed Ismail Bennanifrom lldbsuite.test.decorators import *
9f3176f5fSMed Ismail Bennanifrom lldbsuite.test.lldbtest import *
10f3176f5fSMed Ismail Bennanifrom lldbsuite.test import lldbutil
11f3176f5fSMed Ismail Bennanifrom lldbsuite.test import lldbtest
12f3176f5fSMed Ismail Bennani
13c1928033SMed Ismail Bennaniimport dummy_scripted_process
14c1928033SMed Ismail Bennani
15f3176f5fSMed Ismail Bennani
162238dcc3SJonas Devlieghereclass ScriptedProcesTestCase(TestBase):
17d327108dSMed Ismail Bennani    NO_DEBUG_INFO_TESTCASE = True
18d327108dSMed Ismail Bennani
19d69e5dfaSMed Ismail Bennani    @skipUnlessDarwin
20f3176f5fSMed Ismail Bennani    def test_python_plugin_package(self):
21f3176f5fSMed Ismail Bennani        """Test that the lldb python module has a `plugins.scripted_process`
22f3176f5fSMed Ismail Bennani        package."""
232238dcc3SJonas Devlieghere        self.expect(
242238dcc3SJonas Devlieghere            "script import lldb.plugins",
252238dcc3SJonas Devlieghere            substrs=["ModuleNotFoundError"],
262238dcc3SJonas Devlieghere            matching=False,
272238dcc3SJonas Devlieghere        )
28f3176f5fSMed Ismail Bennani
292238dcc3SJonas Devlieghere        self.expect("script dir(lldb.plugins)", substrs=["scripted_process"])
30f3176f5fSMed Ismail Bennani
312238dcc3SJonas Devlieghere        self.expect(
322238dcc3SJonas Devlieghere            "script import lldb.plugins.scripted_process",
332238dcc3SJonas Devlieghere            substrs=["ModuleNotFoundError"],
342238dcc3SJonas Devlieghere            matching=False,
352238dcc3SJonas Devlieghere        )
36f3176f5fSMed Ismail Bennani
372238dcc3SJonas Devlieghere        self.expect(
382238dcc3SJonas Devlieghere            "script dir(lldb.plugins.scripted_process)", substrs=["ScriptedProcess"]
392238dcc3SJonas Devlieghere        )
40f3176f5fSMed Ismail Bennani
412238dcc3SJonas Devlieghere        self.expect(
422238dcc3SJonas Devlieghere            "script from lldb.plugins.scripted_process import ScriptedProcess",
432238dcc3SJonas Devlieghere            substrs=["ImportError"],
442238dcc3SJonas Devlieghere            matching=False,
452238dcc3SJonas Devlieghere        )
46f3176f5fSMed Ismail Bennani
472238dcc3SJonas Devlieghere        self.expect("script dir(ScriptedProcess)", substrs=["launch"])
48f3176f5fSMed Ismail Bennani
496aa48034SMed Ismail Bennani    def move_blueprint_to_dsym(self, blueprint_name):
506aa48034SMed Ismail Bennani        blueprint_origin_path = os.path.join(self.getSourceDir(), blueprint_name)
516aa48034SMed Ismail Bennani        dsym_bundle = self.getBuildArtifact("a.out.dSYM")
522238dcc3SJonas Devlieghere        blueprint_destination_path = os.path.join(
532238dcc3SJonas Devlieghere            dsym_bundle, "Contents", "Resources", "Python"
542238dcc3SJonas Devlieghere        )
556aa48034SMed Ismail Bennani        if not os.path.exists(blueprint_destination_path):
566aa48034SMed Ismail Bennani            os.mkdir(blueprint_destination_path)
576aa48034SMed Ismail Bennani
582238dcc3SJonas Devlieghere        blueprint_destination_path = os.path.join(
592238dcc3SJonas Devlieghere            blueprint_destination_path, "a_out.py"
602238dcc3SJonas Devlieghere        )
616aa48034SMed Ismail Bennani        shutil.copy(blueprint_origin_path, blueprint_destination_path)
626aa48034SMed Ismail Bennani
63ea828534SDavid Spickett    # No dylib on Windows.
64ea828534SDavid Spickett    @skipIfWindows
650a211446SMed Ismail Bennani    def test_missing_methods_scripted_register_context(self):
660a211446SMed Ismail Bennani        """Test that we only instanciate scripted processes if they implement
670a211446SMed Ismail Bennani        all the required abstract methods."""
680a211446SMed Ismail Bennani        self.build()
690a211446SMed Ismail Bennani
700a211446SMed Ismail Bennani        os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] = "1"
710a211446SMed Ismail Bennani
720a211446SMed Ismail Bennani        def cleanup():
730a211446SMed Ismail Bennani            del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
740a211446SMed Ismail Bennani
750a211446SMed Ismail Bennani        self.addTearDownHook(cleanup)
760a211446SMed Ismail Bennani
770a211446SMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
780a211446SMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
790a211446SMed Ismail Bennani        log_file = self.getBuildArtifact("script.log")
800a211446SMed Ismail Bennani        self.runCmd("log enable lldb script -f " + log_file)
810a211446SMed Ismail Bennani        self.assertTrue(os.path.isfile(log_file))
820a211446SMed Ismail Bennani        script_path = os.path.join(
830a211446SMed Ismail Bennani            self.getSourceDir(), "missing_methods_scripted_process.py"
840a211446SMed Ismail Bennani        )
850a211446SMed Ismail Bennani        self.runCmd("command script import " + script_path)
860a211446SMed Ismail Bennani
870a211446SMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
880a211446SMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
890a211446SMed Ismail Bennani        launch_info.SetScriptedProcessClassName(
900a211446SMed Ismail Bennani            "missing_methods_scripted_process.MissingMethodsScriptedProcess"
910a211446SMed Ismail Bennani        )
920a211446SMed Ismail Bennani        error = lldb.SBError()
930a211446SMed Ismail Bennani
940a211446SMed Ismail Bennani        process = target.Launch(launch_info, error)
950a211446SMed Ismail Bennani
960a211446SMed Ismail Bennani        self.assertFailure(error)
970a211446SMed Ismail Bennani
980a211446SMed Ismail Bennani        with open(log_file, "r") as f:
990a211446SMed Ismail Bennani            log = f.read()
1000a211446SMed Ismail Bennani
1010a211446SMed Ismail Bennani        self.assertIn(
1020a211446SMed Ismail Bennani            "Abstract method MissingMethodsScriptedProcess.read_memory_at_address not implemented",
1030a211446SMed Ismail Bennani            log,
1040a211446SMed Ismail Bennani        )
1050a211446SMed Ismail Bennani        self.assertIn(
1060a211446SMed Ismail Bennani            "Abstract method MissingMethodsScriptedProcess.is_alive not implemented",
1070a211446SMed Ismail Bennani            log,
1080a211446SMed Ismail Bennani        )
1090a211446SMed Ismail Bennani        self.assertIn(
1100a211446SMed Ismail Bennani            "Abstract method MissingMethodsScriptedProcess.get_scripted_thread_plugin not implemented",
1110a211446SMed Ismail Bennani            log,
1120a211446SMed Ismail Bennani        )
1130a211446SMed Ismail Bennani
114c3ca2c6bSMed Ismail Bennani    @skipUnlessDarwin
115caea440aSMed Ismail Bennani    def test_invalid_scripted_register_context(self):
116caea440aSMed Ismail Bennani        """Test that we can launch an lldb scripted process with an invalid
117caea440aSMed Ismail Bennani        Scripted Thread, with invalid register context."""
118caea440aSMed Ismail Bennani        self.build()
119caea440aSMed Ismail Bennani
1202238dcc3SJonas Devlieghere        os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] = "1"
1212238dcc3SJonas Devlieghere
122a6b56243SMed Ismail Bennani        def cleanup():
123a6b56243SMed Ismail Bennani            del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
1242238dcc3SJonas Devlieghere
125a6b56243SMed Ismail Bennani        self.addTearDownHook(cleanup)
126a6b56243SMed Ismail Bennani
1276aa48034SMed Ismail Bennani        self.runCmd("settings set target.load-script-from-symbol-file true")
1282238dcc3SJonas Devlieghere        self.move_blueprint_to_dsym("invalid_scripted_process.py")
1296aa48034SMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
1306aa48034SMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
1312238dcc3SJonas Devlieghere        log_file = self.getBuildArtifact("thread.log")
1326aa48034SMed Ismail Bennani        self.runCmd("log enable lldb thread -f " + log_file)
1336aa48034SMed Ismail Bennani        self.assertTrue(os.path.isfile(log_file))
134caea440aSMed Ismail Bennani
135caea440aSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
136caea440aSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
1376aa48034SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("a_out.InvalidScriptedProcess")
138caea440aSMed Ismail Bennani        error = lldb.SBError()
1399c144b3bSMed Ismail Bennani
140caea440aSMed Ismail Bennani        process = target.Launch(launch_info, error)
141caea440aSMed Ismail Bennani
142779bbbf2SDave Lee        self.assertSuccess(error)
143caea440aSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
144caea440aSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 666)
145caea440aSMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 0)
146caea440aSMed Ismail Bennani
147ebdbc26aSMed Ismail Bennani        impl = process.GetScriptedImplementation()
148ebdbc26aSMed Ismail Bennani        self.assertTrue(impl)
149ebdbc26aSMed Ismail Bennani        impl = process.GetScriptedImplementation()
150ebdbc26aSMed Ismail Bennani        self.assertTrue(impl)
151ebdbc26aSMed Ismail Bennani        impl = process.GetScriptedImplementation()
152ebdbc26aSMed Ismail Bennani        self.assertTrue(impl)
153ebdbc26aSMed Ismail Bennani        impl = process.GetScriptedImplementation()
154ebdbc26aSMed Ismail Bennani        self.assertTrue(impl)
155ebdbc26aSMed Ismail Bennani
1567e01924eSMed Ismail Bennani        addr = 0x500000000
1577e01924eSMed Ismail Bennani        buff = process.ReadMemory(addr, 4, error)
1587e01924eSMed Ismail Bennani        self.assertEqual(buff, None)
1597e01924eSMed Ismail Bennani        self.assertTrue(error.Fail())
1607e01924eSMed Ismail Bennani        self.assertEqual(error.GetCString(), "This is an invalid scripted process!")
1617e01924eSMed Ismail Bennani
1622238dcc3SJonas Devlieghere        with open(log_file, "r") as f:
1639c144b3bSMed Ismail Bennani            log = f.read()
1649c144b3bSMed Ismail Bennani
1659c144b3bSMed Ismail Bennani        self.assertIn("Failed to get scripted thread registers data.", log)
166caea440aSMed Ismail Bennani
16786e6030eSMed Ismail Bennani    @skipUnlessDarwin
168a758c9f7SMed Ismail Bennani    def test_scripted_process_and_scripted_thread(self):
169312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process using the SBAPI,
170a758c9f7SMed Ismail Bennani        check its process ID, read string from memory, check scripted thread
171a758c9f7SMed Ismail Bennani        id, name stop reason and register context.
172a758c9f7SMed Ismail Bennani        """
173312b43daSMed Ismail Bennani        self.build()
174a3d4f739SMed Ismail Bennani        target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
175a3d4f739SMed Ismail Bennani        self.assertTrue(target_0, VALID_TARGET)
176312b43daSMed Ismail Bennani
1772238dcc3SJonas Devlieghere        os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"] = "1"
1782238dcc3SJonas Devlieghere
179a6b56243SMed Ismail Bennani        def cleanup():
180a6b56243SMed Ismail Bennani            del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
1812238dcc3SJonas Devlieghere
182a6b56243SMed Ismail Bennani        self.addTearDownHook(cleanup)
183a6b56243SMed Ismail Bennani
1842238dcc3SJonas Devlieghere        scripted_process_example_relpath = "dummy_scripted_process.py"
1852238dcc3SJonas Devlieghere        self.runCmd(
1862238dcc3SJonas Devlieghere            "command script import "
1872238dcc3SJonas Devlieghere            + os.path.join(self.getSourceDir(), scripted_process_example_relpath)
1882238dcc3SJonas Devlieghere        )
189312b43daSMed Ismail Bennani
190*b3a835e1SMed Ismail Bennani        self.runCmd(
191*b3a835e1SMed Ismail Bennani            "target stop-hook add -k first -v 1 -k second -v 2 -P dummy_scripted_process.DummyStopHook"
192*b3a835e1SMed Ismail Bennani        )
193*b3a835e1SMed Ismail Bennani
194312b43daSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
195312b43daSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
1962238dcc3SJonas Devlieghere        launch_info.SetScriptedProcessClassName(
1972238dcc3SJonas Devlieghere            "dummy_scripted_process.DummyScriptedProcess"
1982238dcc3SJonas Devlieghere        )
199312b43daSMed Ismail Bennani
200312b43daSMed Ismail Bennani        error = lldb.SBError()
201a3d4f739SMed Ismail Bennani        process_0 = target_0.Launch(launch_info, error)
202a3d4f739SMed Ismail Bennani        self.assertTrue(process_0 and process_0.IsValid(), PROCESS_IS_VALID)
203a3d4f739SMed Ismail Bennani        self.assertEqual(process_0.GetProcessID(), 42)
204a3d4f739SMed Ismail Bennani        self.assertEqual(process_0.GetNumThreads(), 1)
20559d8dd79SMed Ismail Bennani
206a3d4f739SMed Ismail Bennani        py_impl = process_0.GetScriptedImplementation()
207c1928033SMed Ismail Bennani        self.assertTrue(py_impl)
2089c246882SJordan Rupprecht        self.assertIsInstance(py_impl, dummy_scripted_process.DummyScriptedProcess)
2092238dcc3SJonas Devlieghere        self.assertFalse(hasattr(py_impl, "my_super_secret_member"))
210c1928033SMed Ismail Bennani        py_impl.my_super_secret_member = 42
2112238dcc3SJonas Devlieghere        self.assertTrue(hasattr(py_impl, "my_super_secret_member"))
212c1928033SMed Ismail Bennani        self.assertEqual(py_impl.my_super_secret_method(), 42)
213c1928033SMed Ismail Bennani
214*b3a835e1SMed Ismail Bennani        self.assertTrue(hasattr(py_impl, "handled_stop"))
215*b3a835e1SMed Ismail Bennani        self.assertTrue(py_impl.handled_stop)
216*b3a835e1SMed Ismail Bennani
217a3d4f739SMed Ismail Bennani        # Try reading from target #0 process ...
2187e01924eSMed Ismail Bennani        addr = 0x500000000
219a3d4f739SMed Ismail Bennani        message = "Hello, target 0"
220a3d4f739SMed Ismail Bennani        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
2217e01924eSMed Ismail Bennani        self.assertSuccess(error)
2227e01924eSMed Ismail Bennani        self.assertEqual(buff, message)
2237e01924eSMed Ismail Bennani
224a3d4f739SMed Ismail Bennani        target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
225a3d4f739SMed Ismail Bennani        self.assertTrue(target_1, VALID_TARGET)
226b9d4c94aSMed Ismail Bennani
227b9d4c94aSMed Ismail Bennani        # We still need to specify a PID when attaching even for scripted processes
228b9d4c94aSMed Ismail Bennani        attach_info = lldb.SBAttachInfo(42)
229b9d4c94aSMed Ismail Bennani        attach_info.SetProcessPluginName("ScriptedProcess")
2302238dcc3SJonas Devlieghere        attach_info.SetScriptedProcessClassName(
2312238dcc3SJonas Devlieghere            "dummy_scripted_process.DummyScriptedProcess"
2322238dcc3SJonas Devlieghere        )
233b9d4c94aSMed Ismail Bennani
234a3d4f739SMed Ismail Bennani        error = lldb.SBError()
235b9d4c94aSMed Ismail Bennani        process_1 = target_1.Attach(attach_info, error)
236a3d4f739SMed Ismail Bennani        self.assertTrue(process_1 and process_1.IsValid(), PROCESS_IS_VALID)
237a3d4f739SMed Ismail Bennani        self.assertEqual(process_1.GetProcessID(), 42)
238a3d4f739SMed Ismail Bennani        self.assertEqual(process_1.GetNumThreads(), 1)
239a3d4f739SMed Ismail Bennani
240a3d4f739SMed Ismail Bennani        # ... then try reading from target #1 process ...
241a3d4f739SMed Ismail Bennani        message = "Hello, target 1"
242a3d4f739SMed Ismail Bennani        buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error)
243a3d4f739SMed Ismail Bennani        self.assertSuccess(error)
244a3d4f739SMed Ismail Bennani        self.assertEqual(buff, message)
245a3d4f739SMed Ismail Bennani
246a3d4f739SMed Ismail Bennani        # ... now, reading again from target #0 process to make sure the call
247a3d4f739SMed Ismail Bennani        # gets dispatched to the right target.
248a3d4f739SMed Ismail Bennani        message = "Hello, target 0"
249a3d4f739SMed Ismail Bennani        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
250a3d4f739SMed Ismail Bennani        self.assertSuccess(error)
251a3d4f739SMed Ismail Bennani        self.assertEqual(buff, message)
252a3d4f739SMed Ismail Bennani
253f190ec68SMed Ismail Bennani        # Let's write some memory.
254f190ec68SMed Ismail Bennani        message = "Hello, world!"
255f190ec68SMed Ismail Bennani        bytes_written = process_0.WriteMemoryAsCString(addr, message, error)
256f190ec68SMed Ismail Bennani        self.assertSuccess(error)
257f190ec68SMed Ismail Bennani        self.assertEqual(bytes_written, len(message) + 1)
258f190ec68SMed Ismail Bennani
259f190ec68SMed Ismail Bennani        # ... and check if that memory was saved properly.
260f190ec68SMed Ismail Bennani        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
261f190ec68SMed Ismail Bennani        self.assertSuccess(error)
262f190ec68SMed Ismail Bennani        self.assertEqual(buff, message)
263f190ec68SMed Ismail Bennani
264a3d4f739SMed Ismail Bennani        thread = process_0.GetSelectedThread()
26559d8dd79SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
26659d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetThreadID(), 0x19)
267a758c9f7SMed Ismail Bennani        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
2688f407b8eSMed Ismail Bennani        self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonTrace)
26959d8dd79SMed Ismail Bennani
27059d8dd79SMed Ismail Bennani        self.assertGreater(thread.GetNumFrames(), 0)
27159d8dd79SMed Ismail Bennani
27259d8dd79SMed Ismail Bennani        frame = thread.GetFrameAtIndex(0)
273976867b5SMed Ismail Bennani        GPRs = None
27459d8dd79SMed Ismail Bennani        register_set = frame.registers  # Returns an SBValueList.
27559d8dd79SMed Ismail Bennani        for regs in register_set:
2762238dcc3SJonas Devlieghere            if "general purpose" in regs.name.lower():
277976867b5SMed Ismail Bennani                GPRs = regs
27859d8dd79SMed Ismail Bennani                break
27959d8dd79SMed Ismail Bennani
280976867b5SMed Ismail Bennani        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
281c3ca2c6bSMed Ismail Bennani        self.assertGreater(GPRs.GetNumChildren(), 0)
282976867b5SMed Ismail Bennani        for idx, reg in enumerate(GPRs, start=1):
283c3ca2c6bSMed Ismail Bennani            if idx > 21:
284c3ca2c6bSMed Ismail Bennani                break
28559d8dd79SMed Ismail Bennani            self.assertEqual(idx, int(reg.value, 16))
28659d8dd79SMed Ismail Bennani
28770665844SMed Ismail Bennani        self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
288a3d4f739SMed Ismail Bennani        pc = frame.GetPCAddress().GetLoadAddress(target_0)
2892238dcc3SJonas Devlieghere        self.assertEqual(pc, 0x0100001B00)
290