207 lines · python
1"""2Test that we page getting a long backtrace on more than one thread3"""4 5 6import lldb7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10 11 12class TestThreadBacktracePage(TestBase):13 NO_DEBUG_INFO_TESTCASE = True14 15 def test_thread_backtrace_one_thread(self):16 """Run a simplified version of the test that just hits one breakpoint and17 doesn't care about synchronizing the two threads - hopefully this will18 run on more systems."""19 self.build()20 (21 self.inferior_target,22 self.process,23 thread,24 bkpt,25 ) = lldbutil.run_to_source_breakpoint(26 self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False27 )28 29 # We hit the breakpoint on at least one thread. If we hit it on both threads30 # simultaneously, we are ready to run our tests. Otherwise, suspend the thread31 # that hit the breakpoint, and continue till the second thread hits32 # the breakpoint:33 34 (breakpoint_threads, other_threads) = ([], [])35 lldbutil.sort_stopped_threads(36 self.process,37 breakpoint_threads=breakpoint_threads,38 other_threads=other_threads,39 )40 self.assertGreater(41 len(breakpoint_threads), 0, "We hit at least one breakpoint thread"42 )43 self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")44 thread_id = breakpoint_threads[0].idx45 name = breakpoint_threads[0].frame[1].name.split("(")[0]46 self.check_one_thread(thread_id, name)47 48 def setUp(self):49 # Call super's setUp().50 TestBase.setUp(self)51 # Find the line number for our breakpoint.52 self.bkpt_string = "// Set breakpoint here"53 54 def check_one_thread(self, thread_id, func_name):55 # Now issue some thread backtrace commands and make sure they56 # get the right answer back.57 interp = self.dbg.GetCommandInterpreter()58 result = lldb.SBCommandReturnObject()59 60 # Run the real backtrace, remember to pass True for add_to_history since61 # we don't generate repeat commands for commands that aren't going into the history.62 interp.HandleCommand(63 "thread backtrace --count 10 {0}".format(thread_id), result, True64 )65 self.assertTrue(result.Succeeded(), "bt with count succeeded")66 # There should be 11 lines:67 lines = result.GetOutput().splitlines()68 self.assertEqual(len(lines), 11, "Got the right number of lines")69 # First frame is stop_here:70 self.assertNotEqual(lines[1].find("stop_here"), -1, "Found Stop Here")71 for line in lines[2:10]:72 self.assertNotEqual(73 line.find(func_name),74 -1,75 "Name {0} not found in line: {1}".format(func_name, line),76 )77 # The last entry should be 43:78 self.assertNotEqual(lines[10].find("count=43"), -1, "First show ends at 43")79 80 # Now try a repeat, and make sure we get 10 more on this thread:81 # import pdb; pdb.set_trace()82 interp.HandleCommand("", result, True)83 self.assertTrue(84 result.Succeeded(), "repeat command failed: {0}".format(result.GetError())85 )86 lines = result.GetOutput().splitlines()87 self.assertEqual(len(lines), 11, "Repeat got 11 lines")88 # Every line should now be the recurse function:89 for line in lines[1:10]:90 self.assertNotEqual(line.find(func_name), -1, "Name in every line")91 self.assertNotEqual(lines[10].find("count=33"), -1, "Last one is now 33")92 93 def check_two_threads(94 self, result_str, thread_id_1, name_1, thread_id_2, name_2, start_idx, end_idx95 ):96 # We should have 2 occurrences ot the thread header:97 self.assertEqual(98 result_str.count("thread #{0}".format(thread_id_1)), 1, "One for thread 1"99 )100 self.assertEqual(101 result_str.count("thread #{0}".format(thread_id_2)), 1, "One for thread 2"102 )103 # We should have 10 occurrences of each name:104 self.assertEqual(result_str.count(name_1), 10, "Found 10 of {0}".format(name_1))105 self.assertEqual(result_str.count(name_2), 10, "Found 10 of {0}".format(name_1))106 # There should be two instances of count=<start_idx> and none of count=<start-1>:107 self.assertEqual(108 result_str.count("count={0}".format(start_idx)),109 2,110 "Two instances of start_idx",111 )112 self.assertEqual(113 result_str.count("count={0}".format(start_idx - 1)),114 0,115 "No instances of start_idx - 1",116 )117 # There should be two instances of count=<end_idx> and none of count=<end_idx+1>:118 self.assertEqual(119 result_str.count("count={0}".format(end_idx)), 2, "Two instances of end_idx"120 )121 self.assertEqual(122 result_str.count("count={0}".format(end_idx + 1)),123 0,124 "No instances after end idx",125 )126 127 # The setup of this test was copied from the step-out test, and I can't tell from128 # the comments whether it was getting two threads to the same breakpoint that was129 # problematic, or the step-out part. This test stops at the rendevous point so I'm130 # removing the skipIfLinux to see if we see any flakiness in just this part of the test.131 @skipIfWindows # This test will hang on windows llvm.org/pr21753132 @expectedFailureAll(oslist=["windows"])133 @expectedFailureNetBSD134 def test_thread_backtrace_two_threads(self):135 """Test that repeat works even when backtracing on more than one thread."""136 self.build()137 (138 self.inferior_target,139 self.process,140 thread,141 bkpt,142 ) = lldbutil.run_to_source_breakpoint(143 self, self.bkpt_string, lldb.SBFileSpec("main.cpp"), only_one_thread=False144 )145 146 # We hit the breakpoint on at least one thread. If we hit it on both threads147 # simultaneously, we are ready to run our tests. Otherwise, suspend the thread148 # that hit the breakpoint, and continue till the second thread hits149 # the breakpoint:150 151 (breakpoint_threads, other_threads) = ([], [])152 lldbutil.sort_stopped_threads(153 self.process,154 breakpoint_threads=breakpoint_threads,155 other_threads=other_threads,156 )157 if len(breakpoint_threads) == 1:158 success = thread.Suspend()159 self.assertTrue(success, "Couldn't suspend a thread")160 breakpoint_threads = lldbutil.continue_to_breakpoint(self.process, bkpt)161 self.assertEqual(len(breakpoint_threads), 2, "Second thread stopped")162 163 # Figure out which thread is which:164 thread_id_1 = breakpoint_threads[0].idx165 self.assertGreater(len(breakpoint_threads[0].frames), 2, "I can go up")166 name_1 = breakpoint_threads[0].frame[1].name.split("(")[0]167 168 thread_id_2 = breakpoint_threads[1].idx169 self.assertGreater(len(breakpoint_threads[1].frames), 2, "I can go up")170 name_2 = breakpoint_threads[1].frame[1].name.split("(")[0]171 172 # Check that backtrace and repeat works on one thread, then works on the second173 # when we switch to it:174 self.check_one_thread(thread_id_1, name_1)175 self.check_one_thread(thread_id_2, name_2)176 177 # The output is looking right at this point, let's just do a couple more quick checks178 # to see we handle two threads and a start count:179 interp = self.dbg.GetCommandInterpreter()180 result = lldb.SBCommandReturnObject()181 182 interp.HandleCommand(183 "thread backtrace --count 10 --start 10 {0} {1}".format(184 thread_id_1, thread_id_2185 ),186 result,187 True,188 )189 self.assertTrue(result.Succeeded(), "command succeeded for two threads")190 191 result.Clear()192 interp.HandleCommand("", result, True)193 self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")194 result_str = result.GetOutput()195 self.check_two_threads(196 result_str, thread_id_1, name_1, thread_id_2, name_2, 23, 32197 )198 199 # Finally make sure the repeat repeats:200 result.Clear()201 interp.HandleCommand("", result, True)202 self.assertTrue(result.Succeeded(), "repeat command succeeded for two threads")203 result_str = result.GetOutput()204 self.check_two_threads(205 result_str, thread_id_1, name_1, thread_id_2, name_2, 13, 22206 )207