xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision 326516448c839d8f9cc515b20a34d0f3a6ee2374)
1"""
2Test python scripted process in lldb
3"""
4
5import os, json, tempfile
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11from lldbsuite.test import lldbtest
12
13class ScriptedProcesTestCase(TestBase):
14
15    mydir = TestBase.compute_mydir(__file__)
16
17    def setUp(self):
18        TestBase.setUp(self)
19
20    def tearDown(self):
21        TestBase.tearDown(self)
22        if "SKIP_SCRIPTED_PROCESS_LAUNCH" in os.environ:
23          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
24
25    def test_python_plugin_package(self):
26        """Test that the lldb python module has a `plugins.scripted_process`
27        package."""
28        self.expect('script import lldb.plugins',
29                    substrs=["ModuleNotFoundError"], matching=False)
30
31        self.expect('script dir(lldb.plugins)',
32                    substrs=["scripted_process"])
33
34        self.expect('script import lldb.plugins.scripted_process',
35                    substrs=["ModuleNotFoundError"], matching=False)
36
37        self.expect('script dir(lldb.plugins.scripted_process)',
38                    substrs=["ScriptedProcess"])
39
40        self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
41                    substrs=["ImportError"], matching=False)
42
43        self.expect('script dir(ScriptedProcess)',
44                    substrs=["launch"])
45
46    @skipUnlessDarwin
47    def test_invalid_scripted_register_context(self):
48        """Test that we can launch an lldb scripted process with an invalid
49        Scripted Thread, with invalid register context."""
50        self.build()
51        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
52        self.assertTrue(target, VALID_TARGET)
53        log_file = self.getBuildArtifact('thread.log')
54        self.runCmd("log enable lldb thread -f " + log_file)
55        self.assertTrue(os.path.isfile(log_file))
56
57        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
58        scripted_process_example_relpath = 'invalid_scripted_process.py'
59        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
60                                                            scripted_process_example_relpath))
61
62        launch_info = lldb.SBLaunchInfo(None)
63        launch_info.SetProcessPluginName("ScriptedProcess")
64        launch_info.SetScriptedProcessClassName("invalid_scripted_process.InvalidScriptedProcess")
65        error = lldb.SBError()
66
67        process = target.Launch(launch_info, error)
68
69        self.assertTrue(error.Success(), error.GetCString())
70        self.assertTrue(process, PROCESS_IS_VALID)
71        self.assertEqual(process.GetProcessID(), 666)
72        self.assertEqual(process.GetNumThreads(), 0)
73
74        with open(log_file, 'r') as f:
75            log = f.read()
76
77        self.assertIn("Failed to get scripted thread registers data.", log)
78
79    @skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e']))
80    def test_scripted_process_and_scripted_thread(self):
81        """Test that we can launch an lldb scripted process using the SBAPI,
82        check its process ID, read string from memory, check scripted thread
83        id, name stop reason and register context.
84        """
85        self.build()
86        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
87        self.assertTrue(target, VALID_TARGET)
88
89        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
90        scripted_process_example_relpath = 'dummy_scripted_process.py'
91        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
92                                                            scripted_process_example_relpath))
93
94        launch_info = lldb.SBLaunchInfo(None)
95        launch_info.SetProcessPluginName("ScriptedProcess")
96        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
97
98        error = lldb.SBError()
99        process = target.Launch(launch_info, error)
100        self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
101        self.assertEqual(process.GetProcessID(), 42)
102
103        self.assertEqual(process.GetNumThreads(), 1)
104
105        thread = process.GetSelectedThread()
106        self.assertTrue(thread, "Invalid thread.")
107        self.assertEqual(thread.GetThreadID(), 0x19)
108        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
109        self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
110
111        self.assertGreater(thread.GetNumFrames(), 0)
112
113        frame = thread.GetFrameAtIndex(0)
114        GPRs = None
115        register_set = frame.registers # Returns an SBValueList.
116        for regs in register_set:
117            if 'general purpose' in regs.name.lower():
118                GPRs = regs
119                break
120
121        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
122        self.assertGreater(GPRs.GetNumChildren(), 0)
123        for idx, reg in enumerate(GPRs, start=1):
124            if idx > 21:
125                break
126            self.assertEqual(idx, int(reg.value, 16))
127
128    def create_stack_skinny_corefile(self, file):
129        self.build()
130        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
131                                                                       lldb.SBFileSpec("main.cpp"))
132        self.assertTrue(process.IsValid(), "Process is invalid.")
133        # FIXME: Use SBAPI to save the process corefile.
134        self.runCmd("process save-core -s stack  " + file)
135        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
136        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
137
138    @skipUnlessDarwin
139    @skipIfOutOfTreeDebugserver
140    def test_launch_scripted_process_stack_frames(self):
141        """Test that we can launch an lldb scripted process from the command
142        line, check its process ID and read string from memory."""
143        self.build()
144        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
145        self.assertTrue(target, VALID_TARGET)
146
147        for module in target.modules:
148            if 'a.out' in module.GetFileSpec().GetFilename():
149                main_module = module
150                break
151
152        self.assertTrue(main_module, "Invalid main module.")
153        error = target.SetModuleLoadAddress(main_module, 0)
154        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
155
156        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
157        scripted_process_example_relpath = 'stack_core_scripted_process.py'
158        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
159                                                            scripted_process_example_relpath))
160
161        corefile_process = None
162        with tempfile.NamedTemporaryFile() as file:
163            self.create_stack_skinny_corefile(file.name)
164            corefile_target = self.dbg.CreateTarget(None)
165            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
166        self.assertTrue(corefile_process, PROCESS_IS_VALID)
167
168        structured_data = lldb.SBStructuredData()
169        structured_data.SetFromJSON(json.dumps({
170            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
171        }))
172        launch_info = lldb.SBLaunchInfo(None)
173        launch_info.SetProcessPluginName("ScriptedProcess")
174        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
175        launch_info.SetScriptedProcessDictionary(structured_data)
176
177        error = lldb.SBError()
178        process = target.Launch(launch_info, error)
179        self.assertTrue(error.Success(), error.GetCString())
180        self.assertTrue(process, PROCESS_IS_VALID)
181        self.assertEqual(process.GetProcessID(), 42)
182
183        self.assertEqual(process.GetNumThreads(), 3)
184        thread = process.GetThreadAtIndex(2)
185        self.assertTrue(thread, "Invalid thread.")
186        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-2")
187
188        self.assertEqual(thread.GetNumFrames(), 6)
189        frame = thread.GetSelectedFrame()
190        self.assertTrue(frame, "Invalid frame.")
191        self.assertIn("bar", frame.GetFunctionName())
192        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
193        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
194