xref: /llvm-project/lldb/test/API/functionalities/plugins/python_os_plugin/TestPythonOSPlugin.py (revision f5dd8450940b003afb446846840cd19b067d327d)
1"""
2Test that the Python operating system plugin works correctly
3"""
4
5
6import os
7import lldb
8from lldbsuite.test.lldbtest import *
9import lldbsuite.test.lldbutil as lldbutil
10
11
12class PluginPythonOSPlugin(TestBase):
13    NO_DEBUG_INFO_TESTCASE = True
14
15    def test_python_os_plugin(self):
16        """Test that the Python operating system plugin works correctly"""
17        self.build()
18        self.run_python_os_funcionality()
19
20    @skipIfWindows  # This is flaky on Windows
21    def test_run_python_os_step(self):
22        """Test that the Python operating system plugin works correctly when single stepping a virtual thread"""
23        self.build()
24        self.run_python_os_step()
25
26    def verify_os_thread_registers(self, thread):
27        frame = thread.GetFrameAtIndex(0)
28        registers = frame.GetRegisters().GetValueAtIndex(0)
29        reg_value = thread.GetThreadID() + 1
30        for reg in registers:
31            self.assertEqual(
32                reg.GetValueAsUnsigned(),
33                reg_value,
34                "Verify the registers contains the correct value",
35            )
36            reg_value = reg_value + 1
37
38    def run_python_os_funcionality(self):
39        """Test that the Python operating system plugin works correctly"""
40
41        # Set debugger into synchronous mode
42        self.dbg.SetAsync(False)
43
44        # Create a target by the debugger.
45        exe = self.getBuildArtifact("a.out")
46        python_os_plugin_path = os.path.join(self.getSourceDir(), "operating_system.py")
47        target = self.dbg.CreateTarget(exe)
48        self.assertTrue(target, VALID_TARGET)
49
50        # Set breakpoints inside and outside methods that take pointers to the
51        # containing struct.
52        lldbutil.run_break_set_by_source_regexp(self, "// Set breakpoint here")
53
54        # Register our shared libraries for remote targets so they get
55        # automatically uploaded
56        arguments = None
57        environment = None
58
59        # Now launch the process, and do not stop at entry point.
60        process = target.LaunchSimple(
61            arguments, environment, self.get_process_working_directory()
62        )
63        self.assertTrue(process, PROCESS_IS_VALID)
64
65        # Make sure there are no OS plug-in created thread when we first stop
66        # at our breakpoint in main
67        thread = process.GetThreadByID(0x111111111)
68        self.assertFalse(
69            thread.IsValid(),
70            "Make sure there is no thread 0x111111111 before we load the python OS plug-in",
71        )
72        thread = process.GetThreadByID(0x222222222)
73        self.assertFalse(
74            thread.IsValid(),
75            "Make sure there is no thread 0x222222222 before we load the python OS plug-in",
76        )
77        thread = process.GetThreadByID(0x333333333)
78        self.assertFalse(
79            thread.IsValid(),
80            "Make sure there is no thread 0x333333333 before we load the python OS plug-in",
81        )
82
83        # Now load the python OS plug-in which should update the thread list and we should have
84        # OS plug-in created threads with the IDs: 0x111111111, 0x222222222,
85        # 0x333333333
86        command = (
87            "settings set target.process.python-os-plugin-path '%s'"
88            % python_os_plugin_path
89        )
90        self.dbg.HandleCommand(command)
91
92        # Verify our OS plug-in threads showed up
93        thread = process.GetThreadByID(0x111111111)
94        self.assertTrue(
95            thread.IsValid(),
96            "Make sure there is a thread 0x111111111 after we load the python OS plug-in",
97        )
98        self.verify_os_thread_registers(thread)
99        thread = process.GetThreadByID(0x222222222)
100        self.assertTrue(
101            thread.IsValid(),
102            "Make sure there is a thread 0x222222222 after we load the python OS plug-in",
103        )
104        self.verify_os_thread_registers(thread)
105        thread = process.GetThreadByID(0x333333333)
106        self.assertTrue(
107            thread.IsValid(),
108            "Make sure there is a thread 0x333333333 after we load the python OS plug-in",
109        )
110        self.verify_os_thread_registers(thread)
111
112        # Now clear the OS plug-in path to make the OS plug-in created threads
113        # disappear
114        self.dbg.HandleCommand("settings clear target.process.python-os-plugin-path")
115
116        # Verify the threads are gone after unloading the python OS plug-in
117        thread = process.GetThreadByID(0x111111111)
118        self.assertFalse(
119            thread.IsValid(),
120            "Make sure there is no thread 0x111111111 after we unload the python OS plug-in",
121        )
122        thread = process.GetThreadByID(0x222222222)
123        self.assertFalse(
124            thread.IsValid(),
125            "Make sure there is no thread 0x222222222 after we unload the python OS plug-in",
126        )
127        thread = process.GetThreadByID(0x333333333)
128        self.assertFalse(
129            thread.IsValid(),
130            "Make sure there is no thread 0x333333333 after we unload the python OS plug-in",
131        )
132
133    def run_python_os_step(self):
134        """Test that the Python operating system plugin works correctly and allows single stepping of a virtual thread that is backed by a real thread"""
135
136        # Set debugger into synchronous mode
137        self.dbg.SetAsync(False)
138
139        # Create a target by the debugger.
140        exe = self.getBuildArtifact("a.out")
141        python_os_plugin_path = os.path.join(
142            self.getSourceDir(), "operating_system2.py"
143        )
144        target = self.dbg.CreateTarget(exe)
145        self.assertTrue(target, VALID_TARGET)
146
147        # Set breakpoints inside and outside methods that take pointers to the
148        # containing struct.
149        lldbutil.run_break_set_by_source_regexp(self, "// Set breakpoint here")
150
151        # Register our shared libraries for remote targets so they get
152        # automatically uploaded
153        arguments = None
154        environment = None
155
156        # Now launch the process, and do not stop at entry point.
157        process = target.LaunchSimple(
158            arguments, environment, self.get_process_working_directory()
159        )
160        self.assertTrue(process, PROCESS_IS_VALID)
161
162        # Make sure there are no OS plug-in created thread when we first stop
163        # at our breakpoint in main
164        thread = process.GetThreadByID(0x111111111)
165        self.assertFalse(
166            thread.IsValid(),
167            "Make sure there is no thread 0x111111111 before we load the python OS plug-in",
168        )
169
170        # Now load the python OS plug-in which should update the thread list and we should have
171        # OS plug-in created threads with the IDs: 0x111111111, 0x222222222,
172        # 0x333333333
173        command = (
174            "settings set target.process.python-os-plugin-path '%s'"
175            % python_os_plugin_path
176        )
177        self.dbg.HandleCommand(command)
178
179        # Verify our OS plug-in threads showed up
180        thread = process.GetThreadByID(0x111111111)
181        self.assertTrue(
182            thread.IsValid(),
183            "Make sure there is a thread 0x111111111 after we load the python OS plug-in",
184        )
185
186        frame = thread.GetFrameAtIndex(0)
187        self.assertTrue(
188            frame.IsValid(), "Make sure we get a frame from thread 0x111111111"
189        )
190        line_entry = frame.GetLineEntry()
191
192        self.assertEqual(
193            line_entry.GetFileSpec().GetFilename(),
194            "main.c",
195            "Make sure we stopped on line 5 in main.c",
196        )
197        self.assertEqual(
198            line_entry.GetLine(), 5, "Make sure we stopped on line 5 in main.c"
199        )
200
201        # Now single step thread 0x111111111 and make sure it does what we need
202        # it to
203        thread.StepOver()
204
205        frame = thread.GetFrameAtIndex(0)
206        self.assertTrue(
207            frame.IsValid(), "Make sure we get a frame from thread 0x111111111"
208        )
209        line_entry = frame.GetLineEntry()
210
211        self.assertEqual(
212            line_entry.GetFileSpec().GetFilename(),
213            "main.c",
214            "Make sure we stepped from line 5 to line 6 in main.c",
215        )
216        self.assertEqual(
217            line_entry.GetLine(),
218            6,
219            "Make sure we stepped from line 5 to line 6 in main.c",
220        )
221