1*99451b44SJordan Rupprecht""" 2*99451b44SJordan RupprechtTest stepping out from a function in a multi-threaded program. 3*99451b44SJordan Rupprecht""" 4*99451b44SJordan Rupprecht 5*99451b44SJordan Rupprecht 6*99451b44SJordan Rupprecht 7*99451b44SJordan Rupprechtimport lldb 8*99451b44SJordan Rupprechtfrom lldbsuite.test.decorators import * 9*99451b44SJordan Rupprechtfrom lldbsuite.test.lldbtest import * 10*99451b44SJordan Rupprechtfrom lldbsuite.test import lldbutil 11*99451b44SJordan Rupprecht 12*99451b44SJordan Rupprecht 13*99451b44SJordan Rupprechtclass ThreadStepOutTestCase(TestBase): 14*99451b44SJordan Rupprecht 15*99451b44SJordan Rupprecht mydir = TestBase.compute_mydir(__file__) 16*99451b44SJordan Rupprecht 17*99451b44SJordan Rupprecht # Test occasionally times out on the Linux build bot 18*99451b44SJordan Rupprecht @skipIfLinux 19*99451b44SJordan Rupprecht @expectedFailureAll( 20*99451b44SJordan Rupprecht oslist=["linux"], 21*99451b44SJordan Rupprecht bugnumber="llvm.org/pr23477 Test occasionally times out on the Linux build bot") 22*99451b44SJordan Rupprecht @expectedFailureAll( 23*99451b44SJordan Rupprecht oslist=["freebsd"], 24*99451b44SJordan Rupprecht bugnumber="llvm.org/pr18066 inferior does not exit") 25*99451b44SJordan Rupprecht @skipIfWindows # This test will hang on windows llvm.org/pr21753 26*99451b44SJordan Rupprecht @expectedFailureAll(oslist=["windows"]) 27*99451b44SJordan Rupprecht @expectedFailureNetBSD 28*99451b44SJordan Rupprecht def test_step_single_thread(self): 29*99451b44SJordan Rupprecht """Test thread step out on one thread via command interpreter. """ 30*99451b44SJordan Rupprecht self.build(dictionary=self.getBuildFlags()) 31*99451b44SJordan Rupprecht self.step_out_test(self.step_out_single_thread_with_cmd) 32*99451b44SJordan Rupprecht 33*99451b44SJordan Rupprecht # Test occasionally times out on the Linux build bot 34*99451b44SJordan Rupprecht @skipIfLinux 35*99451b44SJordan Rupprecht @expectedFailureAll( 36*99451b44SJordan Rupprecht oslist=["linux"], 37*99451b44SJordan Rupprecht bugnumber="llvm.org/pr23477 Test occasionally times out on the Linux build bot") 38*99451b44SJordan Rupprecht @expectedFailureAll( 39*99451b44SJordan Rupprecht oslist=["freebsd"], 40*99451b44SJordan Rupprecht bugnumber="llvm.org/pr19347 2nd thread stops at breakpoint") 41*99451b44SJordan Rupprecht @skipIfWindows # This test will hang on windows llvm.org/pr21753 42*99451b44SJordan Rupprecht @expectedFailureAll(oslist=["windows"]) 43*99451b44SJordan Rupprecht @expectedFailureAll(oslist=["watchos"], archs=['armv7k'], bugnumber="rdar://problem/34674488") # stop reason is trace when it should be step-out 44*99451b44SJordan Rupprecht @expectedFailureNetBSD 45*99451b44SJordan Rupprecht def test_step_all_threads(self): 46*99451b44SJordan Rupprecht """Test thread step out on all threads via command interpreter. """ 47*99451b44SJordan Rupprecht self.build(dictionary=self.getBuildFlags()) 48*99451b44SJordan Rupprecht self.step_out_test(self.step_out_all_threads_with_cmd) 49*99451b44SJordan Rupprecht 50*99451b44SJordan Rupprecht # Test occasionally times out on the Linux build bot 51*99451b44SJordan Rupprecht @skipIfLinux 52*99451b44SJordan Rupprecht @expectedFailureAll( 53*99451b44SJordan Rupprecht oslist=["linux"], 54*99451b44SJordan Rupprecht bugnumber="llvm.org/pr23477 Test occasionally times out on the Linux build bot") 55*99451b44SJordan Rupprecht @expectedFailureAll( 56*99451b44SJordan Rupprecht oslist=["freebsd"], 57*99451b44SJordan Rupprecht bugnumber="llvm.org/pr19347 2nd thread stops at breakpoint") 58*99451b44SJordan Rupprecht @skipIfWindows # This test will hang on windows llvm.org/pr21753 59*99451b44SJordan Rupprecht @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24681") 60*99451b44SJordan Rupprecht @expectedFailureNetBSD 61*99451b44SJordan Rupprecht def test_python(self): 62*99451b44SJordan Rupprecht """Test thread step out on one thread via Python API (dwarf).""" 63*99451b44SJordan Rupprecht self.build(dictionary=self.getBuildFlags()) 64*99451b44SJordan Rupprecht self.step_out_test(self.step_out_with_python) 65*99451b44SJordan Rupprecht 66*99451b44SJordan Rupprecht def setUp(self): 67*99451b44SJordan Rupprecht # Call super's setUp(). 68*99451b44SJordan Rupprecht TestBase.setUp(self) 69*99451b44SJordan Rupprecht # Find the line number for our breakpoint. 70*99451b44SJordan Rupprecht self.bkpt_string = '// Set breakpoint here' 71*99451b44SJordan Rupprecht self.breakpoint = line_number('main.cpp', self.bkpt_string) 72*99451b44SJordan Rupprecht 73*99451b44SJordan Rupprecht if "gcc" in self.getCompiler() or self.isIntelCompiler() or self.getArchitecture() in ['arm64', 'arm64e']: 74*99451b44SJordan Rupprecht self.step_out_destination = line_number( 75*99451b44SJordan Rupprecht 'main.cpp', '// Expect to stop here after step-out (icc and gcc; arm64)') 76*99451b44SJordan Rupprecht else: 77*99451b44SJordan Rupprecht self.step_out_destination = line_number( 78*99451b44SJordan Rupprecht 'main.cpp', '// Expect to stop here after step-out (clang)') 79*99451b44SJordan Rupprecht 80*99451b44SJordan Rupprecht def step_out_single_thread_with_cmd(self): 81*99451b44SJordan Rupprecht self.step_out_with_cmd("this-thread") 82*99451b44SJordan Rupprecht self.expect( 83*99451b44SJordan Rupprecht "thread backtrace all", 84*99451b44SJordan Rupprecht "Thread location after step out is correct", 85*99451b44SJordan Rupprecht substrs=[ 86*99451b44SJordan Rupprecht "main.cpp:%d" % 87*99451b44SJordan Rupprecht self.step_out_destination, 88*99451b44SJordan Rupprecht "main.cpp:%d" % 89*99451b44SJordan Rupprecht self.breakpoint]) 90*99451b44SJordan Rupprecht 91*99451b44SJordan Rupprecht def step_out_all_threads_with_cmd(self): 92*99451b44SJordan Rupprecht self.step_out_with_cmd("all-threads") 93*99451b44SJordan Rupprecht self.expect( 94*99451b44SJordan Rupprecht "thread backtrace all", 95*99451b44SJordan Rupprecht "Thread location after step out is correct", 96*99451b44SJordan Rupprecht substrs=[ 97*99451b44SJordan Rupprecht "main.cpp:%d" % 98*99451b44SJordan Rupprecht self.step_out_destination]) 99*99451b44SJordan Rupprecht 100*99451b44SJordan Rupprecht def step_out_with_cmd(self, run_mode): 101*99451b44SJordan Rupprecht self.runCmd("thread select %d" % self.step_out_thread.GetIndexID()) 102*99451b44SJordan Rupprecht self.runCmd("thread step-out -m %s" % run_mode) 103*99451b44SJordan Rupprecht self.expect("process status", "Expected stop reason to be step-out", 104*99451b44SJordan Rupprecht substrs=["stop reason = step out"]) 105*99451b44SJordan Rupprecht 106*99451b44SJordan Rupprecht self.expect( 107*99451b44SJordan Rupprecht "thread list", 108*99451b44SJordan Rupprecht "Selected thread did not change during step-out", 109*99451b44SJordan Rupprecht substrs=[ 110*99451b44SJordan Rupprecht "* thread #%d" % 111*99451b44SJordan Rupprecht self.step_out_thread.GetIndexID()]) 112*99451b44SJordan Rupprecht 113*99451b44SJordan Rupprecht def step_out_with_python(self): 114*99451b44SJordan Rupprecht self.step_out_thread.StepOut() 115*99451b44SJordan Rupprecht 116*99451b44SJordan Rupprecht reason = self.step_out_thread.GetStopReason() 117*99451b44SJordan Rupprecht self.assertEqual( 118*99451b44SJordan Rupprecht lldb.eStopReasonPlanComplete, 119*99451b44SJordan Rupprecht reason, 120*99451b44SJordan Rupprecht "Expected thread stop reason 'plancomplete', but got '%s'" % 121*99451b44SJordan Rupprecht lldbutil.stop_reason_to_str(reason)) 122*99451b44SJordan Rupprecht 123*99451b44SJordan Rupprecht # Verify location after stepping out 124*99451b44SJordan Rupprecht frame = self.step_out_thread.GetFrameAtIndex(0) 125*99451b44SJordan Rupprecht desc = lldbutil.get_description(frame.GetLineEntry()) 126*99451b44SJordan Rupprecht expect = "main.cpp:%d" % self.step_out_destination 127*99451b44SJordan Rupprecht self.assertTrue( 128*99451b44SJordan Rupprecht expect in desc, "Expected %s but thread stopped at %s" % 129*99451b44SJordan Rupprecht (expect, desc)) 130*99451b44SJordan Rupprecht 131*99451b44SJordan Rupprecht def step_out_test(self, step_out_func): 132*99451b44SJordan Rupprecht """Test single thread step out of a function.""" 133*99451b44SJordan Rupprecht (self.inferior_target, self.inferior_process, thread, bkpt) = lldbutil.run_to_source_breakpoint( 134*99451b44SJordan Rupprecht self, self.bkpt_string, lldb.SBFileSpec('main.cpp'), only_one_thread = False) 135*99451b44SJordan Rupprecht 136*99451b44SJordan Rupprecht # We hit the breakpoint on at least one thread. If we hit it on both threads 137*99451b44SJordan Rupprecht # simultaneously, we can try the step out. Otherwise, suspend the thread 138*99451b44SJordan Rupprecht # that hit the breakpoint, and continue till the second thread hits 139*99451b44SJordan Rupprecht # the breakpoint: 140*99451b44SJordan Rupprecht 141*99451b44SJordan Rupprecht (breakpoint_threads, other_threads) = ([], []) 142*99451b44SJordan Rupprecht lldbutil.sort_stopped_threads(self.inferior_process, 143*99451b44SJordan Rupprecht breakpoint_threads=breakpoint_threads, 144*99451b44SJordan Rupprecht other_threads=other_threads) 145*99451b44SJordan Rupprecht if len(breakpoint_threads) == 1: 146*99451b44SJordan Rupprecht success = thread.Suspend() 147*99451b44SJordan Rupprecht self.assertTrue(success, "Couldn't suspend a thread") 148*99451b44SJordan Rupprecht bkpt_threads = lldbutil.continue_to_breakpoint(bkpt) 149*99451b44SJordan Rupprecht self.assertEqual(len(bkpt_threads), 1, "Second thread stopped") 150*99451b44SJordan Rupprecht success = thread.Resume() 151*99451b44SJordan Rupprecht self.assertTrue(success, "Couldn't resume a thread") 152*99451b44SJordan Rupprecht 153*99451b44SJordan Rupprecht self.step_out_thread = breakpoint_threads[0] 154*99451b44SJordan Rupprecht 155*99451b44SJordan Rupprecht # Step out of thread stopped at breakpoint 156*99451b44SJordan Rupprecht step_out_func() 157