1""" 2Test that stepping works even when the OS Plugin doesn't report 3all threads at every stop. 4""" 5 6import os 7import lldb 8from lldbsuite.test.decorators import * 9from lldbsuite.test.lldbtest import * 10import lldbsuite.test.lldbutil as lldbutil 11 12 13class TestOSPluginStepping(TestBase): 14 NO_DEBUG_INFO_TESTCASE = True 15 16 @skipIfWindows 17 @skipIf(oslist=["freebsd"], bugnumber="llvm.org/pr48352") 18 def test_python_os_plugin(self): 19 """Test that stepping works when the OS Plugin doesn't report all 20 threads at every stop""" 21 self.build() 22 self.main_file = lldb.SBFileSpec("main.cpp") 23 self.run_python_os_step_missing_thread(False) 24 25 @skipIfWindows 26 @skipIf(oslist=["freebsd"], bugnumber="llvm.org/pr48352") 27 def test_python_os_plugin_prune(self): 28 """Test that pruning the unreported PlanStacks works""" 29 self.build() 30 self.main_file = lldb.SBFileSpec("main.cpp") 31 self.run_python_os_step_missing_thread(True) 32 33 def get_os_thread(self): 34 return self.process.GetThreadByID(0x111111111) 35 36 def is_os_thread(self, thread): 37 id = thread.GetID() 38 return id == 0x111111111 39 40 def run_python_os_step_missing_thread(self, do_prune): 41 """Test that the Python operating system plugin works correctly""" 42 43 python_os_plugin_path = os.path.join(self.getSourceDir(), "operating_system.py") 44 (target, self.process, thread, thread_bkpt) = lldbutil.run_to_source_breakpoint( 45 self, "first stop in thread - do a step out", self.main_file 46 ) 47 48 main_bkpt = target.BreakpointCreateBySourceRegex( 49 "Stop here and do not make a memory thread for thread_1", self.main_file 50 ) 51 self.assertEqual( 52 main_bkpt.GetNumLocations(), 1, "Main breakpoint has one location" 53 ) 54 55 # There should not be an os thread before we load the plugin: 56 self.assertFalse( 57 self.get_os_thread().IsValid(), "No OS thread before loading plugin" 58 ) 59 60 # Now load the python OS plug-in which should update the thread list and we should have 61 # an OS plug-in thread overlaying thread_1 with id 0x111111111 62 command = ( 63 "settings set target.process.python-os-plugin-path '%s'" 64 % python_os_plugin_path 65 ) 66 self.dbg.HandleCommand(command) 67 68 # Verify our OS plug-in threads showed up 69 os_thread = self.get_os_thread() 70 self.assertTrue( 71 os_thread.IsValid(), 72 "Make sure we added the thread 0x111111111 after we load the python OS plug-in", 73 ) 74 75 # Now we are going to step-out. This should get interrupted by main_bkpt. We've 76 # set up the OS plugin so at this stop, we have lost the OS thread 0x111111111. 77 # Make sure both of these are true: 78 os_thread.StepOut() 79 80 stopped_threads = lldbutil.get_threads_stopped_at_breakpoint( 81 self.process, main_bkpt 82 ) 83 self.assertEqual(len(stopped_threads), 1, "Stopped at main_bkpt") 84 thread = self.process.GetThreadByID(0x111111111) 85 self.assertFalse(thread.IsValid(), "No thread 0x111111111 on second stop.") 86 87 # Make sure we still have the thread plans for this thread: 88 # First, don't show unreported threads, that should fail: 89 command = "thread plan list -t 0x111111111" 90 result = lldb.SBCommandReturnObject() 91 interp = self.dbg.GetCommandInterpreter() 92 interp.HandleCommand(command, result) 93 self.assertFalse( 94 result.Succeeded(), "We found no plans for the unreported thread." 95 ) 96 # Now do it again but with the -u flag: 97 command = "thread plan list -u -t 0x111111111" 98 result = lldb.SBCommandReturnObject() 99 interp.HandleCommand(command, result) 100 self.assertTrue(result.Succeeded(), "We found plans for the unreported thread.") 101 102 if do_prune: 103 # Prune the thread plan and continue, and we will run to exit. 104 interp.HandleCommand("thread plan prune 0x111111111", result) 105 self.assertTrue( 106 result.Succeeded(), "Found the plan for 0x111111111 and pruned it" 107 ) 108 109 # List again, make sure it doesn't work: 110 command = "thread plan list -u -t 0x111111111" 111 interp.HandleCommand(command, result) 112 self.assertFalse( 113 result.Succeeded(), "We still found plans for the unreported thread." 114 ) 115 116 self.process.Continue() 117 self.assertState(self.process.GetState(), lldb.eStateExited, "We exited.") 118 else: 119 # Now we are going to continue, and when we hit the step-out breakpoint, we will 120 # put the OS plugin thread back, lldb will recover its ThreadPlanStack, and 121 # we will stop with a "step-out" reason. 122 self.process.Continue() 123 os_thread = self.get_os_thread() 124 self.assertTrue(os_thread.IsValid(), "The OS thread is back after continue") 125 self.assertIn( 126 "step out", os_thread.GetStopDescription(100), "Completed step out plan" 127 ) 128