xref: /llvm-project/lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py (revision a3d4f739eea357c702754246442a2568f2bace81)
1"""
2Test python scripted process in lldb
3"""
4
5import os, shutil
6
7import lldb
8from lldbsuite.test.decorators import *
9from lldbsuite.test.lldbtest import *
10from lldbsuite.test import lldbutil
11from lldbsuite.test import lldbtest
12
13import dummy_scripted_process
14
15class ScriptedProcesTestCase(TestBase):
16
17    NO_DEBUG_INFO_TESTCASE = True
18
19    @skipUnlessDarwin
20    def test_python_plugin_package(self):
21        """Test that the lldb python module has a `plugins.scripted_process`
22        package."""
23        self.expect('script import lldb.plugins',
24                    substrs=["ModuleNotFoundError"], matching=False)
25
26        self.expect('script dir(lldb.plugins)',
27                    substrs=["scripted_process"])
28
29        self.expect('script import lldb.plugins.scripted_process',
30                    substrs=["ModuleNotFoundError"], matching=False)
31
32        self.expect('script dir(lldb.plugins.scripted_process)',
33                    substrs=["ScriptedProcess"])
34
35        self.expect('script from lldb.plugins.scripted_process import ScriptedProcess',
36                    substrs=["ImportError"], matching=False)
37
38        self.expect('script dir(ScriptedProcess)',
39                    substrs=["launch"])
40
41    def move_blueprint_to_dsym(self, blueprint_name):
42        blueprint_origin_path = os.path.join(self.getSourceDir(), blueprint_name)
43        dsym_bundle = self.getBuildArtifact("a.out.dSYM")
44        blueprint_destination_path = os.path.join(dsym_bundle, "Contents",
45                                                  "Resources", "Python")
46        if not os.path.exists(blueprint_destination_path):
47            os.mkdir(blueprint_destination_path)
48
49        blueprint_destination_path = os.path.join(blueprint_destination_path, "a_out.py")
50        shutil.copy(blueprint_origin_path, blueprint_destination_path)
51
52    @skipUnlessDarwin
53    def test_invalid_scripted_register_context(self):
54        """Test that we can launch an lldb scripted process with an invalid
55        Scripted Thread, with invalid register context."""
56        self.build()
57
58        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
59        def cleanup():
60          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
61        self.addTearDownHook(cleanup)
62
63        self.runCmd("settings set target.load-script-from-symbol-file true")
64        self.move_blueprint_to_dsym('invalid_scripted_process.py')
65        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
66        self.assertTrue(target, VALID_TARGET)
67        log_file = self.getBuildArtifact('thread.log')
68        self.runCmd("log enable lldb thread -f " + log_file)
69        self.assertTrue(os.path.isfile(log_file))
70
71        launch_info = lldb.SBLaunchInfo(None)
72        launch_info.SetProcessPluginName("ScriptedProcess")
73        launch_info.SetScriptedProcessClassName("a_out.InvalidScriptedProcess")
74        error = lldb.SBError()
75
76        process = target.Launch(launch_info, error)
77
78        self.assertSuccess(error)
79        self.assertTrue(process, PROCESS_IS_VALID)
80        self.assertEqual(process.GetProcessID(), 666)
81        self.assertEqual(process.GetNumThreads(), 0)
82
83        addr = 0x500000000
84        buff = process.ReadMemory(addr, 4, error)
85        self.assertEqual(buff, None)
86        self.assertTrue(error.Fail())
87        self.assertEqual(error.GetCString(), "This is an invalid scripted process!")
88
89        with open(log_file, 'r') as f:
90            log = f.read()
91
92        self.assertIn("Failed to get scripted thread registers data.", log)
93
94    @skipUnlessDarwin
95    def test_scripted_process_and_scripted_thread(self):
96        """Test that we can launch an lldb scripted process using the SBAPI,
97        check its process ID, read string from memory, check scripted thread
98        id, name stop reason and register context.
99        """
100        self.build()
101        target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
102        self.assertTrue(target_0, VALID_TARGET)
103
104        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
105        def cleanup():
106          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
107        self.addTearDownHook(cleanup)
108
109        scripted_process_example_relpath = 'dummy_scripted_process.py'
110        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
111                                                            scripted_process_example_relpath))
112
113        launch_info = lldb.SBLaunchInfo(None)
114        launch_info.SetProcessPluginName("ScriptedProcess")
115        launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
116
117        error = lldb.SBError()
118        process_0 = target_0.Launch(launch_info, error)
119        self.assertTrue(process_0 and process_0.IsValid(), PROCESS_IS_VALID)
120        self.assertEqual(process_0.GetProcessID(), 42)
121        self.assertEqual(process_0.GetNumThreads(), 1)
122
123        py_impl = process_0.GetScriptedImplementation()
124        self.assertTrue(py_impl)
125        self.assertTrue(isinstance(py_impl, dummy_scripted_process.DummyScriptedProcess))
126        self.assertFalse(hasattr(py_impl, 'my_super_secret_member'))
127        py_impl.my_super_secret_member = 42
128        self.assertTrue(hasattr(py_impl, 'my_super_secret_member'))
129        self.assertEqual(py_impl.my_super_secret_method(), 42)
130
131        # Try reading from target #0 process ...
132        addr = 0x500000000
133        message = "Hello, target 0"
134        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
135        self.assertSuccess(error)
136        self.assertEqual(buff, message)
137
138        target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
139        self.assertTrue(target_1, VALID_TARGET)
140        error = lldb.SBError()
141        process_1 = target_1.Launch(launch_info, error)
142        self.assertTrue(process_1 and process_1.IsValid(), PROCESS_IS_VALID)
143        self.assertEqual(process_1.GetProcessID(), 42)
144        self.assertEqual(process_1.GetNumThreads(), 1)
145
146        # ... then try reading from target #1 process ...
147        addr = 0x500000000
148        message = "Hello, target 1"
149        buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error)
150        self.assertSuccess(error)
151        self.assertEqual(buff, message)
152
153        # ... now, reading again from target #0 process to make sure the call
154        # gets dispatched to the right target.
155        addr = 0x500000000
156        message = "Hello, target 0"
157        buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
158        self.assertSuccess(error)
159        self.assertEqual(buff, message)
160
161        thread = process_0.GetSelectedThread()
162        self.assertTrue(thread, "Invalid thread.")
163        self.assertEqual(thread.GetThreadID(), 0x19)
164        self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
165        self.assertStopReason(thread.GetStopReason(), lldb.eStopReasonSignal)
166
167        self.assertGreater(thread.GetNumFrames(), 0)
168
169        frame = thread.GetFrameAtIndex(0)
170        GPRs = None
171        register_set = frame.registers # Returns an SBValueList.
172        for regs in register_set:
173            if 'general purpose' in regs.name.lower():
174                GPRs = regs
175                break
176
177        self.assertTrue(GPRs, "Invalid General Purpose Registers Set")
178        self.assertGreater(GPRs.GetNumChildren(), 0)
179        for idx, reg in enumerate(GPRs, start=1):
180            if idx > 21:
181                break
182            self.assertEqual(idx, int(reg.value, 16))
183
184        self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
185        pc = frame.GetPCAddress().GetLoadAddress(target_0)
186        self.assertEqual(pc, 0x0100001b00)
187