xref: /llvm-project/lldb/test/API/commands/thread/backtrace/TestThreadBacktraceRepeat.py (revision a4c18137d84bc48df49ee0101bef465a955e62ac)
1635f03feSJim Ingham"""
2635f03feSJim InghamTest that we page getting a long backtrace on more than one thread
3635f03feSJim Ingham"""
4635f03feSJim Ingham
5635f03feSJim Ingham
6635f03feSJim Inghamimport lldb
7635f03feSJim Inghamfrom lldbsuite.test.decorators import *
8635f03feSJim Inghamfrom lldbsuite.test.lldbtest import *
9635f03feSJim Inghamfrom lldbsuite.test import lldbutil
10635f03feSJim Ingham
11635f03feSJim Ingham
12635f03feSJim Inghamclass TestThreadBacktracePage(TestBase):
13635f03feSJim Ingham    NO_DEBUG_INFO_TESTCASE = True
14635f03feSJim Ingham
15635f03feSJim Ingham    def test_thread_backtrace_one_thread(self):
16635f03feSJim Ingham        """Run a simplified version of the test that just hits one breakpoint and
17635f03feSJim Ingham        doesn't care about synchronizing the two threads - hopefully this will
18635f03feSJim Ingham        run on more systems."""
19635f03feSJim Ingham        self.build()
20*2238dcc3SJonas Devlieghere        (
21*2238dcc3SJonas Devlieghere            self.inferior_target,
22*2238dcc3SJonas Devlieghere            self.process,
23*2238dcc3SJonas Devlieghere            thread,
24*2238dcc3SJonas Devlieghere            bkpt,
25*2238dcc3SJonas Devlieghere        ) = lldbutil.run_to_source_breakpoint(
26*2238dcc3SJonas Devlieghere            self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False
27*2238dcc3SJonas Devlieghere        )
28635f03feSJim Ingham
29635f03feSJim Ingham        # We hit the breakpoint on at least one thread.  If we hit it on both threads
30635f03feSJim Ingham        # simultaneously, we are ready to run our tests.  Otherwise, suspend the thread
31635f03feSJim Ingham        # that hit the breakpoint, and continue till the second thread hits
32635f03feSJim Ingham        # the breakpoint:
33635f03feSJim Ingham
34635f03feSJim Ingham        (breakpoint_threads, other_threads) = ([], [])
35*2238dcc3SJonas Devlieghere        lldbutil.sort_stopped_threads(
36*2238dcc3SJonas Devlieghere            self.process,
37635f03feSJim Ingham            breakpoint_threads=breakpoint_threads,
38*2238dcc3SJonas Devlieghere            other_threads=other_threads,
39*2238dcc3SJonas Devlieghere        )
40*2238dcc3SJonas Devlieghere        self.assertGreater(
41*2238dcc3SJonas Devlieghere            len(breakpoint_threads), 0, "We hit at least one breakpoint thread"
42*2238dcc3SJonas Devlieghere        )
43635f03feSJim Ingham        self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")
44635f03feSJim Ingham        thread_id = breakpoint_threads[0].idx
45635f03feSJim Ingham        name = breakpoint_threads[0].frame[1].name.split("(")[0]
46635f03feSJim Ingham        self.check_one_thread(thread_id, name)
47635f03feSJim Ingham
48635f03feSJim Ingham    def setUp(self):
49635f03feSJim Ingham        # Call super's setUp().
50635f03feSJim Ingham        TestBase.setUp(self)
51635f03feSJim Ingham        # Find the line number for our breakpoint.
52*2238dcc3SJonas Devlieghere        self.bkpt_string = "// Set breakpoint here"
53635f03feSJim Ingham
54635f03feSJim Ingham    def check_one_thread(self, thread_id, func_name):
55635f03feSJim Ingham        # Now issue some thread backtrace commands and make sure they
56635f03feSJim Ingham        # get the right answer back.
57635f03feSJim Ingham        interp = self.dbg.GetCommandInterpreter()
58635f03feSJim Ingham        result = lldb.SBCommandReturnObject()
59635f03feSJim Ingham
60635f03feSJim Ingham        # Run the real backtrace, remember to pass True for add_to_history since
61635f03feSJim Ingham        # we don't generate repeat commands for commands that aren't going into the history.
62*2238dcc3SJonas Devlieghere        interp.HandleCommand(
63*2238dcc3SJonas Devlieghere            "thread backtrace --count 10 {0}".format(thread_id), result, True
64*2238dcc3SJonas Devlieghere        )
65635f03feSJim Ingham        self.assertTrue(result.Succeeded(), "bt with count succeeded")
66635f03feSJim Ingham        # There should be 11 lines:
67635f03feSJim Ingham        lines = result.GetOutput().splitlines()
68635f03feSJim Ingham        self.assertEqual(len(lines), 11, "Got the right number of lines")
69635f03feSJim Ingham        # First frame is stop_here:
70635f03feSJim Ingham        self.assertNotEqual(lines[1].find("stop_here"), -1, "Found Stop Here")
71635f03feSJim Ingham        for line in lines[2:10]:
72*2238dcc3SJonas Devlieghere            self.assertNotEqual(
73*2238dcc3SJonas Devlieghere                line.find(func_name),
74*2238dcc3SJonas Devlieghere                -1,
75*2238dcc3SJonas Devlieghere                "Name {0} not found in line: {1}".format(func_name, line),
76*2238dcc3SJonas Devlieghere            )
77635f03feSJim Ingham        # The last entry should be 43:
78635f03feSJim Ingham        self.assertNotEqual(lines[10].find("count=43"), -1, "First show ends at 43")
79635f03feSJim Ingham
80635f03feSJim Ingham        # Now try a repeat, and make sure we get 10 more on this thread:
81635f03feSJim Ingham        # import pdb; pdb.set_trace()
82635f03feSJim Ingham        interp.HandleCommand("", result, True)
83*2238dcc3SJonas Devlieghere        self.assertTrue(
84*2238dcc3SJonas Devlieghere            result.Succeeded(), "repeat command failed: {0}".format(result.GetError())
85*2238dcc3SJonas Devlieghere        )
86635f03feSJim Ingham        lines = result.GetOutput().splitlines()
87635f03feSJim Ingham        self.assertEqual(len(lines), 11, "Repeat got 11 lines")
88635f03feSJim Ingham        # Every line should now be the recurse function:
89635f03feSJim Ingham        for line in lines[1:10]:
90635f03feSJim Ingham            self.assertNotEqual(line.find(func_name), -1, "Name in every line")
91635f03feSJim Ingham        self.assertNotEqual(lines[10].find("count=33"), -1, "Last one is now 33")
92635f03feSJim Ingham
93*2238dcc3SJonas Devlieghere    def check_two_threads(
94*2238dcc3SJonas Devlieghere        self, result_str, thread_id_1, name_1, thread_id_2, name_2, start_idx, end_idx
95*2238dcc3SJonas Devlieghere    ):
96635f03feSJim Ingham        # We should have 2 occurrences ot the thread header:
97*2238dcc3SJonas Devlieghere        self.assertEqual(
98*2238dcc3SJonas Devlieghere            result_str.count("thread #{0}".format(thread_id_1)), 1, "One for thread 1"
99*2238dcc3SJonas Devlieghere        )
100*2238dcc3SJonas Devlieghere        self.assertEqual(
101*2238dcc3SJonas Devlieghere            result_str.count("thread #{0}".format(thread_id_2)), 1, "One for thread 2"
102*2238dcc3SJonas Devlieghere        )
103635f03feSJim Ingham        # We should have 10 occurrences of each name:
104635f03feSJim Ingham        self.assertEqual(result_str.count(name_1), 10, "Found 10 of {0}".format(name_1))
105635f03feSJim Ingham        self.assertEqual(result_str.count(name_2), 10, "Found 10 of {0}".format(name_1))
106635f03feSJim Ingham        # There should be two instances of count=<start_idx> and none of count=<start-1>:
107*2238dcc3SJonas Devlieghere        self.assertEqual(
108*2238dcc3SJonas Devlieghere            result_str.count("count={0}".format(start_idx)),
109*2238dcc3SJonas Devlieghere            2,
110*2238dcc3SJonas Devlieghere            "Two instances of start_idx",
111*2238dcc3SJonas Devlieghere        )
112*2238dcc3SJonas Devlieghere        self.assertEqual(
113*2238dcc3SJonas Devlieghere            result_str.count("count={0}".format(start_idx - 1)),
114*2238dcc3SJonas Devlieghere            0,
115*2238dcc3SJonas Devlieghere            "No instances of start_idx - 1",
116*2238dcc3SJonas Devlieghere        )
117635f03feSJim Ingham        # There should be two instances of count=<end_idx> and none of count=<end_idx+1>:
118*2238dcc3SJonas Devlieghere        self.assertEqual(
119*2238dcc3SJonas Devlieghere            result_str.count("count={0}".format(end_idx)), 2, "Two instances of end_idx"
120*2238dcc3SJonas Devlieghere        )
121*2238dcc3SJonas Devlieghere        self.assertEqual(
122*2238dcc3SJonas Devlieghere            result_str.count("count={0}".format(end_idx + 1)),
123*2238dcc3SJonas Devlieghere            0,
124*2238dcc3SJonas Devlieghere            "No instances after end idx",
125*2238dcc3SJonas Devlieghere        )
126635f03feSJim Ingham
127635f03feSJim Ingham    # The setup of this test was copied from the step-out test, and I can't tell from
128635f03feSJim Ingham    # the comments whether it was getting two threads to the same breakpoint that was
129635f03feSJim Ingham    # problematic, or the step-out part.  This test stops at the rendevous point so I'm
130635f03feSJim Ingham    # removing the skipIfLinux to see if we see any flakiness in just this part of the test.
131635f03feSJim Ingham    @skipIfWindows  # This test will hang on windows llvm.org/pr21753
132635f03feSJim Ingham    @expectedFailureAll(oslist=["windows"])
133635f03feSJim Ingham    @expectedFailureNetBSD
134635f03feSJim Ingham    def test_thread_backtrace_two_threads(self):
135635f03feSJim Ingham        """Test that repeat works even when backtracing on more than one thread."""
136635f03feSJim Ingham        self.build()
137*2238dcc3SJonas Devlieghere        (
138*2238dcc3SJonas Devlieghere            self.inferior_target,
139*2238dcc3SJonas Devlieghere            self.process,
140*2238dcc3SJonas Devlieghere            thread,
141*2238dcc3SJonas Devlieghere            bkpt,
142*2238dcc3SJonas Devlieghere        ) = lldbutil.run_to_source_breakpoint(
143*2238dcc3SJonas Devlieghere            self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False
144*2238dcc3SJonas Devlieghere        )
145635f03feSJim Ingham
146635f03feSJim Ingham        # We hit the breakpoint on at least one thread.  If we hit it on both threads
147635f03feSJim Ingham        # simultaneously, we are ready to run our tests.  Otherwise, suspend the thread
148635f03feSJim Ingham        # that hit the breakpoint, and continue till the second thread hits
149635f03feSJim Ingham        # the breakpoint:
150635f03feSJim Ingham
151635f03feSJim Ingham        (breakpoint_threads, other_threads) = ([], [])
152*2238dcc3SJonas Devlieghere        lldbutil.sort_stopped_threads(
153*2238dcc3SJonas Devlieghere            self.process,
154635f03feSJim Ingham            breakpoint_threads=breakpoint_threads,
155*2238dcc3SJonas Devlieghere            other_threads=other_threads,
156*2238dcc3SJonas Devlieghere        )
157635f03feSJim Ingham        if len(breakpoint_threads) == 1:
158635f03feSJim Ingham            success = thread.Suspend()
159635f03feSJim Ingham            self.assertTrue(success, "Couldn't suspend a thread")
160*2238dcc3SJonas Devlieghere            breakpoint_threads = lldbutil.continue_to_breakpoint(self.process, bkpt)
161f8d42c55SPavel Labath            self.assertEqual(len(breakpoint_threads), 2, "Second thread stopped")
162635f03feSJim Ingham
163635f03feSJim Ingham        # Figure out which thread is which:
164635f03feSJim Ingham        thread_id_1 = breakpoint_threads[0].idx
165635f03feSJim Ingham        self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")
166635f03feSJim Ingham        name_1 = breakpoint_threads[0].frame[1].name.split("(")[0]
167635f03feSJim Ingham
168635f03feSJim Ingham        thread_id_2 = breakpoint_threads[1].idx
169635f03feSJim Ingham        self.assertGreater(len(breakpoint_threads[1].frames), 2, "I can go up")
170635f03feSJim Ingham        name_2 = breakpoint_threads[1].frame[1].name.split("(")[0]
171635f03feSJim Ingham
172635f03feSJim Ingham        # Check that backtrace and repeat works on one thread, then works on the second
173635f03feSJim Ingham        # when we switch to it:
174635f03feSJim Ingham        self.check_one_thread(thread_id_1, name_1)
175635f03feSJim Ingham        self.check_one_thread(thread_id_2, name_2)
176635f03feSJim Ingham
177635f03feSJim Ingham        # The output is looking right at this point, let's just do a couple more quick checks
178635f03feSJim Ingham        # to see we handle two threads and a start count:
179635f03feSJim Ingham        interp = self.dbg.GetCommandInterpreter()
180635f03feSJim Ingham        result = lldb.SBCommandReturnObject()
181635f03feSJim Ingham
182*2238dcc3SJonas Devlieghere        interp.HandleCommand(
183*2238dcc3SJonas Devlieghere            "thread backtrace --count 10 --start 10 {0} {1}".format(
184*2238dcc3SJonas Devlieghere                thread_id_1, thread_id_2
185*2238dcc3SJonas Devlieghere            ),
186*2238dcc3SJonas Devlieghere            result,
187*2238dcc3SJonas Devlieghere            True,
188*2238dcc3SJonas Devlieghere        )
189635f03feSJim Ingham        self.assertTrue(result.Succeeded(), "command succeeded for two threads")
190635f03feSJim Ingham
191635f03feSJim Ingham        result.Clear()
192635f03feSJim Ingham        interp.HandleCommand("", result, True)
193635f03feSJim Ingham        self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")
194635f03feSJim Ingham        result_str = result.GetOutput()
195*2238dcc3SJonas Devlieghere        self.check_two_threads(
196*2238dcc3SJonas Devlieghere            result_str, thread_id_1, name_1, thread_id_2, name_2, 23, 32
197*2238dcc3SJonas Devlieghere        )
198635f03feSJim Ingham
199635f03feSJim Ingham        # Finally make sure the repeat repeats:
200635f03feSJim Ingham        result.Clear()
201635f03feSJim Ingham        interp.HandleCommand("", result, True)
202635f03feSJim Ingham        self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")
203635f03feSJim Ingham        result_str = result.GetOutput()
204*2238dcc3SJonas Devlieghere        self.check_two_threads(
205*2238dcc3SJonas Devlieghere            result_str, thread_id_1, name_1, thread_id_2, name_2, 13, 22
206*2238dcc3SJonas Devlieghere        )
207