https://github.com/DavidSpickett created 
https://github.com/llvm/llvm-project/pull/218883

Follow up to #218819.

It was agreed in 
https://discourse.llvm.org/t/running-lldb-in-a-container/76801/1
that we would default to ALSR being on during the test
suite. This means people don't have to reconfigure their
systems to run our tests out of the box.

So we need to look before we run a test that needs to
disable ASLR.

Here I am adding a decorator to do that. It assumes it's
always allowed on MacOS and uses personality
(https://man7.org/linux/man-pages/man2/personality.2.html)
to check if we can change it on Linux.

Since we're calling personality on the test process,
this cannot be done for a remote target. We could go
launch a process but for the added complexity I didn't
think the extra coverage was worth it.

So "Not able to disable ASLR" is a bit of a simplification
because sometimes we might be able to but didn't check.

>From 20772b81312ff96b4f85a47251f5aea444b8d2b6 Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Tue, 25 Aug 2026 18:07:09 -0700
Subject: [PATCH 1/3] [lldb] When re-enabling a watchpoint, save the current
 bytes

A watchpoint holds the current byte values of the memory region
it is watching.  When we have a watchpoint in place and re-run,
the saved values are flushed.  If the user then re-enables that
watchpoint in the next Process launch, we need to collect the
current values again for the Watchpoint at that point.

The test depends on watching a byte range that does not change
across process launch.  On Darwin systems, macOS is the only one
that can disable ASLR.  I don't know if this test can be enabled
on Linux with the disable-ASLR process launch option.

rdar://184927603
---
 lldb/source/Breakpoint/Watchpoint.cpp         |  5 ++
 .../run-reenable-watchpoint/Makefile          |  3 ++
 .../TestRunReEnableWatchpoint.py              | 51 +++++++++++++++++++
 .../watchpoint/run-reenable-watchpoint/main.c |  7 +++
 4 files changed, 66 insertions(+)
 create mode 100644 
lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/Makefile
 create mode 100644 
lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
 create mode 100644 
lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c

diff --git a/lldb/source/Breakpoint/Watchpoint.cpp 
b/lldb/source/Breakpoint/Watchpoint.cpp
index e839c8b9f30e7..13bc2556a9b9c 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -421,6 +421,11 @@ void Watchpoint::SetEnabled(bool enabled, bool notify) {
   }
   bool changed = enabled != m_enabled;
   m_enabled = enabled;
+  if (enabled && !m_new_value_sp && m_target.GetProcessSP()) {
+    ExecutionContext exe_ctx;
+    m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+    CaptureWatchedValue(exe_ctx);
+  }
   if (notify && !m_is_ephemeral && changed)
     SendWatchpointChangedEvent(enabled ? eWatchpointEventTypeEnabled
                                        : eWatchpointEventTypeDisabled);
diff --git 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/Makefile 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
new file mode 100644
index 0000000000000..a380ac3f66d58
--- /dev/null
+++ 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
@@ -0,0 +1,51 @@
+"""
+Test that a watchpoint created in one Process can be
+re-enabled in a second Process launch and behave
+correctly.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class RunReEnableWatchpointTestCase(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()
+
+    # We must be able to launch the inferior with ASLR disabled
+    # so the static array lands at the same address after relaunch.
+    @skipUnlessPlatform(["macosx"])
+    def test_rerun_enable_watchpoint(self):
+        """Test set watchpoint, re-run, re-enable wp, hit it."""
+        self.build()
+        self.main_source_file = lldb.SBFileSpec("main.c")
+        li = lldb.SBLaunchInfo(None)
+        li.SetLaunchFlags(lldb.eLaunchFlagDisableASLR)
+        target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
+            self, "break here", self.main_source_file, launch_info=li
+        )
+
+        frame = thread.GetFrameAtIndex(0)
+        self.runCmd("watch set variable arr")
+
+        reason = self.continue_and_report_stop_reason(process, "continue 
first-launch")
+        self.assertEqual(reason, lldb.eStopReasonWatchpoint)
+
+        process.Kill()
+        self.runCmd("process launch --disable-aslr true")
+        process = target.GetProcess()
+        self.assertTrue(process.IsValid())
+
+        target.EnableAllWatchpoints()
+
+        reason = self.continue_and_report_stop_reason(process, "continue 
second-launch")
+        self.assertEqual(reason, lldb.eStopReasonWatchpoint)
diff --git 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c
new file mode 100644
index 0000000000000..35dfe48967755
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c
@@ -0,0 +1,7 @@
+static int arr[] = {1, 2, 0, 3, 4, 0x55555555};
+int main()
+{
+    arr[0]++; // break here
+    arr[0]++;
+    return arr[4];
+}

>From 0f600633b365102c54ca04626399d84e69868ead Mon Sep 17 00:00:00 2001
From: Jason Molenda <[email protected]>
Date: Tue, 25 Aug 2026 18:36:35 -0700
Subject: [PATCH 2/3] ws

---
 .../watchpoint/run-reenable-watchpoint/main.c            | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c
index 35dfe48967755..0969dd247bf74 100644
--- a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c
+++ b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/main.c
@@ -1,7 +1,6 @@
 static int arr[] = {1, 2, 0, 3, 4, 0x55555555};
-int main()
-{
-    arr[0]++; // break here
-    arr[0]++;
-    return arr[4];
+int main() {
+  arr[0]++; // break here
+  arr[0]++;
+  return arr[4];
 }

>From 0fa367adf12487f885f6cbd045b4dbd380964838 Mon Sep 17 00:00:00 2001
From: David Spickett <[email protected]>
Date: Wed, 26 Aug 2026 10:24:10 +0000
Subject: [PATCH 3/3] [lldb][test] Add requiresDisableASLR test decorator

Follow up to #218819.

It was agreed in 
https://discourse.llvm.org/t/running-lldb-in-a-container/76801/1
that we would default to ALSR being on during the test
suite. This means people don't have to reconfigure their
systems to run our tests out of the box.

So we need to look before we run a test that needs to
disable ASLR.

Here I am adding a decorator to do that. It assumes it's
always allowed on MacOS and uses personality
(https://man7.org/linux/man-pages/man2/personality.2.html)
to check if we can change it on Linux.

Since we're calling personality on the test process,
this cannot be done for a remote target. We could go
launch a process but for the added complexity I didn't
think the extra coverage was worth it.

So "Not able to disable ASLR" is a bit of a simplification
because sometimes we might be able to but didn't check.
---
 .../Python/lldbsuite/test/decorators.py       | 40 +++++++++++++++++++
 .../TestRunReEnableWatchpoint.py              |  2 +-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py 
b/lldb/packages/Python/lldbsuite/test/decorators.py
index 306eb20622746..6c02b56d2645f 100644
--- a/lldb/packages/Python/lldbsuite/test/decorators.py
+++ b/lldb/packages/Python/lldbsuite/test/decorators.py
@@ -1289,6 +1289,46 @@ def requireThreadSupport(func):
     )(func)
 
 
+def _can_disable_aslr():
+    original_persona = None
+    GET_CURRENT_PERSONA = 0xFFFFFFFF
+    ADDR_NO_RANDOMIZE = 0x0040000
+    ERR = -1
+
+    libc = ctypes.CDLL(None)
+    personality = libc.personality
+    personality.argtypes = [ctypes.c_ulong]
+    personality.restype = ctypes.c_int
+
+    try:
+        original_persona = personality(GET_CURRENT_PERSONA)
+        if original_persona == ERR:
+            return False
+
+        if personality(original_persona | ADDR_NO_RANDOMIZE) == ERR:
+            return False
+
+        new_persona = personality(GET_CURRENT_PERSONA)
+        if new_persona == ERR:
+            return False
+
+        return new_persona & ADDR_NO_RANDOMIZE
+    finally:
+        if original_persona is not None:
+            personality(original_persona)
+
+
+def requireDisableASLR(func):
+    platform = lldbplatformutil.getPlatform()
+    return unittest.skipIf(
+        platform != "macosx"
+        and not (
+            lldb.remote_platform is None and platform == "linux" and 
_can_disable_aslr()
+        ),
+        UnsupportedReason(f"Not able to disable ASLR"),
+    )(func)
+
+
 def skipIfTargetDoesNotSupportSharedLibraries():
     """Skip tests that require shared library (dylib/so) support."""
     platform = lldbplatformutil.getPlatform()
diff --git 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
index a380ac3f66d58..6b18e460dcb99 100644
--- 
a/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
+++ 
b/lldb/test/API/functionalities/watchpoint/run-reenable-watchpoint/TestRunReEnableWatchpoint.py
@@ -23,7 +23,7 @@ def continue_and_report_stop_reason(self, process, iter_str):
 
     # We must be able to launch the inferior with ASLR disabled
     # so the static array lands at the same address after relaunch.
-    @skipUnlessPlatform(["macosx"])
+    @requireDisableASLR
     def test_rerun_enable_watchpoint(self):
         """Test set watchpoint, re-run, re-enable wp, hit it."""
         self.build()

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to