1*1893065dSJim Ingham""" 2*1893065dSJim InghamTest that thread plan listing, and deleting works. 3*1893065dSJim Ingham""" 4*1893065dSJim Ingham 5*1893065dSJim Ingham 6*1893065dSJim Ingham 7*1893065dSJim Inghamimport lldb 8*1893065dSJim Inghamimport lldbsuite.test.lldbutil as lldbutil 9*1893065dSJim Inghamfrom lldbsuite.test.lldbtest import * 10*1893065dSJim Ingham 11*1893065dSJim Ingham 12*1893065dSJim Inghamclass TestThreadPlanCommands(TestBase): 13*1893065dSJim Ingham 14*1893065dSJim Ingham mydir = TestBase.compute_mydir(__file__) 15*1893065dSJim Ingham 16*1893065dSJim Ingham NO_DEBUG_INFO_TESTCASE = True 17*1893065dSJim Ingham 18*1893065dSJim Ingham def test_thread_plan_actions(self): 19*1893065dSJim Ingham self.build() 20*1893065dSJim Ingham self.main_source_file = lldb.SBFileSpec("main.c") 21*1893065dSJim Ingham self.thread_plan_test() 22*1893065dSJim Ingham 23*1893065dSJim Ingham def check_list_output(self, command, active_plans = [], completed_plans = [], discarded_plans = []): 24*1893065dSJim Ingham # Check the "thread plan list" output against a list of active & completed and discarded plans. 25*1893065dSJim Ingham # If all three check arrays are empty, that means the command is expected to fail. 26*1893065dSJim Ingham 27*1893065dSJim Ingham interp = self.dbg.GetCommandInterpreter() 28*1893065dSJim Ingham result = lldb.SBCommandReturnObject() 29*1893065dSJim Ingham 30*1893065dSJim Ingham num_active = len(active_plans) 31*1893065dSJim Ingham num_completed = len(completed_plans) 32*1893065dSJim Ingham num_discarded = len(discarded_plans) 33*1893065dSJim Ingham 34*1893065dSJim Ingham interp.HandleCommand(command, result) 35*1893065dSJim Ingham if self.TraceOn(): 36*1893065dSJim Ingham print("Command: %s"%(command)) 37*1893065dSJim Ingham print(result.GetOutput()) 38*1893065dSJim Ingham 39*1893065dSJim Ingham if num_active == 0 and num_completed == 0 and num_discarded == 0: 40*1893065dSJim Ingham self.assertFalse(result.Succeeded(), "command: '%s' succeeded when it should have failed: '%s'"% 41*1893065dSJim Ingham (command, result.GetError())) 42*1893065dSJim Ingham return 43*1893065dSJim Ingham 44*1893065dSJim Ingham self.assertTrue(result.Succeeded(), "command: '%s' failed: '%s'"%(command, result.GetError())) 45*1893065dSJim Ingham result_arr = result.GetOutput().splitlines() 46*1893065dSJim Ingham num_results = len(result_arr) 47*1893065dSJim Ingham 48*1893065dSJim Ingham # Match the expected number of elements. 49*1893065dSJim Ingham # Adjust the count for the number of header lines we aren't matching: 50*1893065dSJim Ingham fudge = 0 51*1893065dSJim Ingham 52*1893065dSJim Ingham if num_completed == 0 and num_discarded == 0: 53*1893065dSJim Ingham # The fudge is 3: Thread header, Active Plan header and base plan 54*1893065dSJim Ingham fudge = 3 55*1893065dSJim Ingham elif num_completed == 0 or num_discarded == 0: 56*1893065dSJim Ingham # The fudge is 4: The above plus either the Completed or Discarded Plan header: 57*1893065dSJim Ingham fudge = 4 58*1893065dSJim Ingham else: 59*1893065dSJim Ingham # The fudge is 5 since we have both headers: 60*1893065dSJim Ingham fudge = 5 61*1893065dSJim Ingham 62*1893065dSJim Ingham self.assertEqual(num_results, num_active + num_completed + num_discarded + fudge, 63*1893065dSJim Ingham "Too many elements in match arrays") 64*1893065dSJim Ingham 65*1893065dSJim Ingham # Now iterate through the results array and pick out the results. 66*1893065dSJim Ingham result_idx = 0 67*1893065dSJim Ingham self.assertIn("thread #", result_arr[result_idx], "Found thread header") ; result_idx += 1 68*1893065dSJim Ingham self.assertIn("Active plan stack", result_arr[result_idx], "Found active header") ; result_idx += 1 69*1893065dSJim Ingham self.assertIn("Element 0: Base thread plan", result_arr[result_idx], "Found base plan") ; result_idx += 1 70*1893065dSJim Ingham 71*1893065dSJim Ingham for text in active_plans: 72*1893065dSJim Ingham self.assertFalse("Completed plan stack" in result_arr[result_idx], "Found Completed header too early.") 73*1893065dSJim Ingham self.assertIn(text, result_arr[result_idx], "Didn't find active plan: %s"%(text)) ; result_idx += 1 74*1893065dSJim Ingham 75*1893065dSJim Ingham if len(completed_plans) > 0: 76*1893065dSJim Ingham self.assertIn("Completed plan stack:", result_arr[result_idx], "Found completed plan stack header") ; result_idx += 1 77*1893065dSJim Ingham for text in completed_plans: 78*1893065dSJim Ingham self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 79*1893065dSJim Ingham 80*1893065dSJim Ingham if len(discarded_plans) > 0: 81*1893065dSJim Ingham self.assertIn("Discarded plan stack:", result_arr[result_idx], "Found discarded plan stack header") ; result_idx += 1 82*1893065dSJim Ingham for text in discarded_plans: 83*1893065dSJim Ingham self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 84*1893065dSJim Ingham 85*1893065dSJim Ingham 86*1893065dSJim Ingham def thread_plan_test(self): 87*1893065dSJim Ingham (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, 88*1893065dSJim Ingham "Set a breakpoint here", self.main_source_file) 89*1893065dSJim Ingham 90*1893065dSJim Ingham # Now set a breakpoint in call_me and step over. We should have 91*1893065dSJim Ingham # two public thread plans 92*1893065dSJim Ingham call_me_bkpt = target.BreakpointCreateBySourceRegex("Set another here", self.main_source_file) 93*1893065dSJim Ingham self.assertTrue(call_me_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") 94*1893065dSJim Ingham thread.StepOver() 95*1893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) 96*1893065dSJim Ingham self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over") 97*1893065dSJim Ingham 98*1893065dSJim Ingham current_id = threads[0].GetIndexID() 99*1893065dSJim Ingham current_tid = threads[0].GetThreadID() 100*1893065dSJim Ingham # Run thread plan list without the -i flag: 101*1893065dSJim Ingham command = "thread plan list %d"%(current_id) 102*1893065dSJim Ingham self.check_list_output (command, ["Stepping over line main.c"], []) 103*1893065dSJim Ingham 104*1893065dSJim Ingham # Run thread plan list with the -i flag: 105*1893065dSJim Ingham command = "thread plan list -i %d"%(current_id) 106*1893065dSJim Ingham self.check_list_output(command, ["Stepping over line main.c", "Stepping out from"]) 107*1893065dSJim Ingham 108*1893065dSJim Ingham # Run thread plan list providing TID, output should be the same: 109*1893065dSJim Ingham command = "thread plan list -t %d"%(current_tid) 110*1893065dSJim Ingham self.check_list_output(command, ["Stepping over line main.c"]) 111*1893065dSJim Ingham 112*1893065dSJim Ingham # Provide both index & tid, and make sure we only print once: 113*1893065dSJim Ingham command = "thread plan list -t %d %d"%(current_tid, current_id) 114*1893065dSJim Ingham self.check_list_output(command, ["Stepping over line main.c"]) 115*1893065dSJim Ingham 116*1893065dSJim Ingham # Try a fake TID, and make sure that fails: 117*1893065dSJim Ingham fake_tid = 0 118*1893065dSJim Ingham for i in range(100, 10000, 100): 119*1893065dSJim Ingham fake_tid = current_tid + i 120*1893065dSJim Ingham thread = process.GetThreadByID(fake_tid) 121*1893065dSJim Ingham if not thread: 122*1893065dSJim Ingham break 123*1893065dSJim Ingham 124*1893065dSJim Ingham command = "thread plan list -t %d"%(fake_tid) 125*1893065dSJim Ingham self.check_list_output(command) 126*1893065dSJim Ingham 127*1893065dSJim Ingham # Now continue, and make sure we printed the completed plan: 128*1893065dSJim Ingham process.Continue() 129*1893065dSJim Ingham threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) 130*1893065dSJim Ingham self.assertEqual(len(threads), 1, "One thread completed a step") 131*1893065dSJim Ingham 132*1893065dSJim Ingham # Run thread plan list - there aren't any private plans at this point: 133*1893065dSJim Ingham command = "thread plan list %d"%(current_id) 134*1893065dSJim Ingham self.check_list_output(command, [], ["Stepping over line main.c"]) 135*1893065dSJim Ingham 136*1893065dSJim Ingham # Set another breakpoint that we can run to, to try deleting thread plans. 137*1893065dSJim Ingham second_step_bkpt = target.BreakpointCreateBySourceRegex("Run here to step over again", 138*1893065dSJim Ingham self.main_source_file) 139*1893065dSJim Ingham self.assertTrue(second_step_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") 140*1893065dSJim Ingham final_bkpt = target.BreakpointCreateBySourceRegex("Make sure we get here on last continue", 141*1893065dSJim Ingham self.main_source_file) 142*1893065dSJim Ingham self.assertTrue(final_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") 143*1893065dSJim Ingham 144*1893065dSJim Ingham threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt) 145*1893065dSJim Ingham self.assertEqual(len(threads), 1, "Hit the second step breakpoint") 146*1893065dSJim Ingham 147*1893065dSJim Ingham threads[0].StepOver() 148*1893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) 149*1893065dSJim Ingham 150*1893065dSJim Ingham result = lldb.SBCommandReturnObject() 151*1893065dSJim Ingham interp = self.dbg.GetCommandInterpreter() 152*1893065dSJim Ingham interp.HandleCommand("thread plan discard 1", result) 153*1893065dSJim Ingham self.assertTrue(result.Succeeded(), "Deleted the step over plan: %s"%(result.GetOutput())) 154*1893065dSJim Ingham 155*1893065dSJim Ingham # Make sure the plan gets listed in the discarded plans: 156*1893065dSJim Ingham command = "thread plan list %d"%(current_id) 157*1893065dSJim Ingham self.check_list_output(command, [], [], ["Stepping over line main.c:"]) 158*1893065dSJim Ingham 159*1893065dSJim Ingham process.Continue() 160*1893065dSJim Ingham threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt) 161*1893065dSJim Ingham self.assertEqual(len(threads), 1, "Ran to final breakpoint") 162*1893065dSJim Ingham threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) 163*1893065dSJim Ingham self.assertEqual(len(threads), 0, "Did NOT complete the step over plan") 164*1893065dSJim Ingham 165