xref: /llvm-project/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py (revision 1893065d7bf5c41fbd0dbbee0a39933d3a99806b)
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