Author: Jason Molenda
Date: 2025-04-07T11:11:31-07:00
New Revision: 21d912121c9f41385b165a736be787527f5bd7c2

URL: 
https://github.com/llvm/llvm-project/commit/21d912121c9f41385b165a736be787527f5bd7c2
DIFF: 
https://github.com/llvm/llvm-project/commit/21d912121c9f41385b165a736be787527f5bd7c2.diff

LOG: [lldb][debugserver] Fix an off-by-one error in watchpoint identification 
(#134314)

debugserver takes the address of a watchpoint exception and calculates
which watchpoint was responsible for it. There was an off-by-one error
in the range calculation which causes two watchpoints on consecutive
ranges to not correctly identify hits to the second watchpoint. The
result is that lldb wouldn't show the second watchpoint as ever being
hit.

rdar://145107575

Added: 
    lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/Makefile
    
lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/TestConsecutiveWatchpoints.py
    lldb/test/API/functionalities/watchpoint/consecutive-watchpoints/main.c

Modified: 
    lldb/tools/debugserver/source/DNBBreakpoint.cpp

Removed: 
    


################################################################################
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 <stdint.h>
+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;
     }
   }


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to