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