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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits