diff --git a/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/Makefile b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/TestConsecutiveWatchpoints.py b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/TestConsecutiveWatchpoints.py new file mode 100644 index 0000000000000..229172e6ce0aa --- /dev/null +++ b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/TestConsecutiveWatchpoints.py @@ -0,0 +1,87 @@ +""" +Watch contiguous memory regions with separate watchpoints, check that lldb +correctly detect which watchpoint was hit for each one. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class ConsecutiveWatchpointsTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def continue_and_report_stop_reason(self, process, iter_str): + process.Continue() + self.assertIn( + process.GetState(), [lldb.eStateStopped, lldb.eStateExited], iter_str + ) + thread = process.GetSelectedThread() + return thread.GetStopReason() + + # debugserver only gained the ability to watch larger regions + # with this patch. + def test_large_watchpoint(self): + """Test watchpoint that covers a large region of memory.""" + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "break here", self.main_source_file + ) + + frame = thread.GetFrameAtIndex(0) + + field2_wp = ( + frame.locals["var"][0] + .GetChildMemberWithName("field2") + .Watch(True, False, True) + ) + field3_wp = ( + frame.locals["var"][0] + .GetChildMemberWithName("field3") + .Watch(True, False, True) + ) + field4_wp = ( + frame.locals["var"][0] + .GetChildMemberWithName("field4") + .Watch(True, False, True) + ) + field5_wp = ( + frame.locals["var"][0] + .GetChildMemberWithName("field5") + .Watch(True, False, True) + ) + + self.assertTrue(field2_wp.IsValid()) + self.assertTrue(field3_wp.IsValid()) + self.assertTrue(field4_wp.IsValid()) + self.assertTrue(field5_wp.IsValid()) + + reason = self.continue_and_report_stop_reason(process, "continue to field2 wp") + self.assertEqual(reason, lldb.eStopReasonWatchpoint) + stop_reason_watchpoint_id = ( + process.GetSelectedThread().GetStopReasonDataAtIndex(0) + ) + self.assertEqual(stop_reason_watchpoint_id, field2_wp.GetID()) + + reason = self.continue_and_report_stop_reason(process, "continue to field3 wp") + self.assertEqual(reason, lldb.eStopReasonWatchpoint) + stop_reason_watchpoint_id = ( + process.GetSelectedThread().GetStopReasonDataAtIndex(0) + ) + self.assertEqual(stop_reason_watchpoint_id, field3_wp.GetID()) + + reason = self.continue_and_report_stop_reason(process, "continue to field4 wp") + self.assertEqual(reason, lldb.eStopReasonWatchpoint) + stop_reason_watchpoint_id = ( + process.GetSelectedThread().GetStopReasonDataAtIndex(0) + ) + self.assertEqual(stop_reason_watchpoint_id, field4_wp.GetID()) + + reason = self.continue_and_report_stop_reason(process, "continue to field5 wp") + self.assertEqual(reason, lldb.eStopReasonWatchpoint) + stop_reason_watchpoint_id = ( + process.GetSelectedThread().GetStopReasonDataAtIndex(0) + ) + self.assertEqual(stop_reason_watchpoint_id, field5_wp.GetID()) diff --git a/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/main.c b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/main.c new file mode 100644 index 0000000000000..c0a3530be9f5e --- /dev/null +++ b/lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/main.c @@ -0,0 +1,22 @@ +#include +struct fields { + uint32_t field1; + uint32_t field2; // offset +4 + uint16_t field3; // offset +8 + uint16_t field4; // offset +10 + uint16_t field5; // offset +12 + uint16_t field6; // offset +14 +}; + +int main() { + struct fields var = {0, 0, 0, 0, 0, 0}; + + var.field1 = 5; // break here + var.field2 = 6; + var.field3 = 7; + var.field4 = 8; + var.field5 = 9; + var.field6 = 10; + + return var.field1 + var.field2 + var.field3; +} diff --git a/lldb/tools/debugserver/source/DNBBreakpoint.cpp b/lldb/tools/debugserver/source/DNBBreakpoint.cpp index f63ecf24222bd..e41bf9b4fd905 100644 --- a/lldb/tools/debugserver/source/DNBBreakpoint.cpp +++ b/lldb/tools/debugserver/source/DNBBreakpoint.cpp @@ -98,7 +98,7 @@ DNBBreakpointList::FindNearestWatchpoint(nub_addr_t addr) const { if (pos.second.IsEnabled()) { nub_addr_t start_addr = pos.second.Address(); nub_addr_t end_addr = start_addr + pos.second.ByteSize(); - if (addr >= start_addr && addr <= end_addr) + if (addr >= start_addr && addr < end_addr) return &pos.second; } }