kpdev42 created this revision. kpdev42 added reviewers: clayborg, davide, k8stone, DavidSpickett. kpdev42 added a project: LLDB. Herald added a subscriber: JDevlieghere. Herald added a project: All. kpdev42 requested review of this revision. Herald added a subscriber: lldb-commits.
Currently in some cases lldb reports stop reason as "step out" or "step over" (from thread plan completion) over "breakpoint", if the user breakpoint happens to be set on the same address. The part of https://github.com/llvm/llvm-project/commit/f08f5c99262ff9eaa08956334accbb2614b0f7a2 seems to overwrite internal breakpoint detection logic, so that only the last breakpoint for the current stop address is considered. Together with step-out plans not clearing its breakpoint until they are destrouyed, this creates a situation when there is a user breakpoint set for address, but internal breakpoint makes lldb report a plan completion stop reason instead of breakpoint. This patch reverts that internal breakpoint detection logic to consider all breakpoints Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D140368 Files: lldb/source/Target/StopInfo.cpp lldb/test/API/functionalities/breakpoint/step_out_breakpoint/Makefile lldb/test/API/functionalities/breakpoint/step_out_breakpoint/TestStepOutBreakpoint.py lldb/test/API/functionalities/breakpoint/step_out_breakpoint/main.cpp
Index: lldb/test/API/functionalities/breakpoint/step_out_breakpoint/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/functionalities/breakpoint/step_out_breakpoint/main.cpp @@ -0,0 +1,11 @@ +int func_1() { return 1; } + +int func_2() { + func_1(); // breakpoint_1 + return 1 + func_1(); // breakpoint_2 +} + +int main(int argc, char const *argv[]) { + func_2(); // breakpoint_0 + return 0; // breakpoint_3 +} Index: lldb/test/API/functionalities/breakpoint/step_out_breakpoint/TestStepOutBreakpoint.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/breakpoint/step_out_breakpoint/TestStepOutBreakpoint.py @@ -0,0 +1,85 @@ +""" +Test that breakpoints do not affect stepping. +Check for correct StopReason when stepping to the line with breakpoint +which should be eStopReasonBreakpoint in general, +and eStopReasonPlanComplete when breakpoint's condition fails. +""" + + +import unittest2 +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class StepOverBreakpointsTestCase(TestBase): + + def setUp(self): + TestBase.setUp(self) + + self.build() + exe = self.getBuildArtifact("a.out") + src = lldb.SBFileSpec("main.cpp") + + # Create a target by the debugger. + self.target = self.dbg.CreateTarget(exe) + self.assertTrue(self.target, VALID_TARGET) + + # Setup four breakpoints + self.lines = [line_number('main.cpp', "breakpoint_%i" % i) for i in range(4)] + + self.breakpoints = [self.target.BreakpointCreateByLocation(src, line) for line in self.lines] + self.assertTrue( + self.breakpoints[0] and self.breakpoints[0].GetNumLocations() == 1, + VALID_BREAKPOINT) + + # Start debugging + self.process = self.target.LaunchSimple( + None, None, self.get_process_working_directory()) + self.assertIsNotNone(self.process, PROCESS_IS_VALID) + self.thread = lldbutil.get_one_thread_stopped_at_breakpoint(self.process, self.breakpoints[0]) + self.assertIsNotNone(self.thread, "Didn't stop at breakpoint 0.") + + def check_correct_stop_reason(self, breakpoint_idx, condition): + self.assertState(self.process.GetState(), lldb.eStateStopped) + if condition: + # All breakpoints active, stop reason is breakpoint + thread1 = lldbutil.get_one_thread_stopped_at_breakpoint(self.process, self.breakpoints[breakpoint_idx]) + self.assertEquals(self.thread, thread1, "Didn't stop at breakpoint %i." % breakpoint_idx) + else: + # Breakpoints are inactive, stop reason is plan complete + self.assertEquals(self.thread.GetStopReason(), lldb.eStopReasonPlanComplete, + "Expected stop reason to be step into/over/out for inactive breakpoint %i line." % breakpoint_idx) + + def check_step_out_conditional(self, condition): + conditionStr = 'true' if condition else 'false' + + self.breakpoints[1].GetLocationAtIndex(0).SetCondition(conditionStr) + self.breakpoints[2].GetLocationAtIndex(0).SetCondition(conditionStr) + self.breakpoints[3].GetLocationAtIndex(0).SetCondition(conditionStr) + + self.thread.StepInto() + # We should be stopped at the breakpoint_1 line with the correct stop reason + self.check_correct_stop_reason(1, condition) + + # This step-over creates a step-out from `func_1` plan + self.thread.StepOver() + # We should be stopped at the breakpoint_2 line with the correct stop reason + self.check_correct_stop_reason(2, condition) + + # Check explicit step-out + self.thread.StepOut() + # We should be stopped at the breakpoint_3 line with the correct stop reason + self.check_correct_stop_reason(3, condition) + + # Run the process until termination + self.process.Continue() + self.assertState(self.process.GetState(), lldb.eStateExited) + + def test_step_out_active(self): + # Test with breakpoints 1, 2, 3 enabled + self.check_step_out_conditional(True) + + def test_step_out_inactive(self): + # Test with breakpoints 1, 2, 3 having false condition + self.check_step_out_conditional(False) Index: lldb/test/API/functionalities/breakpoint/step_out_breakpoint/Makefile =================================================================== --- /dev/null +++ lldb/test/API/functionalities/breakpoint/step_out_breakpoint/Makefile @@ -0,0 +1,8 @@ +CXX_SOURCES := main.cpp + +ifneq (,$(findstring icc,$(CC))) + CXXFLAGS_EXTRAS := -debug inline-debug-info +endif + + +include Makefile.rules Index: lldb/source/Target/StopInfo.cpp =================================================================== --- lldb/source/Target/StopInfo.cpp +++ lldb/source/Target/StopInfo.cpp @@ -421,8 +421,6 @@ continue; } - internal_breakpoint = bp_loc_sp->GetBreakpoint().IsInternal(); - // First run the precondition, but since the precondition is per // breakpoint, only run it once per breakpoint. std::pair<std::unordered_set<break_id_t>::iterator, bool> result = @@ -509,7 +507,7 @@ loc_desc.GetData()); // We want this stop reported, so you will know we auto-continued // but only for external breakpoints: - if (!internal_breakpoint) + if (!bp_loc_sp->GetBreakpoint().IsInternal()) thread_sp->SetShouldReportStop(eVoteYes); auto_continue_says_stop = false; } @@ -539,6 +537,9 @@ actually_said_continue = true; } + if (m_should_stop && !bp_loc_sp->GetBreakpoint().IsInternal()) + internal_breakpoint = false; + // If we are going to stop for this breakpoint, then remove the // breakpoint. if (callback_says_stop && bp_loc_sp &&
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits