[Lldb-commits] [lldb] LLDB: WatchAddress ignores modify option (PR #124847)
Ben Jackson via lldb-commits
lldb-commits at lists.llvm.org
Tue Jan 28 13:59:23 PST 2025
https://github.com/puremourning updated https://github.com/llvm/llvm-project/pull/124847
>From 3baafc236fb722a27799bd3abccb74e01656afab Mon Sep 17 00:00:00 2001
From: Ben Jackson <puremourning at gmail.com>
Date: Tue, 28 Jan 2025 21:47:24 +0000
Subject: [PATCH] LLDB: WatchAddress ignores modify option
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.
---
lldb/source/API/SBTarget.cpp | 4 +-
.../watchpoint/TestWatchpointRead.py | 130 ++++++++++++++++++
.../watchlocation/TestTargetWatchAddress.py | 71 +++++++++-
3 files changed, 203 insertions(+), 2 deletions(-)
create mode 100644 lldb/test/API/python_api/watchpoint/TestWatchpointRead.py
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 2a33161bc21edc..9192f0be1c85b9 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1342,7 +1342,9 @@ 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 00000000000000..21ba4760071276
--- /dev/null
+++ b/lldb/test/API/python_api/watchpoint/TestWatchpointRead.py
@@ -0,0 +1,130 @@
+"""
+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()
+
+
+ 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"
+ )
+
+ 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 cbab3c6382e431..7a0e42a4fc2781 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