11893065dSJim Ingham""" 21893065dSJim InghamTest that thread plan listing, and deleting works. 31893065dSJim Ingham""" 41893065dSJim Ingham 51893065dSJim Ingham 61893065dSJim Inghamimport lldb 72d658c56SJim Inghamfrom lldbsuite.test.decorators import * 81893065dSJim Inghamimport lldbsuite.test.lldbutil as lldbutil 91893065dSJim Inghamfrom lldbsuite.test.lldbtest import * 101893065dSJim Ingham 111893065dSJim Ingham 121893065dSJim Inghamclass TestThreadPlanCommands(TestBase): 131893065dSJim Ingham NO_DEBUG_INFO_TESTCASE = True 141893065dSJim Ingham 152d658c56SJim Ingham @skipIfWindows 161893065dSJim Ingham def test_thread_plan_actions(self): 171893065dSJim Ingham self.build() 181893065dSJim Ingham self.main_source_file = lldb.SBFileSpec("main.c") 191893065dSJim Ingham self.thread_plan_test() 201893065dSJim Ingham 212238dcc3SJonas Devlieghere def check_list_output( 222238dcc3SJonas Devlieghere self, command, active_plans=[], completed_plans=[], discarded_plans=[] 232238dcc3SJonas Devlieghere ): 241893065dSJim Ingham # Check the "thread plan list" output against a list of active & completed and discarded plans. 251893065dSJim Ingham # If all three check arrays are empty, that means the command is expected to fail. 261893065dSJim Ingham 271893065dSJim Ingham interp = self.dbg.GetCommandInterpreter() 281893065dSJim Ingham result = lldb.SBCommandReturnObject() 291893065dSJim Ingham 301893065dSJim Ingham num_active = len(active_plans) 311893065dSJim Ingham num_completed = len(completed_plans) 321893065dSJim Ingham num_discarded = len(discarded_plans) 331893065dSJim Ingham 341893065dSJim Ingham interp.HandleCommand(command, result) 351893065dSJim Ingham print("Command: %s" % (command)) 361893065dSJim Ingham print(result.GetOutput()) 371893065dSJim Ingham 381893065dSJim Ingham if num_active == 0 and num_completed == 0 and num_discarded == 0: 392238dcc3SJonas Devlieghere self.assertFalse( 402238dcc3SJonas Devlieghere result.Succeeded(), 412238dcc3SJonas Devlieghere "command: '%s' succeeded when it should have failed: '%s'" 422238dcc3SJonas Devlieghere % (command, result.GetError()), 432238dcc3SJonas Devlieghere ) 441893065dSJim Ingham return 451893065dSJim Ingham 462238dcc3SJonas Devlieghere self.assertTrue( 472238dcc3SJonas Devlieghere result.Succeeded(), 482238dcc3SJonas Devlieghere "command: '%s' failed: '%s'" % (command, result.GetError()), 492238dcc3SJonas Devlieghere ) 501893065dSJim Ingham result_arr = result.GetOutput().splitlines() 511893065dSJim Ingham num_results = len(result_arr) 521893065dSJim Ingham 531893065dSJim Ingham # Now iterate through the results array and pick out the results. 541893065dSJim Ingham result_idx = 0 552238dcc3SJonas Devlieghere self.assertIn("thread #", result_arr[result_idx], "Found thread header") 562238dcc3SJonas Devlieghere result_idx += 1 572238dcc3SJonas Devlieghere self.assertIn( 582238dcc3SJonas Devlieghere "Active plan stack", result_arr[result_idx], "Found active header" 592238dcc3SJonas Devlieghere ) 602238dcc3SJonas Devlieghere result_idx += 1 612238dcc3SJonas Devlieghere self.assertIn( 622238dcc3SJonas Devlieghere "Element 0: Base thread plan", result_arr[result_idx], "Found base plan" 632238dcc3SJonas Devlieghere ) 642238dcc3SJonas Devlieghere result_idx += 1 651893065dSJim Ingham 661893065dSJim Ingham for text in active_plans: 672238dcc3SJonas Devlieghere self.assertIn( 682238dcc3SJonas Devlieghere text, result_arr[result_idx], "Didn't find active plan: %s" % (text) 692238dcc3SJonas Devlieghere ) 702238dcc3SJonas Devlieghere result_idx += 1 71aa4b37b2SJim Ingham 721893065dSJim Ingham if len(completed_plans) > 0: 73aa4b37b2SJim Ingham # First consume any remaining active plans: 74aa4b37b2SJim Ingham while not "Completed plan stack:" in result_arr[result_idx]: 75aa4b37b2SJim Ingham result_idx += 1 76aa4b37b2SJim Ingham if result_idx == num_results: 772238dcc3SJonas Devlieghere self.fail( 782238dcc3SJonas Devlieghere "There should have been completed plans, but I never saw the completed stack header" 792238dcc3SJonas Devlieghere ) 80aa4b37b2SJim Ingham # We are at the Completed header, skip it: 81aa4b37b2SJim Ingham result_idx += 1 821893065dSJim Ingham for text in completed_plans: 832238dcc3SJonas Devlieghere self.assertIn( 842238dcc3SJonas Devlieghere text, 852238dcc3SJonas Devlieghere result_arr[result_idx], 862238dcc3SJonas Devlieghere "Didn't find completed plan: %s" % (text), 872238dcc3SJonas Devlieghere ) 882238dcc3SJonas Devlieghere result_idx += 1 891893065dSJim Ingham 901893065dSJim Ingham if len(discarded_plans) > 0: 91aa4b37b2SJim Ingham # First consume any remaining completed plans: 92aa4b37b2SJim Ingham while not "Discarded plan stack:" in result_arr[result_idx]: 93aa4b37b2SJim Ingham result_idx += 1 94aa4b37b2SJim Ingham if result_idx == num_results: 952238dcc3SJonas Devlieghere self.fail( 962238dcc3SJonas Devlieghere "There should have been discarded plans, but I never saw the discarded stack header" 972238dcc3SJonas Devlieghere ) 98aa4b37b2SJim Ingham 99aa4b37b2SJim Ingham # We are at the Discarded header, skip it: 100aa4b37b2SJim Ingham result_idx += 1 1011893065dSJim Ingham for text in discarded_plans: 1022238dcc3SJonas Devlieghere self.assertIn( 1032238dcc3SJonas Devlieghere text, 1042238dcc3SJonas Devlieghere result_arr[result_idx], 1052238dcc3SJonas Devlieghere "Didn't find discarded plan: %s" % (text), 1062238dcc3SJonas Devlieghere ) 1072238dcc3SJonas Devlieghere result_idx += 1 1081893065dSJim Ingham 1091893065dSJim Ingham def thread_plan_test(self): 1102238dcc3SJonas Devlieghere (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 1112238dcc3SJonas Devlieghere self, "Set a breakpoint here", self.main_source_file 1122238dcc3SJonas Devlieghere ) 1131893065dSJim Ingham 114aa4b37b2SJim Ingham # We need to have an internal plan so we can test listing one. 115aa4b37b2SJim Ingham # The most consistent way to do that is to use a scripted thread plan 116aa4b37b2SJim Ingham # that uses a sub-plan. Source that in now. 117aa4b37b2SJim Ingham source_path = os.path.join(self.getSourceDir(), "wrap_step_over.py") 118aa4b37b2SJim Ingham self.runCmd("command script import '%s'" % (source_path)) 119aa4b37b2SJim Ingham 120aa4b37b2SJim Ingham # Now set a breakpoint that we will hit by running our scripted step. 1212238dcc3SJonas Devlieghere call_me_bkpt = target.BreakpointCreateBySourceRegex( 1222238dcc3SJonas Devlieghere "Set another here", self.main_source_file 1232238dcc3SJonas Devlieghere ) 124*9c246882SJordan Rupprecht self.assertGreater( 125*9c246882SJordan Rupprecht call_me_bkpt.GetNumLocations(), 0, "Set the breakpoint successfully" 1262238dcc3SJonas Devlieghere ) 127aa4b37b2SJim Ingham thread.StepUsingScriptedThreadPlan("wrap_step_over.WrapStepOver") 1281893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) 1291893065dSJim Ingham self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over") 1301893065dSJim Ingham 1311893065dSJim Ingham current_id = threads[0].GetIndexID() 1321893065dSJim Ingham current_tid = threads[0].GetThreadID() 1331893065dSJim Ingham # Run thread plan list without the -i flag: 1341893065dSJim Ingham command = "thread plan list %d" % (current_id) 135aa4b37b2SJim Ingham self.check_list_output(command, ["wrap_step_over.WrapStepOver"], []) 1361893065dSJim Ingham 1371893065dSJim Ingham # Run thread plan list with the -i flag: 1381893065dSJim Ingham command = "thread plan list -i %d" % (current_id) 139aa4b37b2SJim Ingham self.check_list_output(command, ["WrapStepOver", "Stepping over line main.c"]) 1401893065dSJim Ingham 1411893065dSJim Ingham # Run thread plan list providing TID, output should be the same: 1421893065dSJim Ingham command = "thread plan list -t %d" % (current_tid) 143aa4b37b2SJim Ingham self.check_list_output(command, ["wrap_step_over.WrapStepOver"]) 1441893065dSJim Ingham 1451893065dSJim Ingham # Provide both index & tid, and make sure we only print once: 1461893065dSJim Ingham command = "thread plan list -t %d %d" % (current_tid, current_id) 147aa4b37b2SJim Ingham self.check_list_output(command, ["wrap_step_over.WrapStepOver"]) 1481893065dSJim Ingham 1491893065dSJim Ingham # Try a fake TID, and make sure that fails: 1501893065dSJim Ingham fake_tid = 0 1511893065dSJim Ingham for i in range(100, 10000, 100): 1521893065dSJim Ingham fake_tid = current_tid + i 1531893065dSJim Ingham thread = process.GetThreadByID(fake_tid) 1541893065dSJim Ingham if not thread: 1551893065dSJim Ingham break 1561893065dSJim Ingham 1571893065dSJim Ingham command = "thread plan list -t %d" % (fake_tid) 1581893065dSJim Ingham self.check_list_output(command) 1591893065dSJim Ingham 1601893065dSJim Ingham # Now continue, and make sure we printed the completed plan: 1611893065dSJim Ingham process.Continue() 1621893065dSJim Ingham threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) 1631893065dSJim Ingham self.assertEqual(len(threads), 1, "One thread completed a step") 1641893065dSJim Ingham 1651893065dSJim Ingham # Run thread plan list - there aren't any private plans at this point: 1661893065dSJim Ingham command = "thread plan list %d" % (current_id) 167aa4b37b2SJim Ingham self.check_list_output(command, [], ["wrap_step_over.WrapStepOver"]) 1681893065dSJim Ingham 1691893065dSJim Ingham # Set another breakpoint that we can run to, to try deleting thread plans. 1702238dcc3SJonas Devlieghere second_step_bkpt = target.BreakpointCreateBySourceRegex( 1712238dcc3SJonas Devlieghere "Run here to step over again", self.main_source_file 1722238dcc3SJonas Devlieghere ) 173*9c246882SJordan Rupprecht self.assertGreater( 174*9c246882SJordan Rupprecht second_step_bkpt.GetNumLocations(), 0, "Set the breakpoint successfully" 1752238dcc3SJonas Devlieghere ) 1762238dcc3SJonas Devlieghere final_bkpt = target.BreakpointCreateBySourceRegex( 1772238dcc3SJonas Devlieghere "Make sure we get here on last continue", self.main_source_file 1782238dcc3SJonas Devlieghere ) 179*9c246882SJordan Rupprecht self.assertGreater( 180*9c246882SJordan Rupprecht final_bkpt.GetNumLocations(), 0, "Set the breakpoint successfully" 1812238dcc3SJonas Devlieghere ) 1821893065dSJim Ingham 1831893065dSJim Ingham threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt) 1841893065dSJim Ingham self.assertEqual(len(threads), 1, "Hit the second step breakpoint") 1851893065dSJim Ingham 1861893065dSJim Ingham threads[0].StepOver() 1871893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) 1881893065dSJim Ingham 1891893065dSJim Ingham result = lldb.SBCommandReturnObject() 1901893065dSJim Ingham interp = self.dbg.GetCommandInterpreter() 1911893065dSJim Ingham interp.HandleCommand("thread plan discard 1", result) 1922238dcc3SJonas Devlieghere self.assertTrue( 1932238dcc3SJonas Devlieghere result.Succeeded(), "Deleted the step over plan: %s" % (result.GetOutput()) 1942238dcc3SJonas Devlieghere ) 1951893065dSJim Ingham 1961893065dSJim Ingham # Make sure the plan gets listed in the discarded plans: 1971893065dSJim Ingham command = "thread plan list %d" % (current_id) 1981893065dSJim Ingham self.check_list_output(command, [], [], ["Stepping over line main.c:"]) 1991893065dSJim Ingham 2001893065dSJim Ingham process.Continue() 2011893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt) 2021893065dSJim Ingham self.assertEqual(len(threads), 1, "Ran to final breakpoint") 2031893065dSJim Ingham threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) 2041893065dSJim Ingham self.assertEqual(len(threads), 0, "Did NOT complete the step over plan") 205