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