xref: /llvm-project/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py (revision aa4b37b2acda8f0879ed5507e1a732c37e6ec5aa)
11893065dSJim Ingham"""
21893065dSJim InghamTest that thread plan listing, and deleting works.
31893065dSJim Ingham"""
41893065dSJim Ingham
51893065dSJim Ingham
61893065dSJim Ingham
71893065dSJim Inghamimport lldb
82d658c56SJim Inghamfrom lldbsuite.test.decorators import *
91893065dSJim Inghamimport lldbsuite.test.lldbutil as lldbutil
101893065dSJim Inghamfrom lldbsuite.test.lldbtest import *
111893065dSJim Ingham
121893065dSJim Ingham
131893065dSJim Inghamclass TestThreadPlanCommands(TestBase):
141893065dSJim Ingham
151893065dSJim Ingham    mydir = TestBase.compute_mydir(__file__)
161893065dSJim Ingham
171893065dSJim Ingham    NO_DEBUG_INFO_TESTCASE = True
181893065dSJim Ingham
192d658c56SJim Ingham    @skipIfWindows
204f644ff9SPavel Labath    @expectedFailureAll(oslist=["linux"], archs=["aarch64"])
211893065dSJim Ingham    def test_thread_plan_actions(self):
221893065dSJim Ingham        self.build()
231893065dSJim Ingham        self.main_source_file = lldb.SBFileSpec("main.c")
241893065dSJim Ingham        self.thread_plan_test()
251893065dSJim Ingham
261893065dSJim Ingham    def check_list_output(self, command, active_plans = [], completed_plans = [], discarded_plans = []):
271893065dSJim Ingham        # Check the "thread plan list" output against a list of active & completed and discarded plans.
281893065dSJim Ingham        # If all three check arrays are empty, that means the command is expected to fail.
291893065dSJim Ingham
301893065dSJim Ingham        interp = self.dbg.GetCommandInterpreter()
311893065dSJim Ingham        result = lldb.SBCommandReturnObject()
321893065dSJim Ingham
331893065dSJim Ingham        num_active = len(active_plans)
341893065dSJim Ingham        num_completed = len(completed_plans)
351893065dSJim Ingham        num_discarded = len(discarded_plans)
361893065dSJim Ingham
371893065dSJim Ingham        interp.HandleCommand(command, result)
381893065dSJim Ingham        print("Command: %s"%(command))
391893065dSJim Ingham        print(result.GetOutput())
401893065dSJim Ingham
411893065dSJim Ingham        if num_active == 0 and num_completed == 0 and num_discarded == 0:
421893065dSJim Ingham            self.assertFalse(result.Succeeded(), "command: '%s' succeeded when it should have failed: '%s'"%
431893065dSJim Ingham                             (command, result.GetError()))
441893065dSJim Ingham            return
451893065dSJim Ingham
461893065dSJim Ingham        self.assertTrue(result.Succeeded(), "command: '%s' failed: '%s'"%(command, result.GetError()))
471893065dSJim Ingham        result_arr = result.GetOutput().splitlines()
481893065dSJim Ingham        num_results = len(result_arr)
491893065dSJim Ingham
501893065dSJim Ingham        # Now iterate through the results array and pick out the results.
511893065dSJim Ingham        result_idx = 0
521893065dSJim Ingham        self.assertIn("thread #", result_arr[result_idx], "Found thread header") ; result_idx += 1
531893065dSJim Ingham        self.assertIn("Active plan stack", result_arr[result_idx], "Found active header") ; result_idx += 1
541893065dSJim Ingham        self.assertIn("Element 0: Base thread plan", result_arr[result_idx], "Found base plan") ; result_idx += 1
551893065dSJim Ingham
561893065dSJim Ingham        for text in active_plans:
571893065dSJim Ingham            self.assertIn(text, result_arr[result_idx], "Didn't find active plan: %s"%(text)) ; result_idx += 1
581893065dSJim Ingham
59*aa4b37b2SJim Ingham
601893065dSJim Ingham        if len(completed_plans) > 0:
61*aa4b37b2SJim Ingham            # First consume any remaining active plans:
62*aa4b37b2SJim Ingham            while not "Completed plan stack:" in result_arr[result_idx]:
63*aa4b37b2SJim Ingham                result_idx += 1
64*aa4b37b2SJim Ingham                if result_idx == num_results:
65*aa4b37b2SJim Ingham                    self.fail("There should have been completed plans, but I never saw the completed stack header")
66*aa4b37b2SJim Ingham            # We are at the Completed header, skip it:
67*aa4b37b2SJim Ingham            result_idx += 1
681893065dSJim Ingham            for text in completed_plans:
691893065dSJim Ingham                self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1
701893065dSJim Ingham
711893065dSJim Ingham        if len(discarded_plans) > 0:
72*aa4b37b2SJim Ingham            # First consume any remaining completed plans:
73*aa4b37b2SJim Ingham            while not "Discarded plan stack:" in result_arr[result_idx]:
74*aa4b37b2SJim Ingham                result_idx += 1
75*aa4b37b2SJim Ingham                if result_idx == num_results:
76*aa4b37b2SJim Ingham                    self.fail("There should have been discarded plans, but I never saw the discarded stack header")
77*aa4b37b2SJim Ingham
78*aa4b37b2SJim Ingham            # We are at the Discarded header, skip it:
79*aa4b37b2SJim Ingham            result_idx += 1
801893065dSJim Ingham            for text in discarded_plans:
81*aa4b37b2SJim Ingham                self.assertIn(text, result_arr[result_idx], "Didn't find discarded plan: %s"%(text)) ; result_idx += 1
821893065dSJim Ingham
831893065dSJim Ingham
841893065dSJim Ingham    def thread_plan_test(self):
851893065dSJim Ingham        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self,
861893065dSJim Ingham                                   "Set a breakpoint here", self.main_source_file)
871893065dSJim Ingham
88*aa4b37b2SJim Ingham        # We need to have an internal plan so we can test listing one.
89*aa4b37b2SJim Ingham        # The most consistent way to do that is to use a scripted thread plan
90*aa4b37b2SJim Ingham        # that uses a sub-plan.  Source that in now.
91*aa4b37b2SJim Ingham        source_path = os.path.join(self.getSourceDir(), "wrap_step_over.py")
92*aa4b37b2SJim Ingham        self.runCmd("command script import '%s'"%(source_path))
93*aa4b37b2SJim Ingham
94*aa4b37b2SJim Ingham        # Now set a breakpoint that we will hit by running our scripted step.
951893065dSJim Ingham        call_me_bkpt = target.BreakpointCreateBySourceRegex("Set another here", self.main_source_file)
961893065dSJim Ingham        self.assertTrue(call_me_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
97*aa4b37b2SJim Ingham        thread.StepUsingScriptedThreadPlan("wrap_step_over.WrapStepOver")
981893065dSJim Ingham        threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt)
991893065dSJim Ingham        self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over")
1001893065dSJim Ingham
1011893065dSJim Ingham        current_id = threads[0].GetIndexID()
1021893065dSJim Ingham        current_tid = threads[0].GetThreadID()
1031893065dSJim Ingham        # Run thread plan list without the -i flag:
1041893065dSJim Ingham        command = "thread plan list %d"%(current_id)
105*aa4b37b2SJim Ingham        self.check_list_output (command, ["wrap_step_over.WrapStepOver"], [])
1061893065dSJim Ingham
1071893065dSJim Ingham        # Run thread plan list with the -i flag:
1081893065dSJim Ingham        command = "thread plan list -i %d"%(current_id)
109*aa4b37b2SJim Ingham        self.check_list_output(command, ["WrapStepOver", "Stepping over line main.c"])
1101893065dSJim Ingham
1111893065dSJim Ingham        # Run thread plan list providing TID, output should be the same:
1121893065dSJim Ingham        command = "thread plan list -t %d"%(current_tid)
113*aa4b37b2SJim Ingham        self.check_list_output(command, ["wrap_step_over.WrapStepOver"])
1141893065dSJim Ingham
1151893065dSJim Ingham        # Provide both index & tid, and make sure we only print once:
1161893065dSJim Ingham        command = "thread plan list -t %d %d"%(current_tid, current_id)
117*aa4b37b2SJim Ingham        self.check_list_output(command, ["wrap_step_over.WrapStepOver"])
1181893065dSJim Ingham
1191893065dSJim Ingham        # Try a fake TID, and make sure that fails:
1201893065dSJim Ingham        fake_tid = 0
1211893065dSJim Ingham        for i in range(100, 10000, 100):
1221893065dSJim Ingham            fake_tid = current_tid + i
1231893065dSJim Ingham            thread = process.GetThreadByID(fake_tid)
1241893065dSJim Ingham            if not thread:
1251893065dSJim Ingham                break
1261893065dSJim Ingham
1271893065dSJim Ingham        command = "thread plan list -t %d"%(fake_tid)
1281893065dSJim Ingham        self.check_list_output(command)
1291893065dSJim Ingham
1301893065dSJim Ingham        # Now continue, and make sure we printed the completed plan:
1311893065dSJim Ingham        process.Continue()
1321893065dSJim Ingham        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
1331893065dSJim Ingham        self.assertEqual(len(threads), 1, "One thread completed a step")
1341893065dSJim Ingham
1351893065dSJim Ingham        # Run thread plan list - there aren't any private plans at this point:
1361893065dSJim Ingham        command = "thread plan list %d"%(current_id)
137*aa4b37b2SJim Ingham        self.check_list_output(command, [], ["wrap_step_over.WrapStepOver"])
1381893065dSJim Ingham
1391893065dSJim Ingham        # Set another breakpoint that we can run to, to try deleting thread plans.
1401893065dSJim Ingham        second_step_bkpt = target.BreakpointCreateBySourceRegex("Run here to step over again",
1411893065dSJim Ingham                                                                self.main_source_file)
1421893065dSJim Ingham        self.assertTrue(second_step_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
1431893065dSJim Ingham        final_bkpt = target.BreakpointCreateBySourceRegex("Make sure we get here on last continue",
1441893065dSJim Ingham                                                          self.main_source_file)
1451893065dSJim Ingham        self.assertTrue(final_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully")
1461893065dSJim Ingham
1471893065dSJim Ingham        threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt)
1481893065dSJim Ingham        self.assertEqual(len(threads), 1, "Hit the second step breakpoint")
1491893065dSJim Ingham
1501893065dSJim Ingham        threads[0].StepOver()
1511893065dSJim Ingham        threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt)
1521893065dSJim Ingham
1531893065dSJim Ingham        result = lldb.SBCommandReturnObject()
1541893065dSJim Ingham        interp = self.dbg.GetCommandInterpreter()
1551893065dSJim Ingham        interp.HandleCommand("thread plan discard 1", result)
1561893065dSJim Ingham        self.assertTrue(result.Succeeded(), "Deleted the step over plan: %s"%(result.GetOutput()))
1571893065dSJim Ingham
1581893065dSJim Ingham        # Make sure the plan gets listed in the discarded plans:
1591893065dSJim Ingham        command = "thread plan list %d"%(current_id)
1601893065dSJim Ingham        self.check_list_output(command, [], [], ["Stepping over line main.c:"])
1611893065dSJim Ingham
1621893065dSJim Ingham        process.Continue()
1631893065dSJim Ingham        threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt)
1641893065dSJim Ingham        self.assertEqual(len(threads), 1, "Ran to final breakpoint")
1651893065dSJim Ingham        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete)
1661893065dSJim Ingham        self.assertEqual(len(threads), 0, "Did NOT complete the step over plan")
1671893065dSJim Ingham
168