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
44caea440aSMed Ismail Bennani    def test_invalid_scripted_register_context(self):
45caea440aSMed Ismail Bennani        """Test that we can launch an lldb scripted process with an invalid
46caea440aSMed Ismail Bennani        Scripted Thread, with invalid register context."""
47caea440aSMed Ismail Bennani        self.build()
48caea440aSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
49caea440aSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
509c144b3bSMed Ismail Bennani        log_file = self.getBuildArtifact('thread.log')
519c144b3bSMed Ismail Bennani        self.runCmd("log enable lldb thread -f " + log_file)
529c144b3bSMed Ismail Bennani        self.assertTrue(os.path.isfile(log_file))
53caea440aSMed Ismail Bennani
54caea440aSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
55caea440aSMed Ismail Bennani        def cleanup():
56caea440aSMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
57caea440aSMed Ismail Bennani        self.addTearDownHook(cleanup)
58caea440aSMed Ismail Bennani
59caea440aSMed Ismail Bennani        scripted_process_example_relpath = 'invalid_scripted_process.py'
60caea440aSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
61caea440aSMed Ismail Bennani                                                            scripted_process_example_relpath))
62caea440aSMed Ismail Bennani
63caea440aSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
64caea440aSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
65caea440aSMed Ismail Bennani        launch_info.SetScriptedProcessClassName("invalid_scripted_process.InvalidScriptedProcess")
66caea440aSMed Ismail Bennani        error = lldb.SBError()
679c144b3bSMed Ismail Bennani
68caea440aSMed Ismail Bennani        process = target.Launch(launch_info, error)
69caea440aSMed Ismail Bennani
70caea440aSMed Ismail Bennani        self.assertTrue(error.Success(), error.GetCString())
71caea440aSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
72caea440aSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 666)
73caea440aSMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 0)
74caea440aSMed Ismail Bennani
759c144b3bSMed Ismail Bennani        with open(log_file, 'r') as f:
769c144b3bSMed Ismail Bennani            log = f.read()
779c144b3bSMed Ismail Bennani
789c144b3bSMed Ismail Bennani        self.assertIn("Failed to get scripted thread registers data.", log)
79caea440aSMed Ismail Bennani
80976867b5SMed Ismail Bennani    @skipIf(archs=no_match(['x86_64']))
81a758c9f7SMed Ismail Bennani    def test_scripted_process_and_scripted_thread(self):
82312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process using the SBAPI,
83a758c9f7SMed Ismail Bennani        check its process ID, read string from memory, check scripted thread
84a758c9f7SMed Ismail Bennani        id, name stop reason and register context.
85a758c9f7SMed Ismail Bennani        """
86312b43daSMed Ismail Bennani        self.build()
87312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
88312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
89312b43daSMed Ismail Bennani
90312b43daSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
91419b4711SMed Ismail Bennani        def cleanup():
92419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
93419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
94419b4711SMed Ismail Bennani
95419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'dummy_scripted_process.py'
96312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
97a758c9f7SMed Ismail Bennani                                                            scripted_process_example_relpath))
98312b43daSMed Ismail Bennani
99312b43daSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
100312b43daSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
101a758c9f7SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
102312b43daSMed Ismail Bennani
103312b43daSMed Ismail Bennani        error = lldb.SBError()
104312b43daSMed Ismail Bennani        process = target.Launch(launch_info, error)
105312b43daSMed Ismail Bennani        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
106312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
107312b43daSMed Ismail Bennani
10859d8dd79SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 1)
10959d8dd79SMed Ismail Bennani
11059d8dd79SMed Ismail Bennani        thread = process.GetSelectedThread()
11159d8dd79SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
11259d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetThreadID(), 0x19)
113a758c9f7SMed Ismail Bennani        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
11459d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
11559d8dd79SMed Ismail Bennani
11659d8dd79SMed Ismail Bennani        self.assertGreater(thread.GetNumFrames(), 0)
11759d8dd79SMed Ismail Bennani
11859d8dd79SMed Ismail Bennani        frame = thread.GetFrameAtIndex(0)
119976867b5SMed Ismail Bennani        GPRs = None
12059d8dd79SMed Ismail Bennani        register_set = frame.registers # Returns an SBValueList.
12159d8dd79SMed Ismail Bennani        for regs in register_set:
122976867b5SMed Ismail Bennani            if 'general purpose' in regs.name.lower():
123976867b5SMed Ismail Bennani                GPRs = regs
12459d8dd79SMed Ismail Bennani                break
12559d8dd79SMed Ismail Bennani
126976867b5SMed Ismail Bennani        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
127976867b5SMed Ismail Bennani        self.assertEqual(GPRs.GetNumChildren(), 21)
128976867b5SMed Ismail Bennani        for idx, reg in enumerate(GPRs, start=1):
12959d8dd79SMed Ismail Bennani            self.assertEqual(idx, int(reg.value, 16))
13059d8dd79SMed Ismail Bennani
131976867b5SMed Ismail Bennani    def create_stack_skinny_corefile(self, file):
132976867b5SMed Ismail Bennani        self.build()
133d3e0f7e1SMed Ismail Bennani        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
134d3e0f7e1SMed Ismail Bennani                                                                       lldb.SBFileSpec("main.cpp"))
135976867b5SMed Ismail Bennani        self.assertTrue(process.IsValid(), "Process is invalid.")
136976867b5SMed Ismail Bennani        # FIXME: Use SBAPI to save the process corefile.
137976867b5SMed Ismail Bennani        self.runCmd("process save-core -s stack  " + file)
138976867b5SMed Ismail Bennani        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
139976867b5SMed Ismail Bennani        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
140976867b5SMed Ismail Bennani
141815c87fbSMed Ismail Bennani    @skipUnlessDarwin
142419b4711SMed Ismail Bennani    @skipIfOutOfTreeDebugserver
143a758c9f7SMed Ismail Bennani    def test_launch_scripted_process_stack_frames(self):
144312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process from the command
145312b43daSMed Ismail Bennani        line, check its process ID and read string from memory."""
146312b43daSMed Ismail Bennani        self.build()
147312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
148312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
149312b43daSMed Ismail Bennani
150a758c9f7SMed Ismail Bennani        for module in target.modules:
151a758c9f7SMed Ismail Bennani            if 'a.out' in module.GetFileSpec().GetFilename():
152a758c9f7SMed Ismail Bennani                main_module = module
153976867b5SMed Ismail Bennani                break
154a758c9f7SMed Ismail Bennani
155a758c9f7SMed Ismail Bennani        self.assertTrue(main_module, "Invalid main module.")
156a758c9f7SMed Ismail Bennani        error = target.SetModuleLoadAddress(main_module, 0)
157a758c9f7SMed Ismail Bennani        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
158a758c9f7SMed Ismail Bennani
159976867b5SMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
160419b4711SMed Ismail Bennani        def cleanup():
161419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
162419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
163419b4711SMed Ismail Bennani
164419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'stack_core_scripted_process.py'
165312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
166976867b5SMed Ismail Bennani                                                            scripted_process_example_relpath))
167312b43daSMed Ismail Bennani
168976867b5SMed Ismail Bennani        corefile_process = None
169976867b5SMed Ismail Bennani        with tempfile.NamedTemporaryFile() as file:
170976867b5SMed Ismail Bennani            self.create_stack_skinny_corefile(file.name)
171976867b5SMed Ismail Bennani            corefile_target = self.dbg.CreateTarget(None)
172976867b5SMed Ismail Bennani            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
173976867b5SMed Ismail Bennani        self.assertTrue(corefile_process, PROCESS_IS_VALID)
174976867b5SMed Ismail Bennani
175976867b5SMed Ismail Bennani        structured_data = lldb.SBStructuredData()
176976867b5SMed Ismail Bennani        structured_data.SetFromJSON(json.dumps({
177976867b5SMed Ismail Bennani            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
178976867b5SMed Ismail Bennani        }))
179976867b5SMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
180976867b5SMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
181976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
182976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessDictionary(structured_data)
183976867b5SMed Ismail Bennani
184976867b5SMed Ismail Bennani        error = lldb.SBError()
185976867b5SMed Ismail Bennani        process = target.Launch(launch_info, error)
186976867b5SMed Ismail Bennani        self.assertTrue(error.Success(), error.GetCString())
187312b43daSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
188312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
189312b43daSMed Ismail Bennani
190d3e0f7e1SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 3)
191*cfa55bfeSMed Ismail Bennani        thread = process.GetThreadAtIndex(2)
192a758c9f7SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
193*cfa55bfeSMed Ismail Bennani        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")
194312b43daSMed Ismail Bennani
195*cfa55bfeSMed Ismail Bennani        self.assertEqual(thread.GetNumFrames(), 6)
196a758c9f7SMed Ismail Bennani        frame = thread.GetSelectedFrame()
197a758c9f7SMed Ismail Bennani        self.assertTrue(frame, "Invalid frame.")
198*cfa55bfeSMed Ismail Bennani        self.assertIn("bar", frame.GetFunctionName())
199*cfa55bfeSMed Ismail Bennani        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
200*cfa55bfeSMed Ismail Bennani        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
201