1""" 2Test thread step-in, step-over and step-out work with the "Avoid no debug" option. 3""" 4 5 6import lldb 7from lldbsuite.test.decorators import * 8from lldbsuite.test.lldbtest import * 9from lldbsuite.test import lldbutil 10 11 12class StepAvoidsNoDebugTestCase(TestBase): 13 @add_test_categories(["pyapi"]) 14 @expectedFailureAll( 15 archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" 16 ) 17 def test_step_out_with_python(self): 18 """Test stepping out using avoid-no-debug with dsyms.""" 19 self.build() 20 self.get_to_starting_point() 21 self.do_step_out_past_nodebug() 22 23 @add_test_categories(["pyapi"]) 24 @decorators.expectedFailureAll(compiler="gcc", bugnumber="llvm.org/pr28549") 25 @decorators.expectedFailureAll( 26 compiler="clang", 27 compiler_version=[">=", "3.9"], 28 archs=["i386"], 29 oslist=no_match(["freebsd"]), 30 bugnumber="llvm.org/pr28549", 31 ) 32 @expectedFailureAll( 33 archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" 34 ) 35 def test_step_over_with_python(self): 36 """Test stepping over using avoid-no-debug with dwarf.""" 37 self.build() 38 self.get_to_starting_point() 39 self.do_step_over_past_nodebug() 40 41 @add_test_categories(["pyapi"]) 42 @decorators.expectedFailureAll(compiler="gcc", bugnumber="llvm.org/pr28549") 43 @decorators.expectedFailureAll( 44 compiler="clang", 45 compiler_version=[">=", "3.9"], 46 archs=["i386"], 47 oslist=no_match(["freebsd"]), 48 bugnumber="llvm.org/pr28549", 49 ) 50 @expectedFailureAll( 51 archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" 52 ) 53 def test_step_in_with_python(self): 54 """Test stepping in using avoid-no-debug with dwarf.""" 55 self.build() 56 self.get_to_starting_point() 57 self.do_step_in_past_nodebug() 58 59 def setUp(self): 60 TestBase.setUp(self) 61 self.main_source = "with-debug.c" 62 self.main_source_spec = lldb.SBFileSpec("with-debug.c") 63 self.dbg.HandleCommand( 64 "settings set target.process.thread.step-out-avoid-nodebug true" 65 ) 66 67 def tearDown(self): 68 self.dbg.HandleCommand( 69 "settings set target.process.thread.step-out-avoid-nodebug false" 70 ) 71 TestBase.tearDown(self) 72 73 def hit_correct_line(self, pattern): 74 target_line = line_number(self.main_source, pattern) 75 self.assertNotEqual(target_line, 0, "Could not find source pattern " + pattern) 76 cur_line = self.thread.frames[0].GetLineEntry().GetLine() 77 self.assertEqual( 78 cur_line, 79 target_line, 80 "Stepped to line %d instead of expected %d with pattern '%s'." 81 % (cur_line, target_line, pattern), 82 ) 83 84 def hit_correct_function(self, pattern): 85 name = self.thread.frames[0].GetFunctionName() 86 self.assertIn( 87 pattern, 88 name, 89 "Got to '%s' not the expected function '%s'." % (name, pattern), 90 ) 91 92 def get_to_starting_point(self): 93 exe = self.getBuildArtifact("a.out") 94 error = lldb.SBError() 95 96 self.target = self.dbg.CreateTarget(exe) 97 self.assertTrue(self.target, VALID_TARGET) 98 99 inner_bkpt = self.target.BreakpointCreateBySourceRegex( 100 "Stop here and step out of me", self.main_source_spec 101 ) 102 self.assertTrue(inner_bkpt, VALID_BREAKPOINT) 103 104 # Now launch the process, and do not stop at entry point. 105 self.process = self.target.LaunchSimple( 106 None, None, self.get_process_working_directory() 107 ) 108 109 self.assertTrue(self.process, PROCESS_IS_VALID) 110 111 # Now finish, and make sure the return value is correct. 112 threads = lldbutil.get_threads_stopped_at_breakpoint(self.process, inner_bkpt) 113 self.assertEqual(len(threads), 1, "Stopped at inner breakpoint.") 114 self.thread = threads[0] 115 116 def do_step_out_past_nodebug(self): 117 # The first step out takes us to the called_from_nodebug frame, just to make sure setting 118 # step-out-avoid-nodebug doesn't change the behavior in frames with 119 # debug info. 120 self.thread.StepOut() 121 self.hit_correct_line( 122 "intermediate_return_value = called_from_nodebug_actual(some_value)" 123 ) 124 self.thread.StepOut() 125 self.hit_correct_line( 126 "int return_value = no_debug_caller(5, called_from_nodebug)" 127 ) 128 129 def do_step_over_past_nodebug(self): 130 self.thread.StepOver() 131 self.hit_correct_line( 132 "intermediate_return_value = called_from_nodebug_actual(some_value)" 133 ) 134 self.thread.StepOver() 135 self.hit_correct_line("return intermediate_return_value") 136 self.thread.StepOver() 137 # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in" 138 # when exiting a frame. In all cases we leave the pc at the point where we exited the 139 # frame. In gdb, step-over/step-in move to the end of the line they stepped out to. 140 # If we ever change this we will need to fix this test. 141 self.hit_correct_line( 142 "int return_value = no_debug_caller(5, called_from_nodebug)" 143 ) 144 145 def do_step_in_past_nodebug(self): 146 self.thread.StepInto() 147 self.hit_correct_line( 148 "intermediate_return_value = called_from_nodebug_actual(some_value)" 149 ) 150 self.thread.StepInto() 151 self.hit_correct_line("return intermediate_return_value") 152 self.thread.StepInto() 153 # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in" 154 # when exiting a frame. In all cases we leave the pc at the point where we exited the 155 # frame. In gdb, step-over/step-in move to the end of the line they stepped out to. 156 # If we ever change this we will need to fix this test. 157 self.hit_correct_line( 158 "int return_value = no_debug_caller(5, called_from_nodebug)" 159 ) 160