[Lldb-commits] [lldb] 75e8620 - Reland "[lldb] Add 'modify' type watchpoints, make it default (#66308)"

David Spickett via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 21 03:35:41 PDT 2023


Author: David Spickett
Date: 2023-09-21T10:35:15Z
New Revision: 75e862077834c06e574d34e8958dd2ee7cc1d334

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

LOG: Reland "[lldb] Add 'modify' type watchpoints, make it default (#66308)"

This reverts commit a7b78cac9a77e3ef6bbbd8ab1a559891dc693401.

With updates to the tests.

TestWatchTaggedAddress.py: Updated the expected watchpoint types,
though I'm not sure there should be a differnt default for the two
ways of setting them, that needs to be confirmed.

TestStepOverWatchpoint.py: Skipped this everywhere because I think
what used to happen is you couldn't put 2 watchpoints on the same
address (after alignment). I guess that this is now allowed because
modify watchpoints aren't accounted for, but likely should be.
Needs investigating.

Added: 
    lldb/bindings/interface/SBWatchpointOptionsDocstrings.i
    lldb/include/lldb/API/SBWatchpointOptions.h
    lldb/source/API/SBWatchpointOptions.cpp
    lldb/test/API/functionalities/watchpoint/modify-watchpoints/Makefile
    lldb/test/API/functionalities/watchpoint/modify-watchpoints/TestModifyWatchpoint.py
    lldb/test/API/functionalities/watchpoint/modify-watchpoints/main.c

Modified: 
    lldb/bindings/headers.swig
    lldb/bindings/interfaces.swig
    lldb/include/lldb/API/SBTarget.h
    lldb/include/lldb/Breakpoint/Watchpoint.h
    lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
    lldb/include/lldb/lldb-defines.h
    lldb/include/lldb/lldb-enumerations.h
    lldb/include/lldb/lldb-forward.h
    lldb/source/API/CMakeLists.txt
    lldb/source/API/SBTarget.cpp
    lldb/source/API/SBValue.cpp
    lldb/source/API/SBWatchpoint.cpp
    lldb/source/Breakpoint/Watchpoint.cpp
    lldb/source/Commands/CommandObjectWatchpoint.cpp
    lldb/source/Interpreter/OptionGroupWatchpoint.cpp
    lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/source/Target/StopInfo.cpp
    lldb/source/Target/Target.cpp
    lldb/test/API/commands/watchpoints/multiple_hits/main.cpp
    lldb/test/API/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py
    lldb/test/API/commands/watchpoints/step_over_watchpoint/main.c
    lldb/test/API/commands/watchpoints/unaligned-watchpoint/main.c
    lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
    lldb/test/API/functionalities/gdb_remote_client/TestNoWatchpointSupportInfo.py
    lldb/test/API/functionalities/watchpoint/large-watchpoint/TestLargeWatchpoint.py
    lldb/test/API/functionalities/watchpoint/unaligned-spanning-two-dwords/TestUnalignedSpanningDwords.py
    lldb/test/API/python_api/default-constructor/sb_target.py
    lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py

Removed: 
    


################################################################################
diff  --git a/lldb/bindings/headers.swig b/lldb/bindings/headers.swig
index f7871765624dd31..d392ed43d8c0c9e 100644
--- a/lldb/bindings/headers.swig
+++ b/lldb/bindings/headers.swig
@@ -77,4 +77,5 @@
 #include "lldb/API/SBValueList.h"
 #include "lldb/API/SBVariablesOptions.h"
 #include "lldb/API/SBWatchpoint.h"
+#include "lldb/API/SBWatchpointOptions.h"
 %}

diff  --git a/lldb/bindings/interface/SBWatchpointOptionsDocstrings.i b/lldb/bindings/interface/SBWatchpointOptionsDocstrings.i
new file mode 100644
index 000000000000000..370bf95401dcb5e
--- /dev/null
+++ b/lldb/bindings/interface/SBWatchpointOptionsDocstrings.i
@@ -0,0 +1,12 @@
+%feature("docstring",
+"A container for options to use when creating watchpoints."
+) lldb::SBWatchpointOptions;
+
+%feature("docstring", "Sets whether the watchpoint should stop on read accesses."
+) lldb::SBWatchpointOptions::SetWatchpointTypeRead;
+%feature("docstring", "Gets whether the watchpoint should stop on read accesses."
+) lldb::SBWatchpointOptions::GetWatchpointTypeRead;
+%feature("docstring", "Sets whether the watchpoint should stop on write accesses. eWatchpointWriteTypeOnModify is the most commonly useful mode, where lldb will stop when the watched value has changed. eWatchpointWriteTypeAlways will stop on any write to the watched region, even if it's the value is the same."
+) lldb::SBWatchpointOptions::SetWatchpointTypeWrite;
+%feature("docstring", "Gets whether the watchpoint should stop on write accesses, returning WatchpointWriteType to indicate the type of write watching that is enabled, or eWatchpointWriteTypeDisabled."
+) lldb::SBWatchpointOptions::GetWatchpointTypeWrite;

diff  --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig
index 53f8fcc8145ac18..306cfe683893271 100644
--- a/lldb/bindings/interfaces.swig
+++ b/lldb/bindings/interfaces.swig
@@ -80,6 +80,7 @@
 %include "./interface/SBValueListDocstrings.i"
 %include "./interface/SBVariablesOptionsDocstrings.i"
 %include "./interface/SBWatchpointDocstrings.i"
+%include "./interface/SBWatchpointOptionsDocstrings.i"
 
 /* API headers */
 %include "lldb/API/SBAddress.h"
@@ -152,6 +153,7 @@
 %include "lldb/API/SBValueList.h"
 %include "lldb/API/SBVariablesOptions.h"
 %include "lldb/API/SBWatchpoint.h"
+%include "lldb/API/SBWatchpointOptions.h"
 
 /* Extensions for SB classes */
 %include "./interface/SBAddressExtensions.i"

diff  --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 07bd6a8b76d2f19..83087623088c5b4 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -21,6 +21,7 @@
 #include "lldb/API/SBType.h"
 #include "lldb/API/SBValue.h"
 #include "lldb/API/SBWatchpoint.h"
+#include "lldb/API/SBWatchpointOptions.h"
 
 namespace lldb_private {
 namespace python {
@@ -828,8 +829,13 @@ class LLDB_API SBTarget {
 
   lldb::SBWatchpoint FindWatchpointByID(lldb::watch_id_t watch_id);
 
+  LLDB_DEPRECATED("WatchAddress deprecated, use WatchpointCreateByAddress")
   lldb::SBWatchpoint WatchAddress(lldb::addr_t addr, size_t size, bool read,
-                                  bool write, SBError &error);
+                                  bool modify, SBError &error);
+
+  lldb::SBWatchpoint
+  WatchpointCreateByAddress(lldb::addr_t addr, size_t size,
+                            lldb::SBWatchpointOptions options, SBError &error);
 
   bool EnableAllWatchpoints();
 

diff  --git a/lldb/include/lldb/API/SBWatchpointOptions.h b/lldb/include/lldb/API/SBWatchpointOptions.h
new file mode 100644
index 000000000000000..5d1d6ab9e09fff6
--- /dev/null
+++ b/lldb/include/lldb/API/SBWatchpointOptions.h
@@ -0,0 +1,43 @@
+//===-- SBWatchpointOptions.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_API_SBWATCHPOINTOPTIONS_H
+#define LLDB_API_SBWATCHPOINTOPTIONS_H
+
+#include "lldb/API/SBDefines.h"
+
+class WatchpointOptionsImpl;
+
+namespace lldb {
+
+class LLDB_API SBWatchpointOptions {
+public:
+  SBWatchpointOptions();
+
+  SBWatchpointOptions(const lldb::SBWatchpointOptions &rhs);
+
+  ~SBWatchpointOptions();
+
+  const SBWatchpointOptions &operator=(const lldb::SBWatchpointOptions &rhs);
+
+  /// Stop when the watched memory region is read.
+  void SetWatchpointTypeRead(bool read);
+  bool GetWatchpointTypeRead() const;
+
+  /// Stop when the watched memory region is written to/modified
+  void SetWatchpointTypeWrite(lldb::WatchpointWriteType write_type);
+  lldb::WatchpointWriteType GetWatchpointTypeWrite() const;
+
+private:
+  // This auto_pointer is made in the constructor and is always valid.
+  mutable std::unique_ptr<WatchpointOptionsImpl> m_opaque_up;
+};
+
+} // namespace lldb
+
+#endif // LLDB_API_SBWATCHPOINTOPTIONS_H

diff  --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h
index 8fde3b563a3f064..c86d66663c7f8c0 100644
--- a/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -76,12 +76,14 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
   
   bool WatchpointRead() const;
   bool WatchpointWrite() const;
+  bool WatchpointModify() const;
   uint32_t GetIgnoreCount() const;
   void SetIgnoreCount(uint32_t n);
   void SetWatchpointType(uint32_t type, bool notify = true);
   void SetDeclInfo(const std::string &str);
   std::string GetWatchSpec();
   void SetWatchSpec(const std::string &str);
+  bool WatchedValueReportable(const ExecutionContext &exe_ctx);
 
   // Snapshot management interface.
   bool IsWatchVariable() const;
@@ -212,7 +214,8 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
   // again, we check the count, if it is more than 1, it means the user-
   // supplied actions actually want the watchpoint to be disabled!
   uint32_t m_watch_read : 1, // 1 if we stop when the watched data is read from
-      m_watch_write : 1;     // 1 if we stop when the watched data is written to
+      m_watch_write : 1,     // 1 if we stop when the watched data is written to
+      m_watch_modify : 1;    // 1 if we stop when the watched data is changed
   uint32_t m_ignore_count;      // Number of times to ignore this watchpoint
   std::string m_decl_str;       // Declaration information, if any.
   std::string m_watch_spec_str; // Spec for the watchpoint.

diff  --git a/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h b/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
index 201ab1d134f2554..f009fa145f30344 100644
--- a/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
+++ b/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
@@ -30,13 +30,15 @@ class OptionGroupWatchpoint : public OptionGroup {
 
   void OptionParsingStarting(ExecutionContext *execution_context) override;
 
-  // Note:
-  // eWatchRead == LLDB_WATCH_TYPE_READ; and
-  // eWatchWrite == LLDB_WATCH_TYPE_WRITE
+  /// eWatchRead == LLDB_WATCH_TYPE_READ
+  /// eWatchWrite == LLDB_WATCH_TYPE_WRITE
+  /// eWatchModify == LLDB_WATCH_TYPE_MODIFY
+  /// eWatchReadWrite == LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE
   enum WatchType {
     eWatchInvalid = 0,
     eWatchRead,
     eWatchWrite,
+    eWatchModify,
     eWatchReadWrite
   };
 

diff  --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index 5e43f55224f5202..ce7fd6f3754516e 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -44,8 +44,10 @@
 #define LLDB_WATCH_ID_IS_VALID(uid) ((uid) != (LLDB_INVALID_WATCH_ID))
 #define LLDB_WATCH_TYPE_READ (1u << 0)
 #define LLDB_WATCH_TYPE_WRITE (1u << 1)
+#define LLDB_WATCH_TYPE_MODIFY (1u << 2)
 #define LLDB_WATCH_TYPE_IS_VALID(type)                                         \
-  ((type & LLDB_WATCH_TYPE_READ) || (type & LLDB_WATCH_TYPE_WRITE))
+  ((type & LLDB_WATCH_TYPE_READ) || (type & LLDB_WATCH_TYPE_WRITE) ||          \
+   (type & LLDB_WATCH_TYPE_MODIFY))
 
 // Generic Register Numbers
 #define LLDB_REGNUM_GENERIC_PC 0    // Program Counter

diff  --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 21e098481ce8022..36f3030c5226d60 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -431,6 +431,21 @@ FLAGS_ENUM(WatchpointEventType){
     eWatchpointEventTypeThreadChanged = (1u << 11),
     eWatchpointEventTypeTypeChanged = (1u << 12)};
 
+enum WatchpointWriteType {
+  /// Don't stop when the watched memory region is written to.
+  eWatchpointWriteTypeDisabled,
+  /// Stop on any write access to the memory region, even if
+  /// the value doesn't change.  On some architectures, a write
+  /// near the memory region may be falsely reported as a match,
+  /// and notify this spurious stop as a watchpoint trap.
+  eWatchpointWriteTypeAlways,
+  /// Stop on a write to the memory region that changes its value.
+  /// This is most likely the behavior a user expects, and is the
+  /// behavior in gdb.  lldb can silently ignore writes near the
+  /// watched memory region that are reported as accesses to lldb.
+  eWatchpointWriteTypeOnModify
+};
+
 /// Programming language type.
 ///
 /// These enumerations use the same language enumerations as the DWARF

diff  --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index c159d82911a04ad..3cd71c8a4ba3c0a 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -284,6 +284,7 @@ class VariableList;
 class Watchpoint;
 class WatchpointList;
 class WatchpointOptions;
+class WatchpointSetOptions;
 struct CompilerContext;
 struct LineEntry;
 struct PropertyDefinition;

diff  --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index 39ac451c471c5d8..910cb667e16b708 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -91,6 +91,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
   SBValueList.cpp
   SBVariablesOptions.cpp
   SBWatchpoint.cpp
+  SBWatchpointOptions.cpp
   SBUnixSignals.cpp
   SystemInitializerFull.cpp
   ${lldb_python_wrapper}

diff  --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index e38edf8e44652e6..a4a7ac338c20768 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1322,27 +1322,39 @@ SBWatchpoint SBTarget::FindWatchpointByID(lldb::watch_id_t wp_id) {
 }
 
 lldb::SBWatchpoint SBTarget::WatchAddress(lldb::addr_t addr, size_t size,
-                                          bool read, bool write,
+                                          bool read, bool modify,
                                           SBError &error) {
   LLDB_INSTRUMENT_VA(this, addr, size, read, write, error);
 
+  SBWatchpointOptions options;
+  options.SetWatchpointTypeRead(read);
+  options.SetWatchpointTypeWrite(eWatchpointWriteTypeOnModify);
+  return WatchpointCreateByAddress(addr, size, options, error);
+}
+
+lldb::SBWatchpoint
+SBTarget::WatchpointCreateByAddress(lldb::addr_t addr, size_t size,
+                                    SBWatchpointOptions options,
+                                    SBError &error) {
+  LLDB_INSTRUMENT_VA(this, addr, size, options, error);
+
   SBWatchpoint sb_watchpoint;
   lldb::WatchpointSP watchpoint_sp;
   TargetSP target_sp(GetSP());
-  if (target_sp && (read || write) && addr != LLDB_INVALID_ADDRESS &&
-      size > 0) {
+  uint32_t watch_type = 0;
+  if (options.GetWatchpointTypeRead())
+    watch_type |= LLDB_WATCH_TYPE_READ;
+  if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeAlways)
+    watch_type |= LLDB_WATCH_TYPE_WRITE;
+  if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeOnModify)
+    watch_type |= LLDB_WATCH_TYPE_MODIFY;
+  if (watch_type == 0) {
+    error.SetErrorString("Can't create a watchpoint that is neither read nor "
+                         "write nor modify.");
+    return sb_watchpoint;
+  }
+  if (target_sp && addr != LLDB_INVALID_ADDRESS && size > 0) {
     std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
-    uint32_t watch_type = 0;
-    if (read)
-      watch_type |= LLDB_WATCH_TYPE_READ;
-    if (write)
-      watch_type |= LLDB_WATCH_TYPE_WRITE;
-    if (watch_type == 0) {
-      error.SetErrorString(
-          "Can't create a watchpoint that is neither read nor write.");
-      return sb_watchpoint;
-    }
-
     // Target::CreateWatchpoint() is thread safe.
     Status cw_error;
     // This API doesn't take in a type, so we can't figure out what it is.

diff  --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index 738773c93c49b03..e14f1196c6316b9 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -1433,10 +1433,17 @@ lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, bool write,
       return sb_watchpoint;
 
     uint32_t watch_type = 0;
-    if (read)
+    if (read) {
       watch_type |= LLDB_WATCH_TYPE_READ;
-    if (write)
-      watch_type |= LLDB_WATCH_TYPE_WRITE;
+      // read + write, the most likely intention
+      // is to catch all writes to this, not just
+      // value modifications.
+      if (write)
+        watch_type |= LLDB_WATCH_TYPE_WRITE;
+    } else {
+      if (write)
+        watch_type |= LLDB_WATCH_TYPE_MODIFY;
+    }
 
     Status rc;
     CompilerType type(value_sp->GetCompilerType());

diff  --git a/lldb/source/API/SBWatchpoint.cpp b/lldb/source/API/SBWatchpoint.cpp
index 6a63e65956bc434..8b4e0ad3178b182 100644
--- a/lldb/source/API/SBWatchpoint.cpp
+++ b/lldb/source/API/SBWatchpoint.cpp
@@ -354,7 +354,8 @@ bool SBWatchpoint::IsWatchingWrites() {
     std::lock_guard<std::recursive_mutex> guard(
         watchpoint_sp->GetTarget().GetAPIMutex());
 
-    return watchpoint_sp->WatchpointWrite();
+    return watchpoint_sp->WatchpointWrite() ||
+           watchpoint_sp->WatchpointModify();
   }
 
   return false;

diff  --git a/lldb/source/API/SBWatchpointOptions.cpp b/lldb/source/API/SBWatchpointOptions.cpp
new file mode 100644
index 000000000000000..62e9c21a857957d
--- /dev/null
+++ b/lldb/source/API/SBWatchpointOptions.cpp
@@ -0,0 +1,73 @@
+//===-- SBWatchpointOptions.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBWatchpointOptions.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Utility/Instrumentation.h"
+
+#include "Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class WatchpointOptionsImpl {
+public:
+  bool m_read = false;
+  bool m_write = false;
+  bool m_modify = false;
+};
+
+
+SBWatchpointOptions::SBWatchpointOptions()
+    : m_opaque_up(new WatchpointOptionsImpl()) {
+  LLDB_INSTRUMENT_VA(this);
+}
+
+SBWatchpointOptions::SBWatchpointOptions(const SBWatchpointOptions &rhs) {
+  LLDB_INSTRUMENT_VA(this, rhs);
+
+  m_opaque_up = clone(rhs.m_opaque_up);
+}
+
+const SBWatchpointOptions &
+SBWatchpointOptions::operator=(const SBWatchpointOptions &rhs) {
+  LLDB_INSTRUMENT_VA(this, rhs);
+
+  if (this != &rhs)
+    m_opaque_up = clone(rhs.m_opaque_up);
+  return *this;
+}
+
+SBWatchpointOptions::~SBWatchpointOptions() = default;
+
+void SBWatchpointOptions::SetWatchpointTypeRead(bool read) {
+  m_opaque_up->m_read = read;
+}
+bool SBWatchpointOptions::GetWatchpointTypeRead() const {
+  return m_opaque_up->m_read;
+}
+
+void SBWatchpointOptions::SetWatchpointTypeWrite(
+    WatchpointWriteType write_type) {
+  if (write_type == eWatchpointWriteTypeOnModify) {
+    m_opaque_up->m_write = false;
+    m_opaque_up->m_modify = true;
+  } else if (write_type == eWatchpointWriteTypeAlways) {
+    m_opaque_up->m_write = true;
+    m_opaque_up->m_modify = false;
+  } else
+    m_opaque_up->m_write = m_opaque_up->m_modify = false;
+}
+
+WatchpointWriteType SBWatchpointOptions::GetWatchpointTypeWrite() const {
+  if (m_opaque_up->m_modify)
+    return eWatchpointWriteTypeOnModify;
+  if (m_opaque_up->m_write)
+    return eWatchpointWriteTypeAlways;
+  return eWatchpointWriteTypeDisabled;
+}

diff  --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index f88e899eb711fed..14144214faea747 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -29,7 +29,8 @@ Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size,
     : StoppointSite(0, addr, size, hardware), m_target(target),
       m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false),
       m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0),
-      m_watch_write(0), m_ignore_count(0), m_being_created(true) {
+      m_watch_write(0), m_watch_modify(0), m_ignore_count(0),
+      m_being_created(true) {
 
   if (type && type->IsValid())
     m_type = *type;
@@ -193,7 +194,7 @@ bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; }
 void Watchpoint::SetWatchVariable(bool val) { m_is_watch_variable = val; }
 
 bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
-  ConstString watch_name("$__lldb__watch_value");
+  ConstString g_watch_name("$__lldb__watch_value");
   m_old_value_sp = m_new_value_sp;
   Address watch_address(GetLoadAddress());
   if (!m_type.IsValid()) {
@@ -205,12 +206,47 @@ bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) {
     return false;
   }
   m_new_value_sp = ValueObjectMemory::Create(
-      exe_ctx.GetBestExecutionContextScope(), watch_name.GetStringRef(),
+      exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
       watch_address, m_type);
-  m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+  m_new_value_sp = m_new_value_sp->CreateConstantValue(g_watch_name);
   return (m_new_value_sp && m_new_value_sp->GetError().Success());
 }
 
+bool Watchpoint::WatchedValueReportable(const ExecutionContext &exe_ctx) {
+  if (!m_watch_modify || m_watch_read)
+    return true;
+  if (!m_type.IsValid())
+    return true;
+
+  ConstString g_watch_name("$__lldb__watch_value");
+  Address watch_address(GetLoadAddress());
+  ValueObjectSP newest_valueobj_sp = ValueObjectMemory::Create(
+      exe_ctx.GetBestExecutionContextScope(), g_watch_name.GetStringRef(),
+      watch_address, m_type);
+  newest_valueobj_sp = newest_valueobj_sp->CreateConstantValue(g_watch_name);
+  Status error;
+
+  DataExtractor new_data;
+  DataExtractor old_data;
+
+  newest_valueobj_sp->GetData(new_data, error);
+  if (error.Fail())
+    return true;
+  m_new_value_sp->GetData(old_data, error);
+  if (error.Fail())
+    return true;
+
+  if (new_data.GetByteSize() != old_data.GetByteSize() ||
+      new_data.GetByteSize() == 0)
+    return true;
+
+  if (memcmp(new_data.GetDataStart(), old_data.GetDataStart(),
+             old_data.GetByteSize()) == 0)
+    return false; // Value has not changed, user requested modify watchpoint
+
+  return true;
+}
+
 // RETURNS - true if we should stop at this breakpoint, false if we
 // should continue.
 
@@ -268,10 +304,10 @@ void Watchpoint::DumpWithLevel(Stream *s,
          description_level <= lldb::eDescriptionLevelVerbose);
 
   s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64
-            " size = %u state = %s type = %s%s",
+            " size = %u state = %s type = %s%s%s",
             GetID(), GetLoadAddress(), m_byte_size,
             IsEnabled() ? "enabled" : "disabled", m_watch_read ? "r" : "",
-            m_watch_write ? "w" : "");
+            m_watch_write ? "w" : "", m_watch_modify ? "m" : "");
 
   if (description_level >= lldb::eDescriptionLevelFull) {
     if (!m_decl_str.empty())
@@ -333,10 +369,13 @@ void Watchpoint::SetEnabled(bool enabled, bool notify) {
 void Watchpoint::SetWatchpointType(uint32_t type, bool notify) {
   int old_watch_read = m_watch_read;
   int old_watch_write = m_watch_write;
+  int old_watch_modify = m_watch_modify;
   m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
   m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+  m_watch_modify = (type & LLDB_WATCH_TYPE_MODIFY) != 0;
   if (notify &&
-      (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
+      (old_watch_read != m_watch_read || old_watch_write != m_watch_write ||
+       old_watch_modify != m_watch_modify))
     SendWatchpointChangedEvent(eWatchpointEventTypeTypeChanged);
 }
 
@@ -344,6 +383,8 @@ bool Watchpoint::WatchpointRead() const { return m_watch_read != 0; }
 
 bool Watchpoint::WatchpointWrite() const { return m_watch_write != 0; }
 
+bool Watchpoint::WatchpointModify() const { return m_watch_modify != 0; }
+
 uint32_t Watchpoint::GetIgnoreCount() const { return m_ignore_count; }
 
 void Watchpoint::SetIgnoreCount(uint32_t n) {

diff  --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index a4929ea0d5159ac..83c2fb824bb9d3d 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -803,7 +803,7 @@ class CommandObjectWatchpointSetVariable : public CommandObjectParsed {
             "Set a watchpoint on a variable. "
             "Use the '-w' option to specify the type of watchpoint and "
             "the '-s' option to specify the byte size to watch for. "
-            "If no '-w' option is specified, it defaults to write. "
+            "If no '-w' option is specified, it defaults to modify. "
             "If no '-s' option is specified, it defaults to the variable's "
             "byte size. "
             "Note that there are limited hardware resources for watchpoints. "
@@ -878,9 +878,9 @@ corresponding to the byte size of the data type.");
       return false;
     }
 
-    // If no '-w' is specified, default to '-w write'.
+    // If no '-w' is specified, default to '-w modify'.
     if (!m_option_watchpoint.watch_type_specified) {
-      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchModify;
     }
 
     // We passed the sanity check for the command. Proceed to set the
@@ -947,7 +947,23 @@ corresponding to the byte size of the data type.");
     }
 
     // Now it's time to create the watchpoint.
-    uint32_t watch_type = m_option_watchpoint.watch_type;
+    uint32_t watch_type = 0;
+    switch (m_option_watchpoint.watch_type) {
+    case OptionGroupWatchpoint::eWatchModify:
+      watch_type |= LLDB_WATCH_TYPE_MODIFY;
+      break;
+    case OptionGroupWatchpoint::eWatchRead:
+      watch_type |= LLDB_WATCH_TYPE_READ;
+      break;
+    case OptionGroupWatchpoint::eWatchReadWrite:
+      watch_type |= LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE;
+      break;
+    case OptionGroupWatchpoint::eWatchWrite:
+      watch_type |= LLDB_WATCH_TYPE_WRITE;
+      break;
+    case OptionGroupWatchpoint::eWatchInvalid:
+      break;
+    };
 
     error.Clear();
     WatchpointSP watch_sp =
@@ -999,7 +1015,7 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
             "Use the '-l' option to specify the language of the expression. "
             "Use the '-w' option to specify the type of watchpoint and "
             "the '-s' option to specify the byte size to watch for. "
-            "If no '-w' option is specified, it defaults to write. "
+            "If no '-w' option is specified, it defaults to modify. "
             "If no '-s' option is specified, it defaults to the target's "
             "pointer byte size. "
             "Note that there are limited hardware resources for watchpoints. "
@@ -1013,7 +1029,7 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
         R"(
 Examples:
 
-(lldb) watchpoint set expression -w write -s 1 -- foo + 32
+(lldb) watchpoint set expression -w modify -s 1 -- foo + 32
 
     Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
 
@@ -1073,7 +1089,7 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
 
     // If no '-w' is specified, default to '-w write'.
     if (!m_option_watchpoint.watch_type_specified) {
-      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+      m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchModify;
     }
 
     // We passed the sanity check for the command. Proceed to set the

diff  --git a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
index c2f78d8c2dd14a1..c3708e7a1e80fd2 100644
--- a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -27,6 +27,11 @@ static constexpr OptionEnumValueElement g_watch_type[] = {
         "write",
         "Watch for write",
     },
+    {
+        OptionGroupWatchpoint::eWatchModify,
+        "modify",
+        "Watch for modifications",
+    },
     {
         OptionGroupWatchpoint::eWatchReadWrite,
         "read_write",

diff  --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 4d489f1ac947d73..56fc5490657ea71 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3109,14 +3109,16 @@ static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) {
   assert(wp);
   bool watch_read = wp->WatchpointRead();
   bool watch_write = wp->WatchpointWrite();
+  bool watch_modify = wp->WatchpointModify();
 
-  // watch_read and watch_write cannot both be false.
-  assert(watch_read || watch_write);
-  if (watch_read && watch_write)
+  // watch_read, watch_write, watch_modify cannot all be false.
+  assert((watch_read || watch_write || watch_modify) &&
+         "watch_read, watch_write, watch_modify cannot all be false.");
+  if (watch_read && (watch_write || watch_modify))
     return eWatchpointReadWrite;
   else if (watch_read)
     return eWatchpointRead;
-  else // Must be watch_write, then.
+  else // Must be watch_write or watch_modify, then.
     return eWatchpointWrite;
 }
 

diff  --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index ff3d8f68833c827..a189f4be1926a6f 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -982,6 +982,12 @@ class StopInfoWatchpoint : public StopInfo {
             m_should_stop = false;
           }
         }
+
+        // Don't stop if the watched region value is unmodified, and
+        // this is a Modify-type watchpoint.
+        if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx))
+          m_should_stop = false;
+
         // Finally, if we are going to stop, print out the new & old values:
         if (m_should_stop) {
           wp_sp->CaptureWatchedValue(exe_ctx);

diff  --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 8de4fd033ec8785..f197b1b1aa097c3 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -860,7 +860,8 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
     size_t old_size = matched_sp->GetByteSize();
     uint32_t old_type =
         (matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) |
-        (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0);
+        (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0) |
+        (matched_sp->WatchpointModify() ? LLDB_WATCH_TYPE_MODIFY : 0);
     // Return the existing watchpoint if both size and type match.
     if (size == old_size && kind == old_type) {
       wp_sp = matched_sp;

diff  --git a/lldb/test/API/commands/watchpoints/multiple_hits/main.cpp b/lldb/test/API/commands/watchpoints/multiple_hits/main.cpp
index c8ce8a018869156..f3596f21fa2130b 100644
--- a/lldb/test/API/commands/watchpoints/multiple_hits/main.cpp
+++ b/lldb/test/API/commands/watchpoints/multiple_hits/main.cpp
@@ -1,5 +1,6 @@
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <string.h>
 alignas(16) uint8_t buf[32];
 // This uses inline assembly to generate an instruction that writes to a large
 // block of memory. If it fails on your compiler/architecture, please add
@@ -8,6 +9,7 @@ alignas(16) uint8_t buf[32];
 // this test.
 
 int main() {
+  memset(buf, UINT32_MAX, 8);
 #if defined(__i386__) || defined(__x86_64__)
   asm volatile ("movdqa %%xmm0, %0" : : "m"(buf));
 #elif defined(__arm__)

diff  --git a/lldb/test/API/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py b/lldb/test/API/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py
index c2eb6fb0bd8a0f8..7d4be91bb4fbdb1 100644
--- a/lldb/test/API/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py
+++ b/lldb/test/API/commands/watchpoints/step_over_watchpoint/TestStepOverWatchpoint.py
@@ -49,6 +49,8 @@ def test_step_over(self):
         )
         self.assertEquals(thread.GetStopDescription(20), "watchpoint 1")
 
+    # Skip everywhere while modify watchpoints are sorted out.
+    @skipTestIfFn(lambda : True)
     @expectedFailureAll(
         oslist=["freebsd", "linux"],
         archs=["aarch64", "arm"],

diff  --git a/lldb/test/API/commands/watchpoints/step_over_watchpoint/main.c b/lldb/test/API/commands/watchpoints/step_over_watchpoint/main.c
index e48d43cb7a9745b..f1831c5c5a18b66 100644
--- a/lldb/test/API/commands/watchpoints/step_over_watchpoint/main.c
+++ b/lldb/test/API/commands/watchpoints/step_over_watchpoint/main.c
@@ -1,6 +1,6 @@
-char g_watch_me_read;
-char g_watch_me_write;
-char g_temp;
+long g_watch_me_read = 1;
+long g_watch_me_write = 2;
+long g_temp = 3;
 
 void watch_read() {
     g_temp = g_watch_me_read;
@@ -14,6 +14,6 @@ int main() {
     watch_read(); // Set a breakpoint here
     g_temp = g_watch_me_read; // Set breakpoint after call
     watch_write();
-    g_watch_me_write = g_temp;
+    g_watch_me_write = g_temp + 1;
     return 0;
 }

diff  --git a/lldb/test/API/commands/watchpoints/unaligned-watchpoint/main.c b/lldb/test/API/commands/watchpoints/unaligned-watchpoint/main.c
index b071346e933a501..78a4e793cb328ae 100644
--- a/lldb/test/API/commands/watchpoints/unaligned-watchpoint/main.c
+++ b/lldb/test/API/commands/watchpoints/unaligned-watchpoint/main.c
@@ -5,7 +5,9 @@ int main() {
     uint8_t buf[8];
     uint64_t val;
   } a;
-  a.val = 0; // break here
+  a.val = 0;
+  puts ("ready to loop"); // break here
+  a.val = UINT64_MAX;
   for (int i = 0; i < 5; i++) {
     a.val = i;
     printf("a.val is %lu\n", a.val);

diff  --git a/lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py b/lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
index 6369a3034b810ab..336938082d83536 100644
--- a/lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
+++ b/lldb/test/API/commands/watchpoints/watch_tagged_addr/TestWatchTaggedAddress.py
@@ -62,7 +62,7 @@ def test_watch_hit_tagged_ptr_access(self):
             substrs=[
                 "Watchpoint created",
                 "size = 4",
-                "type = w",
+                "type = m",
                 "%s:%d" % (self.source, self.decl),
             ],
         )
@@ -96,7 +96,7 @@ def test_watch_set_on_tagged_ptr(self):
         self.expect(
             "watchpoint set expression -s 4 -- tagged_ptr",
             WATCHPOINT_CREATED,
-            substrs=["Watchpoint created", "size = 4", "type = w"],
+            substrs=["Watchpoint created", "size = 4", "type = rw"],
         )
 
         self.verify_watch_hits()

diff  --git a/lldb/test/API/functionalities/gdb_remote_client/TestNoWatchpointSupportInfo.py b/lldb/test/API/functionalities/gdb_remote_client/TestNoWatchpointSupportInfo.py
index aaf4ef3e52c706a..a51b228e917cc7a 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestNoWatchpointSupportInfo.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestNoWatchpointSupportInfo.py
@@ -58,7 +58,9 @@ def qXferRead(self, obj, annex, offset, length):
             print(result.GetOutput())
 
         err = lldb.SBError()
-        wp = target.WatchAddress(0x100, 8, False, True, err)
+        wp_opts = lldb.SBWatchpointOptions()
+        wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+        wp = target.WatchpointCreateByAddress(0x100, 8, wp_opts, err)
         if self.TraceOn() and (err.Fail() or wp.IsValid == False):
             strm = lldb.SBStream()
             err.GetDescription(strm)

diff  --git a/lldb/test/API/functionalities/watchpoint/large-watchpoint/TestLargeWatchpoint.py b/lldb/test/API/functionalities/watchpoint/large-watchpoint/TestLargeWatchpoint.py
index 07895c192ec1b0e..c5e161497e6281d 100644
--- a/lldb/test/API/functionalities/watchpoint/large-watchpoint/TestLargeWatchpoint.py
+++ b/lldb/test/API/functionalities/watchpoint/large-watchpoint/TestLargeWatchpoint.py
@@ -45,7 +45,9 @@ def test_large_watchpoint(self):
         # to a 1024 byte boundary to begin with, force alignment.
         wa_256_addr = (array_addr + 1024) & ~(1024 - 1)
         err = lldb.SBError()
-        wp = target.WatchAddress(wa_256_addr, 1024, False, True, err)
+        wp_opts = lldb.SBWatchpointOptions()
+        wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+        wp = target.WatchpointCreateByAddress(wa_256_addr, 1024, wp_opts, err)
         self.assertTrue(wp.IsValid())
         self.assertSuccess(err)
 

diff  --git a/lldb/test/API/functionalities/watchpoint/modify-watchpoints/Makefile b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/Makefile
new file mode 100644
index 000000000000000..10495940055b63d
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules

diff  --git a/lldb/test/API/functionalities/watchpoint/modify-watchpoints/TestModifyWatchpoint.py b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/TestModifyWatchpoint.py
new file mode 100644
index 000000000000000..b581969208da50a
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/TestModifyWatchpoint.py
@@ -0,0 +1,40 @@
+"""
+Confirm that lldb modify watchpoints only stop
+when the value being watched changes.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+ at skipIfWindows
+class ModifyWatchpointTestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_modify_watchpoint(self):
+        """Test that a modify watchpoint only stops when the value changes."""
+        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
+        )
+
+        self.runCmd("watch set variable value")
+        process.Continue()
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+        self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 10)
+
+        process.Continue()
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+        self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 5)
+
+        process.Continue()
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+        self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 7)
+
+        process.Continue()
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+        self.assertEqual(frame.locals["value"][0].GetValueAsUnsigned(), 9)

diff  --git a/lldb/test/API/functionalities/watchpoint/modify-watchpoints/main.c b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/main.c
new file mode 100644
index 000000000000000..819c96c15fb0815
--- /dev/null
+++ b/lldb/test/API/functionalities/watchpoint/modify-watchpoints/main.c
@@ -0,0 +1,20 @@
+#include <stdint.h>
+int main() {
+  int value = 5;
+
+  value = 5; // break here
+  value = 5;
+  value = 5;
+  value = 5;
+  value = 5;
+  value = 5;
+  value = 10;
+  value = 10;
+  value = 10;
+  value = 10;
+  value = 5;
+  value = 7;
+  value = 9;
+
+  return value;
+}

diff  --git a/lldb/test/API/functionalities/watchpoint/unaligned-spanning-two-dwords/TestUnalignedSpanningDwords.py b/lldb/test/API/functionalities/watchpoint/unaligned-spanning-two-dwords/TestUnalignedSpanningDwords.py
index f6f171460ff2ecc..9a0f451c64c3026 100644
--- a/lldb/test/API/functionalities/watchpoint/unaligned-spanning-two-dwords/TestUnalignedSpanningDwords.py
+++ b/lldb/test/API/functionalities/watchpoint/unaligned-spanning-two-dwords/TestUnalignedSpanningDwords.py
@@ -48,7 +48,9 @@ def test_unaligned_watchpoint(self):
         a_bytebuf_6 = frame.GetValueForVariablePath("a.bytebuf[6]")
         a_bytebuf_6_addr = a_bytebuf_6.GetAddress().GetLoadAddress(target)
         err = lldb.SBError()
-        wp = target.WatchAddress(a_bytebuf_6_addr, 4, False, True, err)
+        wp_opts = lldb.SBWatchpointOptions()
+        wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+        wp = target.WatchpointCreateByAddress(a_bytebuf_6_addr, 4, wp_opts, err)
         self.assertTrue(err.Success())
         self.assertTrue(wp.IsEnabled())
         self.assertEqual(wp.GetWatchSize(), 4)

diff  --git a/lldb/test/API/python_api/default-constructor/sb_target.py b/lldb/test/API/python_api/default-constructor/sb_target.py
index 2ba72d39f91016c..1acf1024a0d91dd 100644
--- a/lldb/test/API/python_api/default-constructor/sb_target.py
+++ b/lldb/test/API/python_api/default-constructor/sb_target.py
@@ -53,7 +53,10 @@ def fuzz_obj(obj):
     obj.GetByteOrder()
     obj.GetTriple()
     error = lldb.SBError()
-    obj.WatchAddress(123, 8, True, True, error)
+    wp_opts = lldb.SBWatchpointOptions()
+    wp_opts.SetWatchpointTypeRead(True)
+    wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+    obj.WatchpointCreateByAddress(123, 8, wp_opts, error)
     obj.GetBroadcaster()
     obj.GetDescription(lldb.SBStream(), lldb.eDescriptionLevelBrief)
     obj.Clear()

diff  --git a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
index 79124b3991e7d1a..bf31819d4070de6 100644
--- a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
+++ b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
@@ -1,5 +1,5 @@
 """
-Use lldb Python SBtarget.WatchAddress() API to create a watchpoint for write of '*g_char_ptr'.
+Use lldb Python SBtarget.WatchpointCreateByAddress() API to create a watchpoint for write of '*g_char_ptr'.
 """
 
 import lldb
@@ -8,7 +8,7 @@
 from lldbsuite.test import lldbutil
 
 
-class TargetWatchAddressAPITestCase(TestBase):
+class TargetWatchpointCreateByAddressPITestCase(TestBase):
     NO_DEBUG_INFO_TESTCASE = True
 
     def setUp(self):
@@ -22,7 +22,7 @@ def setUp(self):
         self.violating_func = "do_bad_thing_with_location"
 
     def test_watch_address(self):
-        """Exercise SBTarget.WatchAddress() API to set a watchpoint."""
+        """Exercise SBTarget.WatchpointCreateByAddress() API to set a watchpoint."""
         self.build()
         exe = self.getBuildArtifact("a.out")
 
@@ -51,8 +51,10 @@ def test_watch_address(self):
         )
         # Watch for write to *g_char_ptr.
         error = lldb.SBError()
-        watchpoint = target.WatchAddress(
-            value.GetValueAsUnsigned(), 1, False, True, error
+        wp_opts = lldb.SBWatchpointOptions()
+        wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+        watchpoint = target.WatchpointCreateByAddress(
+            value.GetValueAsUnsigned(), 1, wp_opts, error
         )
         self.assertTrue(
             value and watchpoint, "Successfully found the pointer and set a watchpoint"
@@ -90,7 +92,7 @@ def test_watch_address(self):
     @skipIf(archs=["mips", "mipsel", "mips64", "mips64el"])
     @skipIf(archs=["s390x"])  # Likewise on SystemZ
     def test_watch_address_with_invalid_watch_size(self):
-        """Exercise SBTarget.WatchAddress() API but pass an invalid watch_size."""
+        """Exercise SBTarget.WatchpointCreateByAddress() API but pass an invalid watch_size."""
         self.build()
         exe = self.getBuildArtifact("a.out")
 
@@ -124,8 +126,10 @@ def test_watch_address_with_invalid_watch_size(self):
         if self.getArchitecture() not in ["arm64", "arm64e", "arm64_32"]:
             # Watch for write to *g_char_ptr.
             error = lldb.SBError()
-            watchpoint = target.WatchAddress(
-                value.GetValueAsUnsigned(), 365, False, True, error
+            wp_opts = lldb.SBWatchpointOptions()
+            wp_opts.SetWatchpointTypeWrite(lldb.eWatchpointWriteTypeOnModify)
+            watchpoint = target.WatchpointCreateByAddress(
+                value.GetValueAsUnsigned(), 365, wp_opts, error
             )
             self.assertFalse(watchpoint)
             self.expect(


        


More information about the lldb-commits mailing list