xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision ef74c8002ae86d95fd9d1927233102aac52d769c)
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    def test_launch_scripted_process_stack_frames(self):
143        """Test that we can launch an lldb scripted process from the command
144        line, check its process ID and read string from memory."""
145        self.build()
146        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
147        self.assertTrue(target, VALID_TARGET)
148
149        for module in target.modules:
150            if 'a.out' in module.GetFileSpec().GetFilename():
151                main_module = module
152                break
153
154        self.assertTrue(main_module, "Invalid main module.")
155        error = target.SetModuleLoadAddress(main_module, 0)
156        self.assertTrue(error.Success(), "Reloading main module at offset 0 failed.")
157
158        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
159        def cleanup():
160          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
161        self.addTearDownHook(cleanup)
162
163        scripted_process_example_relpath = 'stack_core_scripted_process.py'
164        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
165                                                            scripted_process_example_relpath))
166
167        corefile_process = None
168        with tempfile.NamedTemporaryFile() as file:
169            self.create_stack_skinny_corefile(file.name)
170            corefile_target = self.dbg.CreateTarget(None)
171            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
172        self.assertTrue(corefile_process, PROCESS_IS_VALID)
173
174        structured_data = lldb.SBStructuredData()
175        structured_data.SetFromJSON(json.dumps({
176            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget())
177        }))
178        launch_info = lldb.SBLaunchInfo(None)
179        launch_info.SetProcessPluginName("ScriptedProcess")
180        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
181        launch_info.SetScriptedProcessDictionary(structured_data)
182
183        error = lldb.SBError()
184        process = target.Launch(launch_info, error)
185        self.assertTrue(error.Success(), error.GetCString())
186        self.assertTrue(process, PROCESS_IS_VALID)
187        self.assertEqual(process.GetProcessID(), 42)
188
189        self.assertEqual(process.GetNumThreads(), 1)
190        thread = process.GetSelectedThread()
191        self.assertTrue(thread, "Invalid thread.")
192        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
193
194        self.assertEqual(thread.GetNumFrames(), 3)
195        frame = thread.GetSelectedFrame()
196        self.assertTrue(frame, "Invalid frame.")
197        self.assertEqual(frame.GetFunctionName(), "bar")
198        self.assertEqual(int(frame.FindValue("i", lldb.eValueTypeVariableArgument).GetValue()), 42)
199        self.assertEqual(int(frame.FindValue("j", lldb.eValueTypeVariableLocal).GetValue()), 42 * 42)
200