File: TestThreadBacktraceRepeat.py

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (208 lines) | stat: -rw-r--r-- 8,783 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
"""
Test that we page getting a long backtrace on more than one thread
"""


import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class TestThreadBacktracePage(TestBase):
    NO_DEBUG_INFO_TESTCASE = True

    def test_thread_backtrace_one_thread(self):
        """Run a simplified version of the test that just hits one breakpoint and
        doesn't care about synchronizing the two threads - hopefully this will
        run on more systems."""

    def test_thread_backtrace_one_thread(self):
        self.build()
        (
            self.inferior_target,
            self.process,
            thread,
            bkpt,
        ) = lldbutil.run_to_source_breakpoint(
            self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False
        )

        # We hit the breakpoint on at least one thread.  If we hit it on both threads
        # simultaneously, we are ready to run our tests.  Otherwise, suspend the thread
        # that hit the breakpoint, and continue till the second thread hits
        # the breakpoint:

        (breakpoint_threads, other_threads) = ([], [])
        lldbutil.sort_stopped_threads(
            self.process,
            breakpoint_threads=breakpoint_threads,
            other_threads=other_threads,
        )
        self.assertGreater(
            len(breakpoint_threads), 0, "We hit at least one breakpoint thread"
        )
        self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")
        thread_id = breakpoint_threads[0].idx
        name = breakpoint_threads[0].frame[1].name.split("(")[0]
        self.check_one_thread(thread_id, name)

    def setUp(self):
        # Call super's setUp().
        TestBase.setUp(self)
        # Find the line number for our breakpoint.
        self.bkpt_string = "// Set breakpoint here"

    def check_one_thread(self, thread_id, func_name):
        # Now issue some thread backtrace commands and make sure they
        # get the right answer back.
        interp = self.dbg.GetCommandInterpreter()
        result = lldb.SBCommandReturnObject()

        # Run the real backtrace, remember to pass True for add_to_history since
        # we don't generate repeat commands for commands that aren't going into the history.
        interp.HandleCommand(
            "thread backtrace --count 10 {0}".format(thread_id), result, True
        )
        self.assertTrue(result.Succeeded(), "bt with count succeeded")
        # There should be 11 lines:
        lines = result.GetOutput().splitlines()
        self.assertEqual(len(lines), 11, "Got the right number of lines")
        # First frame is stop_here:
        self.assertNotEqual(lines[1].find("stop_here"), -1, "Found Stop Here")
        for line in lines[2:10]:
            self.assertNotEqual(
                line.find(func_name),
                -1,
                "Name {0} not found in line: {1}".format(func_name, line),
            )
        # The last entry should be 43:
        self.assertNotEqual(lines[10].find("count=43"), -1, "First show ends at 43")

        # Now try a repeat, and make sure we get 10 more on this thread:
        # import pdb; pdb.set_trace()
        interp.HandleCommand("", result, True)
        self.assertTrue(
            result.Succeeded(), "repeat command failed: {0}".format(result.GetError())
        )
        lines = result.GetOutput().splitlines()
        self.assertEqual(len(lines), 11, "Repeat got 11 lines")
        # Every line should now be the recurse function:
        for line in lines[1:10]:
            self.assertNotEqual(line.find(func_name), -1, "Name in every line")
        self.assertNotEqual(lines[10].find("count=33"), -1, "Last one is now 33")

    def check_two_threads(
        self, result_str, thread_id_1, name_1, thread_id_2, name_2, start_idx, end_idx
    ):
        # We should have 2 occurrences ot the thread header:
        self.assertEqual(
            result_str.count("thread #{0}".format(thread_id_1)), 1, "One for thread 1"
        )
        self.assertEqual(
            result_str.count("thread #{0}".format(thread_id_2)), 1, "One for thread 2"
        )
        # We should have 10 occurrences of each name:
        self.assertEqual(result_str.count(name_1), 10, "Found 10 of {0}".format(name_1))
        self.assertEqual(result_str.count(name_2), 10, "Found 10 of {0}".format(name_1))
        # There should be two instances of count=<start_idx> and none of count=<start-1>:
        self.assertEqual(
            result_str.count("count={0}".format(start_idx)),
            2,
            "Two instances of start_idx",
        )
        self.assertEqual(
            result_str.count("count={0}".format(start_idx - 1)),
            0,
            "No instances of start_idx - 1",
        )
        # There should be two instances of count=<end_idx> and none of count=<end_idx+1>:
        self.assertEqual(
            result_str.count("count={0}".format(end_idx)), 2, "Two instances of end_idx"
        )
        self.assertEqual(
            result_str.count("count={0}".format(end_idx + 1)),
            0,
            "No instances after end idx",
        )

    # The setup of this test was copied from the step-out test, and I can't tell from
    # the comments whether it was getting two threads to the same breakpoint that was
    # problematic, or the step-out part.  This test stops at the rendevous point so I'm
    # removing the skipIfLinux to see if we see any flakiness in just this part of the test.
    @skipIfWindows  # This test will hang on windows llvm.org/pr21753
    @expectedFailureAll(oslist=["windows"])
    @expectedFailureNetBSD
    def test_thread_backtrace_two_threads(self):
        """Test that repeat works even when backtracing on more than one thread."""
        self.build()
        (
            self.inferior_target,
            self.process,
            thread,
            bkpt,
        ) = lldbutil.run_to_source_breakpoint(
            self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False
        )

        # We hit the breakpoint on at least one thread.  If we hit it on both threads
        # simultaneously, we are ready to run our tests.  Otherwise, suspend the thread
        # that hit the breakpoint, and continue till the second thread hits
        # the breakpoint:

        (breakpoint_threads, other_threads) = ([], [])
        lldbutil.sort_stopped_threads(
            self.process,
            breakpoint_threads=breakpoint_threads,
            other_threads=other_threads,
        )
        if len(breakpoint_threads) == 1:
            success = thread.Suspend()
            self.assertTrue(success, "Couldn't suspend a thread")
            breakpoint_threads = lldbutil.continue_to_breakpoint(self.process, bkpt)
            self.assertEqual(len(breakpoint_threads), 2, "Second thread stopped")

        # Figure out which thread is which:
        thread_id_1 = breakpoint_threads[0].idx
        self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")
        name_1 = breakpoint_threads[0].frame[1].name.split("(")[0]

        thread_id_2 = breakpoint_threads[1].idx
        self.assertGreater(len(breakpoint_threads[1].frames), 2, "I can go up")
        name_2 = breakpoint_threads[1].frame[1].name.split("(")[0]

        # Check that backtrace and repeat works on one thread, then works on the second
        # when we switch to it:
        self.check_one_thread(thread_id_1, name_1)
        self.check_one_thread(thread_id_2, name_2)

        # The output is looking right at this point, let's just do a couple more quick checks
        # to see we handle two threads and a start count:
        interp = self.dbg.GetCommandInterpreter()
        result = lldb.SBCommandReturnObject()

        interp.HandleCommand(
            "thread backtrace --count 10 --start 10 {0} {1}".format(
                thread_id_1, thread_id_2
            ),
            result,
            True,
        )
        self.assertTrue(result.Succeeded(), "command succeeded for two threads")

        result.Clear()
        interp.HandleCommand("", result, True)
        self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")
        result_str = result.GetOutput()
        self.check_two_threads(
            result_str, thread_id_1, name_1, thread_id_2, name_2, 23, 32
        )

        # Finally make sure the repeat repeats:
        result.Clear()
        interp.HandleCommand("", result, True)
        self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")
        result_str = result.GetOutput()
        self.check_two_threads(
            result_str, thread_id_1, name_1, thread_id_2, name_2, 13, 22
        )