| """ | |
| Test thread step-in, step-over and step-out work with the "Avoid no debug" option. | |
| """ | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.lldbtest import * | |
| from lldbsuite.test import lldbutil | |
| class StepAvoidsNoDebugTestCase(TestBase): | |
| @add_test_categories(["pyapi"]) | |
| @expectedFailureAll( | |
| archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" | |
| ) | |
| def test_step_out_with_python(self): | |
| """Test stepping out using avoid-no-debug with dsyms.""" | |
| self.build() | |
| self.get_to_starting_point() | |
| self.do_step_out_past_nodebug() | |
| @add_test_categories(["pyapi"]) | |
| @decorators.expectedFailureAll(compiler="gcc", bugnumber="llvm.org/pr28549") | |
| @decorators.expectedFailureAll( | |
| compiler="clang", | |
| compiler_version=[">=", "3.9"], | |
| archs=["i386"], | |
| oslist=no_match(["freebsd"]), | |
| bugnumber="llvm.org/pr28549", | |
| ) | |
| @expectedFailureAll( | |
| archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" | |
| ) | |
| def test_step_over_with_python(self): | |
| """Test stepping over using avoid-no-debug with dwarf.""" | |
| self.build() | |
| self.get_to_starting_point() | |
| self.do_step_over_past_nodebug() | |
| @add_test_categories(["pyapi"]) | |
| @decorators.expectedFailureAll(compiler="gcc", bugnumber="llvm.org/pr28549") | |
| @decorators.expectedFailureAll( | |
| compiler="clang", | |
| compiler_version=[">=", "3.9"], | |
| archs=["i386"], | |
| oslist=no_match(["freebsd"]), | |
| bugnumber="llvm.org/pr28549", | |
| ) | |
| @expectedFailureAll( | |
| archs=["aarch64"], oslist=["windows"], bugnumber="llvm.org/pr56292" | |
| ) | |
| def test_step_in_with_python(self): | |
| """Test stepping in using avoid-no-debug with dwarf.""" | |
| self.build() | |
| self.get_to_starting_point() | |
| self.do_step_in_past_nodebug() | |
| def setUp(self): | |
| TestBase.setUp(self) | |
| self.main_source = "with-debug.c" | |
| self.main_source_spec = lldb.SBFileSpec("with-debug.c") | |
| self.dbg.HandleCommand( | |
| "settings set target.process.thread.step-out-avoid-nodebug true" | |
| ) | |
| def tearDown(self): | |
| self.dbg.HandleCommand( | |
| "settings set target.process.thread.step-out-avoid-nodebug false" | |
| ) | |
| TestBase.tearDown(self) | |
| def hit_correct_line(self, pattern): | |
| target_line = line_number(self.main_source, pattern) | |
| self.assertNotEqual(target_line, 0, "Could not find source pattern " + pattern) | |
| cur_line = self.thread.frames[0].GetLineEntry().GetLine() | |
| self.assertEqual( | |
| cur_line, | |
| target_line, | |
| "Stepped to line %d instead of expected %d with pattern '%s'." | |
| % (cur_line, target_line, pattern), | |
| ) | |
| def hit_correct_function(self, pattern): | |
| name = self.thread.frames[0].GetFunctionName() | |
| self.assertIn( | |
| pattern, | |
| name, | |
| "Got to '%s' not the expected function '%s'." % (name, pattern), | |
| ) | |
| def get_to_starting_point(self): | |
| self.target, self.process, self.thread, _ = lldbutil.run_to_source_breakpoint( | |
| self, "Stop here and step out of me", self.main_source_spec | |
| ) | |
| def do_step_out_past_nodebug(self): | |
| # The first step out takes us to the called_from_nodebug frame, just to make sure setting | |
| # step-out-avoid-nodebug doesn't change the behavior in frames with | |
| # debug info. | |
| self.thread.StepOut() | |
| self.hit_correct_line( | |
| "intermediate_return_value = called_from_nodebug_actual(some_value)" | |
| ) | |
| self.thread.StepOut() | |
| self.hit_correct_line( | |
| "int return_value = no_debug_caller(5, called_from_nodebug)" | |
| ) | |
| def do_step_over_past_nodebug(self): | |
| self.thread.StepOver() | |
| self.hit_correct_line( | |
| "intermediate_return_value = called_from_nodebug_actual(some_value)" | |
| ) | |
| self.thread.StepOver() | |
| self.hit_correct_line("return intermediate_return_value") | |
| self.thread.StepOver() | |
| # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in" | |
| # when exiting a frame. In all cases we leave the pc at the point where we exited the | |
| # frame. In gdb, step-over/step-in move to the end of the line they stepped out to. | |
| # If we ever change this we will need to fix this test. | |
| self.hit_correct_line( | |
| "int return_value = no_debug_caller(5, called_from_nodebug)" | |
| ) | |
| def do_step_in_past_nodebug(self): | |
| self.thread.StepInto() | |
| self.hit_correct_line( | |
| "intermediate_return_value = called_from_nodebug_actual(some_value)" | |
| ) | |
| self.thread.StepInto() | |
| self.hit_correct_line("return intermediate_return_value") | |
| self.thread.StepInto() | |
| # Note, lldb doesn't follow gdb's distinction between "step-out" and "step-over/step-in" | |
| # when exiting a frame. In all cases we leave the pc at the point where we exited the | |
| # frame. In gdb, step-over/step-in move to the end of the line they stepped out to. | |
| # If we ever change this we will need to fix this test. | |
| self.hit_correct_line( | |
| "int return_value = no_debug_caller(5, called_from_nodebug)" | |
| ) |