1f3176f5fSMed Ismail Bennani"""
2f3176f5fSMed Ismail BennaniTest python scripted process in lldb
3f3176f5fSMed Ismail Bennani"""
4f3176f5fSMed Ismail Bennani
5976867b5SMed Ismail Bennaniimport os, json, tempfile
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
13312b43daSMed Ismail Bennaniclass ScriptedProcesTestCase(TestBase):
14f3176f5fSMed Ismail Bennani
15f3176f5fSMed Ismail Bennani    mydir = TestBase.compute_mydir(__file__)
16f3176f5fSMed Ismail Bennani
17f3176f5fSMed Ismail Bennani    def setUp(self):
18f3176f5fSMed Ismail Bennani        TestBase.setUp(self)
19f3176f5fSMed Ismail Bennani
20f3176f5fSMed Ismail Bennani    def tearDown(self):
21f3176f5fSMed Ismail Bennani        TestBase.tearDown(self)
22f3176f5fSMed Ismail Bennani
23f3176f5fSMed Ismail Bennani    def test_python_plugin_package(self):
24f3176f5fSMed Ismail Bennani        """Test that the lldb python module has a `plugins.scripted_process`
25f3176f5fSMed Ismail Bennani        package."""
26f3176f5fSMed Ismail Bennani        self.expect('script import lldb.plugins',
27f3176f5fSMed Ismail Bennani                    substrs=["ModuleNotFoundError"], matching=False)
28f3176f5fSMed Ismail Bennani
29f3176f5fSMed Ismail Bennani        self.expect('script dir(lldb.plugins)',
30f3176f5fSMed Ismail Bennani                    substrs=["scripted_process"])
31f3176f5fSMed Ismail Bennani
32f3176f5fSMed Ismail Bennani        self.expect('script import lldb.plugins.scripted_process',
33f3176f5fSMed Ismail Bennani                    substrs=["ModuleNotFoundError"], matching=False)
34f3176f5fSMed Ismail Bennani
35f3176f5fSMed Ismail Bennani        self.expect('script dir(lldb.plugins.scripted_process)',
36f3176f5fSMed Ismail Bennani                    substrs=["ScriptedProcess"])
37f3176f5fSMed Ismail Bennani
38f3176f5fSMed Ismail Bennani        self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
39f3176f5fSMed Ismail Bennani                    substrs=["ImportError"], matching=False)
40f3176f5fSMed Ismail Bennani
41f3176f5fSMed Ismail Bennani        self.expect('script dir(ScriptedProcess)',
42f3176f5fSMed Ismail Bennani                    substrs=["launch"])
43f3176f5fSMed Ismail Bennani
44*c3ca2c6bSMed Ismail Bennani    @skipUnlessDarwin
45caea440aSMed Ismail Bennani    def test_invalid_scripted_register_context(self):
46caea440aSMed Ismail Bennani        """Test that we can launch an lldb scripted process with an invalid
47caea440aSMed Ismail Bennani        Scripted Thread, with invalid register context."""
48caea440aSMed Ismail Bennani        self.build()
49caea440aSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
50caea440aSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
519c144b3bSMed Ismail Bennani        log_file = self.getBuildArtifact('thread.log')
529c144b3bSMed Ismail Bennani        self.runCmd("log enable lldb thread -f " + log_file)
539c144b3bSMed Ismail Bennani        self.assertTrue(os.path.isfile(log_file))
54caea440aSMed Ismail Bennani
55caea440aSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
56caea440aSMed Ismail Bennani        def cleanup():
57caea440aSMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
58caea440aSMed Ismail Bennani        self.addTearDownHook(cleanup)
59caea440aSMed Ismail Bennani
60caea440aSMed Ismail Bennani        scripted_process_example_relpath = 'invalid_scripted_process.py'
61caea440aSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
62caea440aSMed Ismail Bennani                                                            scripted_process_example_relpath))
63caea440aSMed Ismail Bennani
64caea440aSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
65caea440aSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
66caea440aSMed Ismail Bennani        launch_info.SetScriptedProcessClassName("invalid_scripted_process.InvalidScriptedProcess")
67caea440aSMed Ismail Bennani        error = lldb.SBError()
689c144b3bSMed Ismail Bennani
69caea440aSMed Ismail Bennani        process = target.Launch(launch_info, error)
70caea440aSMed Ismail Bennani
71caea440aSMed Ismail Bennani        self.assertTrue(error.Success(), error.GetCString())
72caea440aSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
73caea440aSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 666)
74caea440aSMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 0)
75caea440aSMed Ismail Bennani
769c144b3bSMed Ismail Bennani        with open(log_file, 'r') as f:
779c144b3bSMed Ismail Bennani            log = f.read()
789c144b3bSMed Ismail Bennani
799c144b3bSMed Ismail Bennani        self.assertIn("Failed to get scripted thread registers data.", log)
80caea440aSMed Ismail Bennani
81*c3ca2c6bSMed Ismail Bennani    @skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e']))
82a758c9f7SMed Ismail Bennani    def test_scripted_process_and_scripted_thread(self):
83312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process using the SBAPI,
84a758c9f7SMed Ismail Bennani        check its process ID, read string from memory, check scripted thread
85a758c9f7SMed Ismail Bennani        id, name stop reason and register context.
86a758c9f7SMed Ismail Bennani        """
87312b43daSMed Ismail Bennani        self.build()
88312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
89312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
90312b43daSMed Ismail Bennani
91312b43daSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
92419b4711SMed Ismail Bennani        def cleanup():
93419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
94419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
95419b4711SMed Ismail Bennani
96419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'dummy_scripted_process.py'
97312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
98a758c9f7SMed Ismail Bennani                                                            scripted_process_example_relpath))
99312b43daSMed Ismail Bennani
100312b43daSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
101312b43daSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
102a758c9f7SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
103312b43daSMed Ismail Bennani
104312b43daSMed Ismail Bennani        error = lldb.SBError()
105312b43daSMed Ismail Bennani        process = target.Launch(launch_info, error)
106312b43daSMed Ismail Bennani        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
107312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
108312b43daSMed Ismail Bennani
10959d8dd79SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 1)
11059d8dd79SMed Ismail Bennani
11159d8dd79SMed Ismail Bennani        thread = process.GetSelectedThread()
11259d8dd79SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
11359d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetThreadID(), 0x19)
114a758c9f7SMed Ismail Bennani        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
11559d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
11659d8dd79SMed Ismail Bennani
11759d8dd79SMed Ismail Bennani        self.assertGreater(thread.GetNumFrames(), 0)
11859d8dd79SMed Ismail Bennani
11959d8dd79SMed Ismail Bennani        frame = thread.GetFrameAtIndex(0)
120976867b5SMed Ismail Bennani        GPRs = None
12159d8dd79SMed Ismail Bennani        register_set = frame.registers # Returns an SBValueList.
12259d8dd79SMed Ismail Bennani        for regs in register_set:
123976867b5SMed Ismail Bennani            if 'general purpose' in regs.name.lower():
124976867b5SMed Ismail Bennani                GPRs = regs
12559d8dd79SMed Ismail Bennani                break
12659d8dd79SMed Ismail Bennani
127976867b5SMed Ismail Bennani        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
128*c3ca2c6bSMed Ismail Bennani        self.assertGreater(GPRs.GetNumChildren(), 0)
129976867b5SMed Ismail Bennani        for idx, reg in enumerate(GPRs, start=1):
130*c3ca2c6bSMed Ismail Bennani            if idx > 21:
131*c3ca2c6bSMed Ismail Bennani                break
13259d8dd79SMed Ismail Bennani            self.assertEqual(idx, int(reg.value, 16))
13359d8dd79SMed Ismail Bennani
134976867b5SMed Ismail Bennani    def create_stack_skinny_corefile(self, file):
135976867b5SMed Ismail Bennani        self.build()
136d3e0f7e1SMed Ismail Bennani        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
137d3e0f7e1SMed Ismail Bennani                                                                       lldb.SBFileSpec("main.cpp"))
138976867b5SMed Ismail Bennani        self.assertTrue(process.IsValid(), "Process is invalid.")
139976867b5SMed Ismail Bennani        # FIXME: Use SBAPI to save the process corefile.
140976867b5SMed Ismail Bennani        self.runCmd("process save-core -s stack  " + file)
141976867b5SMed Ismail Bennani        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
142976867b5SMed Ismail Bennani        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
143976867b5SMed Ismail Bennani
144815c87fbSMed Ismail Bennani    @skipUnlessDarwin
145419b4711SMed Ismail Bennani    @skipIfOutOfTreeDebugserver
146a758c9f7SMed Ismail Bennani    def test_launch_scripted_process_stack_frames(self):
147312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process from the command
148312b43daSMed Ismail Bennani        line, check its process ID and read string from memory."""
149312b43daSMed Ismail Bennani        self.build()
150312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
151312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
152312b43daSMed Ismail Bennani
153a758c9f7SMed Ismail Bennani        for module in target.modules:
154a758c9f7SMed Ismail Bennani            if 'a.out' in module.GetFileSpec().GetFilename():
155a758c9f7SMed Ismail Bennani                main_module = module
156976867b5SMed Ismail Bennani                break
157a758c9f7SMed Ismail Bennani
158a758c9f7SMed Ismail Bennani        self.assertTrue(main_module, "Invalid main module.")
159a758c9f7SMed Ismail Bennani        error = target.SetModuleLoadAddress(main_module, 0)
160a758c9f7SMed Ismail Bennani        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
161a758c9f7SMed Ismail Bennani
162976867b5SMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
163419b4711SMed Ismail Bennani        def cleanup():
164419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
165419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
166419b4711SMed Ismail Bennani
167419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'stack_core_scripted_process.py'
168312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
169976867b5SMed Ismail Bennani                                                            scripted_process_example_relpath))
170312b43daSMed Ismail Bennani
171976867b5SMed Ismail Bennani        corefile_process = None
172976867b5SMed Ismail Bennani        with tempfile.NamedTemporaryFile() as file:
173976867b5SMed Ismail Bennani            self.create_stack_skinny_corefile(file.name)
174976867b5SMed Ismail Bennani            corefile_target = self.dbg.CreateTarget(None)
175976867b5SMed Ismail Bennani            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
176976867b5SMed Ismail Bennani        self.assertTrue(corefile_process, PROCESS_IS_VALID)
177976867b5SMed Ismail Bennani
178976867b5SMed Ismail Bennani        structured_data = lldb.SBStructuredData()
179976867b5SMed Ismail Bennani        structured_data.SetFromJSON(json.dumps({
180976867b5SMed Ismail Bennani            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
181976867b5SMed Ismail Bennani        }))
182976867b5SMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
183976867b5SMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
184976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
185976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessDictionary(structured_data)
186976867b5SMed Ismail Bennani
187976867b5SMed Ismail Bennani        error = lldb.SBError()
188976867b5SMed Ismail Bennani        process = target.Launch(launch_info, error)
189976867b5SMed Ismail Bennani        self.assertTrue(error.Success(), error.GetCString())
190312b43daSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
191312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
192312b43daSMed Ismail Bennani
193d3e0f7e1SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 3)
194cfa55bfeSMed Ismail Bennani        thread = process.GetThreadAtIndex(2)
195a758c9f7SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
196cfa55bfeSMed Ismail Bennani        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")
197312b43daSMed Ismail Bennani
198cfa55bfeSMed Ismail Bennani        self.assertEqual(thread.GetNumFrames(), 6)
199a758c9f7SMed Ismail Bennani        frame = thread.GetSelectedFrame()
200a758c9f7SMed Ismail Bennani        self.assertTrue(frame, "Invalid frame.")
201cfa55bfeSMed Ismail Bennani        self.assertIn("bar", frame.GetFunctionName())
202cfa55bfeSMed Ismail Bennani        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
203cfa55bfeSMed Ismail Bennani        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
204