[Lldb-commits] [lldb] e8d437f - [lldb] WatchAddress ignores modify option (#124847)

via lldb-commits lldb-commits at lists.llvm.org
Tue Feb 4 16:03:16 PST 2025


Author: Ben Jackson
Date: 2025-02-04T16:03:13-08:00
New Revision: e8d437f827144061d051ecf199d4075bef317285

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

LOG: [lldb] WatchAddress ignores modify option (#124847)

The WatchAddress API includes a flag to indicate if watchpoint should be
for read, modify or both. This API uses 2 booleans, but the 'modify'
flag was ignored and WatchAddress unconditionally watched write
(actually modify).

We now only watch for modify when the modify flag is true.

---

The included test fails prior to this patch and succeeds after. That is
previously specifying `False` for `modify` would still stop on _write_,
but after the patch correctly only stops on _read_

Added: 
    lldb/test/API/python_api/watchpoint/TestWatchpointRead.py

Modified: 
    lldb/source/API/SBTarget.cpp
    lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py

Removed: 
    


################################################################################
diff  --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 2a33161bc21edc7..dd9caa724ea3628 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1342,7 +1342,8 @@ lldb::SBWatchpoint SBTarget::WatchAddress(lldb::addr_t addr, size_t size,
 
   SBWatchpointOptions options;
   options.SetWatchpointTypeRead(read);
-  options.SetWatchpointTypeWrite(eWatchpointWriteTypeOnModify);
+  if (modify)
+    options.SetWatchpointTypeWrite(eWatchpointWriteTypeOnModify);
   return WatchpointCreateByAddress(addr, size, options, error);
 }
 

diff  --git a/lldb/test/API/python_api/watchpoint/TestWatchpointRead.py b/lldb/test/API/python_api/watchpoint/TestWatchpointRead.py
new file mode 100644
index 000000000000000..f482ebe5b1ecee6
--- /dev/null
+++ b/lldb/test/API/python_api/watchpoint/TestWatchpointRead.py
@@ -0,0 +1,129 @@
+"""
+Use lldb Python SBTarget API to set read watchpoints
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class SetReadOnlyWatchpointTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Our simple source filename.
+        self.source = "main.c"
+        # Find the line number to break inside main().
+        self.line = line_number(self.source, "// Set break point at this line.")
+        self.build()
+
+    # Intel hardware does not support read-only watchpoints
+    @expectedFailureAll(archs=["i386", "x86_64"])
+    def test_read_watchpoint_watch_address(self):
+        exe = self.getBuildArtifact("a.out")
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Now create a breakpoint on main.c.
+        breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
+        )
+
+        # Now launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(None, None, self.get_process_working_directory())
+
+        # We should be stopped due to the breakpoint.  Get frame #0.
+        process = target.GetProcess()
+        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        frame0 = thread.GetFrameAtIndex(0)
+
+        value = frame0.FindValue("global", lldb.eValueTypeVariableGlobal)
+        local = frame0.FindValue("local", lldb.eValueTypeVariableLocal)
+        error = lldb.SBError()
+
+        watchpoint = target.WatchAddress(value.GetLoadAddress(), 1, True, False, error)
+        self.assertTrue(
+            value and local and watchpoint,
+            "Successfully found the values and set a watchpoint",
+        )
+        self.DebugSBValue(value)
+        self.DebugSBValue(local)
+
+        # Hide stdout if not running with '-t' option.
+        if not self.TraceOn():
+            self.HideStdout()
+
+        print(watchpoint)
+
+        # Continue.  Expect the program to stop due to the variable being
+        # read, but *not* written to.
+        process.Continue()
+
+        if self.TraceOn():
+            lldbutil.print_stacktraces(process)
+
+        self.assertTrue(
+            local.GetValueAsSigned() > 0, "The local variable has been incremented"
+        )
+
+    # Intel hardware does not support read-only watchpoints
+    @expectedFailureAll(archs=["i386", "x86_64"])
+    def test_read_watchpoint_watch_create_by_address(self):
+        exe = self.getBuildArtifact("a.out")
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Now create a breakpoint on main.c.
+        breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
+        )
+
+        # Now launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(None, None, self.get_process_working_directory())
+
+        # We should be stopped due to the breakpoint.  Get frame #0.
+        process = target.GetProcess()
+        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        frame0 = thread.GetFrameAtIndex(0)
+
+        value = frame0.FindValue("global", lldb.eValueTypeVariableGlobal)
+        local = frame0.FindValue("local", lldb.eValueTypeVariableLocal)
+        error = lldb.SBError()
+
+        wp_opts = lldb.SBWatchpointOptions()
+        wp_opts.SetWatchpointTypeRead(True)
+        watchpoint = target.WatchpointCreateByAddress(
+            value.GetLoadAddress(), 1, wp_opts, error
+        )
+        self.assertTrue(
+            value and local and watchpoint,
+            "Successfully found the values and set a watchpoint",
+        )
+        self.DebugSBValue(value)
+        self.DebugSBValue(local)
+
+        # Hide stdout if not running with '-t' option.
+        if not self.TraceOn():
+            self.HideStdout()
+
+        print(watchpoint)
+
+        # Continue.  Expect the program to stop due to the variable being
+        # read, but *not* written to.
+        process.Continue()
+
+        if self.TraceOn():
+            lldbutil.print_stacktraces(process)
+
+        self.assertTrue(
+            local.GetValueAsSigned() > 0, "The local variable has been incremented"
+        )

diff  --git a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
index cbab3c6382e431d..7a0e42a4fc2781b 100644
--- a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
+++ b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
@@ -21,7 +21,7 @@ def setUp(self):
         # This is for verifying that watch location works.
         self.violating_func = "do_bad_thing_with_location"
 
-    def test_watch_address(self):
+    def test_watch_create_by_address(self):
         """Exercise SBTarget.WatchpointCreateByAddress() API to set a watchpoint."""
         self.build()
         exe = self.getBuildArtifact("a.out")
@@ -88,6 +88,75 @@ def test_watch_address(self):
 
         # This finishes our test.
 
+    def test_watch_address(self):
+        """Exercise SBTarget.WatchAddress() API to set a watchpoint.
+        Same as test_watch_create_by_address, but uses the simpler API.
+        """
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+
+        # Create a target by the debugger.
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Now create a breakpoint on main.c.
+        breakpoint = target.BreakpointCreateByLocation(self.source, self.line)
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
+        )
+
+        # Now launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple(None, None, self.get_process_working_directory())
+
+        # We should be stopped due to the breakpoint.  Get frame #0.
+        process = target.GetProcess()
+        self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        frame0 = thread.GetFrameAtIndex(0)
+
+        value = frame0.FindValue("g_char_ptr", lldb.eValueTypeVariableGlobal)
+        pointee = value.CreateValueFromAddress(
+            "pointee", value.GetValueAsUnsigned(0), value.GetType().GetPointeeType()
+        )
+        # Watch for write to *g_char_ptr.
+        error = lldb.SBError()
+        watch_read = False
+        watch_write = True
+        watchpoint = target.WatchAddress(
+            value.GetValueAsUnsigned(), 1, watch_read, watch_write, error
+        )
+        self.assertTrue(
+            value and watchpoint, "Successfully found the pointer and set a watchpoint"
+        )
+        self.DebugSBValue(value)
+        self.DebugSBValue(pointee)
+
+        # Hide stdout if not running with '-t' option.
+        if not self.TraceOn():
+            self.HideStdout()
+
+        print(watchpoint)
+
+        # Continue.  Expect the program to stop due to the variable being
+        # written to.
+        process.Continue()
+
+        if self.TraceOn():
+            lldbutil.print_stacktraces(process)
+
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonWatchpoint)
+        self.assertTrue(thread, "The thread stopped due to watchpoint")
+        self.DebugSBValue(value)
+        self.DebugSBValue(pointee)
+
+        self.expect(
+            lldbutil.print_stacktrace(thread, string_buffer=True),
+            exe=False,
+            substrs=[self.violating_func],
+        )
+
+        # This finishes our test.
+
     # No size constraint on MIPS for watches
     @skipIf(archs=["mips", "mipsel", "mips64", "mips64el"])
     @skipIf(archs=["s390x"])  # Likewise on SystemZ


        


More information about the lldb-commits mailing list