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
44976867b5SMed Ismail Bennani    @skipIf(archs=no_match(['x86_64']))
45a758c9f7SMed Ismail Bennani    def test_scripted_process_and_scripted_thread(self):
46312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process using the SBAPI,
47a758c9f7SMed Ismail Bennani        check its process ID, read string from memory, check scripted thread
48a758c9f7SMed Ismail Bennani        id, name stop reason and register context.
49a758c9f7SMed Ismail Bennani        """
50312b43daSMed Ismail Bennani        self.build()
51312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
52312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
53312b43daSMed Ismail Bennani
54312b43daSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
55*419b4711SMed Ismail Bennani        def cleanup():
56*419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
57*419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
58*419b4711SMed Ismail Bennani
59*419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'dummy_scripted_process.py'
60312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
61a758c9f7SMed Ismail Bennani                                                            scripted_process_example_relpath))
62312b43daSMed Ismail Bennani
63312b43daSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
64312b43daSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
65a758c9f7SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
66312b43daSMed Ismail Bennani
67312b43daSMed Ismail Bennani        error = lldb.SBError()
68312b43daSMed Ismail Bennani        process = target.Launch(launch_info, error)
69312b43daSMed Ismail Bennani        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
70312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
71312b43daSMed Ismail Bennani
7259d8dd79SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 1)
7359d8dd79SMed Ismail Bennani
7459d8dd79SMed Ismail Bennani        thread = process.GetSelectedThread()
7559d8dd79SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
7659d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetThreadID(), 0x19)
77a758c9f7SMed Ismail Bennani        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
7859d8dd79SMed Ismail Bennani        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
7959d8dd79SMed Ismail Bennani
8059d8dd79SMed Ismail Bennani        self.assertGreater(thread.GetNumFrames(), 0)
8159d8dd79SMed Ismail Bennani
8259d8dd79SMed Ismail Bennani        frame = thread.GetFrameAtIndex(0)
83976867b5SMed Ismail Bennani        GPRs = None
8459d8dd79SMed Ismail Bennani        register_set = frame.registers # Returns an SBValueList.
8559d8dd79SMed Ismail Bennani        for regs in register_set:
86976867b5SMed Ismail Bennani            if 'general purpose' in regs.name.lower():
87976867b5SMed Ismail Bennani                GPRs = regs
8859d8dd79SMed Ismail Bennani                break
8959d8dd79SMed Ismail Bennani
90976867b5SMed Ismail Bennani        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
91976867b5SMed Ismail Bennani        self.assertEqual(GPRs.GetNumChildren(), 21)
92976867b5SMed Ismail Bennani        for idx, reg in enumerate(GPRs, start=1):
9359d8dd79SMed Ismail Bennani            self.assertEqual(idx, int(reg.value, 16))
9459d8dd79SMed Ismail Bennani
95976867b5SMed Ismail Bennani    def create_stack_skinny_corefile(self, file):
96976867b5SMed Ismail Bennani        self.build()
97976867b5SMed Ismail Bennani        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
98976867b5SMed Ismail Bennani        self.assertTrue(process.IsValid(), "Process is invalid.")
99976867b5SMed Ismail Bennani        # FIXME: Use SBAPI to save the process corefile.
100976867b5SMed Ismail Bennani        self.runCmd("process save-core -s stack  " + file)
101976867b5SMed Ismail Bennani        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
102976867b5SMed Ismail Bennani        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
103976867b5SMed Ismail Bennani
104815c87fbSMed Ismail Bennani    @skipUnlessDarwin
105*419b4711SMed Ismail Bennani    @skipIfOutOfTreeDebugserver
106976867b5SMed Ismail Bennani    @skipIf(archs=no_match(['x86_64']))
107a758c9f7SMed Ismail Bennani    def test_launch_scripted_process_stack_frames(self):
108312b43daSMed Ismail Bennani        """Test that we can launch an lldb scripted process from the command
109312b43daSMed Ismail Bennani        line, check its process ID and read string from memory."""
110312b43daSMed Ismail Bennani        self.build()
111312b43daSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
112312b43daSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
113312b43daSMed Ismail Bennani
114a758c9f7SMed Ismail Bennani        for module in target.modules:
115a758c9f7SMed Ismail Bennani            if 'a.out' in module.GetFileSpec().GetFilename():
116a758c9f7SMed Ismail Bennani                main_module = module
117976867b5SMed Ismail Bennani                break
118a758c9f7SMed Ismail Bennani
119a758c9f7SMed Ismail Bennani        self.assertTrue(main_module, "Invalid main module.")
120a758c9f7SMed Ismail Bennani        error = target.SetModuleLoadAddress(main_module, 0)
121a758c9f7SMed Ismail Bennani        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
122a758c9f7SMed Ismail Bennani
123976867b5SMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
124*419b4711SMed Ismail Bennani        def cleanup():
125*419b4711SMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
126*419b4711SMed Ismail Bennani        self.addTearDownHook(cleanup)
127*419b4711SMed Ismail Bennani
128*419b4711SMed Ismail Bennani        scripted_process_example_relpath = 'stack_core_scripted_process.py'
129312b43daSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
130976867b5SMed Ismail Bennani                                                            scripted_process_example_relpath))
131312b43daSMed Ismail Bennani
132976867b5SMed Ismail Bennani        corefile_process = None
133976867b5SMed Ismail Bennani        with tempfile.NamedTemporaryFile() as file:
134976867b5SMed Ismail Bennani            self.create_stack_skinny_corefile(file.name)
135976867b5SMed Ismail Bennani            corefile_target = self.dbg.CreateTarget(None)
136976867b5SMed Ismail Bennani            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
137976867b5SMed Ismail Bennani        self.assertTrue(corefile_process, PROCESS_IS_VALID)
138976867b5SMed Ismail Bennani
139976867b5SMed Ismail Bennani        structured_data = lldb.SBStructuredData()
140976867b5SMed Ismail Bennani        structured_data.SetFromJSON(json.dumps({
141976867b5SMed Ismail Bennani            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
142976867b5SMed Ismail Bennani        }))
143976867b5SMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
144976867b5SMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
145976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
146976867b5SMed Ismail Bennani        launch_info.SetScriptedProcessDictionary(structured_data)
147976867b5SMed Ismail Bennani
148976867b5SMed Ismail Bennani        error = lldb.SBError()
149976867b5SMed Ismail Bennani        process = target.Launch(launch_info, error)
150976867b5SMed Ismail Bennani        self.assertTrue(error.Success(), error.GetCString())
151312b43daSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
152312b43daSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
153312b43daSMed Ismail Bennani
154976867b5SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 1)
155a758c9f7SMed Ismail Bennani        thread = process.GetSelectedThread()
156a758c9f7SMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
157976867b5SMed Ismail Bennani        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
158312b43daSMed Ismail Bennani
159976867b5SMed Ismail Bennani        self.assertEqual(thread.GetNumFrames(), 3)
160a758c9f7SMed Ismail Bennani        frame = thread.GetSelectedFrame()
161a758c9f7SMed Ismail Bennani        self.assertTrue(frame, "Invalid frame.")
162a758c9f7SMed Ismail Bennani        self.assertEqual(frame.GetFunctionName(), "bar")
163a758c9f7SMed Ismail Bennani        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
164a758c9f7SMed Ismail Bennani        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
165