[Lldb-commits] [lldb] [lldb] [mostly NFC] Large WP foundation: WatchpointResources (PR #68845)

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Thu Nov 16 18:14:41 PST 2023


https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/68845

>From a25de94cfe5decb452cc460348c468cfa8826f34 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 11 Oct 2023 20:05:58 -0700
Subject: [PATCH 01/11] [lldb] [mostly NFC] Large WP foundation:
 WatchpointResources

This patch is rearranging code a bit to add WatchpointResources to
Process.  A WatchpointResource is meant to represent a hardware
watchpoint register in the inferior process.  It has an address, a
size, a type, and a list of Watchpoints that are using this
WatchpointResource.

This current patch doesn't add any of the features of WatchpointResources
that make them interesting -- a user asking to watch a 24 byte
object could watch this with three 8 byte WatchpointResources.  Or
a Watchpoint on 1 byte at 0x1002 and a second watchpoint on 1 byte
at 0x1003, these must both be served by a single WatchpointResource
on that doubleword at 0x1000 on a 64-bit target, if two hardware
watchpoint registers were used to track these separately, one of
them may not be hit.  Or if you have one Watchpoint on a variable
with a condition set, and another Watchpoint on that same variable
with a command defined or different condition, or ignorecount, both
of those Watchpoints need to evaluate their criteria/commands when
their WatchpointResource has been hit.

There's a bit of code movement to rearrange things in the direction
I'll need for implementing this feature, so I want to start with
reviewing & landing this mostly NFC patch and we can focus on the
algorithmic choices about how WatchpointResources are shared and
handled as they're triggeed, separately.

This patch also stops printing "Watchpoint <n> hit: old value: <x>,
new vlaue: <y>" for Read watchpoints.  I could make an argument for
print "Watchpoint <n> hit: current value <x>" but the current output
doesn't make any sense, and the user can print the value if they
are particularly interested.  Read watchpoints are used primarily
to understand what code is reading a variable.

This patch adds more fallbacks for how to print the objects being
watched if we have types, instead of assuming they are all integral
values, so a struct will print its elements.  As large watchpoints
are added, we'll be doing a lot more of those.

To track the WatchpointSP in the WatchpointResources, I changed
the internal API which took a WatchpointSP and devolved it to a
Watchpoint*, which meant touching several different Process files.
I removed the watchpoint code in ProcessKDP which only reported
that watchpoints aren't supported, the base class does that already.

I haven't yet changed how we receive a watchpoint to identify
the WatchpointResource responsible for the trigger, and identify
all Watchpoints that are using this Resource to evaluate their
conditions etc.  This is the same work that a BreakpointSite needs
to do when it has been tiggered, where multiple Breakpoints may be
at the same address.

There is not yet any printing of the Resources that a Watchpoint
is implemented in terms of ("watchpoint list", or
SBWatchpoint::GetDescription).

"watchpoint set var" and "watchpoint set expression" take a size
argument which was previously 1, 2, 4, or 8 (an enum).  I've
changed this to an unsigned int.  Most hardware implementations
can only watch 1, 2, 4, 8 byte ranges, but with Resources we'll
allow a user to ask for different sized watchpoints and set
them in hardware-expressble terms soon.

I've annotated areas where I know there is work still needed with
LWP_TODO that I'll be working on once this is landed.

I've tested this on aarch64 macOS, aarch64 Linux, and Intel macOS.

https://discourse.llvm.org/t/rfc-large-watchpoint-support-in-lldb/72116
---
 lldb/include/lldb/Breakpoint/Watchpoint.h     |   2 +-
 .../lldb/Interpreter/OptionGroupWatchpoint.h  |   5 +-
 lldb/include/lldb/Target/Process.h            |  12 +-
 lldb/include/lldb/Target/WatchpointResource.h |  57 +++++
 .../lldb/Target/WatchpointResourceList.h      |  85 ++++++++
 lldb/include/lldb/lldb-forward.h              |   2 +
 lldb/source/API/SBWatchpoint.cpp              |   4 +-
 lldb/source/Breakpoint/Watchpoint.cpp         |  71 ++++--
 .../Commands/CommandObjectWatchpoint.cpp      |   8 +-
 .../Interpreter/OptionGroupWatchpoint.cpp     |  43 +---
 .../Process/MacOSX-Kernel/ProcessKDP.cpp      |  14 --
 .../Process/MacOSX-Kernel/ProcessKDP.h        |   7 -
 .../Process/Utility/StopInfoMachException.cpp |   9 +
 .../Process/Windows/Common/ProcessWindows.cpp |  38 ++--
 .../Process/Windows/Common/ProcessWindows.h   |   6 +-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   | 203 ++++++++++++------
 .../Process/gdb-remote/ProcessGDBRemote.h     |   6 +-
 lldb/source/Target/CMakeLists.txt             |   2 +
 lldb/source/Target/Process.cpp                |   7 +-
 lldb/source/Target/StopInfo.cpp               |  17 +-
 lldb/source/Target/Target.cpp                 |  31 +--
 lldb/source/Target/WatchpointResource.cpp     |  49 +++++
 lldb/source/Target/WatchpointResourceList.cpp |  61 ++++++
 .../watchpoints/watchpoint_count/main.c       |   4 +-
 .../watchlocation/TestTargetWatchAddress.py   |   2 +-
 lldb/test/Shell/Watchpoint/Inputs/val.c       |   3 +
 .../LocalVariableWatchpointDisabler.test      |   7 +
 lldb/test/Shell/Watchpoint/SetErrorCases.test |   2 +-
 28 files changed, 562 insertions(+), 195 deletions(-)
 create mode 100644 lldb/include/lldb/Target/WatchpointResource.h
 create mode 100644 lldb/include/lldb/Target/WatchpointResourceList.h
 create mode 100644 lldb/source/Target/WatchpointResource.cpp
 create mode 100644 lldb/source/Target/WatchpointResourceList.cpp

diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h
index c86d66663c7f8c0..851162af24c74e0 100644
--- a/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -126,7 +126,7 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
 
   void GetDescription(Stream *s, lldb::DescriptionLevel level);
   void Dump(Stream *s) const override;
-  void DumpSnapshots(Stream *s, const char *prefix = nullptr) const;
+  bool DumpSnapshots(Stream *s, const char *prefix = nullptr) const;
   void DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const;
   Target &GetTarget() { return m_target; }
   const Status &GetError() { return m_error; }
diff --git a/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h b/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
index f009fa145f30344..527a2612b189bd3 100644
--- a/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
+++ b/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_INTERPRETER_OPTIONGROUPWATCHPOINT_H
 #define LLDB_INTERPRETER_OPTIONGROUPWATCHPOINT_H
 
+#include "lldb/Interpreter/OptionValueUInt64.h"
 #include "lldb/Interpreter/Options.h"
 
 namespace lldb_private {
@@ -21,8 +22,6 @@ class OptionGroupWatchpoint : public OptionGroup {
 
   ~OptionGroupWatchpoint() override = default;
 
-  static bool IsWatchSizeSupported(uint32_t watch_size);
-
   llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
 
   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
@@ -43,7 +42,7 @@ class OptionGroupWatchpoint : public OptionGroup {
   };
 
   WatchType watch_type;
-  uint32_t watch_size;
+  OptionValueUInt64 watch_size;
   bool watch_type_specified;
   lldb::LanguageType language_type;
 
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 08e3c60f7c324e6..65fe74620a26dea 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -41,6 +41,8 @@
 #include "lldb/Target/ThreadList.h"
 #include "lldb/Target/ThreadPlanStack.h"
 #include "lldb/Target/Trace.h"
+#include "lldb/Target/WatchpointResource.h"
+#include "lldb/Target/WatchpointResourceList.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/Broadcaster.h"
 #include "lldb/Utility/Event.h"
@@ -2161,9 +2163,10 @@ class Process : public std::enable_shared_from_this<Process>,
                                      lldb::BreakpointSiteSP &bp_site_sp);
 
   // Process Watchpoints (optional)
-  virtual Status EnableWatchpoint(Watchpoint *wp, bool notify = true);
+  virtual Status EnableWatchpoint(lldb::WatchpointSP wp_sp, bool notify = true);
 
-  virtual Status DisableWatchpoint(Watchpoint *wp, bool notify = true);
+  virtual Status DisableWatchpoint(lldb::WatchpointSP wp_sp,
+                                   bool notify = true);
 
   // Thread Queries
 
@@ -3017,6 +3020,8 @@ void PruneThreadPlans();
       m_queue_list; ///< The list of libdispatch queues at a given stop point
   uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was
                                  ///last fetched
+  WatchpointResourceList
+      m_watchpoint_resource_list; ///< Watchpoint resources currently in use.
   std::vector<Notifications> m_notifications; ///< The list of notifications
                                               ///that this process can deliver.
   std::vector<lldb::addr_t> m_image_tokens;
@@ -3097,6 +3102,9 @@ void PruneThreadPlans();
   std::unique_ptr<UtilityFunction> m_dlopen_utility_func_up;
   llvm::once_flag m_dlopen_utility_func_flag_once;
 
+  // Watchpoint hardware registers currently in use.
+  std::vector<lldb::WatchpointResourceSP> m_watchpoint_resources;
+
   /// Per process source file cache.
   SourceManager::SourceFileCache m_source_file_cache;
 
diff --git a/lldb/include/lldb/Target/WatchpointResource.h b/lldb/include/lldb/Target/WatchpointResource.h
new file mode 100644
index 000000000000000..73b539e79f9bfbb
--- /dev/null
+++ b/lldb/include/lldb/Target/WatchpointResource.h
@@ -0,0 +1,57 @@
+//===-- WatchpointResource.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_TARGET_WATCHPOINTRESOURCE_H
+#define LLDB_TARGET_WATCHPOINTRESOURCE_H
+
+#include "lldb/lldb-public.h"
+
+#include <set>
+
+namespace lldb_private {
+
+class WatchpointResource
+    : public std::enable_shared_from_this<WatchpointResource> {
+
+public:
+  // Constructors and Destructors
+  WatchpointResource(lldb::addr_t addr, size_t size, bool read, bool write);
+
+  ~WatchpointResource();
+
+  void GetResourceMemoryRange(lldb::addr_t &addr, size_t &size) const;
+
+  void GetResourceType(bool &read, bool &write) const;
+
+  void RegisterWatchpoint(lldb::WatchpointSP &wp_sp);
+
+  void DeregisterWatchpoint(lldb::WatchpointSP &wp_sp);
+
+  size_t GetNumDependantWatchpoints();
+
+  bool DependantWatchpointsContains(lldb::WatchpointSP wp_sp_to_match);
+
+private:
+  WatchpointResource(const WatchpointResource &) = delete;
+  const WatchpointResource &operator=(const WatchpointResource &) = delete;
+
+  // start address & size aligned & expanded to be a valid watchpoint
+  // memory granule on this target.
+  lldb::addr_t m_addr;
+  size_t m_size;
+
+  bool m_watch_read;  // true if we stop when the watched data is read from
+  bool m_watch_write; // true if we stop when the watched data is written to
+
+  // The watchpoints using this WatchpointResource.
+  std::set<lldb::WatchpointSP> m_watchpoints;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_WATCHPOINTRESOURCE_H
diff --git a/lldb/include/lldb/Target/WatchpointResourceList.h b/lldb/include/lldb/Target/WatchpointResourceList.h
new file mode 100644
index 000000000000000..9570e337f1e6ccb
--- /dev/null
+++ b/lldb/include/lldb/Target/WatchpointResourceList.h
@@ -0,0 +1,85 @@
+//===-- WatchpointResourceList.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_TARGET_WATCHPOINTRESOURCELIST_H
+#define LLDB_TARGET_WATCHPOINTRESOURCELIST_H
+
+#include "lldb/Utility/Iterable.h"
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-public.h"
+
+#include <mutex>
+#include <vector>
+
+namespace lldb_private {
+
+class WatchpointResourceList {
+
+public:
+  // Constructors and Destructors
+  WatchpointResourceList();
+
+  ~WatchpointResourceList();
+
+  /// Get the number of WatchpointResources that are available.
+  ///
+  /// \return
+  ///     The number of WatchpointResources that are stored in the
+  ///     WatchpointResourceList.
+  uint32_t GetSize();
+
+  /// Get the WatchpointResource at a given index.
+  ///
+  /// \param [in] idx
+  ///     The index of the resource.
+  /// \return
+  ///     The WatchpointResource at that index number.
+  lldb::WatchpointResourceSP GetResourceAtIndex(uint32_t idx);
+
+  /// Remove a WatchpointResource from the list.
+  ///
+  /// The WatchpointResource must have already been disabled in the
+  /// Process; this method only removes it from the list.
+  ///
+  /// \param [in] wp_resource_sp
+  ///     The WatchpointResource to remove.
+  void RemoveWatchpointResource(lldb::WatchpointResourceSP wp_resource_sp);
+
+  typedef std::vector<lldb::WatchpointResourceSP> collection;
+  typedef LockingAdaptedIterable<collection, lldb::WatchpointResourceSP,
+                                 vector_adapter, std::mutex>
+      WatchpointResourceIterable;
+
+  /// Iterate over the list of WatchpointResources.
+  ///
+  /// \return
+  ///     An Iterable object which can be used to loop over the resources
+  ///     that exist.
+  WatchpointResourceIterable Resources() {
+    return WatchpointResourceIterable(m_resources, m_mutex);
+  }
+
+  /// Clear out the list of resources from the WatchpointResourceList
+  void Clear();
+
+  /// Add a WatchpointResource to the WatchpointResourceList.
+  ///
+  /// \param [in] resource
+  ///     A WatchpointResource to be added.
+  void AddResource(lldb::WatchpointResourceSP resource_sp);
+
+  std::mutex &GetMutex();
+
+private:
+  collection m_resources;
+  std::mutex m_mutex;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_WATCHPOINTRESOURCELIST_H
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index d38985f5c1f9238..fa352cc7d9d91a2 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -289,6 +289,7 @@ class VariableList;
 class Watchpoint;
 class WatchpointList;
 class WatchpointOptions;
+class WatchpointResource;
 class WatchpointSetOptions;
 struct CompilerContext;
 struct LineEntry;
@@ -469,6 +470,7 @@ typedef std::shared_ptr<lldb_private::Variable> VariableSP;
 typedef std::shared_ptr<lldb_private::VariableList> VariableListSP;
 typedef std::shared_ptr<lldb_private::ValueObjectList> ValueObjectListSP;
 typedef std::shared_ptr<lldb_private::Watchpoint> WatchpointSP;
+typedef std::shared_ptr<lldb_private::WatchpointResource> WatchpointResourceSP;
 
 } // namespace lldb
 
diff --git a/lldb/source/API/SBWatchpoint.cpp b/lldb/source/API/SBWatchpoint.cpp
index 8e60e6d5bb73ee1..9664bbe618600cb 100644
--- a/lldb/source/API/SBWatchpoint.cpp
+++ b/lldb/source/API/SBWatchpoint.cpp
@@ -142,9 +142,9 @@ void SBWatchpoint::SetEnabled(bool enabled) {
     const bool notify = true;
     if (process_sp) {
       if (enabled)
-        process_sp->EnableWatchpoint(watchpoint_sp.get(), notify);
+        process_sp->EnableWatchpoint(watchpoint_sp, notify);
       else
-        process_sp->DisableWatchpoint(watchpoint_sp.get(), notify);
+        process_sp->DisableWatchpoint(watchpoint_sp, notify);
     } else {
       watchpoint_sp->SetEnabled(enabled, notify);
     }
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index b58455f73030c9b..2718852a68e15f2 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/Value.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/DataFormatters/DumpValueObjectOptions.h"
 #include "lldb/Expression/UserExpression.h"
 #include "lldb/Symbol/TypeSystem.h"
 #include "lldb/Target/Process.h"
@@ -161,7 +162,7 @@ bool Watchpoint::VariableWatchpointDisabler(void *baton,
               "callback for watchpoint %" PRId32
               " matched internal breakpoint execution context",
               watch_sp->GetID());
-    process_sp->DisableWatchpoint(watch_sp.get());
+    process_sp->DisableWatchpoint(watch_sp);
     return false;
   }
   LLDB_LOGF(log,
@@ -266,33 +267,73 @@ void Watchpoint::Dump(Stream *s) const {
 
 // If prefix is nullptr, we display the watch id and ignore the prefix
 // altogether.
-void Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
-  if (!prefix) {
-    s->Printf("\nWatchpoint %u hit:", GetID());
-    prefix = "";
-  }
+bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
+  bool printed_anything = false;
+
+  // For read watchpoints, don't display any before/after value changes.
+  if (m_watch_read && !m_watch_modify && !m_watch_write)
+    return printed_anything;
+
+  s->Printf("\n");
+  s->Printf("Watchpoint %u hit:\n", GetID());
+
+  StreamString values_ss;
+  if (prefix)
+    values_ss.Indent(prefix);
 
   if (m_old_value_sp) {
     const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
-    if (old_value_cstr && old_value_cstr[0])
-      s->Printf("\n%sold value: %s", prefix, old_value_cstr);
-    else {
+    if (old_value_cstr) {
+      values_ss.Printf("old value: %s", old_value_cstr);
+    } else {
       const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
-      if (old_summary_cstr && old_summary_cstr[0])
-        s->Printf("\n%sold value: %s", prefix, old_summary_cstr);
+      if (old_summary_cstr)
+        values_ss.Printf("old value: %s", old_summary_cstr);
+      else {
+        StreamString strm;
+        DumpValueObjectOptions options;
+        options.SetUseDynamicType(eNoDynamicValues)
+            .SetHideRootType(true)
+            .SetHideRootName(true)
+            .SetHideName(true);
+        m_old_value_sp->Dump(strm, options);
+        if (strm.GetData())
+          values_ss.Printf("old value: %s", strm.GetData());
+      }
     }
   }
 
   if (m_new_value_sp) {
+    if (values_ss.GetSize())
+      values_ss.Printf("\n");
+
     const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
-    if (new_value_cstr && new_value_cstr[0])
-      s->Printf("\n%snew value: %s", prefix, new_value_cstr);
+    if (new_value_cstr)
+      values_ss.Printf("new value: %s", new_value_cstr);
     else {
       const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
-      if (new_summary_cstr && new_summary_cstr[0])
-        s->Printf("\n%snew value: %s", prefix, new_summary_cstr);
+      if (new_summary_cstr)
+        values_ss.Printf("new value: %s", new_summary_cstr);
+      else {
+        StreamString strm;
+        DumpValueObjectOptions options;
+        options.SetUseDynamicType(eNoDynamicValues)
+            .SetHideRootType(true)
+            .SetHideRootName(true)
+            .SetHideName(true);
+        m_new_value_sp->Dump(strm, options);
+        if (strm.GetData())
+          values_ss.Printf("new value: %s", strm.GetData());
+      }
     }
   }
+
+  if (values_ss.GetSize()) {
+    s->Printf("%s", values_ss.GetData());
+    printed_anything = true;
+  }
+
+  return printed_anything;
 }
 
 void Watchpoint::DumpWithLevel(Stream *s,
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index cd1d226988f243e..c80868d33905e92 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -918,9 +918,9 @@ corresponding to the byte size of the data type.");
       if (addr_type == eAddressTypeLoad) {
         // We're in business.
         // Find out the size of this variable.
-        size = m_option_watchpoint.watch_size == 0
+        size = m_option_watchpoint.watch_size.GetCurrentValue() == 0
                    ? valobj_sp->GetByteSize().value_or(0)
-                   : m_option_watchpoint.watch_size;
+                   : m_option_watchpoint.watch_size.GetCurrentValue();
       }
       compiler_type = valobj_sp->GetCompilerType();
     } else {
@@ -1113,8 +1113,8 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
       return;
     }
 
-    if (m_option_watchpoint.watch_size != 0)
-      size = m_option_watchpoint.watch_size;
+    if (m_option_watchpoint.watch_size.GetCurrentValue() != 0)
+      size = m_option_watchpoint.watch_size.GetCurrentValue();
     else
       size = target->GetArchitecture().GetAddressByteSize();
 
diff --git a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
index c3708e7a1e80fd2..d1ae916cd74b1c0 100644
--- a/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
+++ b/lldb/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -39,35 +39,12 @@ static constexpr OptionEnumValueElement g_watch_type[] = {
     },
 };
 
-static constexpr OptionEnumValueElement g_watch_size[] = {
-    {
-        1,
-        "1",
-        "Watch for byte size of 1",
-    },
-    {
-        2,
-        "2",
-        "Watch for byte size of 2",
-    },
-    {
-        4,
-        "4",
-        "Watch for byte size of 4",
-    },
-    {
-        8,
-        "8",
-        "Watch for byte size of 8",
-    },
-};
-
 static constexpr OptionDefinition g_option_table[] = {
     {LLDB_OPT_SET_1, false, "watch", 'w', OptionParser::eRequiredArgument,
      nullptr, OptionEnumValues(g_watch_type), 0, eArgTypeWatchType,
      "Specify the type of watching to perform."},
     {LLDB_OPT_SET_1, false, "size", 's', OptionParser::eRequiredArgument,
-     nullptr, OptionEnumValues(g_watch_size), 0, eArgTypeByteSize,
+     nullptr, {}, 0, eArgTypeByteSize, 
      "Number of bytes to use to watch a region."},
     {LLDB_OPT_SET_2,
      false,
@@ -80,16 +57,6 @@ static constexpr OptionDefinition g_option_table[] = {
      eArgTypeLanguage,
      "Language of expression to run"}};
 
-bool OptionGroupWatchpoint::IsWatchSizeSupported(uint32_t watch_size) {
-  for (const auto& size : g_watch_size) {
-    if (0  == size.value)
-      break;
-    if (watch_size == size.value)
-      return true;
-  }
-  return false;
-}
-
 Status
 OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx,
                                       llvm::StringRef option_arg,
@@ -120,8 +87,10 @@ OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx,
     break;
   }
   case 's':
-    watch_size = (uint32_t)OptionArgParser::ToOptionEnum(
-        option_arg, g_option_table[option_idx].enum_values, 0, error);
+    error = watch_size.SetValueFromString(option_arg);
+    if (watch_size.GetCurrentValue() == 0)
+      error.SetErrorStringWithFormat("invalid --size option value '%s'",
+                                     option_arg.str().c_str());
     break;
 
   default:
@@ -135,7 +104,7 @@ void OptionGroupWatchpoint::OptionParsingStarting(
     ExecutionContext *execution_context) {
   watch_type_specified = false;
   watch_type = eWatchInvalid;
-  watch_size = 0;
+  watch_size.Clear();
   language_type = eLanguageTypeUnknown;
 }
 
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index e0956b49ae1f151..70bb9aa7a833c08 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -671,20 +671,6 @@ Status ProcessKDP::DisableBreakpointSite(BreakpointSite *bp_site) {
   return DisableSoftwareBreakpoint(bp_site);
 }
 
-Status ProcessKDP::EnableWatchpoint(Watchpoint *wp, bool notify) {
-  Status error;
-  error.SetErrorString(
-      "watchpoints are not supported in kdp remote debugging");
-  return error;
-}
-
-Status ProcessKDP::DisableWatchpoint(Watchpoint *wp, bool notify) {
-  Status error;
-  error.SetErrorString(
-      "watchpoints are not supported in kdp remote debugging");
-  return error;
-}
-
 void ProcessKDP::Clear() { m_thread_list.Clear(); }
 
 Status ProcessKDP::DoSignal(int signo) {
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
index 3c12fd4074499a9..e5ec5914f9600d0 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -124,13 +124,6 @@ class ProcessKDP : public lldb_private::Process {
   lldb_private::Status
   DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override;
 
-  // Process Watchpoints
-  lldb_private::Status EnableWatchpoint(lldb_private::Watchpoint *wp,
-                                        bool notify = true) override;
-
-  lldb_private::Status DisableWatchpoint(lldb_private::Watchpoint *wp,
-                                         bool notify = true) override;
-
   CommunicationKDP &GetCommunication() { return m_comm; }
 
 protected:
diff --git a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
index 5c947bbc8d9cb95..565941d3168f1fa 100644
--- a/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
+++ b/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -491,6 +491,9 @@ static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target,
                                            uint64_t exc_sub_sub_code) {
   // Try hardware watchpoint.
   if (target) {
+    // LWP_TODO: We need to find the WatchpointResource that matches
+    // the address, and evaluate its Watchpoints.
+
     // The exc_sub_code indicates the data break address.
     lldb::WatchpointSP wp_sp =
         target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
@@ -666,6 +669,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
     case llvm::Triple::thumb:
       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
       {
+        // LWP_TODO: We need to find the WatchpointResource that matches
+        // the address, and evaluate its Watchpoints.
+
         // It's a watchpoint, then, if the exc_sub_code indicates a
         // known/enabled data break address from our watchpoint list.
         lldb::WatchpointSP wp_sp;
@@ -742,6 +748,9 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException(
       }
       if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
       {
+        // LWP_TODO: We need to find the WatchpointResource that matches
+        // the address, and evaluate its Watchpoints.
+
         // It's a watchpoint, then, if the exc_sub_code indicates a
         // known/enabled data break address from our watchpoint list.
         lldb::WatchpointSP wp_sp;
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 91b3216a57c34c1..eb0834b1159f645 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -835,11 +835,11 @@ std::optional<uint32_t> ProcessWindows::GetWatchpointSlotCount() {
   return RegisterContextWindows::GetNumHardwareBreakpointSlots();
 }
 
-Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessWindows::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
 
-  if (wp->IsEnabled()) {
-    wp->SetEnabled(true, notify);
+  if (wp_sp->IsEnabled()) {
+    wp_sp->SetEnabled(true, notify);
     return error;
   }
 
@@ -851,13 +851,13 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
       break;
   if (info.slot_id == RegisterContextWindows::GetNumHardwareBreakpointSlots()) {
     error.SetErrorStringWithFormat("Can't find free slot for watchpoint %i",
-                                   wp->GetID());
+                                   wp_sp->GetID());
     return error;
   }
-  info.address = wp->GetLoadAddress();
-  info.size = wp->GetByteSize();
-  info.read = wp->WatchpointRead();
-  info.write = wp->WatchpointWrite();
+  info.address = wp_sp->GetLoadAddress();
+  info.size = wp_sp->GetByteSize();
+  info.read = wp_sp->WatchpointRead();
+  info.write = wp_sp->WatchpointWrite();
 
   for (unsigned i = 0U; i < m_thread_list.GetSize(); i++) {
     Thread *thread = m_thread_list.GetThreadAtIndex(i).get();
@@ -866,7 +866,7 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
     if (!reg_ctx->AddHardwareBreakpoint(info.slot_id, info.address, info.size,
                                         info.read, info.write)) {
       error.SetErrorStringWithFormat(
-          "Can't enable watchpoint %i on thread 0x%llx", wp->GetID(),
+          "Can't enable watchpoint %i on thread 0x%llx", wp_sp->GetID(),
           thread->GetID());
       break;
     }
@@ -881,26 +881,26 @@ Status ProcessWindows::EnableWatchpoint(Watchpoint *wp, bool notify) {
     return error;
   }
 
-  m_watchpoints[wp->GetID()] = info;
-  m_watchpoint_ids[info.slot_id] = wp->GetID();
+  m_watchpoints[wp_sp->GetID()] = info;
+  m_watchpoint_ids[info.slot_id] = wp_sp->GetID();
 
-  wp->SetEnabled(true, notify);
+  wp_sp->SetEnabled(true, notify);
 
   return error;
 }
 
-Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessWindows::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
 
-  if (!wp->IsEnabled()) {
-    wp->SetEnabled(false, notify);
+  if (!wp_sp->IsEnabled()) {
+    wp_sp->SetEnabled(false, notify);
     return error;
   }
 
-  auto it = m_watchpoints.find(wp->GetID());
+  auto it = m_watchpoints.find(wp_sp->GetID());
   if (it == m_watchpoints.end()) {
     error.SetErrorStringWithFormat("Info about watchpoint %i is not found",
-                                   wp->GetID());
+                                   wp_sp->GetID());
     return error;
   }
 
@@ -910,7 +910,7 @@ Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
         thread->GetRegisterContext().get());
     if (!reg_ctx->RemoveHardwareBreakpoint(it->second.slot_id)) {
       error.SetErrorStringWithFormat(
-          "Can't disable watchpoint %i on thread 0x%llx", wp->GetID(),
+          "Can't disable watchpoint %i on thread 0x%llx", wp_sp->GetID(),
           thread->GetID());
       break;
     }
@@ -921,7 +921,7 @@ Status ProcessWindows::DisableWatchpoint(Watchpoint *wp, bool notify) {
   m_watchpoint_ids[it->second.slot_id] = LLDB_INVALID_BREAK_ID;
   m_watchpoints.erase(it);
 
-  wp->SetEnabled(false, notify);
+  wp_sp->SetEnabled(false, notify);
 
   return error;
 }
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
index ed083b9e78b4bb9..e97cfb790248be4 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -96,8 +96,10 @@ class ProcessWindows : public Process, public ProcessDebugger {
   void OnDebuggerError(const Status &error, uint32_t type) override;
 
   std::optional<uint32_t> GetWatchpointSlotCount() override;
-  Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
-  Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
+  Status EnableWatchpoint(lldb::WatchpointSP wp_sp,
+                          bool notify = true) override;
+  Status DisableWatchpoint(lldb::WatchpointSP wp_sp,
+                           bool notify = true) override;
 
 protected:
   ProcessWindows(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index e653ef5d8ac54e4..ef527a261e859b1 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1799,6 +1799,8 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
           watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
           bool silently_continue = false;
           WatchpointSP wp_sp;
+          // LWP_TODO: We need to find the WatchpointResource that matches
+          // the address, and evaluate its Watchpoints.
           if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
             wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr);
             // On MIPS, \a wp_hit_addr outside the range of a watched
@@ -3107,32 +3109,30 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
 }
 
 // Pre-requisite: wp != NULL.
-static GDBStoppointType GetGDBStoppointType(Watchpoint *wp) {
-  assert(wp);
-  bool watch_read = wp->WatchpointRead();
-  bool watch_write = wp->WatchpointWrite();
-  bool watch_modify = wp->WatchpointModify();
-
-  // 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))
+static GDBStoppointType
+GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
+  assert(wp_res_sp);
+  bool read, write;
+  wp_res_sp->GetResourceType(read, write);
+
+  assert((read || write) && "read and write cannot both be false.");
+  if (read && write)
     return eWatchpointReadWrite;
-  else if (watch_read)
+  else if (read)
     return eWatchpointRead;
-  else // Must be watch_write or watch_modify, then.
+  else
     return eWatchpointWrite;
 }
 
-Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
-  if (wp) {
-    user_id_t watchID = wp->GetID();
-    addr_t addr = wp->GetLoadAddress();
+  if (wp_sp) {
+    user_id_t watchID = wp_sp->GetID();
+    addr_t addr = wp_sp->GetLoadAddress();
     Log *log(GetLog(GDBRLog::Watchpoints));
     LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
               watchID);
-    if (wp->IsEnabled()) {
+    if (wp_sp->IsEnabled()) {
       LLDB_LOGF(log,
                 "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
                 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
@@ -3140,41 +3140,111 @@ Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) {
       return error;
     }
 
-    GDBStoppointType type = GetGDBStoppointType(wp);
-    // Pass down an appropriate z/Z packet...
-    if (m_gdb_comm.SupportsGDBStoppointPacket(type)) {
-      if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr,
-                                                wp->GetByteSize(),
-                                                GetInterruptTimeout()) == 0) {
-        wp->SetEnabled(true, notify);
-        return error;
-      } else
-        error.SetErrorString("sending gdb watchpoint packet failed");
-    } else
-      error.SetErrorString("watchpoints not supported");
+    bool read = wp_sp->WatchpointRead();
+    bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
+    size_t size = wp_sp->GetByteSize();
+
+    // New WatchpointResources needed to implement this Watchpoint.
+    std::vector<WatchpointResourceSP> resources;
+
+    // LWP_TODO: Break up the user's request into pieces that can be watched
+    // given the capabilities of the target cpu / stub software.
+    // As a default, breaking the watched region up into target-pointer-sized,
+    // aligned, groups.
+    //
+    // Beyond the default, a stub can / should inform us of its capabilities,
+    // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints.
+    //
+    // And the cpu may have unique capabilities. AArch64 BAS watchpoints
+    // can watch any sequential bytes in a doubleword, but Intel watchpoints
+    // can only watch 1, 2, 4, 8 bytes within a doubleword.
+    WatchpointResourceSP wp_res_sp =
+        std::make_shared<WatchpointResource>(addr, size, read, write);
+    resources.push_back(wp_res_sp);
+
+    // LWP_TODO: Now that we know the WP Resources needed to implement this
+    // Watchpoint, we need to look at currently allocated Resources in the
+    // Process and if they match, or are within the same memory granule, or
+    // overlapping memory ranges, then we need to combine them.  e.g. one
+    // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1
+    // byte at 0x1003, they must use the same hardware watchpoint register
+    // (Resource) to watch them.
+
+    // This may mean that an existing resource changes its type (read to
+    // read+write) or address range it is watching, in which case the old
+    // watchpoint needs to be disabled and the new Resource addr/size/type
+    // watchpoint enabled.
+
+    // If we modify a shared Resource to accomodate this newly added Watchpoint,
+    // and we are unable to set all of the Resources for it in the inferior, we
+    // will return an error for this Watchpoint and the shared Resource should
+    // be restored.  e.g. this Watchpoint requires three Resources, one which
+    // is shared with another Watchpoint.  We extend the shared Resouce to
+    // handle both Watchpoints and we try to set two new ones.  But if we don't
+    // have sufficient watchpoint register for all 3, we need to show an error
+    // for creating this Watchpoint and we should reset the shared Resource to
+    // its original configuration because it is no longer shared.
+
+    bool set_all_resources = true;
+    std::vector<WatchpointResourceSP> succesfully_set_resources;
+    for (const auto &wp_res_sp : resources) {
+      addr_t addr;
+      size_t size;
+      wp_res_sp->GetResourceMemoryRange(addr, size);
+      GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+      if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
+          m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+                                                GetInterruptTimeout())) {
+        set_all_resources = false;
+        break;
+      } else {
+        succesfully_set_resources.push_back(wp_res_sp);
+      }
+    }
+    if (set_all_resources) {
+      wp_sp->SetEnabled(true, notify);
+      for (const auto &wp_res_sp : resources) {
+        // LWP_TODO: If we expanded/reused an existing Resource,
+        // it's already in the WatchpointResourceList.
+        wp_res_sp->RegisterWatchpoint(wp_sp);
+        m_watchpoint_resource_list.AddResource(wp_res_sp);
+      }
+      return error;
+    } else {
+      // We failed to allocate one of the resources.  Unset all
+      // of the new resources we did successfully set in the
+      // process.
+      for (const auto &wp_res_sp : succesfully_set_resources) {
+        addr_t addr;
+        size_t size;
+        wp_res_sp->GetResourceMemoryRange(addr, size);
+        GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+        m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+                                              GetInterruptTimeout());
+      }
+      error.SetErrorString("Setting one of the watchpoint resources failed");
+    }
   } else {
-    error.SetErrorString("Watchpoint argument was NULL.");
+    error.SetErrorString("No watchpoint specified");
   }
-  if (error.Success())
-    error.SetErrorToGenericError();
   return error;
 }
 
-Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
+Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
-  if (wp) {
-    user_id_t watchID = wp->GetID();
+  if (wp_sp) {
+    user_id_t watchID = wp_sp->GetID();
 
     Log *log(GetLog(GDBRLog::Watchpoints));
 
-    addr_t addr = wp->GetLoadAddress();
+    addr_t addr = wp_sp->GetLoadAddress();
 
     LLDB_LOGF(log,
               "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
               ") addr = 0x%8.8" PRIx64,
               watchID, (uint64_t)addr);
 
-    if (!wp->IsEnabled()) {
+    if (!wp_sp->IsEnabled()) {
       LLDB_LOGF(log,
                 "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
                 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
@@ -3182,27 +3252,41 @@ Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) {
       // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
       // attempt might come from the user-supplied actions, we'll route it in
       // order for the watchpoint object to intelligently process this action.
-      wp->SetEnabled(false, notify);
+      wp_sp->SetEnabled(false, notify);
       return error;
     }
 
-    if (wp->IsHardware()) {
-      GDBStoppointType type = GetGDBStoppointType(wp);
-      // Pass down an appropriate z/Z packet...
-      if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr,
-                                                wp->GetByteSize(),
-                                                GetInterruptTimeout()) == 0) {
-        wp->SetEnabled(false, notify);
-        return error;
-      } else
-        error.SetErrorString("sending gdb watchpoint packet failed");
+    if (wp_sp->IsHardware()) {
+      bool disabled_all = true;
+
+      std::vector<WatchpointResourceSP> unused_resouces;
+      for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
+        if (wp_res_sp->DependantWatchpointsContains(wp_sp)) {
+          GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+          addr_t addr;
+          size_t size;
+          wp_res_sp->GetResourceMemoryRange(addr, size);
+          if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+                                                    GetInterruptTimeout())) {
+            disabled_all = false;
+          } else {
+            wp_res_sp->DeregisterWatchpoint(wp_sp);
+            if (wp_res_sp->GetNumDependantWatchpoints() == 0)
+              unused_resouces.push_back(wp_res_sp);
+          }
+        }
+      }
+      for (auto &wp_res_sp : unused_resouces)
+        m_watchpoint_resource_list.RemoveWatchpointResource(wp_res_sp);
+
+      wp_sp->SetEnabled(false, notify);
+      if (!disabled_all)
+        error.SetErrorString(
+            "Failure disabling one of the watchpoint locations");
     }
-    // TODO: clear software watchpoints if we implement them
   } else {
     error.SetErrorString("Watchpoint argument was NULL.");
   }
-  if (error.Success())
-    error.SetErrorToGenericError();
   return error;
 }
 
@@ -5454,16 +5538,13 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
     });
   }
 
-  WatchpointList &wps = GetTarget().GetWatchpointList();
-  size_t wp_count = wps.GetSize();
-  for (size_t i = 0; i < wp_count; ++i) {
-    WatchpointSP wp = wps.GetByIndex(i);
-    if (wp->IsEnabled()) {
-      GDBStoppointType type = GetGDBStoppointType(wp.get());
-      m_gdb_comm.SendGDBStoppointTypePacket(type, enable, wp->GetLoadAddress(),
-                                            wp->GetByteSize(),
-                                            GetInterruptTimeout());
-    }
+  for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
+    addr_t addr;
+    size_t size;
+    wp_res_sp->GetResourceMemoryRange(addr, size);
+    GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+    m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+                                          GetInterruptTimeout());
   }
 }
 
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index f3787e7169047e2..c1ea1cc79055879 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -158,9 +158,11 @@ class ProcessGDBRemote : public Process,
   Status DisableBreakpointSite(BreakpointSite *bp_site) override;
 
   // Process Watchpoints
-  Status EnableWatchpoint(Watchpoint *wp, bool notify = true) override;
+  Status EnableWatchpoint(lldb::WatchpointSP wp_sp,
+                          bool notify = true) override;
 
-  Status DisableWatchpoint(Watchpoint *wp, bool notify = true) override;
+  Status DisableWatchpoint(lldb::WatchpointSP wp_sp,
+                           bool notify = true) override;
 
   std::optional<uint32_t> GetWatchpointSlotCount() override;
 
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index cf4818eae3eb8b4..617a0610ac96360 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -78,6 +78,8 @@ add_lldb_library(lldbTarget
   UnixSignals.cpp
   UnwindAssembly.cpp
   UnwindLLDB.cpp
+  WatchpointResource.cpp
+  WatchpointResourceList.cpp
 
   LINK_LIBS
     lldbBreakpoint
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 21b80b8240ab64b..044cd9eed469f5b 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -436,7 +436,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
       m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this),
       m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this),
       m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0),
-      m_notifications(), m_image_tokens(),
+      m_watchpoint_resource_list(), m_notifications(), m_image_tokens(),
       m_breakpoint_site_list(), m_dynamic_checkers_up(),
       m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(),
       m_stdio_communication("process.stdio"), m_stdio_communication_mutex(),
@@ -547,6 +547,7 @@ void Process::Finalize() {
   m_extended_thread_list.Destroy();
   m_queue_list.Clear();
   m_queue_list_stop_id = 0;
+  m_watchpoint_resource_list.Clear();
   std::vector<Notifications> empty_notifications;
   m_notifications.swap(empty_notifications);
   m_image_tokens.clear();
@@ -2408,13 +2409,13 @@ bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr,
   return true;
 }
 
-Status Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) {
+Status Process::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
   error.SetErrorString("watchpoints are not supported");
   return error;
 }
 
-Status Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) {
+Status Process::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
   error.SetErrorString("watchpoints are not supported");
   return error;
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 0b858454782bc11..678605af74e588a 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -631,7 +631,7 @@ class StopInfoWatchpoint : public StopInfo {
       if (process_sp && watchpoint_sp) {
         const bool notify = false;
         watchpoint_sp->TurnOnEphemeralMode();
-        process_sp->DisableWatchpoint(watchpoint_sp.get(), notify);
+        process_sp->DisableWatchpoint(watchpoint_sp, notify);
         process_sp->AddPreResumeAction(SentryPreResumeAction, this);
       }
     }
@@ -642,9 +642,9 @@ class StopInfoWatchpoint : public StopInfo {
         watchpoint_sp->TurnOffEphemeralMode();
         const bool notify = false;
         if (was_disabled) {
-          process_sp->DisableWatchpoint(watchpoint_sp.get(), notify);
+          process_sp->DisableWatchpoint(watchpoint_sp, notify);
         } else {
-          process_sp->EnableWatchpoint(watchpoint_sp.get(), notify);
+          process_sp->EnableWatchpoint(watchpoint_sp, notify);
         }
       }
     }
@@ -707,7 +707,7 @@ class StopInfoWatchpoint : public StopInfo {
         return true;
 
       if (!m_did_disable_wp) {
-        GetThread().GetProcess()->DisableWatchpoint(m_watch_sp.get(), false);
+        GetThread().GetProcess()->DisableWatchpoint(m_watch_sp, false);
         m_did_disable_wp = true;
       }
       return true;
@@ -991,9 +991,10 @@ class StopInfoWatchpoint : public StopInfo {
 
           Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
           StreamSP output_sp = debugger.GetAsyncOutputStream();
-          wp_sp->DumpSnapshots(output_sp.get());
-          output_sp->EOL();
-          output_sp->Flush();
+          if (wp_sp->DumpSnapshots(output_sp.get())) {
+            output_sp->EOL();
+            output_sp->Flush();
+          }
         }
 
       } else {
@@ -1366,6 +1367,8 @@ StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
   return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop));
 }
 
+// LWP_TODO: We'll need a CreateStopReasonWithWatchpointResourceID akin
+// to CreateStopReasonWithBreakpointSiteID
 StopInfoSP StopInfo::CreateStopReasonWithWatchpointID(Thread &thread,
                                                       break_id_t watch_id,
                                                       bool silently_continue) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index a6d7148c84e20be..2e8d1dfdaa1769a 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -892,6 +892,18 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
   if (ABISP abi = m_process_sp->GetABI())
     addr = abi->FixDataAddress(addr);
 
+  // LWP_TODO this sequence is looking for an existing watchpoint
+  // at the exact same user-specified address, disables the new one
+  // if addr/size/type match.  If type/size differ, disable old one.
+  // This isn't correct, we need both watchpoints to use a shared
+  // WatchpointResource in the target, and expand the WatchpointResource
+  // to handle the needs of both Watchpoints.
+  // Also, even if the addresses don't match, they may need to be
+  // supported by the same WatchpointResource, e.g. a watchpoint
+  // watching 1 byte at 0x102 and a watchpoint watching 1 byte at 0x103.
+  // They're in the same word and must be watched by a single hardware
+  // watchpoint register.
+
   std::unique_lock<std::recursive_mutex> lock;
   this->GetWatchpointList().GetListMutex(lock);
   WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr);
@@ -907,7 +919,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
       wp_sp->SetEnabled(false, notify);
     } else {
       // Nil the matched watchpoint; we will be creating a new one.
-      m_process_sp->DisableWatchpoint(matched_sp.get(), notify);
+      m_process_sp->DisableWatchpoint(matched_sp, notify);
       m_watchpoint_list.Remove(matched_sp->GetID(), true);
     }
   }
@@ -918,7 +930,7 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
     m_watchpoint_list.Add(wp_sp, true);
   }
 
-  error = m_process_sp->EnableWatchpoint(wp_sp.get(), notify);
+  error = m_process_sp->EnableWatchpoint(wp_sp, notify);
   LLDB_LOGF(log, "Target::%s (creation of watchpoint %s with id = %u)\n",
             __FUNCTION__, error.Success() ? "succeeded" : "failed",
             wp_sp->GetID());
@@ -927,11 +939,6 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size,
     // Enabling the watchpoint on the device side failed. Remove the said
     // watchpoint from the list maintained by the target instance.
     m_watchpoint_list.Remove(wp_sp->GetID(), true);
-    // See if we could provide more helpful error message.
-    if (!OptionGroupWatchpoint::IsWatchSizeSupported(size))
-      error.SetErrorStringWithFormat(
-          "watch size of %" PRIu64 " is not supported", (uint64_t)size);
-
     wp_sp.reset();
   } else
     m_last_created_watchpoint = wp_sp;
@@ -1231,7 +1238,7 @@ bool Target::RemoveAllWatchpoints(bool end_to_end) {
     if (!wp_sp)
       return false;
 
-    Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+    Status rc = m_process_sp->DisableWatchpoint(wp_sp);
     if (rc.Fail())
       return false;
   }
@@ -1260,7 +1267,7 @@ bool Target::DisableAllWatchpoints(bool end_to_end) {
     if (!wp_sp)
       return false;
 
-    Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+    Status rc = m_process_sp->DisableWatchpoint(wp_sp);
     if (rc.Fail())
       return false;
   }
@@ -1287,7 +1294,7 @@ bool Target::EnableAllWatchpoints(bool end_to_end) {
     if (!wp_sp)
       return false;
 
-    Status rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+    Status rc = m_process_sp->EnableWatchpoint(wp_sp);
     if (rc.Fail())
       return false;
   }
@@ -1350,7 +1357,7 @@ bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) {
 
   WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id);
   if (wp_sp) {
-    Status rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+    Status rc = m_process_sp->DisableWatchpoint(wp_sp);
     if (rc.Success())
       return true;
 
@@ -1369,7 +1376,7 @@ bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) {
 
   WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id);
   if (wp_sp) {
-    Status rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+    Status rc = m_process_sp->EnableWatchpoint(wp_sp);
     if (rc.Success())
       return true;
 
diff --git a/lldb/source/Target/WatchpointResource.cpp b/lldb/source/Target/WatchpointResource.cpp
new file mode 100644
index 000000000000000..b1ecffc73a415d5
--- /dev/null
+++ b/lldb/source/Target/WatchpointResource.cpp
@@ -0,0 +1,49 @@
+//===-- WatchpointResource.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/Target/WatchpointResource.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
+                                       bool read, bool write)
+    : m_addr(addr), m_size(size), m_watch_read(read), m_watch_write(write) {}
+
+WatchpointResource::~WatchpointResource() { m_watchpoints.clear(); }
+
+void WatchpointResource::GetResourceMemoryRange(lldb::addr_t &addr,
+                                                size_t &size) const {
+  addr = m_addr;
+  size = m_size;
+}
+
+void WatchpointResource::GetResourceType(bool &read, bool &write) const {
+  read = m_watch_read;
+  write = m_watch_write;
+}
+
+void WatchpointResource::RegisterWatchpoint(lldb::WatchpointSP &wp_sp) {
+  m_watchpoints.insert(wp_sp);
+}
+
+void WatchpointResource::DeregisterWatchpoint(lldb::WatchpointSP &wp_sp) {
+  m_watchpoints.erase(wp_sp);
+}
+
+size_t WatchpointResource::GetNumDependantWatchpoints() {
+  return m_watchpoints.size();
+}
+
+bool WatchpointResource::DependantWatchpointsContains(
+    WatchpointSP wp_sp_to_match) {
+  for (const WatchpointSP &wp_sp : m_watchpoints)
+    if (wp_sp == wp_sp_to_match)
+      return true;
+  return false;
+}
diff --git a/lldb/source/Target/WatchpointResourceList.cpp b/lldb/source/Target/WatchpointResourceList.cpp
new file mode 100644
index 000000000000000..44888736d59bc9f
--- /dev/null
+++ b/lldb/source/Target/WatchpointResourceList.cpp
@@ -0,0 +1,61 @@
+//===-- WatchpointResourceList.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/Target/WatchpointResourceList.h"
+#include "lldb/Target/WatchpointResource.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointResourceList::WatchpointResourceList() : m_resources(), m_mutex() {}
+
+WatchpointResourceList::~WatchpointResourceList() { Clear(); }
+
+uint32_t WatchpointResourceList::GetSize() {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  return m_resources.size();
+}
+
+lldb::WatchpointResourceSP
+WatchpointResourceList::GetResourceAtIndex(uint32_t idx) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  if (idx < m_resources.size()) {
+    return m_resources[idx];
+  } else {
+    return {};
+  }
+}
+
+void WatchpointResourceList::RemoveWatchpointResource(
+    WatchpointResourceSP wp_resource_sp) {
+  assert(wp_resource_sp->GetNumDependantWatchpoints() == 0);
+
+  std::lock_guard<std::mutex> guard(m_mutex);
+  collection::iterator pos = m_resources.begin();
+  while (pos != m_resources.end()) {
+    if (*pos == wp_resource_sp) {
+      m_resources.erase(pos);
+      return;
+    }
+    ++pos;
+  }
+}
+
+void WatchpointResourceList::Clear() {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  m_resources.clear();
+}
+
+void WatchpointResourceList::AddResource(WatchpointResourceSP resource_sp) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  if (resource_sp) {
+    m_resources.push_back(resource_sp);
+  }
+}
+
+std::mutex &WatchpointResourceList::GetMutex() { return m_mutex; }
diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
index fc9a370e41f3164..a170e173a33db24 100644
--- a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
+++ b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
@@ -2,8 +2,8 @@
 #include <stdio.h>
 
 int main() {
-  uint8_t x1 = 0;
-  uint16_t x2 = 0;
+  long x1 = 0;
+  long x2 = 0;
 
   printf("patatino\n");
 
diff --git a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
index bf31819d4070de6..cbab3c6382e431d 100644
--- a/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
+++ b/lldb/test/API/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
@@ -135,5 +135,5 @@ def test_watch_address_with_invalid_watch_size(self):
             self.expect(
                 error.GetCString(),
                 exe=False,
-                substrs=["watch size of %d is not supported" % 365],
+                substrs=["Setting one of the watchpoint resources failed"],
             )
diff --git a/lldb/test/Shell/Watchpoint/Inputs/val.c b/lldb/test/Shell/Watchpoint/Inputs/val.c
index 5c70375c9d0faa5..4a23ae5b1aa9628 100644
--- a/lldb/test/Shell/Watchpoint/Inputs/val.c
+++ b/lldb/test/Shell/Watchpoint/Inputs/val.c
@@ -1,6 +1,9 @@
 int main() {
   int val = 0;
   // Break here
+  val = 5;
+  val = 10;
+  val = 1;
   val++;
   val++;
   return 0;
diff --git a/lldb/test/Shell/Watchpoint/LocalVariableWatchpointDisabler.test b/lldb/test/Shell/Watchpoint/LocalVariableWatchpointDisabler.test
index dc2b6687964f608..396b4a922fd87fe 100644
--- a/lldb/test/Shell/Watchpoint/LocalVariableWatchpointDisabler.test
+++ b/lldb/test/Shell/Watchpoint/LocalVariableWatchpointDisabler.test
@@ -1,3 +1,10 @@
 # REQUIRES: system-darwin
+# TODO: This test is breaking with my output 
+# reformatting done for Large Watchpoint support,
+# but the lines being output by lldb are identical,
+# by visual inspection.  
+# FileCheck is seeing some difference between them,
+# which I need to get to the bottom of.
+# UNSUPPORTED: system-darwin
 # RUN: %clang_host -x c %S/Inputs/val.c -g -o %t
 # RUN: %lldb -b -s %S/Inputs/watchpoint.in %t 2>&1 | FileCheck %S/Inputs/watchpoint.in
diff --git a/lldb/test/Shell/Watchpoint/SetErrorCases.test b/lldb/test/Shell/Watchpoint/SetErrorCases.test
index cc67d0adfc3feb6..6020186b9e3f516 100644
--- a/lldb/test/Shell/Watchpoint/SetErrorCases.test
+++ b/lldb/test/Shell/Watchpoint/SetErrorCases.test
@@ -25,4 +25,4 @@ watchpoint set expression MyAggregateDataType
 # CHECK: error: expression did not evaluate to an address
 
 watchpoint set variable -s -128
-# CHECK: error: invalid enumeration value
+# CHECK: error: invalid --size option value

>From 9985093f858893ac87528142deed93ece32f3b72 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Mon, 23 Oct 2023 00:57:06 -0700
Subject: [PATCH 02/11] Restructure WatchpointResources to be closer to
 BreakpointSites

Restructure the way I added WatchpointResources to be
much more in line with how BreakpointLocations relate to
BreakpointSites.  Similar to BreakpointSites, when we have
a watchpoint access, we will identify the WatchpointResource
that tiggered it, and evaluate all Watchpoints who own that
WatchpointResource.

There's been a "hardware index" in watchpoints which we initialize
if the remote gdb stub happens to give us the hardware index of the
watchpoint register, but there way lldb receives this index depended
on non-standard additions to the watchpoint packet.  Instead, I
have WatchpointResources contain an ID which is the hardware target
register used for that watchpoint, which I initialize heuristically
assuming that the stub will set new watchpoints in the first available
slot starting at 0, and when a watchpoint is deleted/disabled, that
spot will now be unused.  It's only a heuristic, but it's no worse
than our current sometimes-we-can-get-an-index system.

With this update to the PR, this patch is still not breaking a
user's watchpoint up into multiple WatchpointResources, it is not
sharing a single WatchpointResource for multiple Watchpoints, and
it is still not updating all Watchpoints for a Resource when an
access is received.

I am starting to be a little worried about the work needing to be
done in the Process plugin to finish this feature - I will have
no ability to build or test ProcessWindows or NativeProcessWindows.
I will do the rest of the work trying to keep it in base classes
to reduce the amount of change needed in those, but I doubt it will
be enough that I can change those blindly.
---
 lldb/include/lldb/Breakpoint/Watchpoint.h     |   2 +
 .../lldb/Breakpoint/WatchpointCollection.h    | 114 +++++++++++++
 .../lldb/Breakpoint/WatchpointResource.h      | 140 ++++++++++++++++
 .../lldb/Breakpoint/WatchpointResourceList.h  | 146 +++++++++++++++++
 lldb/include/lldb/Target/Process.h            |  10 +-
 lldb/include/lldb/Target/WatchpointResource.h |  57 -------
 .../lldb/Target/WatchpointResourceList.h      |  85 ----------
 lldb/include/lldb/lldb-defines.h              |   1 +
 lldb/include/lldb/lldb-forward.h              |   1 +
 lldb/include/lldb/lldb-types.h                |   1 +
 lldb/source/Breakpoint/CMakeLists.txt         |   3 +
 lldb/source/Breakpoint/Watchpoint.cpp         |  11 ++
 .../Breakpoint/WatchpointCollection.cpp       |  90 ++++++++++
 lldb/source/Breakpoint/WatchpointResource.cpp |  96 +++++++++++
 .../Breakpoint/WatchpointResourceList.cpp     | 154 ++++++++++++++++++
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  67 +++++---
 lldb/source/Target/CMakeLists.txt             |   2 -
 lldb/source/Target/StopInfo.cpp               |   1 +
 lldb/source/Target/WatchpointResource.cpp     |  49 ------
 lldb/source/Target/WatchpointResourceList.cpp |  61 -------
 .../watchpoints/watchpoint_count/main.c       |   4 +-
 21 files changed, 810 insertions(+), 285 deletions(-)
 create mode 100644 lldb/include/lldb/Breakpoint/WatchpointCollection.h
 create mode 100644 lldb/include/lldb/Breakpoint/WatchpointResource.h
 create mode 100644 lldb/include/lldb/Breakpoint/WatchpointResourceList.h
 delete mode 100644 lldb/include/lldb/Target/WatchpointResource.h
 delete mode 100644 lldb/include/lldb/Target/WatchpointResourceList.h
 create mode 100644 lldb/source/Breakpoint/WatchpointCollection.cpp
 create mode 100644 lldb/source/Breakpoint/WatchpointResource.cpp
 create mode 100644 lldb/source/Breakpoint/WatchpointResourceList.cpp
 delete mode 100644 lldb/source/Target/WatchpointResource.cpp
 delete mode 100644 lldb/source/Target/WatchpointResourceList.cpp

diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h
index 851162af24c74e0..e5b7291441e8484 100644
--- a/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -188,6 +188,8 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
 
   const CompilerType &GetCompilerType() { return m_type; }
 
+  uint32_t GetHardwareIndex() const override;
+
 private:
   friend class Target;
   friend class WatchpointList;
diff --git a/lldb/include/lldb/Breakpoint/WatchpointCollection.h b/lldb/include/lldb/Breakpoint/WatchpointCollection.h
new file mode 100644
index 000000000000000..55b707942ba043e
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/WatchpointCollection.h
@@ -0,0 +1,114 @@
+//===-- WatchpointCollection.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_WATCHPOINT_WATCHPOINTCOLLECTION_H
+#define LLDB_WATCHPOINT_WATCHPOINTCOLLECTION_H
+
+#include <mutex>
+#include <vector>
+
+#include "lldb/Utility/Iterable.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class WatchpointCollection {
+public:
+  WatchpointCollection();
+
+  ~WatchpointCollection();
+
+  WatchpointCollection &operator=(const WatchpointCollection &rhs);
+
+  /// Add the watchpoint \a wp_sp to the list.
+  ///
+  /// \param[in] wp_sp
+  ///     Shared pointer to the watchpoint that will get added
+  ///     to the list.
+  void Add(const lldb::WatchpointSP &wp_sp);
+
+  /// Removes the watchpoint given by \a wp_sp from this
+  /// list.
+  ///
+  /// \param[in] wp_sp
+  ///     The watchpoint to remove.
+  ///
+  /// \result
+  ///     \b true if the watchpoint was removed.
+  bool Remove(lldb::WatchpointSP &wp_sp);
+
+  /// Returns a shared pointer to the watchpoint with index
+  /// \a i.
+  ///
+  /// \param[in] i
+  ///     The watchpoint index to seek for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint.  May return
+  ///     empty shared pointer if the index is out of bounds.
+  lldb::WatchpointSP GetByIndex(size_t i);
+
+  /// Returns a shared pointer to the watchpoint with index
+  /// \a i, const version.
+  ///
+  /// \param[in] i
+  ///     The watchpoint index to seek for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint.  May return
+  ///     empty shared pointer if the index is out of bounds.
+  const lldb::WatchpointSP GetByIndex(size_t i) const;
+
+  /// Returns if the collection includes a WatchpointSP.
+  ///
+  /// \param[in] wp_sp
+  ///     The WatchpointSP to search for.
+  ///
+  /// \result
+  ///     true if this collection includes the WatchpointSP.
+  bool Contains(const lldb::WatchpointSP &wp_sp);
+
+  /// Returns if the collection includes a Watchpoint.
+  ///
+  /// \param[in] wp
+  ///     The Watchpoint to search for.
+  ///
+  /// \result
+  ///     true if this collection includes the WatchpointSP.
+  bool Contains(const Watchpoint *wp);
+
+  /// Returns the number of elements in this watchpoint list.
+  ///
+  /// \result
+  ///     The number of elements.
+  size_t GetSize() const { return m_collection.size(); }
+
+  /// Clear the watchpoint list.
+  void Clear();
+
+private:
+  // For WatchpointCollection only
+
+  typedef std::vector<lldb::WatchpointSP> collection;
+  typedef collection::iterator iterator;
+  typedef collection::const_iterator const_iterator;
+
+  collection m_collection;
+  mutable std::mutex m_collection_mutex;
+
+public:
+  typedef AdaptedIterable<collection, lldb::WatchpointSP, vector_adapter>
+      WatchpointCollectionIterable;
+  WatchpointCollectionIterable Watchpoints() {
+    return WatchpointCollectionIterable(m_collection);
+  }
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_WATCHPOINT_WATCHPOINTCOLLECTION_H
diff --git a/lldb/include/lldb/Breakpoint/WatchpointResource.h b/lldb/include/lldb/Breakpoint/WatchpointResource.h
new file mode 100644
index 000000000000000..092a82a7d63edcb
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/WatchpointResource.h
@@ -0,0 +1,140 @@
+//===-- WatchpointResource.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_BREAKPOINT_WATCHPOINTRESOURCE_H
+#define LLDB_BREAKPOINT_WATCHPOINTRESOURCE_H
+
+#include "lldb/Breakpoint/WatchpointCollection.h"
+#include "lldb/lldb-public.h"
+
+#include <set>
+
+namespace lldb_private {
+
+class WatchpointResource
+    : public std::enable_shared_from_this<WatchpointResource> {
+
+public:
+  // Constructors and Destructors
+  WatchpointResource(lldb::addr_t addr, size_t size, bool read, bool write);
+
+  ~WatchpointResource();
+
+  void GetMemoryRange(lldb::addr_t &addr, size_t &size) const;
+
+  lldb::addr_t GetAddress() const;
+
+  size_t GetByteSize() const;
+
+  void GetType(bool &read, bool &write) const;
+
+  void SetType(bool read, bool write);
+
+  /// The "Owners" are the watchpoints that share this resource.
+  /// The method adds the \a owner to this resource's owner list.
+  ///
+  /// \param[in] owner
+  ///    \a owner is the Wachpoint to add.
+  void AddOwner(const lldb::WatchpointSP &owner);
+
+  /// The method removes the owner at \a owner from this watchpoint
+  /// resource.
+  void RemoveOwner(lldb::WatchpointSP &owner);
+
+  /// This method returns the number of Watchpoints currently using
+  /// watchpoint resource.
+  ///
+  /// \return
+  ///    The number of owners.
+  size_t GetNumberOfOwners();
+
+  /// This method returns the Watchpoint at index \a index using this
+  /// Resource.  The owners are listed ordinally from 0 to
+  /// GetNumberOfOwners() - 1 so you can use this method to iterate over the
+  /// owners.
+  ///
+  /// \param[in] idx
+  ///     The index in the list of owners for which you wish the owner location.
+  ///
+  /// \return
+  ///    The Watchpoint at that index.
+  lldb::WatchpointSP GetOwnerAtIndex(size_t idx);
+
+  /// Check if the owners includes a watchpoint.
+  ///
+  /// \param[in] wp_sp
+  ///     The WatchpointSP to search for.
+  ///
+  /// \result
+  ///     true if this resource's owners includes the watchpoint.
+  bool OwnersContains(lldb::WatchpointSP &wp_sp);
+
+  /// Check if the owners includes a watchpoint.
+  ///
+  /// \param[in] wp
+  ///     The Watchpoint to search for.
+  ///
+  /// \result
+  ///     true if this resource's owners includes the watchpoint.
+  bool OwnersContains(const lldb_private::Watchpoint *wp);
+
+  /// This method copies the watchpoint resource's owners into a new collection.
+  /// It does this while the owners mutex is locked.
+  ///
+  /// \param[out] out_collection
+  ///    The BreakpointLocationCollection into which to put the owners
+  ///    of this breakpoint site.
+  ///
+  /// \return
+  ///    The number of elements copied into out_collection.
+  size_t CopyOwnersList(WatchpointCollection &out_collection);
+
+  // The ID of the WatchpointResource is set by the WatchpointResourceList
+  // when the Resource has been set in the inferior and is being added
+  // to the List, in an attempt to match the hardware watchpoint register
+  // ordering.  If a Process can correctly identify the hardware watchpoint
+  // register index when it has created the Resource, it may initialize it
+  // before it is inserted in the WatchpointResourceList.
+  void SetID(lldb::wp_resource_id_t);
+
+  lldb::wp_resource_id_t GetID() const;
+
+  bool Contains(lldb::addr_t addr);
+
+protected:
+  // The StopInfoWatchpoint knows when it is processing a hit for a thread for
+  // a site, so let it be the one to manage setting the location hit count once
+  // and only once.
+  friend class StopInfoWatchpoint;
+
+  void BumpHitCounts();
+
+private:
+  lldb::wp_resource_id_t m_id;
+
+  // start address & size aligned & expanded to be a valid watchpoint
+  // memory granule on this target.
+  lldb::addr_t m_addr;
+  size_t m_size;
+
+  bool m_watch_read;  // true if we stop when the watched data is read from
+  bool m_watch_write; // true if we stop when the watched data is written to
+
+  // The watchpoints using this WatchpointResource.
+  WatchpointCollection m_owners;
+
+  std::recursive_mutex
+      m_owners_mutex; ///< This mutex protects the owners collection.
+
+  WatchpointResource(const WatchpointResource &) = delete;
+  const WatchpointResource &operator=(const WatchpointResource &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_BREAKPOINT_WATCHPOINTRESOURCE_H
diff --git a/lldb/include/lldb/Breakpoint/WatchpointResourceList.h b/lldb/include/lldb/Breakpoint/WatchpointResourceList.h
new file mode 100644
index 000000000000000..17c8a3cd3f8b2b1
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/WatchpointResourceList.h
@@ -0,0 +1,146 @@
+//===-- WatchpointResourceList.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_BREAKPOINT_WATCHPOINTRESOURCELIST_H
+#define LLDB_BREAKPOINT_WATCHPOINTRESOURCELIST_H
+
+#include "lldb/Utility/Iterable.h"
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-public.h"
+
+#include <mutex>
+#include <vector>
+
+namespace lldb_private {
+
+class WatchpointResourceList {
+
+public:
+  // Constructors and Destructors
+  WatchpointResourceList();
+
+  ~WatchpointResourceList();
+
+  /// Add a WatchpointResource to the list.
+  ///
+  /// \param[in] wp_res_sp
+  ///    A shared pointer to a breakpoint site being added to the list.
+  ///
+  /// \return
+  ///    The ID of the BreakpointSite in the list.
+  lldb::wp_resource_id_t Add(const lldb::WatchpointResourceSP &wp_res_sp);
+
+  /// Removes the watchpoint resource given by \a id from this list.
+  ///
+  /// \param[in] id
+  ///   The watchpoint resource to remove.
+  ///
+  /// \result
+  ///   \b true if the watchpoint resource \a id was in the list.
+  bool Remove(lldb::wp_resource_id_t id);
+
+  /// Removes the watchpoint resource containing address \a addr from this list.
+  ///
+  /// \param[in] addr
+  ///   The address from which to remove a watchpoint resource.
+  ///
+  /// \result
+  ///   \b true if \a addr had a watchpoint resource to remove from the list.
+  bool RemoveByAddress(lldb::addr_t addr);
+
+  /// Returns a shared pointer to the watchpoint resource which contains
+  /// \a addr.
+  ///
+  /// \param[in] addr
+  ///     The address to look for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint resource. May contain a nullptr
+  ///     pointer if no watchpoint site exists with a matching address.
+  lldb::WatchpointResourceSP FindByAddress(lldb::addr_t addr);
+
+  /// Returns a shared pointer to the watchpoint resource which is owned
+  /// by \a wp_sp.
+  ///
+  /// \param[in] wp_sp
+  ///     The WatchpointSP to look for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint resource. May contain a nullptr
+  ///     pointer if no watchpoint site exists
+  lldb::WatchpointResourceSP FindByWatchpointSP(lldb::WatchpointSP &wp_sp);
+
+  /// Returns a shared pointer to the watchpoint resource which is owned
+  /// by \a wp.
+  ///
+  /// \param[in] wp
+  ///     The Watchpoint to look for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint resource. May contain a nullptr
+  ///     pointer if no watchpoint site exists
+  lldb::WatchpointResourceSP
+  FindByWatchpoint(const lldb_private::Watchpoint *wp);
+
+  /// Returns a shared pointer to the watchpoint resource which has hardware
+  /// index \a id.  Some Process plugins may not have access to the actual
+  /// hardware watchpoint register number used for a WatchpointResource, so
+  /// the wp_resource_id_t may not be correctly tracking the target's wp
+  /// register target.
+  ///
+  /// \param[in] id
+  ///     The hardware resource index to search for.
+  ///
+  /// \result
+  ///     A shared pointer to the watchpoint resource. May contain a nullptr
+  ///     pointer if no watchpoint site exists with a matching id.
+  lldb::WatchpointResourceSP FindByID(lldb::wp_resource_id_t id);
+
+  ///
+  /// Get the number of WatchpointResources that are available.
+  ///
+  /// \return
+  ///     The number of WatchpointResources that are stored in the
+  ///     WatchpointResourceList.
+  uint32_t GetSize();
+
+  /// Get the WatchpointResource at a given index.
+  ///
+  /// \param [in] idx
+  ///     The index of the resource.
+  /// \return
+  ///     The WatchpointResource at that index number.
+  lldb::WatchpointResourceSP GetResourceAtIndex(uint32_t idx);
+
+  typedef std::vector<lldb::WatchpointResourceSP> collection;
+  typedef LockingAdaptedIterable<collection, lldb::WatchpointResourceSP,
+                                 vector_adapter, std::mutex>
+      WatchpointResourceIterable;
+
+  /// Iterate over the list of WatchpointResources.
+  ///
+  /// \return
+  ///     An Iterable object which can be used to loop over the resources
+  ///     that exist.
+  WatchpointResourceIterable Resources() {
+    return WatchpointResourceIterable(m_resources, m_mutex);
+  }
+
+  /// Clear out the list of resources from the WatchpointResourceList
+  void Clear();
+
+  std::mutex &GetMutex();
+
+private:
+  collection m_resources;
+  std::mutex m_mutex;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_BREAKPOINT_WATCHPOINTRESOURCELIST_H
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 65fe74620a26dea..6f140dd1a10ea57 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "lldb/Breakpoint/BreakpointSiteList.h"
+#include "lldb/Breakpoint/WatchpointResourceList.h"
 #include "lldb/Core/LoadedModuleInfoList.h"
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/Core/SourceManager.h"
@@ -41,8 +42,6 @@
 #include "lldb/Target/ThreadList.h"
 #include "lldb/Target/ThreadPlanStack.h"
 #include "lldb/Target/Trace.h"
-#include "lldb/Target/WatchpointResource.h"
-#include "lldb/Target/WatchpointResourceList.h"
 #include "lldb/Utility/ArchSpec.h"
 #include "lldb/Utility/Broadcaster.h"
 #include "lldb/Utility/Event.h"
@@ -2185,6 +2184,10 @@ class Process : public std::enable_shared_from_this<Process>,
 
   ThreadList &GetThreadList() { return m_thread_list; }
 
+  WatchpointResourceList &GetWatchpointResourceList() {
+    return m_watchpoint_resource_list;
+  }
+
   // When ExtendedBacktraces are requested, the HistoryThreads that are created
   // need an owner -- they're saved here in the Process.  The threads in this
   // list are not iterated over - driver programs need to request the extended
@@ -3102,9 +3105,6 @@ void PruneThreadPlans();
   std::unique_ptr<UtilityFunction> m_dlopen_utility_func_up;
   llvm::once_flag m_dlopen_utility_func_flag_once;
 
-  // Watchpoint hardware registers currently in use.
-  std::vector<lldb::WatchpointResourceSP> m_watchpoint_resources;
-
   /// Per process source file cache.
   SourceManager::SourceFileCache m_source_file_cache;
 
diff --git a/lldb/include/lldb/Target/WatchpointResource.h b/lldb/include/lldb/Target/WatchpointResource.h
deleted file mode 100644
index 73b539e79f9bfbb..000000000000000
--- a/lldb/include/lldb/Target/WatchpointResource.h
+++ /dev/null
@@ -1,57 +0,0 @@
-//===-- WatchpointResource.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_TARGET_WATCHPOINTRESOURCE_H
-#define LLDB_TARGET_WATCHPOINTRESOURCE_H
-
-#include "lldb/lldb-public.h"
-
-#include <set>
-
-namespace lldb_private {
-
-class WatchpointResource
-    : public std::enable_shared_from_this<WatchpointResource> {
-
-public:
-  // Constructors and Destructors
-  WatchpointResource(lldb::addr_t addr, size_t size, bool read, bool write);
-
-  ~WatchpointResource();
-
-  void GetResourceMemoryRange(lldb::addr_t &addr, size_t &size) const;
-
-  void GetResourceType(bool &read, bool &write) const;
-
-  void RegisterWatchpoint(lldb::WatchpointSP &wp_sp);
-
-  void DeregisterWatchpoint(lldb::WatchpointSP &wp_sp);
-
-  size_t GetNumDependantWatchpoints();
-
-  bool DependantWatchpointsContains(lldb::WatchpointSP wp_sp_to_match);
-
-private:
-  WatchpointResource(const WatchpointResource &) = delete;
-  const WatchpointResource &operator=(const WatchpointResource &) = delete;
-
-  // start address & size aligned & expanded to be a valid watchpoint
-  // memory granule on this target.
-  lldb::addr_t m_addr;
-  size_t m_size;
-
-  bool m_watch_read;  // true if we stop when the watched data is read from
-  bool m_watch_write; // true if we stop when the watched data is written to
-
-  // The watchpoints using this WatchpointResource.
-  std::set<lldb::WatchpointSP> m_watchpoints;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_TARGET_WATCHPOINTRESOURCE_H
diff --git a/lldb/include/lldb/Target/WatchpointResourceList.h b/lldb/include/lldb/Target/WatchpointResourceList.h
deleted file mode 100644
index 9570e337f1e6ccb..000000000000000
--- a/lldb/include/lldb/Target/WatchpointResourceList.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===-- WatchpointResourceList.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_TARGET_WATCHPOINTRESOURCELIST_H
-#define LLDB_TARGET_WATCHPOINTRESOURCELIST_H
-
-#include "lldb/Utility/Iterable.h"
-#include "lldb/lldb-private.h"
-#include "lldb/lldb-public.h"
-
-#include <mutex>
-#include <vector>
-
-namespace lldb_private {
-
-class WatchpointResourceList {
-
-public:
-  // Constructors and Destructors
-  WatchpointResourceList();
-
-  ~WatchpointResourceList();
-
-  /// Get the number of WatchpointResources that are available.
-  ///
-  /// \return
-  ///     The number of WatchpointResources that are stored in the
-  ///     WatchpointResourceList.
-  uint32_t GetSize();
-
-  /// Get the WatchpointResource at a given index.
-  ///
-  /// \param [in] idx
-  ///     The index of the resource.
-  /// \return
-  ///     The WatchpointResource at that index number.
-  lldb::WatchpointResourceSP GetResourceAtIndex(uint32_t idx);
-
-  /// Remove a WatchpointResource from the list.
-  ///
-  /// The WatchpointResource must have already been disabled in the
-  /// Process; this method only removes it from the list.
-  ///
-  /// \param [in] wp_resource_sp
-  ///     The WatchpointResource to remove.
-  void RemoveWatchpointResource(lldb::WatchpointResourceSP wp_resource_sp);
-
-  typedef std::vector<lldb::WatchpointResourceSP> collection;
-  typedef LockingAdaptedIterable<collection, lldb::WatchpointResourceSP,
-                                 vector_adapter, std::mutex>
-      WatchpointResourceIterable;
-
-  /// Iterate over the list of WatchpointResources.
-  ///
-  /// \return
-  ///     An Iterable object which can be used to loop over the resources
-  ///     that exist.
-  WatchpointResourceIterable Resources() {
-    return WatchpointResourceIterable(m_resources, m_mutex);
-  }
-
-  /// Clear out the list of resources from the WatchpointResourceList
-  void Clear();
-
-  /// Add a WatchpointResource to the WatchpointResourceList.
-  ///
-  /// \param [in] resource
-  ///     A WatchpointResource to be added.
-  void AddResource(lldb::WatchpointResourceSP resource_sp);
-
-  std::mutex &GetMutex();
-
-private:
-  collection m_resources;
-  std::mutex m_mutex;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_TARGET_WATCHPOINTRESOURCELIST_H
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index 6950a4f3a496acf..16bf253232e92c8 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -92,6 +92,7 @@
 #define LLDB_INVALID_COLUMN_NUMBER 0
 #define LLDB_INVALID_QUEUE_ID 0
 #define LLDB_INVALID_CPU_ID UINT32_MAX
+#define LLDB_INVALID_WATCHPOINT_RESOURCE_ID UINT32_MAX
 
 /// CPU Type definitions
 #define LLDB_ARCH_DEFAULT "systemArch"
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index fa352cc7d9d91a2..4feff7439bfe565 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -290,6 +290,7 @@ class Watchpoint;
 class WatchpointList;
 class WatchpointOptions;
 class WatchpointResource;
+class WatchpointResourceCollection;
 class WatchpointSetOptions;
 struct CompilerContext;
 struct LineEntry;
diff --git a/lldb/include/lldb/lldb-types.h b/lldb/include/lldb/lldb-types.h
index d9c2a21c2daa062..d60686e33142ac3 100644
--- a/lldb/include/lldb/lldb-types.h
+++ b/lldb/include/lldb/lldb-types.h
@@ -83,6 +83,7 @@ typedef uint64_t tid_t;
 typedef uint64_t offset_t;
 typedef int32_t break_id_t;
 typedef int32_t watch_id_t;
+typedef uint32_t wp_resource_id_t;
 typedef void *opaque_compiler_type_t;
 typedef uint64_t queue_id_t;
 typedef uint32_t cpu_id_t; // CPU core id
diff --git a/lldb/source/Breakpoint/CMakeLists.txt b/lldb/source/Breakpoint/CMakeLists.txt
index 5c2802322ed52c1..47cfd67a6920da8 100644
--- a/lldb/source/Breakpoint/CMakeLists.txt
+++ b/lldb/source/Breakpoint/CMakeLists.txt
@@ -22,7 +22,10 @@ add_lldb_library(lldbBreakpoint NO_PLUGIN_DEPENDENCIES
   StoppointSite.cpp
   Watchpoint.cpp
   WatchpointList.cpp
+  WatchpointCollection.cpp
   WatchpointOptions.cpp
+  WatchpointResource.cpp
+  WatchpointResourceList.cpp
 
   LINK_LIBS
     lldbCore
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index 2718852a68e15f2..1a9e0359d24e4b3 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -9,6 +9,7 @@
 #include "lldb/Breakpoint/Watchpoint.h"
 
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
 #include "lldb/Core/Value.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Core/ValueObjectMemory.h"
@@ -372,6 +373,16 @@ void Watchpoint::DumpWithLevel(Stream *s,
 
 bool Watchpoint::IsEnabled() const { return m_enabled; }
 
+uint32_t Watchpoint::GetHardwareIndex() const {
+  if (IsEnabled())
+    return m_target.GetProcessSP()
+        ->GetWatchpointResourceList()
+        .FindByWatchpoint(this)
+        ->GetID();
+  else
+    return UINT32_MAX;
+}
+
 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
 // temporarily disable the watchpoint in order to perform possible watchpoint
 // actions without triggering further watchpoint events. After the temporary
diff --git a/lldb/source/Breakpoint/WatchpointCollection.cpp b/lldb/source/Breakpoint/WatchpointCollection.cpp
new file mode 100644
index 000000000000000..ab8df84d00b2364
--- /dev/null
+++ b/lldb/source/Breakpoint/WatchpointCollection.cpp
@@ -0,0 +1,90 @@
+//===-- WatchpointCollection.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/Breakpoint/WatchpointCollection.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// WatchpointCollection constructor
+WatchpointCollection::WatchpointCollection() = default;
+
+// Destructor
+WatchpointCollection::~WatchpointCollection() = default;
+
+void WatchpointCollection::Add(const WatchpointSP &wp) {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  m_collection.push_back(wp);
+}
+
+bool WatchpointCollection::Remove(WatchpointSP &wp) {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  for (collection::iterator pos = m_collection.begin();
+       pos != m_collection.end(); ++pos) {
+    if (*pos == wp) {
+      m_collection.erase(pos);
+      return true;
+    }
+  }
+  return false;
+}
+
+WatchpointSP WatchpointCollection::GetByIndex(size_t i) {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  if (i < m_collection.size())
+    return m_collection[i];
+  return {};
+}
+
+const WatchpointSP WatchpointCollection::GetByIndex(size_t i) const {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  if (i < m_collection.size())
+    return m_collection[i];
+  return {};
+}
+
+WatchpointCollection &
+WatchpointCollection::operator=(const WatchpointCollection &rhs) {
+  if (this != &rhs) {
+    std::lock(m_collection_mutex, rhs.m_collection_mutex);
+    std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
+    std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex,
+                                          std::adopt_lock);
+    m_collection = rhs.m_collection;
+  }
+  return *this;
+}
+
+void WatchpointCollection::Clear() {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  m_collection.clear();
+}
+
+bool WatchpointCollection::Contains(const WatchpointSP &wp_sp) {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  const size_t size = m_collection.size();
+  for (size_t i = 0; i < size; ++i) {
+    if (m_collection[i] == wp_sp)
+      return true;
+  }
+  return false;
+}
+
+bool WatchpointCollection::Contains(const Watchpoint *wp) {
+  std::lock_guard<std::mutex> guard(m_collection_mutex);
+  const size_t size = m_collection.size();
+  for (size_t i = 0; i < size; ++i) {
+    if (m_collection[i].get() == wp)
+      return true;
+  }
+  return false;
+}
diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
new file mode 100644
index 000000000000000..ed8c707a34faf5b
--- /dev/null
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -0,0 +1,96 @@
+//===-- WatchpointResource.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/Breakpoint/WatchpointResource.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
+                                       bool read, bool write)
+    : m_id(LLDB_INVALID_WATCHPOINT_RESOURCE_ID), m_addr(addr), m_size(size),
+      m_watch_read(read), m_watch_write(write) {}
+
+WatchpointResource::~WatchpointResource() {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  m_owners.Clear();
+}
+
+void WatchpointResource::GetMemoryRange(lldb::addr_t &addr,
+                                        size_t &size) const {
+  addr = m_addr;
+  size = m_size;
+}
+
+addr_t WatchpointResource::GetAddress() const { return m_addr; }
+
+size_t WatchpointResource::GetByteSize() const { return m_size; }
+
+void WatchpointResource::GetType(bool &read, bool &write) const {
+  read = m_watch_read;
+  write = m_watch_write;
+}
+
+void WatchpointResource::SetType(bool read, bool write) {
+  m_watch_read = read;
+  m_watch_write = write;
+}
+
+wp_resource_id_t WatchpointResource::GetID() const { return m_id; }
+
+void WatchpointResource::SetID(wp_resource_id_t id) { m_id = id; }
+
+bool WatchpointResource::Contains(addr_t addr) {
+  if (addr >= m_addr && addr < m_addr + m_size)
+    return true;
+  return false;
+}
+
+void WatchpointResource::AddOwner(const WatchpointSP &wp_sp) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  m_owners.Add(wp_sp);
+}
+
+void WatchpointResource::RemoveOwner(WatchpointSP &wp_sp) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  m_owners.Remove(wp_sp);
+}
+
+size_t WatchpointResource::GetNumberOfOwners() {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  return m_owners.GetSize();
+}
+
+bool WatchpointResource::OwnersContains(WatchpointSP &wp_sp) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  return m_owners.Contains(wp_sp);
+}
+
+bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  return m_owners.Contains(wp);
+}
+
+WatchpointSP WatchpointResource::GetOwnerAtIndex(size_t idx) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  assert(idx < m_owners.GetSize());
+  if (idx >= m_owners.GetSize())
+    return {};
+
+  return m_owners.GetByIndex(idx);
+}
+
+size_t
+WatchpointResource::CopyOwnersList(WatchpointCollection &out_collection) {
+  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  const size_t size = m_owners.GetSize();
+  for (size_t i = 0; i < size; ++i) {
+    out_collection.Add(m_owners.GetByIndex(i));
+  }
+  return out_collection.GetSize();
+}
diff --git a/lldb/source/Breakpoint/WatchpointResourceList.cpp b/lldb/source/Breakpoint/WatchpointResourceList.cpp
new file mode 100644
index 000000000000000..8a65ae231211c0c
--- /dev/null
+++ b/lldb/source/Breakpoint/WatchpointResourceList.cpp
@@ -0,0 +1,154 @@
+//===-- WatchpointResourceList.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/Breakpoint/WatchpointResourceList.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointResourceList::WatchpointResourceList() : m_resources(), m_mutex() {}
+
+WatchpointResourceList::~WatchpointResourceList() { Clear(); }
+
+wp_resource_id_t
+WatchpointResourceList::Add(const WatchpointResourceSP &wp_res_sp) {
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  std::lock_guard<std::mutex> guard(m_mutex);
+
+  LLDB_LOGF(log, "WatchpointResourceList::Add(addr 0x%" PRIx64 " size %zu)",
+            wp_res_sp->GetAddress(), wp_res_sp->GetByteSize());
+
+  // The goal is to have the wp_resource_id_t match the actual hardware
+  // watchpoint register number.  If we assume that the remote stub is
+  // setting them in the register context in the same order that they
+  // are sent from lldb, and if a watchpoint is removed and then a new
+  // one is added and gets the same register number, then we can
+  // iterate over all used IDs looking for the first unused number.
+
+  // If the Process was able to find the actual hardware watchpoint register
+  // number that was used, it can set the ID for the WatchpointResource
+  // before we get here.
+
+  if (wp_res_sp->GetID() == LLDB_INVALID_WATCHPOINT_RESOURCE_ID) {
+    std::set<wp_resource_id_t> used_ids;
+    size_t size = m_resources.size();
+    for (size_t i = 0; i < size; ++i)
+      used_ids.insert(m_resources[i]->GetID());
+
+    wp_resource_id_t best = 0;
+    for (wp_resource_id_t id : used_ids)
+      if (id == best)
+        best++;
+      else
+        break;
+
+    LLDB_LOGF(log,
+              "WatchpointResourceList::Add assigning next "
+              "available WatchpointResource ID, %u",
+              best);
+    wp_res_sp->SetID(best);
+  }
+
+  m_resources.push_back(wp_res_sp);
+  return wp_res_sp->GetID();
+}
+
+bool WatchpointResourceList::Remove(wp_resource_id_t id) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos) {
+    if ((*pos)->GetID() == id) {
+      LLDB_LOGF(log,
+                "WatchpointResourceList::Remove(addr 0x%" PRIx64 " size %zu)",
+                (*pos)->GetAddress(), (*pos)->GetByteSize());
+      m_resources.erase(pos);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool WatchpointResourceList::RemoveByAddress(addr_t addr) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  Log *log = GetLog(LLDBLog::Watchpoints);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos) {
+    if ((*pos)->Contains(addr)) {
+      LLDB_LOGF(log,
+                "WatchpointResourceList::RemoveByAddress(addr 0x%" PRIx64
+                " size %zu)",
+                (*pos)->GetAddress(), (*pos)->GetByteSize());
+      m_resources.erase(pos);
+      return true;
+    }
+  }
+  return false;
+}
+
+WatchpointResourceSP WatchpointResourceList::FindByAddress(addr_t addr) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos)
+    if ((*pos)->Contains(addr))
+      return *pos;
+  return {};
+}
+
+WatchpointResourceSP
+WatchpointResourceList::FindByWatchpointSP(WatchpointSP &wp_sp) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos)
+    if ((*pos)->OwnersContains(wp_sp))
+      return *pos;
+  return {};
+}
+
+WatchpointResourceSP
+WatchpointResourceList::FindByWatchpoint(const Watchpoint *wp) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos)
+    if ((*pos)->OwnersContains(wp))
+      return *pos;
+  return {};
+}
+
+WatchpointResourceSP WatchpointResourceList::FindByID(wp_resource_id_t id) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
+       ++pos)
+    if ((*pos)->GetID() == id)
+      return *pos;
+  return {};
+}
+
+uint32_t WatchpointResourceList::GetSize() {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  return m_resources.size();
+}
+
+lldb::WatchpointResourceSP
+WatchpointResourceList::GetResourceAtIndex(uint32_t idx) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  if (idx < m_resources.size())
+    return m_resources[idx];
+
+  return {};
+}
+
+void WatchpointResourceList::Clear() {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  m_resources.clear();
+}
+
+std::mutex &WatchpointResourceList::GetMutex() { return m_mutex; }
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index ef527a261e859b1..d6aa4a338b60717 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 
 #include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
@@ -1798,27 +1799,41 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
           addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
           watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
           bool silently_continue = false;
-          WatchpointSP wp_sp;
-          // LWP_TODO: We need to find the WatchpointResource that matches
-          // the address, and evaluate its Watchpoints.
+          WatchpointResourceSP wp_resource_sp;
+          if (wp_hw_index != LLDB_INVALID_WATCHPOINT_RESOURCE_ID) {
+            wp_resource_sp = m_watchpoint_resource_list.FindByID(wp_hw_index);
+            if (wp_resource_sp) {
+              // If we were given an access address, and the Resource we
+              // found by watchpoint register index does not contain that
+              // address, then the wp_resource_id's have not tracked the
+              // hardware watchpoint registers correctly, discard this
+              // Resource found by ID and look it up by access address.
+              if (wp_hit_addr != LLDB_INVALID_ADDRESS &&
+                  !wp_resource_sp->Contains(wp_hit_addr)) {
+                wp_resource_sp.reset();
+              }
+            }
+          }
           if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
-            wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr);
+            wp_resource_sp =
+                m_watchpoint_resource_list.FindByAddress(wp_hit_addr);
             // On MIPS, \a wp_hit_addr outside the range of a watched
             // region means we should silently continue, it is a false hit.
             ArchSpec::Core core = GetTarget().GetArchitecture().GetCore();
-            if (!wp_sp && core >= ArchSpec::kCore_mips_first &&
+            if (!wp_resource_sp && core >= ArchSpec::kCore_mips_first &&
                 core <= ArchSpec::kCore_mips_last)
               silently_continue = true;
           }
-          if (!wp_sp && wp_addr != LLDB_INVALID_ADDRESS)
-            wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
-          if (wp_sp) {
-            watch_id = wp_sp->GetID();
-          }
-          if (watch_id == LLDB_INVALID_WATCH_ID) {
+          if (!wp_resource_sp && wp_addr != LLDB_INVALID_ADDRESS)
+            wp_resource_sp = m_watchpoint_resource_list.FindByAddress(wp_addr);
+          if (!wp_resource_sp) {
             Log *log(GetLog(GDBRLog::Watchpoints));
             LLDB_LOGF(log, "failed to find watchpoint");
           }
+          // LWP_TODO: This is hardcoding a single Watchpoint in a
+          // Resource, need to add
+          // StopInfo::CreateStopReasonWithWatchpointResource
+          watch_id = wp_resource_sp->GetOwnerAtIndex(0)->GetID();
           thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
               *thread_sp, watch_id, silently_continue));
           handled = true;
@@ -2241,8 +2256,12 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
         lldb::addr_t wp_addr = LLDB_INVALID_ADDRESS;
         value.getAsInteger(16, wp_addr);
 
-        WatchpointSP wp_sp =
-            GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+        WatchpointResourceSP wp_resource_sp =
+            m_watchpoint_resource_list.FindByAddress(wp_addr);
+        uint32_t wp_index = LLDB_INVALID_INDEX32;
+
+        if (wp_resource_sp)
+          wp_index = wp_resource_sp->GetID();
 
         // Rewrite gdb standard watch/rwatch/awatch to
         // "reason:watchpoint" + "description:ADDR",
@@ -3113,7 +3132,7 @@ static GDBStoppointType
 GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
   assert(wp_res_sp);
   bool read, write;
-  wp_res_sp->GetResourceType(read, write);
+  wp_res_sp->GetType(read, write);
 
   assert((read || write) && "read and write cannot both be false.");
   if (read && write)
@@ -3190,7 +3209,7 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
     for (const auto &wp_res_sp : resources) {
       addr_t addr;
       size_t size;
-      wp_res_sp->GetResourceMemoryRange(addr, size);
+      wp_res_sp->GetMemoryRange(addr, size);
       GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
       if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
           m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
@@ -3206,8 +3225,8 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
       for (const auto &wp_res_sp : resources) {
         // LWP_TODO: If we expanded/reused an existing Resource,
         // it's already in the WatchpointResourceList.
-        wp_res_sp->RegisterWatchpoint(wp_sp);
-        m_watchpoint_resource_list.AddResource(wp_res_sp);
+        wp_res_sp->AddOwner(wp_sp);
+        m_watchpoint_resource_list.Add(wp_res_sp);
       }
       return error;
     } else {
@@ -3217,7 +3236,7 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
       for (const auto &wp_res_sp : succesfully_set_resources) {
         addr_t addr;
         size_t size;
-        wp_res_sp->GetResourceMemoryRange(addr, size);
+        wp_res_sp->GetMemoryRange(addr, size);
         GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
         m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
                                               GetInterruptTimeout());
@@ -3261,23 +3280,23 @@ Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
 
       std::vector<WatchpointResourceSP> unused_resouces;
       for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
-        if (wp_res_sp->DependantWatchpointsContains(wp_sp)) {
+        if (wp_res_sp->OwnersContains(wp_sp)) {
           GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
           addr_t addr;
           size_t size;
-          wp_res_sp->GetResourceMemoryRange(addr, size);
+          wp_res_sp->GetMemoryRange(addr, size);
           if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
                                                     GetInterruptTimeout())) {
             disabled_all = false;
           } else {
-            wp_res_sp->DeregisterWatchpoint(wp_sp);
-            if (wp_res_sp->GetNumDependantWatchpoints() == 0)
+            wp_res_sp->RemoveOwner(wp_sp);
+            if (wp_res_sp->GetNumberOfOwners() == 0)
               unused_resouces.push_back(wp_res_sp);
           }
         }
       }
       for (auto &wp_res_sp : unused_resouces)
-        m_watchpoint_resource_list.RemoveWatchpointResource(wp_res_sp);
+        m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
 
       wp_sp->SetEnabled(false, notify);
       if (!disabled_all)
@@ -5541,7 +5560,7 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
   for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
     addr_t addr;
     size_t size;
-    wp_res_sp->GetResourceMemoryRange(addr, size);
+    wp_res_sp->GetMemoryRange(addr, size);
     GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
     m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
                                           GetInterruptTimeout());
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index 617a0610ac96360..cf4818eae3eb8b4 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -78,8 +78,6 @@ add_lldb_library(lldbTarget
   UnixSignals.cpp
   UnwindAssembly.cpp
   UnwindLLDB.cpp
-  WatchpointResource.cpp
-  WatchpointResourceList.cpp
 
   LINK_LIBS
     lldbBreakpoint
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 678605af74e588a..0975e6b64d2d7f3 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Expression/UserExpression.h"
diff --git a/lldb/source/Target/WatchpointResource.cpp b/lldb/source/Target/WatchpointResource.cpp
deleted file mode 100644
index b1ecffc73a415d5..000000000000000
--- a/lldb/source/Target/WatchpointResource.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-//===-- WatchpointResource.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/Target/WatchpointResource.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
-                                       bool read, bool write)
-    : m_addr(addr), m_size(size), m_watch_read(read), m_watch_write(write) {}
-
-WatchpointResource::~WatchpointResource() { m_watchpoints.clear(); }
-
-void WatchpointResource::GetResourceMemoryRange(lldb::addr_t &addr,
-                                                size_t &size) const {
-  addr = m_addr;
-  size = m_size;
-}
-
-void WatchpointResource::GetResourceType(bool &read, bool &write) const {
-  read = m_watch_read;
-  write = m_watch_write;
-}
-
-void WatchpointResource::RegisterWatchpoint(lldb::WatchpointSP &wp_sp) {
-  m_watchpoints.insert(wp_sp);
-}
-
-void WatchpointResource::DeregisterWatchpoint(lldb::WatchpointSP &wp_sp) {
-  m_watchpoints.erase(wp_sp);
-}
-
-size_t WatchpointResource::GetNumDependantWatchpoints() {
-  return m_watchpoints.size();
-}
-
-bool WatchpointResource::DependantWatchpointsContains(
-    WatchpointSP wp_sp_to_match) {
-  for (const WatchpointSP &wp_sp : m_watchpoints)
-    if (wp_sp == wp_sp_to_match)
-      return true;
-  return false;
-}
diff --git a/lldb/source/Target/WatchpointResourceList.cpp b/lldb/source/Target/WatchpointResourceList.cpp
deleted file mode 100644
index 44888736d59bc9f..000000000000000
--- a/lldb/source/Target/WatchpointResourceList.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-//===-- WatchpointResourceList.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/Target/WatchpointResourceList.h"
-#include "lldb/Target/WatchpointResource.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-WatchpointResourceList::WatchpointResourceList() : m_resources(), m_mutex() {}
-
-WatchpointResourceList::~WatchpointResourceList() { Clear(); }
-
-uint32_t WatchpointResourceList::GetSize() {
-  std::lock_guard<std::mutex> guard(m_mutex);
-  return m_resources.size();
-}
-
-lldb::WatchpointResourceSP
-WatchpointResourceList::GetResourceAtIndex(uint32_t idx) {
-  std::lock_guard<std::mutex> guard(m_mutex);
-  if (idx < m_resources.size()) {
-    return m_resources[idx];
-  } else {
-    return {};
-  }
-}
-
-void WatchpointResourceList::RemoveWatchpointResource(
-    WatchpointResourceSP wp_resource_sp) {
-  assert(wp_resource_sp->GetNumDependantWatchpoints() == 0);
-
-  std::lock_guard<std::mutex> guard(m_mutex);
-  collection::iterator pos = m_resources.begin();
-  while (pos != m_resources.end()) {
-    if (*pos == wp_resource_sp) {
-      m_resources.erase(pos);
-      return;
-    }
-    ++pos;
-  }
-}
-
-void WatchpointResourceList::Clear() {
-  std::lock_guard<std::mutex> guard(m_mutex);
-  m_resources.clear();
-}
-
-void WatchpointResourceList::AddResource(WatchpointResourceSP resource_sp) {
-  std::lock_guard<std::mutex> guard(m_mutex);
-  if (resource_sp) {
-    m_resources.push_back(resource_sp);
-  }
-}
-
-std::mutex &WatchpointResourceList::GetMutex() { return m_mutex; }
diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
index a170e173a33db24..fc9a370e41f3164 100644
--- a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
+++ b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c
@@ -2,8 +2,8 @@
 #include <stdio.h>
 
 int main() {
-  long x1 = 0;
-  long x2 = 0;
+  uint8_t x1 = 0;
+  uint16_t x2 = 0;
 
   printf("patatino\n");
 

>From eaca59f5683b25a70f718ac30719f8e5f36f7928 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Tue, 24 Oct 2023 22:12:11 -0700
Subject: [PATCH 03/11] Address Alex's feedback

Remove WatchpointCollection, this was little more than
a std::vector, so now it's a typedef to that.  In the
Breakpoint case where a BreakpointSite has a
BreakpointLocationCollection, the lldb container class
was needed.  Clean up WatchpointResource class API.
A few smaller fixups like using early returns to avoid
unnecessary indentation.
---
 .../lldb/Breakpoint/WatchpointCollection.h    | 114 -------
 .../lldb/Breakpoint/WatchpointResource.h      |  23 +-
 lldb/source/Breakpoint/CMakeLists.txt         |   1 -
 .../Breakpoint/WatchpointCollection.cpp       |  90 ------
 lldb/source/Breakpoint/WatchpointResource.cpp |  48 +--
 .../Process/gdb-remote/ProcessGDBRemote.cpp   | 287 +++++++++---------
 6 files changed, 187 insertions(+), 376 deletions(-)
 delete mode 100644 lldb/include/lldb/Breakpoint/WatchpointCollection.h
 delete mode 100644 lldb/source/Breakpoint/WatchpointCollection.cpp

diff --git a/lldb/include/lldb/Breakpoint/WatchpointCollection.h b/lldb/include/lldb/Breakpoint/WatchpointCollection.h
deleted file mode 100644
index 55b707942ba043e..000000000000000
--- a/lldb/include/lldb/Breakpoint/WatchpointCollection.h
+++ /dev/null
@@ -1,114 +0,0 @@
-//===-- WatchpointCollection.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_WATCHPOINT_WATCHPOINTCOLLECTION_H
-#define LLDB_WATCHPOINT_WATCHPOINTCOLLECTION_H
-
-#include <mutex>
-#include <vector>
-
-#include "lldb/Utility/Iterable.h"
-#include "lldb/lldb-private.h"
-
-namespace lldb_private {
-
-class WatchpointCollection {
-public:
-  WatchpointCollection();
-
-  ~WatchpointCollection();
-
-  WatchpointCollection &operator=(const WatchpointCollection &rhs);
-
-  /// Add the watchpoint \a wp_sp to the list.
-  ///
-  /// \param[in] wp_sp
-  ///     Shared pointer to the watchpoint that will get added
-  ///     to the list.
-  void Add(const lldb::WatchpointSP &wp_sp);
-
-  /// Removes the watchpoint given by \a wp_sp from this
-  /// list.
-  ///
-  /// \param[in] wp_sp
-  ///     The watchpoint to remove.
-  ///
-  /// \result
-  ///     \b true if the watchpoint was removed.
-  bool Remove(lldb::WatchpointSP &wp_sp);
-
-  /// Returns a shared pointer to the watchpoint with index
-  /// \a i.
-  ///
-  /// \param[in] i
-  ///     The watchpoint index to seek for.
-  ///
-  /// \result
-  ///     A shared pointer to the watchpoint.  May return
-  ///     empty shared pointer if the index is out of bounds.
-  lldb::WatchpointSP GetByIndex(size_t i);
-
-  /// Returns a shared pointer to the watchpoint with index
-  /// \a i, const version.
-  ///
-  /// \param[in] i
-  ///     The watchpoint index to seek for.
-  ///
-  /// \result
-  ///     A shared pointer to the watchpoint.  May return
-  ///     empty shared pointer if the index is out of bounds.
-  const lldb::WatchpointSP GetByIndex(size_t i) const;
-
-  /// Returns if the collection includes a WatchpointSP.
-  ///
-  /// \param[in] wp_sp
-  ///     The WatchpointSP to search for.
-  ///
-  /// \result
-  ///     true if this collection includes the WatchpointSP.
-  bool Contains(const lldb::WatchpointSP &wp_sp);
-
-  /// Returns if the collection includes a Watchpoint.
-  ///
-  /// \param[in] wp
-  ///     The Watchpoint to search for.
-  ///
-  /// \result
-  ///     true if this collection includes the WatchpointSP.
-  bool Contains(const Watchpoint *wp);
-
-  /// Returns the number of elements in this watchpoint list.
-  ///
-  /// \result
-  ///     The number of elements.
-  size_t GetSize() const { return m_collection.size(); }
-
-  /// Clear the watchpoint list.
-  void Clear();
-
-private:
-  // For WatchpointCollection only
-
-  typedef std::vector<lldb::WatchpointSP> collection;
-  typedef collection::iterator iterator;
-  typedef collection::const_iterator const_iterator;
-
-  collection m_collection;
-  mutable std::mutex m_collection_mutex;
-
-public:
-  typedef AdaptedIterable<collection, lldb::WatchpointSP, vector_adapter>
-      WatchpointCollectionIterable;
-  WatchpointCollectionIterable Watchpoints() {
-    return WatchpointCollectionIterable(m_collection);
-  }
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_WATCHPOINT_WATCHPOINTCOLLECTION_H
diff --git a/lldb/include/lldb/Breakpoint/WatchpointResource.h b/lldb/include/lldb/Breakpoint/WatchpointResource.h
index 092a82a7d63edcb..54335274d881067 100644
--- a/lldb/include/lldb/Breakpoint/WatchpointResource.h
+++ b/lldb/include/lldb/Breakpoint/WatchpointResource.h
@@ -9,9 +9,10 @@
 #ifndef LLDB_BREAKPOINT_WATCHPOINTRESOURCE_H
 #define LLDB_BREAKPOINT_WATCHPOINTRESOURCE_H
 
-#include "lldb/Breakpoint/WatchpointCollection.h"
+#include "lldb/Utility/Iterable.h"
 #include "lldb/lldb-public.h"
 
+#include <mutex>
 #include <set>
 
 namespace lldb_private {
@@ -25,16 +26,30 @@ class WatchpointResource
 
   ~WatchpointResource();
 
-  void GetMemoryRange(lldb::addr_t &addr, size_t &size) const;
-
   lldb::addr_t GetAddress() const;
 
   size_t GetByteSize() const;
 
-  void GetType(bool &read, bool &write) const;
+  bool WatchpointResourceRead() const;
+
+  bool WatchpointResourceWrite() const;
 
   void SetType(bool read, bool write);
 
+  typedef std::vector<lldb::WatchpointSP> WatchpointCollection;
+  typedef LockingAdaptedIterable<WatchpointCollection, lldb::WatchpointSP,
+                                 vector_adapter, std::recursive_mutex>
+      WatchpointIterable;
+
+  /// Iterate over the watchpoint owners for this resource
+  ///
+  /// \return
+  ///     An Iterable object which can be used to loop over the watchpoints
+  ///     that are owners of this resource.
+  WatchpointIterable Owners() {
+    return WatchpointIterable(m_owners, m_owners_mutex);
+  }
+
   /// The "Owners" are the watchpoints that share this resource.
   /// The method adds the \a owner to this resource's owner list.
   ///
diff --git a/lldb/source/Breakpoint/CMakeLists.txt b/lldb/source/Breakpoint/CMakeLists.txt
index 47cfd67a6920da8..bc0ecba0a8f4868 100644
--- a/lldb/source/Breakpoint/CMakeLists.txt
+++ b/lldb/source/Breakpoint/CMakeLists.txt
@@ -22,7 +22,6 @@ add_lldb_library(lldbBreakpoint NO_PLUGIN_DEPENDENCIES
   StoppointSite.cpp
   Watchpoint.cpp
   WatchpointList.cpp
-  WatchpointCollection.cpp
   WatchpointOptions.cpp
   WatchpointResource.cpp
   WatchpointResourceList.cpp
diff --git a/lldb/source/Breakpoint/WatchpointCollection.cpp b/lldb/source/Breakpoint/WatchpointCollection.cpp
deleted file mode 100644
index ab8df84d00b2364..000000000000000
--- a/lldb/source/Breakpoint/WatchpointCollection.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-//===-- WatchpointCollection.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/Breakpoint/WatchpointCollection.h"
-#include "lldb/Breakpoint/Watchpoint.h"
-#include "lldb/Core/ModuleList.h"
-#include "lldb/Target/Thread.h"
-#include "lldb/Target/ThreadSpec.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-// WatchpointCollection constructor
-WatchpointCollection::WatchpointCollection() = default;
-
-// Destructor
-WatchpointCollection::~WatchpointCollection() = default;
-
-void WatchpointCollection::Add(const WatchpointSP &wp) {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  m_collection.push_back(wp);
-}
-
-bool WatchpointCollection::Remove(WatchpointSP &wp) {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  for (collection::iterator pos = m_collection.begin();
-       pos != m_collection.end(); ++pos) {
-    if (*pos == wp) {
-      m_collection.erase(pos);
-      return true;
-    }
-  }
-  return false;
-}
-
-WatchpointSP WatchpointCollection::GetByIndex(size_t i) {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  if (i < m_collection.size())
-    return m_collection[i];
-  return {};
-}
-
-const WatchpointSP WatchpointCollection::GetByIndex(size_t i) const {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  if (i < m_collection.size())
-    return m_collection[i];
-  return {};
-}
-
-WatchpointCollection &
-WatchpointCollection::operator=(const WatchpointCollection &rhs) {
-  if (this != &rhs) {
-    std::lock(m_collection_mutex, rhs.m_collection_mutex);
-    std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
-    std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex,
-                                          std::adopt_lock);
-    m_collection = rhs.m_collection;
-  }
-  return *this;
-}
-
-void WatchpointCollection::Clear() {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  m_collection.clear();
-}
-
-bool WatchpointCollection::Contains(const WatchpointSP &wp_sp) {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  const size_t size = m_collection.size();
-  for (size_t i = 0; i < size; ++i) {
-    if (m_collection[i] == wp_sp)
-      return true;
-  }
-  return false;
-}
-
-bool WatchpointCollection::Contains(const Watchpoint *wp) {
-  std::lock_guard<std::mutex> guard(m_collection_mutex);
-  const size_t size = m_collection.size();
-  for (size_t i = 0; i < size; ++i) {
-    if (m_collection[i].get() == wp)
-      return true;
-  }
-  return false;
-}
diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
index ed8c707a34faf5b..ffd01d4bcb10c11 100644
--- a/lldb/source/Breakpoint/WatchpointResource.cpp
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Breakpoint/WatchpointResource.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -18,22 +19,17 @@ WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
 
 WatchpointResource::~WatchpointResource() {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  m_owners.Clear();
-}
-
-void WatchpointResource::GetMemoryRange(lldb::addr_t &addr,
-                                        size_t &size) const {
-  addr = m_addr;
-  size = m_size;
+  m_owners.clear();
 }
 
 addr_t WatchpointResource::GetAddress() const { return m_addr; }
 
 size_t WatchpointResource::GetByteSize() const { return m_size; }
 
-void WatchpointResource::GetType(bool &read, bool &write) const {
-  read = m_watch_read;
-  write = m_watch_write;
+bool WatchpointResource::WatchpointResourceRead() const { return m_watch_read; }
+
+bool WatchpointResource::WatchpointResourceWrite() const {
+  return m_watch_write;
 }
 
 void WatchpointResource::SetType(bool read, bool write) {
@@ -53,44 +49,52 @@ bool WatchpointResource::Contains(addr_t addr) {
 
 void WatchpointResource::AddOwner(const WatchpointSP &wp_sp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  m_owners.Add(wp_sp);
+  m_owners.push_back(wp_sp);
 }
 
 void WatchpointResource::RemoveOwner(WatchpointSP &wp_sp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  m_owners.Remove(wp_sp);
+  const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
+  if (it != m_owners.end())
+    m_owners.erase(it);
 }
 
 size_t WatchpointResource::GetNumberOfOwners() {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.GetSize();
+  return m_owners.size();
 }
 
 bool WatchpointResource::OwnersContains(WatchpointSP &wp_sp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.Contains(wp_sp);
+  const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
+  if (it != m_owners.end())
+    return true;
+  return false;
 }
 
 bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.Contains(wp);
+  for (WatchpointCollection::const_iterator it = m_owners.begin();
+       it != m_owners.end(); ++it)
+    if ((*it).get() == wp)
+      return true;
+  return false;
 }
 
 WatchpointSP WatchpointResource::GetOwnerAtIndex(size_t idx) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  assert(idx < m_owners.GetSize());
-  if (idx >= m_owners.GetSize())
+  lldbassert(idx < m_owners.size());
+  if (idx >= m_owners.size())
     return {};
 
-  return m_owners.GetByIndex(idx);
+  return m_owners[idx];
 }
 
 size_t
 WatchpointResource::CopyOwnersList(WatchpointCollection &out_collection) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  const size_t size = m_owners.GetSize();
-  for (size_t i = 0; i < size; ++i) {
-    out_collection.Add(m_owners.GetByIndex(i));
+  for (auto wp_sp : m_owners) {
+    out_collection.push_back(wp_sp);
   }
-  return out_collection.GetSize();
+  return out_collection.size();
 }
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index d6aa4a338b60717..bfd83e5d2136db6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3131,10 +3131,11 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
 static GDBStoppointType
 GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
   assert(wp_res_sp);
-  bool read, write;
-  wp_res_sp->GetType(read, write);
+  bool read = wp_res_sp->WatchpointResourceRead();
+  bool write = wp_res_sp->WatchpointResourceWrite();
 
-  assert((read || write) && "read and write cannot both be false.");
+  assert((read || write) &&
+         "WatchpointResource type is neither read nor write");
   if (read && write)
     return eWatchpointReadWrite;
   else if (read)
@@ -3145,166 +3146,163 @@ GetGDBStoppointType(const WatchpointResourceSP &wp_res_sp) {
 
 Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
-  if (wp_sp) {
-    user_id_t watchID = wp_sp->GetID();
-    addr_t addr = wp_sp->GetLoadAddress();
-    Log *log(GetLog(GDBRLog::Watchpoints));
-    LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
-              watchID);
-    if (wp_sp->IsEnabled()) {
-      LLDB_LOGF(log,
-                "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
-                ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
-                watchID, (uint64_t)addr);
-      return error;
-    }
-
-    bool read = wp_sp->WatchpointRead();
-    bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
-    size_t size = wp_sp->GetByteSize();
-
-    // New WatchpointResources needed to implement this Watchpoint.
-    std::vector<WatchpointResourceSP> resources;
+  if (!wp_sp) {
+    error.SetErrorString("No watchpoint specified");
+    return error;
+  }
+  user_id_t watchID = wp_sp->GetID();
+  addr_t addr = wp_sp->GetLoadAddress();
+  Log *log(GetLog(GDBRLog::Watchpoints));
+  LLDB_LOGF(log, "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")",
+            watchID);
+  if (wp_sp->IsEnabled()) {
+    LLDB_LOGF(log,
+              "ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64
+              ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+              watchID, (uint64_t)addr);
+    return error;
+  }
 
-    // LWP_TODO: Break up the user's request into pieces that can be watched
-    // given the capabilities of the target cpu / stub software.
-    // As a default, breaking the watched region up into target-pointer-sized,
-    // aligned, groups.
-    //
-    // Beyond the default, a stub can / should inform us of its capabilities,
-    // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints.
-    //
-    // And the cpu may have unique capabilities. AArch64 BAS watchpoints
-    // can watch any sequential bytes in a doubleword, but Intel watchpoints
-    // can only watch 1, 2, 4, 8 bytes within a doubleword.
-    WatchpointResourceSP wp_res_sp =
-        std::make_shared<WatchpointResource>(addr, size, read, write);
-    resources.push_back(wp_res_sp);
-
-    // LWP_TODO: Now that we know the WP Resources needed to implement this
-    // Watchpoint, we need to look at currently allocated Resources in the
-    // Process and if they match, or are within the same memory granule, or
-    // overlapping memory ranges, then we need to combine them.  e.g. one
-    // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1
-    // byte at 0x1003, they must use the same hardware watchpoint register
-    // (Resource) to watch them.
-
-    // This may mean that an existing resource changes its type (read to
-    // read+write) or address range it is watching, in which case the old
-    // watchpoint needs to be disabled and the new Resource addr/size/type
-    // watchpoint enabled.
-
-    // If we modify a shared Resource to accomodate this newly added Watchpoint,
-    // and we are unable to set all of the Resources for it in the inferior, we
-    // will return an error for this Watchpoint and the shared Resource should
-    // be restored.  e.g. this Watchpoint requires three Resources, one which
-    // is shared with another Watchpoint.  We extend the shared Resouce to
-    // handle both Watchpoints and we try to set two new ones.  But if we don't
-    // have sufficient watchpoint register for all 3, we need to show an error
-    // for creating this Watchpoint and we should reset the shared Resource to
-    // its original configuration because it is no longer shared.
-
-    bool set_all_resources = true;
-    std::vector<WatchpointResourceSP> succesfully_set_resources;
-    for (const auto &wp_res_sp : resources) {
-      addr_t addr;
-      size_t size;
-      wp_res_sp->GetMemoryRange(addr, size);
-      GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
-      if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
-          m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
-                                                GetInterruptTimeout())) {
-        set_all_resources = false;
-        break;
-      } else {
-        succesfully_set_resources.push_back(wp_res_sp);
-      }
-    }
-    if (set_all_resources) {
-      wp_sp->SetEnabled(true, notify);
-      for (const auto &wp_res_sp : resources) {
-        // LWP_TODO: If we expanded/reused an existing Resource,
-        // it's already in the WatchpointResourceList.
-        wp_res_sp->AddOwner(wp_sp);
-        m_watchpoint_resource_list.Add(wp_res_sp);
-      }
-      return error;
+  bool read = wp_sp->WatchpointRead();
+  bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify();
+  size_t size = wp_sp->GetByteSize();
+
+  // New WatchpointResources needed to implement this Watchpoint.
+  std::vector<WatchpointResourceSP> resources;
+
+  // LWP_TODO: Break up the user's request into pieces that can be watched
+  // given the capabilities of the target cpu / stub software.
+  // As a default, breaking the watched region up into target-pointer-sized,
+  // aligned, groups.
+  //
+  // Beyond the default, a stub can / should inform us of its capabilities,
+  // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints.
+  //
+  // And the cpu may have unique capabilities. AArch64 BAS watchpoints
+  // can watch any sequential bytes in a doubleword, but Intel watchpoints
+  // can only watch 1, 2, 4, 8 bytes within a doubleword.
+  WatchpointResourceSP wp_res_sp =
+      std::make_shared<WatchpointResource>(addr, size, read, write);
+  resources.push_back(wp_res_sp);
+
+  // LWP_TODO: Now that we know the WP Resources needed to implement this
+  // Watchpoint, we need to look at currently allocated Resources in the
+  // Process and if they match, or are within the same memory granule, or
+  // overlapping memory ranges, then we need to combine them.  e.g. one
+  // Watchpoint watching 1 byte at 0x1002 and a second watchpoint watching 1
+  // byte at 0x1003, they must use the same hardware watchpoint register
+  // (Resource) to watch them.
+
+  // This may mean that an existing resource changes its type (read to
+  // read+write) or address range it is watching, in which case the old
+  // watchpoint needs to be disabled and the new Resource addr/size/type
+  // watchpoint enabled.
+
+  // If we modify a shared Resource to accomodate this newly added Watchpoint,
+  // and we are unable to set all of the Resources for it in the inferior, we
+  // will return an error for this Watchpoint and the shared Resource should
+  // be restored.  e.g. this Watchpoint requires three Resources, one which
+  // is shared with another Watchpoint.  We extend the shared Resouce to
+  // handle both Watchpoints and we try to set two new ones.  But if we don't
+  // have sufficient watchpoint register for all 3, we need to show an error
+  // for creating this Watchpoint and we should reset the shared Resource to
+  // its original configuration because it is no longer shared.
+
+  bool set_all_resources = true;
+  std::vector<WatchpointResourceSP> succesfully_set_resources;
+  for (const auto &wp_res_sp : resources) {
+    addr_t addr = wp_res_sp->GetAddress();
+    size_t size = wp_res_sp->GetByteSize();
+    GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+    if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
+        m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
+                                              GetInterruptTimeout())) {
+      set_all_resources = false;
+      break;
     } else {
-      // We failed to allocate one of the resources.  Unset all
-      // of the new resources we did successfully set in the
-      // process.
-      for (const auto &wp_res_sp : succesfully_set_resources) {
-        addr_t addr;
-        size_t size;
-        wp_res_sp->GetMemoryRange(addr, size);
-        GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
-        m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
-                                              GetInterruptTimeout());
-      }
-      error.SetErrorString("Setting one of the watchpoint resources failed");
+      succesfully_set_resources.push_back(wp_res_sp);
+    }
+  }
+  if (set_all_resources) {
+    wp_sp->SetEnabled(true, notify);
+    for (const auto &wp_res_sp : resources) {
+      // LWP_TODO: If we expanded/reused an existing Resource,
+      // it's already in the WatchpointResourceList.
+      wp_res_sp->AddOwner(wp_sp);
+      m_watchpoint_resource_list.Add(wp_res_sp);
     }
+    return error;
   } else {
-    error.SetErrorString("No watchpoint specified");
+    // We failed to allocate one of the resources.  Unset all
+    // of the new resources we did successfully set in the
+    // process.
+    for (const auto &wp_res_sp : succesfully_set_resources) {
+      addr_t addr = wp_res_sp->GetAddress();
+      size_t size = wp_res_sp->GetByteSize();
+      GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+      m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+                                            GetInterruptTimeout());
+    }
+    error.SetErrorString("Setting one of the watchpoint resources failed");
   }
   return error;
 }
 
 Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
   Status error;
-  if (wp_sp) {
-    user_id_t watchID = wp_sp->GetID();
+  if (!wp_sp) {
+    error.SetErrorString("Watchpoint argument was NULL.");
+    return error;
+  }
 
-    Log *log(GetLog(GDBRLog::Watchpoints));
+  user_id_t watchID = wp_sp->GetID();
 
-    addr_t addr = wp_sp->GetLoadAddress();
+  Log *log(GetLog(GDBRLog::Watchpoints));
 
+  addr_t addr = wp_sp->GetLoadAddress();
+
+  LLDB_LOGF(log,
+            "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
+            ") addr = 0x%8.8" PRIx64,
+            watchID, (uint64_t)addr);
+
+  if (!wp_sp->IsEnabled()) {
     LLDB_LOGF(log,
               "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
-              ") addr = 0x%8.8" PRIx64,
+              ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
               watchID, (uint64_t)addr);
+    // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
+    // attempt might come from the user-supplied actions, we'll route it in
+    // order for the watchpoint object to intelligently process this action.
+    wp_sp->SetEnabled(false, notify);
+    return error;
+  }
 
-    if (!wp_sp->IsEnabled()) {
-      LLDB_LOGF(log,
-                "ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64
-                ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)",
-                watchID, (uint64_t)addr);
-      // See also 'class WatchpointSentry' within StopInfo.cpp. This disabling
-      // attempt might come from the user-supplied actions, we'll route it in
-      // order for the watchpoint object to intelligently process this action.
-      wp_sp->SetEnabled(false, notify);
-      return error;
-    }
+  if (wp_sp->IsHardware()) {
+    bool disabled_all = true;
 
-    if (wp_sp->IsHardware()) {
-      bool disabled_all = true;
-
-      std::vector<WatchpointResourceSP> unused_resouces;
-      for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
-        if (wp_res_sp->OwnersContains(wp_sp)) {
-          GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
-          addr_t addr;
-          size_t size;
-          wp_res_sp->GetMemoryRange(addr, size);
-          if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
-                                                    GetInterruptTimeout())) {
-            disabled_all = false;
-          } else {
-            wp_res_sp->RemoveOwner(wp_sp);
-            if (wp_res_sp->GetNumberOfOwners() == 0)
-              unused_resouces.push_back(wp_res_sp);
-          }
+    std::vector<WatchpointResourceSP> unused_resouces;
+    for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
+      if (wp_res_sp->OwnersContains(wp_sp)) {
+        GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
+        addr_t addr = wp_res_sp->GetAddress();
+        size_t size = wp_res_sp->GetByteSize();
+        if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
+                                                  GetInterruptTimeout())) {
+          disabled_all = false;
+        } else {
+          wp_res_sp->RemoveOwner(wp_sp);
+          if (wp_res_sp->GetNumberOfOwners() == 0)
+            unused_resouces.push_back(wp_res_sp);
         }
       }
-      for (auto &wp_res_sp : unused_resouces)
-        m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
-
-      wp_sp->SetEnabled(false, notify);
-      if (!disabled_all)
-        error.SetErrorString(
-            "Failure disabling one of the watchpoint locations");
     }
-  } else {
-    error.SetErrorString("Watchpoint argument was NULL.");
+    for (auto &wp_res_sp : unused_resouces)
+      m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
+
+    wp_sp->SetEnabled(false, notify);
+    if (!disabled_all)
+      error.SetErrorString("Failure disabling one of the watchpoint locations");
   }
   return error;
 }
@@ -5558,9 +5556,8 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
   }
 
   for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
-    addr_t addr;
-    size_t size;
-    wp_res_sp->GetMemoryRange(addr, size);
+    addr_t addr = wp_res_sp->GetAddress();
+    size_t size = wp_res_sp->GetByteSize();
     GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
     m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
                                           GetInterruptTimeout());

>From 50f902c29fdc1bf5917edbf005454001bf82d1dd Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 25 Oct 2023 14:54:24 -0700
Subject: [PATCH 04/11] Update WatchpointResource OwnersContains methods

Suggestions from Alex.
---
 lldb/source/Breakpoint/WatchpointResource.cpp | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
index ffd01d4bcb10c11..bc258c84739b347 100644
--- a/lldb/source/Breakpoint/WatchpointResource.cpp
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -67,18 +67,15 @@ size_t WatchpointResource::GetNumberOfOwners() {
 bool WatchpointResource::OwnersContains(WatchpointSP &wp_sp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
   const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
-  if (it != m_owners.end())
-    return true;
-  return false;
+  return it != m_owners.end();
 }
 
 bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
   std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  for (WatchpointCollection::const_iterator it = m_owners.begin();
-       it != m_owners.end(); ++it)
-    if ((*it).get() == wp)
-      return true;
-  return false;
+  WatchpointCollection::const_iterator match =
+      std::find_if(m_owners.begin(), m_owners.end(),
+                   [&wp](const WatchpointSP &x) { return x.get() == wp; });
+  return match != m_owners.end();
 }
 
 WatchpointSP WatchpointResource::GetOwnerAtIndex(size_t idx) {

>From 046fd8782183fa012ea0e8e916d0a16b8a11ae24 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Mon, 30 Oct 2023 19:08:13 -0700
Subject: [PATCH 05/11] Address this second round of comments from Alex and
 Jonas

Jonas' suggestion of trying to unify
BreakpointSiteList/WatchpointResourceList is something I still
need to look at.
---
 .../lldb/Breakpoint/WatchpointResource.h      | 25 ++++++--------
 .../lldb/Breakpoint/WatchpointResourceList.h  |  1 -
 lldb/source/Breakpoint/Watchpoint.cpp         | 15 +++------
 lldb/source/Breakpoint/WatchpointResource.cpp | 33 ++++++++-----------
 4 files changed, 29 insertions(+), 45 deletions(-)

diff --git a/lldb/include/lldb/Breakpoint/WatchpointResource.h b/lldb/include/lldb/Breakpoint/WatchpointResource.h
index 54335274d881067..66c7090f92c588d 100644
--- a/lldb/include/lldb/Breakpoint/WatchpointResource.h
+++ b/lldb/include/lldb/Breakpoint/WatchpointResource.h
@@ -21,7 +21,6 @@ class WatchpointResource
     : public std::enable_shared_from_this<WatchpointResource> {
 
 public:
-  // Constructors and Destructors
   WatchpointResource(lldb::addr_t addr, size_t size, bool read, bool write);
 
   ~WatchpointResource();
@@ -38,7 +37,7 @@ class WatchpointResource
 
   typedef std::vector<lldb::WatchpointSP> WatchpointCollection;
   typedef LockingAdaptedIterable<WatchpointCollection, lldb::WatchpointSP,
-                                 vector_adapter, std::recursive_mutex>
+                                 vector_adapter, std::mutex>
       WatchpointIterable;
 
   /// Iterate over the watchpoint owners for this resource
@@ -87,7 +86,7 @@ class WatchpointResource
   ///
   /// \result
   ///     true if this resource's owners includes the watchpoint.
-  bool OwnersContains(lldb::WatchpointSP &wp_sp);
+  bool OwnersContains(const lldb::WatchpointSP &wp_sp);
 
   /// Check if the owners includes a watchpoint.
   ///
@@ -101,13 +100,9 @@ class WatchpointResource
   /// This method copies the watchpoint resource's owners into a new collection.
   /// It does this while the owners mutex is locked.
   ///
-  /// \param[out] out_collection
-  ///    The BreakpointLocationCollection into which to put the owners
-  ///    of this breakpoint site.
-  ///
   /// \return
-  ///    The number of elements copied into out_collection.
-  size_t CopyOwnersList(WatchpointCollection &out_collection);
+  ///    A copy of the Watchpoints which own this resource.
+  WatchpointCollection CopyOwnersList();
 
   // The ID of the WatchpointResource is set by the WatchpointResourceList
   // when the Resource has been set in the inferior and is being added
@@ -132,19 +127,19 @@ class WatchpointResource
 private:
   lldb::wp_resource_id_t m_id;
 
-  // start address & size aligned & expanded to be a valid watchpoint
+  // Start address & size aligned & expanded to be a valid watchpoint
   // memory granule on this target.
   lldb::addr_t m_addr;
   size_t m_size;
 
-  bool m_watch_read;  // true if we stop when the watched data is read from
-  bool m_watch_write; // true if we stop when the watched data is written to
+  bool m_watch_read;
+  bool m_watch_write;
 
-  // The watchpoints using this WatchpointResource.
+  /// The Watchpoints which own this resource.
   WatchpointCollection m_owners;
 
-  std::recursive_mutex
-      m_owners_mutex; ///< This mutex protects the owners collection.
+  /// This mutex protects the owners collection.
+  std::mutex m_owners_mutex;
 
   WatchpointResource(const WatchpointResource &) = delete;
   const WatchpointResource &operator=(const WatchpointResource &) = delete;
diff --git a/lldb/include/lldb/Breakpoint/WatchpointResourceList.h b/lldb/include/lldb/Breakpoint/WatchpointResourceList.h
index 17c8a3cd3f8b2b1..0e6c5fab877895c 100644
--- a/lldb/include/lldb/Breakpoint/WatchpointResourceList.h
+++ b/lldb/include/lldb/Breakpoint/WatchpointResourceList.h
@@ -21,7 +21,6 @@ namespace lldb_private {
 class WatchpointResourceList {
 
 public:
-  // Constructors and Destructors
   WatchpointResourceList();
 
   ~WatchpointResourceList();
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index 1a9e0359d24e4b3..ec1b755880628c1 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -283,12 +283,10 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
     values_ss.Indent(prefix);
 
   if (m_old_value_sp) {
-    const char *old_value_cstr = m_old_value_sp->GetValueAsCString();
-    if (old_value_cstr) {
+    if (auto *old_value_cstr = m_old_value_sp->GetValueAsCString()) {
       values_ss.Printf("old value: %s", old_value_cstr);
     } else {
-      const char *old_summary_cstr = m_old_value_sp->GetSummaryAsCString();
-      if (old_summary_cstr)
+      if (auto *old_summary_cstr = m_old_value_sp->GetSummaryAsCString())
         values_ss.Printf("old value: %s", old_summary_cstr);
       else {
         StreamString strm;
@@ -308,12 +306,10 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const {
     if (values_ss.GetSize())
       values_ss.Printf("\n");
 
-    const char *new_value_cstr = m_new_value_sp->GetValueAsCString();
-    if (new_value_cstr)
+    if (auto *new_value_cstr = m_new_value_sp->GetValueAsCString())
       values_ss.Printf("new value: %s", new_value_cstr);
     else {
-      const char *new_summary_cstr = m_new_value_sp->GetSummaryAsCString();
-      if (new_summary_cstr)
+      if (auto *new_summary_cstr = m_new_value_sp->GetSummaryAsCString())
         values_ss.Printf("new value: %s", new_summary_cstr);
       else {
         StreamString strm;
@@ -379,8 +375,7 @@ uint32_t Watchpoint::GetHardwareIndex() const {
         ->GetWatchpointResourceList()
         .FindByWatchpoint(this)
         ->GetID();
-  else
-    return UINT32_MAX;
+  return UINT32_MAX;
 }
 
 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
index bc258c84739b347..402e248c02aee79 100644
--- a/lldb/source/Breakpoint/WatchpointResource.cpp
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -6,8 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <assert.h>
+
 #include "lldb/Breakpoint/WatchpointResource.h"
-#include "lldb/Utility/LLDBAssert.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -18,7 +19,7 @@ WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
       m_watch_read(read), m_watch_write(write) {}
 
 WatchpointResource::~WatchpointResource() {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
   m_owners.clear();
 }
 
@@ -48,30 +49,28 @@ bool WatchpointResource::Contains(addr_t addr) {
 }
 
 void WatchpointResource::AddOwner(const WatchpointSP &wp_sp) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
   m_owners.push_back(wp_sp);
 }
 
 void WatchpointResource::RemoveOwner(WatchpointSP &wp_sp) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
   const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
   if (it != m_owners.end())
     m_owners.erase(it);
 }
 
 size_t WatchpointResource::GetNumberOfOwners() {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
   return m_owners.size();
 }
 
-bool WatchpointResource::OwnersContains(WatchpointSP &wp_sp) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
-  return it != m_owners.end();
+bool WatchpointResource::OwnersContains(const WatchpointSP &wp_sp) {
+  return OwnersContains(wp_sp.get());
 }
 
 bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
   WatchpointCollection::const_iterator match =
       std::find_if(m_owners.begin(), m_owners.end(),
                    [&wp](const WatchpointSP &x) { return x.get() == wp; });
@@ -79,19 +78,15 @@ bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
 }
 
 WatchpointSP WatchpointResource::GetOwnerAtIndex(size_t idx) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  lldbassert(idx < m_owners.size());
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
+  assert(idx < m_owners.size());
   if (idx >= m_owners.size())
     return {};
 
   return m_owners[idx];
 }
 
-size_t
-WatchpointResource::CopyOwnersList(WatchpointCollection &out_collection) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  for (auto wp_sp : m_owners) {
-    out_collection.push_back(wp_sp);
-  }
-  return out_collection.size();
+WatchpointResource::WatchpointCollection WatchpointResource::CopyOwnersList() {
+  std::lock_guard<std::mutex> guard(m_owners_mutex);
+  return m_owners;
 }

>From 3093a77134bd296aa76f6678c4282e9ea09221e0 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Mon, 30 Oct 2023 21:09:06 -0700
Subject: [PATCH 06/11] Use foreach iterators in WatchpointResourceList

Missed this review comment by Jonas.
---
 .../Breakpoint/WatchpointResourceList.cpp     | 28 +++++++------------
 1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/lldb/source/Breakpoint/WatchpointResourceList.cpp b/lldb/source/Breakpoint/WatchpointResourceList.cpp
index 8a65ae231211c0c..fa6625adfefb2f7 100644
--- a/lldb/source/Breakpoint/WatchpointResourceList.cpp
+++ b/lldb/source/Breakpoint/WatchpointResourceList.cpp
@@ -96,39 +96,31 @@ bool WatchpointResourceList::RemoveByAddress(addr_t addr) {
 
 WatchpointResourceSP WatchpointResourceList::FindByAddress(addr_t addr) {
   std::lock_guard<std::mutex> guard(m_mutex);
-  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
-       ++pos)
-    if ((*pos)->Contains(addr))
-      return *pos;
+  for (WatchpointResourceSP wp_res_sp : m_resources)
+    if (wp_res_sp->Contains(addr))
+      return wp_res_sp;
   return {};
 }
 
 WatchpointResourceSP
 WatchpointResourceList::FindByWatchpointSP(WatchpointSP &wp_sp) {
-  std::lock_guard<std::mutex> guard(m_mutex);
-  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
-       ++pos)
-    if ((*pos)->OwnersContains(wp_sp))
-      return *pos;
-  return {};
+  return FindByWatchpoint(wp_sp.get());
 }
 
 WatchpointResourceSP
 WatchpointResourceList::FindByWatchpoint(const Watchpoint *wp) {
   std::lock_guard<std::mutex> guard(m_mutex);
-  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
-       ++pos)
-    if ((*pos)->OwnersContains(wp))
-      return *pos;
+  for (WatchpointResourceSP wp_res_sp : m_resources)
+    if (wp_res_sp->OwnersContains(wp))
+      return wp_res_sp;
   return {};
 }
 
 WatchpointResourceSP WatchpointResourceList::FindByID(wp_resource_id_t id) {
   std::lock_guard<std::mutex> guard(m_mutex);
-  for (collection::iterator pos = m_resources.begin(); pos != m_resources.end();
-       ++pos)
-    if ((*pos)->GetID() == id)
-      return *pos;
+  for (WatchpointResourceSP wp_res_sp : m_resources)
+    if (wp_res_sp->GetID() == id)
+      return wp_res_sp;
   return {};
 }
 

>From daff24aa96222ef51b54408691d793be251ac509 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Mon, 13 Nov 2023 10:45:05 -0800
Subject: [PATCH 07/11] Address Jonas' 1st review comments, biggest:
 StopPointSiteList template

My original patch had a BreakpointSiteList and a WatchpointResourceList
which are pretty simple collections with some unique lookup methods
for finding things by the watchpoint resource/breakpoint site IDs.
Jonas asked that to be a template specialized for both classes;
this patch adds a StopPointSiteList template class.

The BreakpointSite / WatchpointResources have "owners".  A
BreakpointSite is owned by the BreakpointLocations that it is
used for.  A WatchpointResource is owned by the Watchpoints
at that memory range.

For some reason the owner name doesn't seem clear to me, and I
thought of a politican who has constituents that they serve.  I
tried out a rename from a Site having "owners" to having "constituents".
I don't know if it's really better in any way.  And the "owners"
terminology is used in other places that Jim wrote; BreakpointLocations
have owners (Breakpoints).  ThreadPlans have owners (Threads).
I don't feel strongly about this and "constituent" is easy to global
search and replace back if anyone thinks this isn't a good choice.
---
 lldb/include/lldb/Breakpoint/BreakpointSite.h |  68 ++---
 .../lldb/Breakpoint/BreakpointSiteList.h      | 173 -------------
 .../lldb/Breakpoint/StopPointSiteList.h       | 175 +++++++++++++
 lldb/include/lldb/Breakpoint/Watchpoint.h     |   2 -
 .../lldb/Breakpoint/WatchpointResource.h      |  79 +++---
 lldb/include/lldb/Target/Process.h            |  37 +--
 lldb/include/lldb/lldb-defines.h              |   3 +
 lldb/include/lldb/lldb-forward.h              |   1 -
 lldb/source/API/SBThread.cpp                  |   4 +-
 lldb/source/Breakpoint/BreakpointLocation.cpp |   6 +-
 lldb/source/Breakpoint/BreakpointSite.cpp     |  84 +++----
 lldb/source/Breakpoint/BreakpointSiteList.cpp | 193 --------------
 lldb/source/Breakpoint/CMakeLists.txt         |   2 +-
 lldb/source/Breakpoint/StopPointSiteList.cpp  | 235 ++++++++++++++++++
 lldb/source/Breakpoint/Watchpoint.cpp         |   9 -
 lldb/source/Breakpoint/WatchpointResource.cpp |  81 +++---
 .../Breakpoint/WatchpointResourceList.cpp     |   8 +-
 lldb/source/Commands/CommandObjectProcess.cpp |   4 +-
 .../ItaniumABI/ItaniumABILanguageRuntime.cpp  |   2 +-
 .../AppleObjCRuntime/AppleObjCRuntime.cpp     |   2 +-
 ...pleThreadPlanStepThroughObjCTrampoline.cpp |   2 +-
 .../Platform/MacOSX/PlatformDarwin.cpp        |   2 +-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  30 +--
 lldb/source/Target/Platform.cpp               |   2 +-
 lldb/source/Target/Process.cpp                |  53 ++--
 lldb/source/Target/StackFrameList.cpp         |   5 +-
 lldb/source/Target/StopInfo.cpp               |  50 ++--
 lldb/source/Target/ThreadPlanCallFunction.cpp |   4 +-
 lldb/source/Target/ThreadPlanStepOut.cpp      |   2 +-
 lldb/source/Target/ThreadPlanStepRange.cpp    |  14 +-
 lldb/source/Target/ThreadPlanStepUntil.cpp    |   4 +-
 31 files changed, 716 insertions(+), 620 deletions(-)
 delete mode 100644 lldb/include/lldb/Breakpoint/BreakpointSiteList.h
 create mode 100644 lldb/include/lldb/Breakpoint/StopPointSiteList.h
 delete mode 100644 lldb/source/Breakpoint/BreakpointSiteList.cpp
 create mode 100644 lldb/source/Breakpoint/StopPointSiteList.cpp

diff --git a/lldb/include/lldb/Breakpoint/BreakpointSite.h b/lldb/include/lldb/Breakpoint/BreakpointSite.h
index e4c850206fd8976..17b76d51c1ae53a 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointSite.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -45,6 +45,9 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
                // display any breakpoint opcodes.
   };
 
+  typedef lldb::break_id_t SiteID;
+  typedef lldb::break_id_t ConstituentID;
+
   ~BreakpointSite() override;
 
   // This section manages the breakpoint traps
@@ -77,8 +80,8 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   /// Tells whether the current breakpoint site is enabled or not
   ///
   /// This is a low-level enable bit for the breakpoint sites.  If a
-  /// breakpoint site has no enabled owners, it should just get removed.  This
-  /// enable/disable is for the low-level target code to enable and disable
+  /// breakpoint site has no enabled constituents, it should just get removed.
+  /// This enable/disable is for the low-level target code to enable and disable
   /// breakpoint sites when single stepping, etc.
   bool IsEnabled() const;
 
@@ -101,44 +104,46 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   /// Standard Dump method
   void Dump(Stream *s) const override;
 
-  /// The "Owners" are the breakpoint locations that share this breakpoint
-  /// site. The method adds the \a owner to this breakpoint site's owner list.
+  /// The "Constituents" are the breakpoint locations that share this breakpoint
+  /// site. The method adds the \a constituent to this breakpoint site's
+  /// constituent list.
   ///
-  /// \param[in] owner
-  ///    \a owner is the Breakpoint Location to add.
-  void AddOwner(const lldb::BreakpointLocationSP &owner);
+  /// \param[in] constituent
+  ///    \a constituent is the Breakpoint Location to add.
+  void AddConstituent(const lldb::BreakpointLocationSP &constituent);
 
   /// This method returns the number of breakpoint locations currently located
   /// at this breakpoint site.
   ///
   /// \return
-  ///    The number of owners.
-  size_t GetNumberOfOwners();
+  ///    The number of constituents.
+  size_t GetNumberOfConstituents();
 
   /// This method returns the breakpoint location at index \a index located at
-  /// this breakpoint site.  The owners are listed ordinally from 0 to
-  /// GetNumberOfOwners() - 1 so you can use this method to iterate over the
-  /// owners
+  /// this breakpoint site.  The constituents are listed ordinally from 0 to
+  /// GetNumberOfConstituents() - 1 so you can use this method to iterate over
+  /// the constituents
   ///
   /// \param[in] idx
-  ///     The index in the list of owners for which you wish the owner location.
+  ///     The index in the list of constituents for which you wish the
+  ///     constituent location.
   ///
   /// \return
   ///    A shared pointer to the breakpoint location at that index.
-  lldb::BreakpointLocationSP GetOwnerAtIndex(size_t idx);
+  lldb::BreakpointLocationSP GetConstituentAtIndex(size_t idx);
 
-  /// This method copies the breakpoint site's owners into a new collection.
-  /// It does this while the owners mutex is locked.
+  /// This method copies the breakpoint site's constituents into a new
+  /// collection. It does this while the constituents mutex is locked.
   ///
   /// \param[out] out_collection
-  ///    The BreakpointLocationCollection into which to put the owners
+  ///    The BreakpointLocationCollection into which to put the constituents
   ///    of this breakpoint site.
   ///
   /// \return
   ///    The number of elements copied into out_collection.
-  size_t CopyOwnersList(BreakpointLocationCollection &out_collection);
+  size_t CopyConstituentsList(BreakpointLocationCollection &out_collection);
 
-  /// Check whether the owners of this breakpoint site have any thread
+  /// Check whether the constituents of this breakpoint site have any thread
   /// specifiers, and if yes, is \a thread contained in any of these
   /// specifiers.
   ///
@@ -151,7 +156,7 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   bool ValidForThisThread(Thread &thread);
 
   /// Print a description of this breakpoint site to the stream \a s.
-  /// GetDescription tells you about the breakpoint site's owners. Use
+  /// GetDescription tells you about the breakpoint site's constituents. Use
   /// BreakpointSite::Dump(Stream *) to get information about the breakpoint
   /// site itself.
   ///
@@ -203,9 +208,10 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
 
   void BumpHitCounts();
 
-  /// The method removes the owner at \a break_loc_id from this breakpoint
+  /// The method removes the constituent at \a break_loc_id from this breakpoint
   /// list.
-  size_t RemoveOwner(lldb::break_id_t break_id, lldb::break_id_t break_loc_id);
+  size_t RemoveConstituent(lldb::break_id_t break_id,
+                           lldb::break_id_t break_loc_id);
 
   BreakpointSite::Type m_type; ///< The type of this breakpoint site.
   uint8_t m_saved_opcode[8]; ///< The saved opcode bytes if this breakpoint site
@@ -215,20 +221,20 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   bool
       m_enabled; ///< Boolean indicating if this breakpoint site enabled or not.
 
-  // Consider adding an optimization where if there is only one owner, we don't
-  // store a list.  The usual case will be only one owner...
-  BreakpointLocationCollection m_owners; ///< This has the BreakpointLocations
-                                         ///that share this breakpoint site.
-  std::recursive_mutex
-      m_owners_mutex; ///< This mutex protects the owners collection.
+  // Consider adding an optimization where if there is only one constituent, we
+  // don't store a list.  The usual case will be only one constituent...
+  BreakpointLocationCollection
+      m_constituents; ///< This has the BreakpointLocations
+                      /// that share this breakpoint site.
+  std::recursive_mutex m_constituents_mutex; ///< This mutex protects the
+                                             ///< constituents collection.
 
   static lldb::break_id_t GetNextID();
 
   // Only the Process can create breakpoint sites in
   // Process::CreateBreakpointSite (lldb::BreakpointLocationSP &, bool).
-  BreakpointSite(BreakpointSiteList *list,
-                 const lldb::BreakpointLocationSP &owner, lldb::addr_t m_addr,
-                 bool use_hardware);
+  BreakpointSite(const lldb::BreakpointLocationSP &constituent,
+                 lldb::addr_t m_addr, bool use_hardware);
 
   BreakpointSite(const BreakpointSite &) = delete;
   const BreakpointSite &operator=(const BreakpointSite &) = delete;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointSiteList.h b/lldb/include/lldb/Breakpoint/BreakpointSiteList.h
deleted file mode 100644
index 98091bbaeb052dd..000000000000000
--- a/lldb/include/lldb/Breakpoint/BreakpointSiteList.h
+++ /dev/null
@@ -1,173 +0,0 @@
-//===-- BreakpointSiteList.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_BREAKPOINT_BREAKPOINTSITELIST_H
-#define LLDB_BREAKPOINT_BREAKPOINTSITELIST_H
-
-#include <functional>
-#include <map>
-#include <mutex>
-
-#include "lldb/Breakpoint/BreakpointSite.h"
-
-namespace lldb_private {
-
-/// \class BreakpointSiteList BreakpointSiteList.h
-/// "lldb/Breakpoint/BreakpointSiteList.h" Class that manages lists of
-/// BreakpointSite shared pointers.
-class BreakpointSiteList {
-  // At present Process directly accesses the map of BreakpointSites so it can
-  // do quick lookups into the map (using GetMap).
-  // FIXME: Find a better interface for this.
-  friend class Process;
-
-public:
-  /// Default constructor makes an empty list.
-  BreakpointSiteList();
-
-  /// Destructor, currently does nothing.
-  ~BreakpointSiteList();
-
-  /// Add a BreakpointSite to the list.
-  ///
-  /// \param[in] bp_site_sp
-  ///    A shared pointer to a breakpoint site being added to the list.
-  ///
-  /// \return
-  ///    The ID of the BreakpointSite in the list.
-  lldb::break_id_t Add(const lldb::BreakpointSiteSP &bp_site_sp);
-
-  /// Standard Dump routine, doesn't do anything at present. \param[in] s
-  ///     Stream into which to dump the description.
-  void Dump(Stream *s) const;
-
-  /// Returns a shared pointer to the breakpoint site at address \a addr.
-  ///
-  /// \param[in] addr
-  ///     The address to look for.
-  ///
-  /// \result
-  ///     A shared pointer to the breakpoint site. May contain a NULL
-  ///     pointer if no breakpoint site exists with a matching address.
-  lldb::BreakpointSiteSP FindByAddress(lldb::addr_t addr);
-
-  /// Returns a shared pointer to the breakpoint site with id \a breakID.
-  ///
-  /// \param[in] breakID
-  ///   The breakpoint site ID to seek for.
-  ///
-  /// \result
-  ///   A shared pointer to the breakpoint site.  May contain a NULL pointer if
-  ///   the
-  ///   breakpoint doesn't exist.
-  lldb::BreakpointSiteSP FindByID(lldb::break_id_t breakID);
-
-  /// Returns a shared pointer to the breakpoint site with id \a breakID -
-  /// const version.
-  ///
-  /// \param[in] breakID
-  ///   The breakpoint site ID to seek for.
-  ///
-  /// \result
-  ///   A shared pointer to the breakpoint site.  May contain a NULL pointer if
-  ///   the
-  ///   breakpoint doesn't exist.
-  const lldb::BreakpointSiteSP FindByID(lldb::break_id_t breakID) const;
-
-  /// Returns the breakpoint site id to the breakpoint site at address \a
-  /// addr.
-  ///
-  /// \param[in] addr
-  ///   The address to match.
-  ///
-  /// \result
-  ///   The ID of the breakpoint site, or LLDB_INVALID_BREAK_ID.
-  lldb::break_id_t FindIDByAddress(lldb::addr_t addr);
-
-  /// Returns whether the breakpoint site \a bp_site_id has \a bp_id
-  //  as one of its owners.
-  ///
-  /// \param[in] bp_site_id
-  ///   The breakpoint site id to query.
-  ///
-  /// \param[in] bp_id
-  ///   The breakpoint id to look for in \a bp_site_id.
-  ///
-  /// \result
-  ///   True if \a bp_site_id exists in the site list AND \a bp_id is one of the
-  ///   owners of that site.
-  bool BreakpointSiteContainsBreakpoint(lldb::break_id_t bp_site_id,
-                                        lldb::break_id_t bp_id);
-
-  void ForEach(std::function<void(BreakpointSite *)> const &callback);
-
-  /// Removes the breakpoint site given by \b breakID from this list.
-  ///
-  /// \param[in] breakID
-  ///   The breakpoint site index to remove.
-  ///
-  /// \result
-  ///   \b true if the breakpoint site \a breakID was in the list.
-  bool Remove(lldb::break_id_t breakID);
-
-  /// Removes the breakpoint site at address \a addr from this list.
-  ///
-  /// \param[in] addr
-  ///   The address from which to remove a breakpoint site.
-  ///
-  /// \result
-  ///   \b true if \a addr had a breakpoint site to remove from the list.
-  bool RemoveByAddress(lldb::addr_t addr);
-
-  bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound,
-                   BreakpointSiteList &bp_site_list) const;
-
-  typedef void (*BreakpointSiteSPMapFunc)(lldb::BreakpointSiteSP &bp,
-                                          void *baton);
-
-  /// Enquires of the breakpoint site on in this list with ID \a breakID
-  /// whether we should stop for the breakpoint or not.
-  ///
-  /// \param[in] context
-  ///    This contains the information about this stop.
-  ///
-  /// \param[in] breakID
-  ///    This break ID that we hit.
-  ///
-  /// \return
-  ///    \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID);
-
-  /// Returns the number of elements in the list.
-  ///
-  /// \result
-  ///   The number of elements.
-  size_t GetSize() const {
-    std::lock_guard<std::recursive_mutex> guard(m_mutex);
-    return m_bp_site_list.size();
-  }
-
-  bool IsEmpty() const {
-    std::lock_guard<std::recursive_mutex> guard(m_mutex);
-    return m_bp_site_list.empty();
-  }
-
-protected:
-  typedef std::map<lldb::addr_t, lldb::BreakpointSiteSP> collection;
-
-  collection::iterator GetIDIterator(lldb::break_id_t breakID);
-
-  collection::const_iterator GetIDConstIterator(lldb::break_id_t breakID) const;
-
-  mutable std::recursive_mutex m_mutex;
-  collection m_bp_site_list; // The breakpoint site list.
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_BREAKPOINT_BREAKPOINTSITELIST_H
diff --git a/lldb/include/lldb/Breakpoint/StopPointSiteList.h b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
new file mode 100644
index 000000000000000..04e6dc5af5eb051
--- /dev/null
+++ b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
@@ -0,0 +1,175 @@
+//===-- StopPointSiteList.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_BREAKPOINT_STOPPOINTSITELIST_H
+#define LLDB_BREAKPOINT_STOPPOINTSITELIST_H
+
+#include <functional>
+#include <map>
+#include <mutex>
+
+#include <lldb/Utility/Iterable.h>
+#include <lldb/Utility/Stream.h>
+
+namespace lldb_private {
+
+template <typename StopPointSite> class StopPointSiteList {
+  // At present Process directly accesses the map of StopPointSites so it can
+  // do quick lookups into the map (using GetMap).
+  // FIXME: Find a better interface for this.
+  friend class Process;
+
+public:
+  using StopPointSiteSP = std::shared_ptr<StopPointSite>;
+
+  /// Add a site to the list.
+  ///
+  /// \param[in] site_sp
+  ///    A shared pointer to a site being added to the list.
+  ///
+  /// \return
+  ///    The ID of the site in the list.
+  typename StopPointSite::SiteID Add(const StopPointSiteSP &site_sp);
+
+  /// Standard Dump routine, doesn't do anything at present.
+  /// \param[in] s
+  ///     Stream into which to dump the description.
+  void Dump(Stream *s) const;
+
+  /// Returns a shared pointer to the site at address \a addr.
+  ///
+  /// \param[in] addr
+  ///     The address to look for.
+  ///
+  /// \result
+  ///     A shared pointer to the site. Nullptr if no site contains
+  ///     the address.
+  StopPointSiteSP FindByAddress(lldb::addr_t addr);
+
+  /// Returns a shared pointer to the site with id \a site_id.
+  ///
+  /// \param[in] site_id
+  ///   The site ID to seek for.
+  ///
+  /// \result
+  ///   A shared pointer to the site. Nullptr if no matching site.
+  StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id);
+
+  /// Returns a shared pointer to the site with id \a site_id -
+  /// const version.
+  ///
+  /// \param[in] site_id
+  ///   The site ID to seek for.
+  ///
+  /// \result
+  ///   A shared pointer to the site. Nullptr if no matching site.
+  const StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) const;
+
+  /// Returns the site id to the site at address \a addr.
+  ///
+  /// \param[in] addr
+  ///   The address to match.
+  ///
+  /// \result
+  ///   The ID of the site, or LLDB_INVALID_SITE_ID.
+  typename StopPointSite::SiteID FindIDByAddress(lldb::addr_t addr);
+
+  /// Returns whether the BreakpointSite \a site_id has a BreakpointLocation
+  /// that is part of Breakpoint \a bp_id.
+  ///
+  /// NB this is only defined when StopPointSiteList is specialized for
+  /// BreakpointSite's.
+  ///
+  /// \param[in] site_id
+  ///   The site id to query.
+  ///
+  /// \param[in] bp_id
+  ///   The breakpoint id to look for in \a site_id's BreakpointLocations.
+  ///
+  /// \result
+  ///   True if \a site_id exists in the site list AND \a bp_id
+  ///   is the breakpoint for one of the BreakpointLocations.
+  bool StopPointSiteContainsBreakpoint(typename StopPointSite::SiteID,
+                                       lldb::break_id_t bp_id);
+
+  void ForEach(std::function<void(StopPointSite *)> const &callback);
+
+  /// Removes the site given by \a site_id from this list.
+  ///
+  /// \param[in] site_id
+  ///   The site ID to remove.
+  ///
+  /// \result
+  ///   \b true if the site \a site_id was in the list.
+  bool Remove(typename StopPointSite::SiteID site_id);
+
+  /// Removes the site at address \a addr from this list.
+  ///
+  /// \param[in] addr
+  ///   The address from which to remove a site.
+  ///
+  /// \result
+  ///   \b true if \a addr had a site to remove from the list.
+  bool RemoveByAddress(lldb::addr_t addr);
+
+  bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound,
+                   StopPointSiteList &bp_site_list) const;
+
+  typedef void (*StopPointSiteSPMapFunc)(StopPointSite &site, void *baton);
+
+  /// Enquires of the site on in this list with ID \a site_id
+  /// whether we should stop for the constituent or not.
+  ///
+  /// \param[in] context
+  ///    This contains the information about this stop.
+  ///
+  /// \param[in] site_id
+  ///    This site ID that we hit.
+  ///
+  /// \return
+  ///    \b true if we should stop, \b false otherwise.
+  bool ShouldStop(StoppointCallbackContext *context,
+                  typename StopPointSite::SiteID site_id);
+
+  /// Returns the number of elements in the list.
+  ///
+  /// \result
+  ///   The number of elements.
+  size_t GetSize() const {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    return m_site_list.size();
+  }
+
+  bool IsEmpty() const {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    return m_site_list.empty();
+  }
+
+  std::vector<StopPointSiteSP> Sites();
+
+  void Clear() {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    m_site_list.clear();
+  }
+
+protected:
+  typedef std::map<lldb::addr_t, StopPointSiteSP> collection;
+
+  typename collection::iterator
+  GetIDIterator(typename StopPointSite::SiteID site_id);
+
+  typename collection::const_iterator
+  GetIDConstIterator(typename StopPointSite::SiteID site_id) const;
+
+  mutable std::recursive_mutex m_mutex;
+  collection m_site_list; // The site list.
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_BREAKPOINT_STOPPOINTSITELIST_H
diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h
index e5b7291441e8484..851162af24c74e0 100644
--- a/lldb/include/lldb/Breakpoint/Watchpoint.h
+++ b/lldb/include/lldb/Breakpoint/Watchpoint.h
@@ -188,8 +188,6 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
 
   const CompilerType &GetCompilerType() { return m_type; }
 
-  uint32_t GetHardwareIndex() const override;
-
 private:
   friend class Target;
   friend class WatchpointList;
diff --git a/lldb/include/lldb/Breakpoint/WatchpointResource.h b/lldb/include/lldb/Breakpoint/WatchpointResource.h
index 66c7090f92c588d..a4c648b131603de 100644
--- a/lldb/include/lldb/Breakpoint/WatchpointResource.h
+++ b/lldb/include/lldb/Breakpoint/WatchpointResource.h
@@ -25,7 +25,10 @@ class WatchpointResource
 
   ~WatchpointResource();
 
-  lldb::addr_t GetAddress() const;
+  typedef lldb::wp_resource_id_t SiteID;
+  typedef lldb::watch_id_t ConstituentID;
+
+  lldb::addr_t GetLoadAddress() const;
 
   size_t GetByteSize() const;
 
@@ -40,69 +43,83 @@ class WatchpointResource
                                  vector_adapter, std::mutex>
       WatchpointIterable;
 
-  /// Iterate over the watchpoint owners for this resource
+  /// Iterate over the watchpoint constituents for this resource
   ///
   /// \return
   ///     An Iterable object which can be used to loop over the watchpoints
-  ///     that are owners of this resource.
-  WatchpointIterable Owners() {
-    return WatchpointIterable(m_owners, m_owners_mutex);
+  ///     that are constituents of this resource.
+  WatchpointIterable Constituents() {
+    return WatchpointIterable(m_constituents, m_constituents_mutex);
   }
 
-  /// The "Owners" are the watchpoints that share this resource.
-  /// The method adds the \a owner to this resource's owner list.
+  /// Enquires of the atchpoints that produced this watchpoint resource
+  /// whether we should stop at this location.
+  ///
+  /// \param[in] context
+  ///    This contains the information about this stop.
+  ///
+  /// \return
+  ///    \b true if we should stop, \b false otherwise.
+  bool ShouldStop(StoppointCallbackContext *context);
+
+  /// Standard Dump method
+  void Dump(Stream *s) const;
+
+  /// The "Constituents" are the watchpoints that share this resource.
+  /// The method adds the \a constituent to this resource's constituent list.
   ///
-  /// \param[in] owner
-  ///    \a owner is the Wachpoint to add.
-  void AddOwner(const lldb::WatchpointSP &owner);
+  /// \param[in] constituent
+  ///    \a constituent is the Wachpoint to add.
+  void AddConstituent(const lldb::WatchpointSP &constituent);
 
-  /// The method removes the owner at \a owner from this watchpoint
+  /// The method removes the constituent at \a constituent from this watchpoint
   /// resource.
-  void RemoveOwner(lldb::WatchpointSP &owner);
+  void RemoveConstituent(lldb::WatchpointSP &constituent);
 
   /// This method returns the number of Watchpoints currently using
   /// watchpoint resource.
   ///
   /// \return
-  ///    The number of owners.
-  size_t GetNumberOfOwners();
+  ///    The number of constituents.
+  size_t GetNumberOfConstituents();
 
   /// This method returns the Watchpoint at index \a index using this
-  /// Resource.  The owners are listed ordinally from 0 to
-  /// GetNumberOfOwners() - 1 so you can use this method to iterate over the
-  /// owners.
+  /// Resource.  The constituents are listed ordinally from 0 to
+  /// GetNumberOfConstituents() - 1 so you can use this method to iterate over
+  /// the constituents.
   ///
   /// \param[in] idx
-  ///     The index in the list of owners for which you wish the owner location.
+  ///     The index in the list of constituents for which you wish the
+  ///     constituent location.
   ///
   /// \return
   ///    The Watchpoint at that index.
-  lldb::WatchpointSP GetOwnerAtIndex(size_t idx);
+  lldb::WatchpointSP GetConstituentAtIndex(size_t idx);
 
-  /// Check if the owners includes a watchpoint.
+  /// Check if the constituents includes a watchpoint.
   ///
   /// \param[in] wp_sp
   ///     The WatchpointSP to search for.
   ///
   /// \result
-  ///     true if this resource's owners includes the watchpoint.
-  bool OwnersContains(const lldb::WatchpointSP &wp_sp);
+  ///     true if this resource's constituents includes the watchpoint.
+  bool ConstituentsContains(const lldb::WatchpointSP &wp_sp);
 
-  /// Check if the owners includes a watchpoint.
+  /// Check if the constituents includes a watchpoint.
   ///
   /// \param[in] wp
   ///     The Watchpoint to search for.
   ///
   /// \result
-  ///     true if this resource's owners includes the watchpoint.
-  bool OwnersContains(const lldb_private::Watchpoint *wp);
+  ///     true if this resource's constituents includes the watchpoint.
+  bool ConstituentsContains(const lldb_private::Watchpoint *wp);
 
-  /// This method copies the watchpoint resource's owners into a new collection.
-  /// It does this while the owners mutex is locked.
+  /// This method copies the watchpoint resource's constituents into a new
+  /// collection. It does this while the constituents mutex is locked.
   ///
   /// \return
   ///    A copy of the Watchpoints which own this resource.
-  WatchpointCollection CopyOwnersList();
+  WatchpointCollection CopyConstituentsList();
 
   // The ID of the WatchpointResource is set by the WatchpointResourceList
   // when the Resource has been set in the inferior and is being added
@@ -136,10 +153,10 @@ class WatchpointResource
   bool m_watch_write;
 
   /// The Watchpoints which own this resource.
-  WatchpointCollection m_owners;
+  WatchpointCollection m_constituents;
 
-  /// This mutex protects the owners collection.
-  std::mutex m_owners_mutex;
+  /// This mutex protects the constituents collection.
+  std::mutex m_constituents_mutex;
 
   WatchpointResource(const WatchpointResource &) = delete;
   const WatchpointResource &operator=(const WatchpointResource &) = delete;
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 6f140dd1a10ea57..4646e3070cf141f 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -22,8 +22,9 @@
 #include <unordered_set>
 #include <vector>
 
-#include "lldb/Breakpoint/BreakpointSiteList.h"
-#include "lldb/Breakpoint/WatchpointResourceList.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Breakpoint/StopPointSiteList.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
 #include "lldb/Core/LoadedModuleInfoList.h"
 #include "lldb/Core/PluginInterface.h"
 #include "lldb/Core/SourceManager.h"
@@ -2140,9 +2141,10 @@ class Process : public std::enable_shared_from_this<Process>,
   // doesn't work for a specific process plug-in.
   virtual Status DisableSoftwareBreakpoint(BreakpointSite *bp_site);
 
-  BreakpointSiteList &GetBreakpointSiteList();
+  StopPointSiteList<lldb_private::BreakpointSite> &GetBreakpointSiteList();
 
-  const BreakpointSiteList &GetBreakpointSiteList() const;
+  const StopPointSiteList<lldb_private::BreakpointSite> &
+  GetBreakpointSiteList() const;
 
   void DisableAllBreakpointSites();
 
@@ -2155,11 +2157,11 @@ class Process : public std::enable_shared_from_this<Process>,
 
   Status EnableBreakpointSiteByID(lldb::user_id_t break_id);
 
-  // BreakpointLocations use RemoveOwnerFromBreakpointSite to remove themselves
-  // from the owner's list of this breakpoint sites.
-  void RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id,
-                                     lldb::user_id_t owner_loc_id,
-                                     lldb::BreakpointSiteSP &bp_site_sp);
+  // BreakpointLocations use RemoveConstituentFromBreakpointSite to remove
+  // themselves from the constituent's list of this breakpoint sites.
+  void RemoveConstituentFromBreakpointSite(lldb::user_id_t site_id,
+                                           lldb::user_id_t constituent_id,
+                                           lldb::BreakpointSiteSP &bp_site_sp);
 
   // Process Watchpoints (optional)
   virtual Status EnableWatchpoint(lldb::WatchpointSP wp_sp, bool notify = true);
@@ -2184,7 +2186,8 @@ class Process : public std::enable_shared_from_this<Process>,
 
   ThreadList &GetThreadList() { return m_thread_list; }
 
-  WatchpointResourceList &GetWatchpointResourceList() {
+  StopPointSiteList<lldb_private::WatchpointResource> &
+  GetWatchpointResourceList() {
     return m_watchpoint_resource_list;
   }
 
@@ -3015,22 +3018,24 @@ void PruneThreadPlans();
                                      /// threads in m_thread_list, as well as
                                      /// threads we knew existed, but haven't
                                      /// determined that they have died yet.
-  ThreadList m_extended_thread_list; ///< Owner for extended threads that may be
-                                     ///generated, cleared on natural stops
+  ThreadList
+      m_extended_thread_list; ///< Constituent for extended threads that may be
+                              /// generated, cleared on natural stops
   uint32_t m_extended_thread_stop_id; ///< The natural stop id when
                                       ///extended_thread_list was last updated
   QueueList
       m_queue_list; ///< The list of libdispatch queues at a given stop point
   uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was
                                  ///last fetched
-  WatchpointResourceList
+  StopPointSiteList<lldb_private::WatchpointResource>
       m_watchpoint_resource_list; ///< Watchpoint resources currently in use.
   std::vector<Notifications> m_notifications; ///< The list of notifications
                                               ///that this process can deliver.
   std::vector<lldb::addr_t> m_image_tokens;
-  BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint
-                                             ///locations we intend to insert in
-                                             ///the target.
+  StopPointSiteList<lldb_private::BreakpointSite>
+      m_breakpoint_site_list; ///< This is the list of breakpoint
+                              /// locations we intend to insert in
+                              /// the target.
   lldb::DynamicLoaderUP m_dyld_up;
   lldb::JITLoaderListUP m_jit_loaders_up;
   lldb::DynamicCheckerFunctionsUP m_dynamic_checkers_up; ///< The functions used
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index 16bf253232e92c8..469be92eabecf31 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -49,6 +49,9 @@
   ((type & LLDB_WATCH_TYPE_READ) || (type & LLDB_WATCH_TYPE_WRITE) ||          \
    (type & LLDB_WATCH_TYPE_MODIFY))
 
+// StopPointSites
+#define LLDB_INVALID_SITE_ID UINT32_MAX
+
 // Generic Register Numbers
 #define LLDB_REGNUM_GENERIC_PC 0    // Program Counter
 #define LLDB_REGNUM_GENERIC_SP 1    // Stack Pointer
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 4feff7439bfe565..068fce4976ed265 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -39,7 +39,6 @@ class BreakpointOptions;
 class BreakpointPrecondition;
 class BreakpointResolver;
 class BreakpointSite;
-class BreakpointSiteList;
 class BroadcastEventSpec;
 class Broadcaster;
 class BroadcasterManager;
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index 18c086bb04c682f..fa4c80e59d973fa 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -181,7 +181,7 @@ size_t SBThread::GetStopReasonDataCount() {
               exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID(
                   site_id));
           if (bp_site_sp)
-            return bp_site_sp->GetNumberOfOwners() * 2;
+            return bp_site_sp->GetNumberOfConstituents() * 2;
           else
             return 0; // Breakpoint must have cleared itself...
         } break;
@@ -241,7 +241,7 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
           if (bp_site_sp) {
             uint32_t bp_index = idx / 2;
             BreakpointLocationSP bp_loc_sp(
-                bp_site_sp->GetOwnerAtIndex(bp_index));
+                bp_site_sp->GetConstituentAtIndex(bp_index));
             if (bp_loc_sp) {
               if (idx & 1) {
                 // Odd idx, return the breakpoint location ID
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 27dc7458dc26f70..9bf528bbd9f4c95 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -472,10 +472,10 @@ bool BreakpointLocation::ClearBreakpointSite() {
     // physical implementation of the breakpoint as well if there are no more
     // owners.  Otherwise just remove this owner.
     if (process_sp)
-      process_sp->RemoveOwnerFromBreakpointSite(GetBreakpoint().GetID(),
-                                                GetID(), m_bp_site_sp);
+      process_sp->RemoveConstituentFromBreakpointSite(GetBreakpoint().GetID(),
+                                                      GetID(), m_bp_site_sp);
     else
-      m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID());
+      m_bp_site_sp->RemoveConstituent(GetBreakpoint().GetID(), GetID());
 
     m_bp_site_sp.reset();
     return true;
diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp
index 5187bc560ba26ca..3ca93f908e30b8b 100644
--- a/lldb/source/Breakpoint/BreakpointSite.cpp
+++ b/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -12,14 +12,12 @@
 
 #include "lldb/Breakpoint/Breakpoint.h"
 #include "lldb/Breakpoint/BreakpointLocation.h"
-#include "lldb/Breakpoint/BreakpointSiteList.h"
 #include "lldb/Utility/Stream.h"
 
 using namespace lldb;
 using namespace lldb_private;
 
-BreakpointSite::BreakpointSite(BreakpointSiteList *list,
-                               const BreakpointLocationSP &owner,
+BreakpointSite::BreakpointSite(const BreakpointLocationSP &constituent,
                                lldb::addr_t addr, bool use_hardware)
     : StoppointSite(GetNextID(), addr, 0, use_hardware),
       m_type(eSoftware), // Process subclasses need to set this correctly using
@@ -28,14 +26,14 @@ BreakpointSite::BreakpointSite(BreakpointSiteList *list,
       m_enabled(false) // Need to create it disabled, so the first enable turns
                        // it on.
 {
-  m_owners.Add(owner);
+  m_constituents.Add(constituent);
 }
 
 BreakpointSite::~BreakpointSite() {
   BreakpointLocationSP bp_loc_sp;
-  const size_t owner_count = m_owners.GetSize();
-  for (size_t i = 0; i < owner_count; i++) {
-    m_owners.GetByIndex(i)->ClearBreakpointSite();
+  const size_t constituent_count = m_constituents.GetSize();
+  for (size_t i = 0; i < constituent_count; i++) {
+    m_constituents.GetByIndex(i)->ClearBreakpointSite();
   }
 }
 
@@ -50,22 +48,22 @@ break_id_t BreakpointSite::GetNextID() {
 bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
   m_hit_counter.Increment();
   // ShouldStop can do a lot of work, and might even come back and hit
-  // this breakpoint site again.  So don't hold the m_owners_mutex the whole
-  // while.  Instead make a local copy of the collection and call ShouldStop on
-  // the copy.
-  BreakpointLocationCollection owners_copy;
+  // this breakpoint site again.  So don't hold the m_constituents_mutex the
+  // whole while.  Instead make a local copy of the collection and call
+  // ShouldStop on the copy.
+  BreakpointLocationCollection constituents_copy;
   {
-    std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-    owners_copy = m_owners;
+    std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+    constituents_copy = m_constituents;
   }
-  return owners_copy.ShouldStop(context);
+  return constituents_copy.ShouldStop(context);
 }
 
 bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  const size_t owner_count = m_owners.GetSize();
-  for (size_t i = 0; i < owner_count; i++) {
-    if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  const size_t constituent_count = m_constituents.GetSize();
+  for (size_t i = 0; i < constituent_count; i++) {
+    if (m_constituents.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
       return true;
   }
   return false;
@@ -82,14 +80,14 @@ void BreakpointSite::Dump(Stream *s) const {
 }
 
 void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
   if (level != lldb::eDescriptionLevelBrief)
     s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(),
               GetLoadAddress());
-  m_owners.GetDescription(s, level);
+  m_constituents.GetDescription(s, level);
 }
 
-bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); }
+bool BreakpointSite::IsInternal() const { return m_constituents.IsInternal(); }
 
 uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }
 
@@ -122,36 +120,36 @@ bool BreakpointSite::IsEnabled() const { return m_enabled; }
 
 void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; }
 
-void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  m_owners.Add(owner);
+void BreakpointSite::AddConstituent(const BreakpointLocationSP &constituent) {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  m_constituents.Add(constituent);
 }
 
-size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id,
-                                   lldb::break_id_t break_loc_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  m_owners.Remove(break_id, break_loc_id);
-  return m_owners.GetSize();
+size_t BreakpointSite::RemoveConstituent(lldb::break_id_t break_id,
+                                         lldb::break_id_t break_loc_id) {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  m_constituents.Remove(break_id, break_loc_id);
+  return m_constituents.GetSize();
 }
 
-size_t BreakpointSite::GetNumberOfOwners() {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.GetSize();
+size_t BreakpointSite::GetNumberOfConstituents() {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  return m_constituents.GetSize();
 }
 
-BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.GetByIndex(index);
+BreakpointLocationSP BreakpointSite::GetConstituentAtIndex(size_t index) {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  return m_constituents.GetByIndex(index);
 }
 
 bool BreakpointSite::ValidForThisThread(Thread &thread) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  return m_owners.ValidForThisThread(thread);
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  return m_constituents.ValidForThisThread(thread);
 }
 
 void BreakpointSite::BumpHitCounts() {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) {
     loc_sp->BumpHitCount();
   }
 }
@@ -198,10 +196,10 @@ bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
   return true;
 }
 
-size_t
-BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) {
-  std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
-  for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
+size_t BreakpointSite::CopyConstituentsList(
+    BreakpointLocationCollection &out_collection) {
+  std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+  for (BreakpointLocationSP loc_sp : m_constituents.BreakpointLocations()) {
     out_collection.Add(loc_sp);
   }
   return out_collection.GetSize();
diff --git a/lldb/source/Breakpoint/BreakpointSiteList.cpp b/lldb/source/Breakpoint/BreakpointSiteList.cpp
deleted file mode 100644
index ab15da82ea4509c..000000000000000
--- a/lldb/source/Breakpoint/BreakpointSiteList.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-//===-- BreakpointSiteList.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/Breakpoint/BreakpointSiteList.h"
-
-#include "lldb/Utility/Stream.h"
-#include <algorithm>
-
-using namespace lldb;
-using namespace lldb_private;
-
-BreakpointSiteList::BreakpointSiteList() = default;
-
-BreakpointSiteList::~BreakpointSiteList() = default;
-
-// Add breakpoint site to the list.  However, if the element already exists in
-// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
-
-lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
-  lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::iterator iter = m_bp_site_list.find(bp_site_load_addr);
-
-  if (iter == m_bp_site_list.end()) {
-    m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp));
-    return bp->GetID();
-  } else {
-    return LLDB_INVALID_BREAK_ID;
-  }
-}
-
-bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context,
-                                    lldb::break_id_t site_id) {
-  BreakpointSiteSP site_sp(FindByID(site_id));
-  if (site_sp) {
-    // Let the BreakpointSite decide if it should stop here (could not have
-    // reached it's target hit count yet, or it could have a callback that
-    // decided it shouldn't stop (shared library loads/unloads).
-    return site_sp->ShouldStop(context);
-  }
-  // We should stop here since this BreakpointSite isn't valid anymore or it
-  // doesn't exist.
-  return true;
-}
-lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) {
-  if (BreakpointSiteSP bp = FindByAddress(addr))
-    return bp.get()->GetID();
-  return LLDB_INVALID_BREAK_ID;
-}
-
-bool BreakpointSiteList::Remove(lldb::break_id_t break_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::iterator pos = GetIDIterator(break_id); // Predicate
-  if (pos != m_bp_site_list.end()) {
-    m_bp_site_list.erase(pos);
-    return true;
-  }
-  return false;
-}
-
-bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::iterator pos = m_bp_site_list.find(address);
-  if (pos != m_bp_site_list.end()) {
-    m_bp_site_list.erase(pos);
-    return true;
-  }
-  return false;
-}
-
-class BreakpointSiteIDMatches {
-public:
-  BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {}
-
-  bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const {
-    return m_break_id == val_pair.second->GetID();
-  }
-
-private:
-  const lldb::break_id_t m_break_id;
-};
-
-BreakpointSiteList::collection::iterator
-BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  return std::find_if(m_bp_site_list.begin(),
-                      m_bp_site_list.end(),               // Search full range
-                      BreakpointSiteIDMatches(break_id)); // Predicate
-}
-
-BreakpointSiteList::collection::const_iterator
-BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  return std::find_if(m_bp_site_list.begin(),
-                      m_bp_site_list.end(),               // Search full range
-                      BreakpointSiteIDMatches(break_id)); // Predicate
-}
-
-BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  BreakpointSiteSP stop_sp;
-  collection::iterator pos = GetIDIterator(break_id);
-  if (pos != m_bp_site_list.end())
-    stop_sp = pos->second;
-
-  return stop_sp;
-}
-
-const BreakpointSiteSP
-BreakpointSiteList::FindByID(lldb::break_id_t break_id) const {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  BreakpointSiteSP stop_sp;
-  collection::const_iterator pos = GetIDConstIterator(break_id);
-  if (pos != m_bp_site_list.end())
-    stop_sp = pos->second;
-
-  return stop_sp;
-}
-
-BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) {
-  BreakpointSiteSP found_sp;
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::iterator iter = m_bp_site_list.find(addr);
-  if (iter != m_bp_site_list.end())
-    found_sp = iter->second;
-  return found_sp;
-}
-
-bool BreakpointSiteList::BreakpointSiteContainsBreakpoint(
-    lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::const_iterator pos = GetIDConstIterator(bp_site_id);
-  if (pos != m_bp_site_list.end())
-    return pos->second->IsBreakpointAtThisSite(bp_id);
-
-  return false;
-}
-
-void BreakpointSiteList::Dump(Stream *s) const {
-  s->Printf("%p: ", static_cast<const void *>(this));
-  // s->Indent();
-  s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
-            (uint32_t)m_bp_site_list.size());
-  s->IndentMore();
-  collection::const_iterator pos;
-  collection::const_iterator end = m_bp_site_list.end();
-  for (pos = m_bp_site_list.begin(); pos != end; ++pos)
-    pos->second->Dump(s);
-  s->IndentLess();
-}
-
-void BreakpointSiteList::ForEach(
-    std::function<void(BreakpointSite *)> const &callback) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  for (auto pair : m_bp_site_list)
-    callback(pair.second.get());
-}
-
-bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
-                                     lldb::addr_t upper_bound,
-                                     BreakpointSiteList &bp_site_list) const {
-  if (lower_bound > upper_bound)
-    return false;
-
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::const_iterator lower, upper, pos;
-  lower = m_bp_site_list.lower_bound(lower_bound);
-  if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
-    return false;
-
-  // This is one tricky bit.  The breakpoint might overlap the bottom end of
-  // the range.  So we grab the breakpoint prior to the lower bound, and check
-  // that that + its byte size isn't in our range.
-  if (lower != m_bp_site_list.begin()) {
-    collection::const_iterator prev_pos = lower;
-    prev_pos--;
-    const BreakpointSiteSP &prev_bp = (*prev_pos).second;
-    if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
-      bp_site_list.Add(prev_bp);
-  }
-
-  upper = m_bp_site_list.upper_bound(upper_bound);
-
-  for (pos = lower; pos != upper; pos++) {
-    bp_site_list.Add((*pos).second);
-  }
-  return true;
-}
diff --git a/lldb/source/Breakpoint/CMakeLists.txt b/lldb/source/Breakpoint/CMakeLists.txt
index bc0ecba0a8f4868..42ac338c315b4ff 100644
--- a/lldb/source/Breakpoint/CMakeLists.txt
+++ b/lldb/source/Breakpoint/CMakeLists.txt
@@ -16,10 +16,10 @@ add_lldb_library(lldbBreakpoint NO_PLUGIN_DEPENDENCIES
   BreakpointResolverName.cpp
   BreakpointResolverScripted.cpp
   BreakpointSite.cpp
-  BreakpointSiteList.cpp
   Stoppoint.cpp
   StoppointCallbackContext.cpp
   StoppointSite.cpp
+  StopPointSiteList.cpp
   Watchpoint.cpp
   WatchpointList.cpp
   WatchpointOptions.cpp
diff --git a/lldb/source/Breakpoint/StopPointSiteList.cpp b/lldb/source/Breakpoint/StopPointSiteList.cpp
new file mode 100644
index 000000000000000..ad5805741e2d8e5
--- /dev/null
+++ b/lldb/source/Breakpoint/StopPointSiteList.cpp
@@ -0,0 +1,235 @@
+//===-- StopPointSiteList.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/Breakpoint/StopPointSiteList.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Breakpoint/WatchpointResource.h"
+
+#include "lldb/Utility/Stream.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Add site to the list.  However, if the element already exists in
+// the list, then we don't add it, and return InvalidSiteID.
+
+template <typename StopPointSite>
+typename StopPointSite::SiteID
+StopPointSiteList<StopPointSite>::Add(const StopPointSiteSP &site) {
+  lldb::addr_t site_load_addr = site->GetLoadAddress();
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::iterator iter = m_site_list.find(site_load_addr);
+
+  if (iter == m_site_list.end()) {
+#if 0
+    m_site_list.insert(iter, collection::value_type(site_load_addr, site));
+#endif
+    m_site_list[site_load_addr] = site;
+    return site->GetID();
+  } else {
+    return UINT32_MAX;
+  }
+}
+
+template <typename StopPointSite>
+bool StopPointSiteList<StopPointSite>::ShouldStop(
+    StoppointCallbackContext *context, typename StopPointSite::SiteID site_id) {
+  StopPointSiteSP site_sp(FindByID(site_id));
+  if (site_sp) {
+    // Let the site decide if it should stop here (could not have
+    // reached it's target hit count yet, or it could have a callback that
+    // decided it shouldn't stop (shared library loads/unloads).
+    return site_sp->ShouldStop(context);
+  }
+  // We should stop here since this site isn't valid anymore or it
+  // doesn't exist.
+  return true;
+}
+
+template <typename StopPointSite>
+typename StopPointSite::SiteID
+StopPointSiteList<StopPointSite>::FindIDByAddress(lldb::addr_t addr) {
+  if (StopPointSiteSP site = FindByAddress(addr))
+    return site->GetID();
+  return UINT32_MAX;
+}
+
+template <typename StopPointSite>
+bool StopPointSiteList<StopPointSite>::Remove(
+    typename StopPointSite::SiteID site_id) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::iterator pos = GetIDIterator(site_id); // Predicate
+  if (pos != m_site_list.end()) {
+    m_site_list.erase(pos);
+    return true;
+  }
+  return false;
+}
+
+template <typename StopPointSite>
+bool StopPointSiteList<StopPointSite>::RemoveByAddress(lldb::addr_t address) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::iterator pos = m_site_list.find(address);
+  if (pos != m_site_list.end()) {
+    m_site_list.erase(pos);
+    return true;
+  }
+  return false;
+}
+
+template <typename StopPointSite>
+typename StopPointSiteList<StopPointSite>::collection::iterator
+StopPointSiteList<StopPointSite>::GetIDIterator(
+    typename StopPointSite::SiteID site_id) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  auto id_matches = [site_id](const std::pair<addr_t, StopPointSiteSP> s) {
+    return site_id == s.second->GetID();
+  };
+  return std::find_if(m_site_list.begin(),
+                      m_site_list.end(), // Search full range
+                      id_matches);
+}
+
+template <typename StopPointSite>
+typename StopPointSiteList<StopPointSite>::collection::const_iterator
+StopPointSiteList<StopPointSite>::GetIDConstIterator(
+    typename StopPointSite::SiteID site_id) const {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  auto id_matches = [site_id](const std::pair<addr_t, StopPointSiteSP> s) {
+    return site_id == s.second->GetID();
+  };
+  return std::find_if(m_site_list.begin(),
+                      m_site_list.end(), // Search full range
+                      id_matches);
+}
+
+template <typename StopPointSite>
+typename StopPointSiteList<StopPointSite>::StopPointSiteSP
+StopPointSiteList<StopPointSite>::FindByID(
+    typename StopPointSite::SiteID site_id) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  StopPointSiteSP stop_sp;
+  typename collection::iterator pos = GetIDIterator(site_id);
+  if (pos != m_site_list.end())
+    stop_sp = pos->second;
+
+  return stop_sp;
+}
+
+template <typename StopPointSite>
+const typename StopPointSiteList<StopPointSite>::StopPointSiteSP
+StopPointSiteList<StopPointSite>::FindByID(
+    typename StopPointSite::SiteID site_id) const {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  StopPointSiteSP stop_sp;
+  typename collection::const_iterator pos = GetIDConstIterator(site_id);
+  if (pos != m_site_list.end())
+    stop_sp = pos->second;
+
+  return stop_sp;
+}
+
+template <typename StopPointSite>
+typename StopPointSiteList<StopPointSite>::StopPointSiteSP
+StopPointSiteList<StopPointSite>::FindByAddress(lldb::addr_t addr) {
+  StopPointSiteSP found_sp;
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::iterator iter = m_site_list.find(addr);
+  if (iter != m_site_list.end())
+    found_sp = iter->second;
+  return found_sp;
+}
+
+// This method is only defined when we're specializing for
+// BreakpointSite / BreakpointLocation / Breakpoint.
+// Watchpoints don't have a similar structure, they are
+// WatchpointResource / Watchpoint
+template <>
+bool StopPointSiteList<BreakpointSite>::StopPointSiteContainsBreakpoint(
+    typename BreakpointSite::SiteID site_id, break_id_t bp_id) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::const_iterator pos = GetIDConstIterator(site_id);
+  if (pos != m_site_list.end())
+    return pos->second->IsBreakpointAtThisSite(bp_id);
+
+  return false;
+}
+
+template <typename StopPointSite>
+void StopPointSiteList<StopPointSite>::Dump(Stream *s) const {
+  s->Printf("%p: ", static_cast<const void *>(this));
+  // s->Indent();
+  s->Printf("StopPointSiteList with %u ConstituentSites:\n",
+            (uint32_t)m_site_list.size());
+  s->IndentMore();
+  typename collection::const_iterator pos;
+  typename collection::const_iterator end = m_site_list.end();
+  for (pos = m_site_list.begin(); pos != end; ++pos)
+    pos->second->Dump(s);
+  s->IndentLess();
+}
+
+template <typename StopPointSite>
+void StopPointSiteList<StopPointSite>::ForEach(
+    std::function<void(StopPointSite *)> const &callback) {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  for (auto pair : m_site_list)
+    callback(pair.second.get());
+}
+
+template <typename StopPointSite>
+bool StopPointSiteList<StopPointSite>::FindInRange(
+    lldb::addr_t lower_bound, lldb::addr_t upper_bound,
+    StopPointSiteList &site_list) const {
+  if (lower_bound > upper_bound)
+    return false;
+
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::const_iterator lower, upper, pos;
+  lower = m_site_list.lower_bound(lower_bound);
+  if (lower == m_site_list.end() || (*lower).first >= upper_bound)
+    return false;
+
+  // This is one tricky bit.  The site might overlap the bottom end of
+  // the range.  So we grab the site prior to the lower bound, and check
+  // that that + its byte size isn't in our range.
+  if (lower != m_site_list.begin()) {
+    typename collection::const_iterator prev_pos = lower;
+    prev_pos--;
+    const StopPointSiteSP &prev_site = (*prev_pos).second;
+    if (prev_site->GetLoadAddress() + prev_site->GetByteSize() > lower_bound)
+      site_list.Add(prev_site);
+  }
+
+  upper = m_site_list.upper_bound(upper_bound);
+
+  for (pos = lower; pos != upper; pos++) {
+    site_list.Add((*pos).second);
+  }
+  return true;
+}
+
+template <typename StopPointSite>
+std::vector<typename StopPointSiteList<StopPointSite>::StopPointSiteSP>
+StopPointSiteList<StopPointSite>::Sites() {
+  std::vector<StopPointSiteSP> sites;
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  typename collection::iterator iter = m_site_list.begin();
+  while (iter != m_site_list.end()) {
+    sites.push_back(iter->second);
+    ++iter;
+  }
+
+  return sites;
+}
+
+namespace lldb_private {
+template class StopPointSiteList<BreakpointSite>;
+template class StopPointSiteList<WatchpointResource>;
+} // namespace lldb_private
diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp
index ec1b755880628c1..4602ce4213b9cda 100644
--- a/lldb/source/Breakpoint/Watchpoint.cpp
+++ b/lldb/source/Breakpoint/Watchpoint.cpp
@@ -369,15 +369,6 @@ void Watchpoint::DumpWithLevel(Stream *s,
 
 bool Watchpoint::IsEnabled() const { return m_enabled; }
 
-uint32_t Watchpoint::GetHardwareIndex() const {
-  if (IsEnabled())
-    return m_target.GetProcessSP()
-        ->GetWatchpointResourceList()
-        .FindByWatchpoint(this)
-        ->GetID();
-  return UINT32_MAX;
-}
-
 // Within StopInfo.cpp, we purposely turn on the ephemeral mode right before
 // temporarily disable the watchpoint in order to perform possible watchpoint
 // actions without triggering further watchpoint events. After the temporary
diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
index 402e248c02aee79..dc46d6c692a9efa 100644
--- a/lldb/source/Breakpoint/WatchpointResource.cpp
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -19,11 +19,11 @@ WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
       m_watch_read(read), m_watch_write(write) {}
 
 WatchpointResource::~WatchpointResource() {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  m_owners.clear();
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  m_constituents.clear();
 }
 
-addr_t WatchpointResource::GetAddress() const { return m_addr; }
+addr_t WatchpointResource::GetLoadAddress() const { return m_addr; }
 
 size_t WatchpointResource::GetByteSize() const { return m_size; }
 
@@ -48,45 +48,70 @@ bool WatchpointResource::Contains(addr_t addr) {
   return false;
 }
 
-void WatchpointResource::AddOwner(const WatchpointSP &wp_sp) {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  m_owners.push_back(wp_sp);
+void WatchpointResource::AddConstituent(const WatchpointSP &wp_sp) {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  m_constituents.push_back(wp_sp);
 }
 
-void WatchpointResource::RemoveOwner(WatchpointSP &wp_sp) {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  const auto &it = std::find(m_owners.begin(), m_owners.end(), wp_sp);
-  if (it != m_owners.end())
-    m_owners.erase(it);
+void WatchpointResource::RemoveConstituent(WatchpointSP &wp_sp) {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  const auto &it =
+      std::find(m_constituents.begin(), m_constituents.end(), wp_sp);
+  if (it != m_constituents.end())
+    m_constituents.erase(it);
 }
 
-size_t WatchpointResource::GetNumberOfOwners() {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  return m_owners.size();
+size_t WatchpointResource::GetNumberOfConstituents() {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  return m_constituents.size();
 }
 
-bool WatchpointResource::OwnersContains(const WatchpointSP &wp_sp) {
-  return OwnersContains(wp_sp.get());
+bool WatchpointResource::ConstituentsContains(const WatchpointSP &wp_sp) {
+  return ConstituentsContains(wp_sp.get());
 }
 
-bool WatchpointResource::OwnersContains(const Watchpoint *wp) {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
+bool WatchpointResource::ConstituentsContains(const Watchpoint *wp) {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
   WatchpointCollection::const_iterator match =
-      std::find_if(m_owners.begin(), m_owners.end(),
+      std::find_if(m_constituents.begin(), m_constituents.end(),
                    [&wp](const WatchpointSP &x) { return x.get() == wp; });
-  return match != m_owners.end();
+  return match != m_constituents.end();
 }
 
-WatchpointSP WatchpointResource::GetOwnerAtIndex(size_t idx) {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  assert(idx < m_owners.size());
-  if (idx >= m_owners.size())
+WatchpointSP WatchpointResource::GetConstituentAtIndex(size_t idx) {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  assert(idx < m_constituents.size());
+  if (idx >= m_constituents.size())
     return {};
 
-  return m_owners[idx];
+  return m_constituents[idx];
 }
 
-WatchpointResource::WatchpointCollection WatchpointResource::CopyOwnersList() {
-  std::lock_guard<std::mutex> guard(m_owners_mutex);
-  return m_owners;
+WatchpointResource::WatchpointCollection
+WatchpointResource::CopyConstituentsList() {
+  std::lock_guard<std::mutex> guard(m_constituents_mutex);
+  return m_constituents;
+}
+
+bool WatchpointResource::ShouldStop(StoppointCallbackContext *context) {
+  // LWP_TODO: Need to poll all Watchpoint constituents and see if
+  // we should stop, like BreakpointSites do.
+#if 0
+  m_hit_counter.Increment();
+  // ShouldStop can do a lot of work, and might even come back and hit
+  // this breakpoint site again.  So don't hold the m_constituents_mutex the
+  // whole while.  Instead make a local copy of the collection and call
+  // ShouldStop on the copy.
+  WatchpointResourceCollection constituents_copy;
+  {
+    std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
+    constituents_copy = m_constituents;
+  }
+  return constituents_copy.ShouldStop(context);
+#endif
+  return true;
+}
+
+void WatchpointResource::Dump(Stream *s) const {
+  return; // LWP_TODO
 }
diff --git a/lldb/source/Breakpoint/WatchpointResourceList.cpp b/lldb/source/Breakpoint/WatchpointResourceList.cpp
index fa6625adfefb2f7..49fca373b22332f 100644
--- a/lldb/source/Breakpoint/WatchpointResourceList.cpp
+++ b/lldb/source/Breakpoint/WatchpointResourceList.cpp
@@ -24,7 +24,7 @@ WatchpointResourceList::Add(const WatchpointResourceSP &wp_res_sp) {
   std::lock_guard<std::mutex> guard(m_mutex);
 
   LLDB_LOGF(log, "WatchpointResourceList::Add(addr 0x%" PRIx64 " size %zu)",
-            wp_res_sp->GetAddress(), wp_res_sp->GetByteSize());
+            wp_res_sp->GetLoadAddress(), wp_res_sp->GetByteSize());
 
   // The goal is to have the wp_resource_id_t match the actual hardware
   // watchpoint register number.  If we assume that the remote stub is
@@ -69,7 +69,7 @@ bool WatchpointResourceList::Remove(wp_resource_id_t id) {
     if ((*pos)->GetID() == id) {
       LLDB_LOGF(log,
                 "WatchpointResourceList::Remove(addr 0x%" PRIx64 " size %zu)",
-                (*pos)->GetAddress(), (*pos)->GetByteSize());
+                (*pos)->GetLoadAddress(), (*pos)->GetByteSize());
       m_resources.erase(pos);
       return true;
     }
@@ -86,7 +86,7 @@ bool WatchpointResourceList::RemoveByAddress(addr_t addr) {
       LLDB_LOGF(log,
                 "WatchpointResourceList::RemoveByAddress(addr 0x%" PRIx64
                 " size %zu)",
-                (*pos)->GetAddress(), (*pos)->GetByteSize());
+                (*pos)->GetLoadAddress(), (*pos)->GetByteSize());
       m_resources.erase(pos);
       return true;
     }
@@ -111,7 +111,7 @@ WatchpointResourceSP
 WatchpointResourceList::FindByWatchpoint(const Watchpoint *wp) {
   std::lock_guard<std::mutex> guard(m_mutex);
   for (WatchpointResourceSP wp_res_sp : m_resources)
-    if (wp_res_sp->OwnersContains(wp))
+    if (wp_res_sp->ConstituentsContains(wp))
       return wp_res_sp;
   return {};
 }
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index c7ce1b1258c196c..181eb2605a7ba3e 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -517,10 +517,10 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
             BreakpointSiteSP bp_site_sp(
                 process->GetBreakpointSiteList().FindByID(bp_site_id));
             if (bp_site_sp) {
-              const size_t num_owners = bp_site_sp->GetNumberOfOwners();
+              const size_t num_owners = bp_site_sp->GetNumberOfConstituents();
               for (size_t i = 0; i < num_owners; i++) {
                 Breakpoint &bp_ref =
-                    bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+                    bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
                 if (!bp_ref.IsInternal()) {
                   bp_ref.SetIgnoreCount(m_options.m_ignore);
                 }
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 6c763ea1558feb1..a5c9ead55f4cd72 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -607,7 +607,7 @@ bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop(
     return false;
 
   uint64_t break_site_id = stop_reason->GetValue();
-  return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(
+  return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint(
       break_site_id, m_cxx_exception_bp_sp->GetID());
 }
 
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 80c7bd071d6bf55..f08f9f0f815d0cc 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -445,7 +445,7 @@ bool AppleObjCRuntime::ExceptionBreakpointsExplainStop(
     return false;
 
   uint64_t break_site_id = stop_reason->GetValue();
-  return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(
+  return m_process->GetBreakpointSiteList().StopPointSiteContainsBreakpoint(
       break_site_id, m_objc_exception_bp_sp->GetID());
 }
 
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
index 547a1f6db97619d..4093cbdd955f759 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
@@ -333,7 +333,7 @@ AppleThreadPlanStepThroughDirectDispatch::DoPlanExplainsStop(Event *event_ptr) {
       if (site_sp->IsBreakpointAtThisSite(break_sp->GetID())) {
         // If we aren't the only one with a breakpoint on this site, then we
         // should just stop and return control to the user.
-        if (site_sp->GetNumberOfOwners() > 1) {
+        if (site_sp->GetNumberOfConstituents() > 1) {
           SetPlanComplete(true);
           return false;
         }
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index ae36d3f9730bbf3..ca7ff5a99f9060b 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -432,7 +432,7 @@ PlatformDarwin::GetSoftwareBreakpointTrapOpcode(Target &target,
 
     // Auto detect arm/thumb if it wasn't explicitly specified
     if (!bp_is_thumb) {
-      lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0));
+      lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0));
       if (bp_loc_sp)
         bp_is_thumb = bp_loc_sp->GetAddress().GetAddressClass() ==
                       AddressClass::eCodeAlternateISA;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index bfd83e5d2136db6..4b2676eceab6058 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1829,11 +1829,13 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
           if (!wp_resource_sp) {
             Log *log(GetLog(GDBRLog::Watchpoints));
             LLDB_LOGF(log, "failed to find watchpoint");
+            abort(); // LWP_TODO FIXME don't continue executing this block if
+                     // we don't get a resource.
           }
           // LWP_TODO: This is hardcoding a single Watchpoint in a
           // Resource, need to add
           // StopInfo::CreateStopReasonWithWatchpointResource
-          watch_id = wp_resource_sp->GetOwnerAtIndex(0)->GetID();
+          watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID();
           thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
               *thread_sp, watch_id, silently_continue));
           handled = true;
@@ -3211,7 +3213,7 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
   bool set_all_resources = true;
   std::vector<WatchpointResourceSP> succesfully_set_resources;
   for (const auto &wp_res_sp : resources) {
-    addr_t addr = wp_res_sp->GetAddress();
+    addr_t addr = wp_res_sp->GetLoadAddress();
     size_t size = wp_res_sp->GetByteSize();
     GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
     if (!m_gdb_comm.SupportsGDBStoppointPacket(type) ||
@@ -3228,7 +3230,7 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
     for (const auto &wp_res_sp : resources) {
       // LWP_TODO: If we expanded/reused an existing Resource,
       // it's already in the WatchpointResourceList.
-      wp_res_sp->AddOwner(wp_sp);
+      wp_res_sp->AddConstituent(wp_sp);
       m_watchpoint_resource_list.Add(wp_res_sp);
     }
     return error;
@@ -3237,7 +3239,7 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) {
     // of the new resources we did successfully set in the
     // process.
     for (const auto &wp_res_sp : succesfully_set_resources) {
-      addr_t addr = wp_res_sp->GetAddress();
+      addr_t addr = wp_res_sp->GetLoadAddress();
       size_t size = wp_res_sp->GetByteSize();
       GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
       m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
@@ -3281,23 +3283,23 @@ Status ProcessGDBRemote::DisableWatchpoint(WatchpointSP wp_sp, bool notify) {
   if (wp_sp->IsHardware()) {
     bool disabled_all = true;
 
-    std::vector<WatchpointResourceSP> unused_resouces;
-    for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
-      if (wp_res_sp->OwnersContains(wp_sp)) {
+    std::vector<WatchpointResourceSP> unused_resources;
+    for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+      if (wp_res_sp->ConstituentsContains(wp_sp)) {
         GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
-        addr_t addr = wp_res_sp->GetAddress();
+        addr_t addr = wp_res_sp->GetLoadAddress();
         size_t size = wp_res_sp->GetByteSize();
         if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, size,
                                                   GetInterruptTimeout())) {
           disabled_all = false;
         } else {
-          wp_res_sp->RemoveOwner(wp_sp);
-          if (wp_res_sp->GetNumberOfOwners() == 0)
-            unused_resouces.push_back(wp_res_sp);
+          wp_res_sp->RemoveConstituent(wp_sp);
+          if (wp_res_sp->GetNumberOfConstituents() == 0)
+            unused_resources.push_back(wp_res_sp);
         }
       }
     }
-    for (auto &wp_res_sp : unused_resouces)
+    for (auto &wp_res_sp : unused_resources)
       m_watchpoint_resource_list.Remove(wp_res_sp->GetID());
 
     wp_sp->SetEnabled(false, notify);
@@ -5555,8 +5557,8 @@ void ProcessGDBRemote::DidForkSwitchHardwareTraps(bool enable) {
     });
   }
 
-  for (const auto &wp_res_sp : m_watchpoint_resource_list.Resources()) {
-    addr_t addr = wp_res_sp->GetAddress();
+  for (const auto &wp_res_sp : m_watchpoint_resource_list.Sites()) {
+    addr_t addr = wp_res_sp->GetLoadAddress();
     size_t size = wp_res_sp->GetByteSize();
     GDBStoppointType type = GetGDBStoppointType(wp_res_sp);
     m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, size,
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index c345e33136070f2..4ce290dfbe035fe 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -2014,7 +2014,7 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
     static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7};
     static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde};
 
-    lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0));
+    lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetConstituentAtIndex(0));
     AddressClass addr_class = AddressClass::eUnknown;
 
     if (bp_loc_sp) {
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 044cd9eed469f5b..aaf3000dcac7615 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1564,11 +1564,12 @@ void Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) {
   m_dynamic_checkers_up.reset(dynamic_checkers);
 }
 
-BreakpointSiteList &Process::GetBreakpointSiteList() {
+StopPointSiteList<BreakpointSite> &Process::GetBreakpointSiteList() {
   return m_breakpoint_site_list;
 }
 
-const BreakpointSiteList &Process::GetBreakpointSiteList() const {
+const StopPointSiteList<BreakpointSite> &
+Process::GetBreakpointSiteList() const {
   return m_breakpoint_site_list;
 }
 
@@ -1616,7 +1617,7 @@ Status Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) {
 }
 
 lldb::break_id_t
-Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
+Process::CreateBreakpointSite(const BreakpointLocationSP &constituent,
                               bool use_hardware) {
   addr_t load_addr = LLDB_INVALID_ADDRESS;
 
@@ -1643,10 +1644,10 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
 
   // Reset the IsIndirect flag here, in case the location changes from pointing
   // to a indirect symbol to a regular symbol.
-  owner->SetIsIndirect(false);
+  constituent->SetIsIndirect(false);
 
-  if (owner->ShouldResolveIndirectFunctions()) {
-    Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol();
+  if (constituent->ShouldResolveIndirectFunctions()) {
+    Symbol *symbol = constituent->GetAddress().CalculateSymbolContextSymbol();
     if (symbol && symbol->IsIndirect()) {
       Status error;
       Address symbol_address = symbol->GetAddress();
@@ -1656,37 +1657,37 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
             "warning: failed to resolve indirect function at 0x%" PRIx64
             " for breakpoint %i.%i: %s\n",
             symbol->GetLoadAddress(&GetTarget()),
-            owner->GetBreakpoint().GetID(), owner->GetID(),
+            constituent->GetBreakpoint().GetID(), constituent->GetID(),
             error.AsCString() ? error.AsCString() : "unknown error");
         return LLDB_INVALID_BREAK_ID;
       }
       Address resolved_address(load_addr);
       load_addr = resolved_address.GetOpcodeLoadAddress(&GetTarget());
-      owner->SetIsIndirect(true);
+      constituent->SetIsIndirect(true);
     } else
-      load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget());
+      load_addr = constituent->GetAddress().GetOpcodeLoadAddress(&GetTarget());
   } else
-    load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget());
+    load_addr = constituent->GetAddress().GetOpcodeLoadAddress(&GetTarget());
 
   if (load_addr != LLDB_INVALID_ADDRESS) {
     BreakpointSiteSP bp_site_sp;
 
-    // Look up this breakpoint site.  If it exists, then add this new owner,
-    // otherwise create a new breakpoint site and add it.
+    // Look up this breakpoint site.  If it exists, then add this new
+    // constituent, otherwise create a new breakpoint site and add it.
 
     bp_site_sp = m_breakpoint_site_list.FindByAddress(load_addr);
 
     if (bp_site_sp) {
-      bp_site_sp->AddOwner(owner);
-      owner->SetBreakpointSite(bp_site_sp);
+      bp_site_sp->AddConstituent(constituent);
+      constituent->SetBreakpointSite(bp_site_sp);
       return bp_site_sp->GetID();
     } else {
-      bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
-                                          load_addr, use_hardware));
+      bp_site_sp.reset(
+          new BreakpointSite(constituent, load_addr, use_hardware));
       if (bp_site_sp) {
         Status error = EnableBreakpointSite(bp_site_sp.get());
         if (error.Success()) {
-          owner->SetBreakpointSite(bp_site_sp);
+          constituent->SetBreakpointSite(bp_site_sp);
           return m_breakpoint_site_list.Add(bp_site_sp);
         } else {
           if (show_error || use_hardware) {
@@ -1694,7 +1695,8 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
             GetTarget().GetDebugger().GetErrorStream().Printf(
                 "warning: failed to set breakpoint site at 0x%" PRIx64
                 " for breakpoint %i.%i: %s\n",
-                load_addr, owner->GetBreakpoint().GetID(), owner->GetID(),
+                load_addr, constituent->GetBreakpoint().GetID(),
+                constituent->GetID(),
                 error.AsCString() ? error.AsCString() : "unknown error");
           }
         }
@@ -1705,11 +1707,12 @@ Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
   return LLDB_INVALID_BREAK_ID;
 }
 
-void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id,
-                                            lldb::user_id_t owner_loc_id,
-                                            BreakpointSiteSP &bp_site_sp) {
-  uint32_t num_owners = bp_site_sp->RemoveOwner(owner_id, owner_loc_id);
-  if (num_owners == 0) {
+void Process::RemoveConstituentFromBreakpointSite(
+    lldb::user_id_t constituent_id, lldb::user_id_t constituent_loc_id,
+    BreakpointSiteSP &bp_site_sp) {
+  uint32_t num_constituents =
+      bp_site_sp->RemoveConstituent(constituent_id, constituent_loc_id);
+  if (num_constituents == 0) {
     // Don't try to disable the site if we don't have a live process anymore.
     if (IsAlive())
       DisableBreakpointSite(bp_site_sp.get());
@@ -1720,7 +1723,7 @@ void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id,
 size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size,
                                                   uint8_t *buf) const {
   size_t bytes_removed = 0;
-  BreakpointSiteList bp_sites_in_range;
+  StopPointSiteList<BreakpointSite> bp_sites_in_range;
 
   if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size,
                                          bp_sites_in_range)) {
@@ -2141,7 +2144,7 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
   // (enabled software breakpoints) any software traps (breakpoints) that we
   // may have placed in our tasks memory.
 
-  BreakpointSiteList bp_sites_in_range;
+  StopPointSiteList<BreakpointSite> bp_sites_in_range;
   if (!m_breakpoint_site_list.FindInRange(addr, addr + size, bp_sites_in_range))
     return WriteMemoryPrivate(addr, buf, size, error);
 
diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp
index 88cc518d0ea0eb2..2273e52e2e04819 100644
--- a/lldb/source/Target/StackFrameList.cpp
+++ b/lldb/source/Target/StackFrameList.cpp
@@ -156,9 +156,10 @@ void StackFrameList::ResetCurrentInlinedDepth() {
         m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id));
     bool all_internal = true;
     if (bp_site_sp) {
-      uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+      uint32_t num_owners = bp_site_sp->GetNumberOfConstituents();
       for (uint32_t i = 0; i < num_owners; i++) {
-        Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+        Breakpoint &bp_ref =
+            bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
         if (!bp_ref.IsInternal()) {
           all_internal = false;
         }
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 0975e6b64d2d7f3..3b65d661c1abd04 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -110,9 +110,9 @@ class StopInfoBreakpoint : public StopInfo {
       BreakpointSiteSP bp_site_sp(
           thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
       if (bp_site_sp) {
-        uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
-        if (num_owners == 1) {
-          BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
+        uint32_t num_constituents = bp_site_sp->GetNumberOfConstituents();
+        if (num_constituents == 1) {
+          BreakpointLocationSP bp_loc_sp = bp_site_sp->GetConstituentAtIndex(0);
           if (bp_loc_sp) {
             Breakpoint & bkpt = bp_loc_sp->GetBreakpoint();
             m_break_id = bkpt.GetID();
@@ -121,8 +121,10 @@ class StopInfoBreakpoint : public StopInfo {
           }
         } else {
           m_was_all_internal = true;
-          for (uint32_t i = 0; i < num_owners; i++) {
-            if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) {
+          for (uint32_t i = 0; i < num_constituents; i++) {
+            if (!bp_site_sp->GetConstituentAtIndex(i)
+                     ->GetBreakpoint()
+                     .IsInternal()) {
               m_was_all_internal = false;
               break;
             }
@@ -190,9 +192,9 @@ class StopInfoBreakpoint : public StopInfo {
           // If we have just hit an internal breakpoint, and it has a kind
           // description, print that instead of the full breakpoint printing:
           if (bp_site_sp->IsInternal()) {
-            size_t num_owners = bp_site_sp->GetNumberOfOwners();
-            for (size_t idx = 0; idx < num_owners; idx++) {
-              const char *kind = bp_site_sp->GetOwnerAtIndex(idx)
+            size_t num_constituents = bp_site_sp->GetNumberOfConstituents();
+            for (size_t idx = 0; idx < num_constituents; idx++) {
+              const char *kind = bp_site_sp->GetConstituentAtIndex(idx)
                                      ->GetBreakpoint()
                                      .GetBreakpointKind();
               if (kind != nullptr) {
@@ -285,13 +287,14 @@ class StopInfoBreakpoint : public StopInfo {
       // Use this variable to tell us if that is true.
       bool actually_hit_any_locations = false;
       if (bp_site_sp) {
-        // Let's copy the owners list out of the site and store them in a local
-        // list.  That way if one of the breakpoint actions changes the site,
-        // then we won't be operating on a bad list.
+        // Let's copy the constituents list out of the site and store them in a
+        // local list.  That way if one of the breakpoint actions changes the
+        // site, then we won't be operating on a bad list.
         BreakpointLocationCollection site_locations;
-        size_t num_owners = bp_site_sp->CopyOwnersList(site_locations);
+        size_t num_constituents =
+            bp_site_sp->CopyConstituentsList(site_locations);
 
-        if (num_owners == 0) {
+        if (num_constituents == 0) {
           m_should_stop = true;
           actually_hit_any_locations = true;  // We're going to stop, don't 
                                               // change the stop info.
@@ -383,20 +386,21 @@ class StopInfoBreakpoint : public StopInfo {
           StoppointCallbackContext context(event_ptr, exe_ctx, false);
 
           // For safety's sake let's also grab an extra reference to the
-          // breakpoint owners of the locations we're going to examine, since
-          // the locations are going to have to get back to their breakpoints,
-          // and the locations don't keep their owners alive.  I'm just
-          // sticking the BreakpointSP's in a vector since I'm only using it to
-          // locally increment their retain counts.
+          // breakpoint constituents of the locations we're going to examine,
+          // since the locations are going to have to get back to their
+          // breakpoints, and the locations don't keep their constituents alive.
+          // I'm just sticking the BreakpointSP's in a vector since I'm only
+          // using it to locally increment their retain counts.
 
-          std::vector<lldb::BreakpointSP> location_owners;
+          std::vector<lldb::BreakpointSP> location_constituents;
 
-          for (size_t j = 0; j < num_owners; j++) {
+          for (size_t j = 0; j < num_constituents; j++) {
             BreakpointLocationSP loc(site_locations.GetByIndex(j));
-            location_owners.push_back(loc->GetBreakpoint().shared_from_this());
+            location_constituents.push_back(
+                loc->GetBreakpoint().shared_from_this());
           }
 
-          for (size_t j = 0; j < num_owners; j++) {
+          for (size_t j = 0; j < num_constituents; j++) {
             lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
             StreamString loc_desc;
             if (log) {
@@ -752,7 +756,7 @@ class StopInfoWatchpoint : public StopInfo {
       if (!m_did_disable_wp)
         return;
       m_did_disable_wp = true;
-      GetThread().GetProcess()->EnableWatchpoint(m_watch_sp.get(), true);
+      GetThread().GetProcess()->EnableWatchpoint(m_watch_sp, true);
     }
 
   private:
diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp
index 31027cd9e0115db..50dcb66b9719fe8 100644
--- a/lldb/source/Target/ThreadPlanCallFunction.cpp
+++ b/lldb/source/Target/ThreadPlanCallFunction.cpp
@@ -291,10 +291,10 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) {
     BreakpointSiteSP bp_site_sp;
     bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id);
     if (bp_site_sp) {
-      uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+      uint32_t num_owners = bp_site_sp->GetNumberOfConstituents();
       bool is_internal = true;
       for (uint32_t i = 0; i < num_owners; i++) {
-        Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+        Breakpoint &bp = bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
         LLDB_LOGF(log,
                   "ThreadPlanCallFunction::PlanExplainsStop: hit "
                   "breakpoint %d while calling function",
diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp
index 7bf1d2a8b579c1b..0a1e2ae605efcf8 100644
--- a/lldb/source/Target/ThreadPlanStepOut.cpp
+++ b/lldb/source/Target/ThreadPlanStepOut.cpp
@@ -322,7 +322,7 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) {
         // important to report the user breakpoint than the step out
         // completion.
 
-        if (site_sp->GetNumberOfOwners() == 1)
+        if (site_sp->GetNumberOfConstituents() == 1)
           return true;
       }
       return false;
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index 0d5144d7a46b5f3..bb92adcae78b715 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -400,14 +400,14 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
     return false;
   else {
     // If we've hit the next branch breakpoint, then clear it.
-    size_t num_owners = bp_site_sp->GetNumberOfOwners();
+    size_t num_constituents = bp_site_sp->GetNumberOfConstituents();
     bool explains_stop = true;
-    // If all the owners are internal, then we are probably just stepping over
-    // this range from multiple threads, or multiple frames, so we want to
+    // If all the constituents are internal, then we are probably just stepping
+    // over this range from multiple threads, or multiple frames, so we want to
     // continue.  If one is not internal, then we should not explain the stop,
     // and let the user breakpoint handle the stop.
-    for (size_t i = 0; i < num_owners; i++) {
-      if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) {
+    for (size_t i = 0; i < num_constituents; i++) {
+      if (!bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint().IsInternal()) {
         explains_stop = false;
         break;
       }
@@ -415,8 +415,8 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop(
     LLDB_LOGF(log,
               "ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit "
               "next range breakpoint which has %" PRIu64
-              " owners - explains stop: %u.",
-              (uint64_t)num_owners, explains_stop);
+              " constituents - explains stop: %u.",
+              (uint64_t)num_constituents, explains_stop);
     ClearNextBranchBreakpoint();
     return explains_stop;
   }
diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp
index f63e97d3c402965..ee0f803510e684c 100644
--- a/lldb/source/Target/ThreadPlanStepUntil.cpp
+++ b/lldb/source/Target/ThreadPlanStepUntil.cpp
@@ -182,7 +182,7 @@ void ThreadPlanStepUntil::AnalyzeStop() {
         } else
           m_should_stop = false;
 
-        if (this_site->GetNumberOfOwners() == 1)
+        if (this_site->GetNumberOfConstituents() == 1)
           m_explains_stop = true;
         else
           m_explains_stop = false;
@@ -228,7 +228,7 @@ void ThreadPlanStepUntil::AnalyzeStop() {
             // only breakpoint here, then we do explain the stop, and we'll
             // continue. If not then we should let higher plans handle this
             // stop.
-            if (this_site->GetNumberOfOwners() == 1)
+            if (this_site->GetNumberOfConstituents() == 1)
               m_explains_stop = true;
             else {
               m_should_stop = true;

>From 4764ffe961f526f1ed4aae3d263582943aaeddac Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 15 Nov 2023 14:28:27 -0800
Subject: [PATCH 08/11] Address Jonas' second round of comments.

---
 lldb/source/Breakpoint/StopPointSiteList.cpp        | 10 ++--------
 .../Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 13 +++++++------
 2 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/lldb/source/Breakpoint/StopPointSiteList.cpp b/lldb/source/Breakpoint/StopPointSiteList.cpp
index ad5805741e2d8e5..da6a74f1c65b6df 100644
--- a/lldb/source/Breakpoint/StopPointSiteList.cpp
+++ b/lldb/source/Breakpoint/StopPointSiteList.cpp
@@ -27,9 +27,6 @@ StopPointSiteList<StopPointSite>::Add(const StopPointSiteSP &site) {
   typename collection::iterator iter = m_site_list.find(site_load_addr);
 
   if (iter == m_site_list.end()) {
-#if 0
-    m_site_list.insert(iter, collection::value_type(site_load_addr, site));
-#endif
     m_site_list[site_load_addr] = site;
     return site->GetID();
   } else {
@@ -40,8 +37,7 @@ StopPointSiteList<StopPointSite>::Add(const StopPointSiteSP &site) {
 template <typename StopPointSite>
 bool StopPointSiteList<StopPointSite>::ShouldStop(
     StoppointCallbackContext *context, typename StopPointSite::SiteID site_id) {
-  StopPointSiteSP site_sp(FindByID(site_id));
-  if (site_sp) {
+  if (StopPointSiteSP site_sp = FindByID(site_id)) {
     // Let the site decide if it should stop here (could not have
     // reached it's target hit count yet, or it could have a callback that
     // decided it shouldn't stop (shared library loads/unloads).
@@ -164,7 +160,6 @@ bool StopPointSiteList<BreakpointSite>::StopPointSiteContainsBreakpoint(
 template <typename StopPointSite>
 void StopPointSiteList<StopPointSite>::Dump(Stream *s) const {
   s->Printf("%p: ", static_cast<const void *>(this));
-  // s->Indent();
   s->Printf("StopPointSiteList with %u ConstituentSites:\n",
             (uint32_t)m_site_list.size());
   s->IndentMore();
@@ -209,9 +204,8 @@ bool StopPointSiteList<StopPointSite>::FindInRange(
 
   upper = m_site_list.upper_bound(upper_bound);
 
-  for (pos = lower; pos != upper; pos++) {
+  for (pos = lower; pos != upper; pos++)
     site_list.Add((*pos).second);
-  }
   return true;
 }
 
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 4b2676eceab6058..16707ef57818713 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1829,13 +1829,14 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
           if (!wp_resource_sp) {
             Log *log(GetLog(GDBRLog::Watchpoints));
             LLDB_LOGF(log, "failed to find watchpoint");
-            abort(); // LWP_TODO FIXME don't continue executing this block if
-                     // we don't get a resource.
+            watch_id = LLDB_INVALID_SITE_ID;
+          } else {
+            // LWP_TODO: This is hardcoding a single Watchpoint in a
+            // Resource, need to add
+            // StopInfo::CreateStopReasonWithWatchpointResource which
+            // represents all watchpoints that were tripped at this stop.
+            watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID();
           }
-          // LWP_TODO: This is hardcoding a single Watchpoint in a
-          // Resource, need to add
-          // StopInfo::CreateStopReasonWithWatchpointResource
-          watch_id = wp_resource_sp->GetConstituentAtIndex(0)->GetID();
           thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
               *thread_sp, watch_id, silently_continue));
           handled = true;

>From 243af4794b29e039f95eb69e923295d5da939766 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 15 Nov 2023 18:04:11 -0800
Subject: [PATCH 09/11] Remove orphaned wp hardware index tracking

---
 .../Process/gdb-remote/ProcessGDBRemote.cpp    | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 16707ef57818713..e075aca278cc716 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1800,20 +1800,6 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
           watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
           bool silently_continue = false;
           WatchpointResourceSP wp_resource_sp;
-          if (wp_hw_index != LLDB_INVALID_WATCHPOINT_RESOURCE_ID) {
-            wp_resource_sp = m_watchpoint_resource_list.FindByID(wp_hw_index);
-            if (wp_resource_sp) {
-              // If we were given an access address, and the Resource we
-              // found by watchpoint register index does not contain that
-              // address, then the wp_resource_id's have not tracked the
-              // hardware watchpoint registers correctly, discard this
-              // Resource found by ID and look it up by access address.
-              if (wp_hit_addr != LLDB_INVALID_ADDRESS &&
-                  !wp_resource_sp->Contains(wp_hit_addr)) {
-                wp_resource_sp.reset();
-              }
-            }
-          }
           if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
             wp_resource_sp =
                 m_watchpoint_resource_list.FindByAddress(wp_hit_addr);
@@ -2261,10 +2247,6 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
 
         WatchpointResourceSP wp_resource_sp =
             m_watchpoint_resource_list.FindByAddress(wp_addr);
-        uint32_t wp_index = LLDB_INVALID_INDEX32;
-
-        if (wp_resource_sp)
-          wp_index = wp_resource_sp->GetID();
 
         // Rewrite gdb standard watch/rwatch/awatch to
         // "reason:watchpoint" + "description:ADDR",

>From 3e5f3715a3862c5130ea9f35fa15a90b126f0454 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Wed, 15 Nov 2023 18:31:45 -0800
Subject: [PATCH 10/11] Move the StopPointSiteList template methods into hdr

I have one method which is only defined for BreakpointSites
which I specialize in the .cpp file still, everything else is
in the .h header file.

I still have one test failure in TestWatchpointCount.py that
should be easy to fix, then I might be done with this PR.
---
 .../lldb/Breakpoint/StopPointSiteList.h       | 163 +++++++++++++--
 lldb/source/Breakpoint/StopPointSiteList.cpp  | 196 +-----------------
 2 files changed, 151 insertions(+), 208 deletions(-)

diff --git a/lldb/include/lldb/Breakpoint/StopPointSiteList.h b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
index 04e6dc5af5eb051..9ff151fd01b69ac 100644
--- a/lldb/include/lldb/Breakpoint/StopPointSiteList.h
+++ b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
@@ -13,6 +13,7 @@
 #include <map>
 #include <mutex>
 
+#include <lldb/Breakpoint/BreakpointSite.h>
 #include <lldb/Utility/Iterable.h>
 #include <lldb/Utility/Stream.h>
 
@@ -34,12 +35,35 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \return
   ///    The ID of the site in the list.
-  typename StopPointSite::SiteID Add(const StopPointSiteSP &site_sp);
+  typename StopPointSite::SiteID Add(const StopPointSiteSP &site_sp) {
+    lldb::addr_t site_load_addr = site_sp->GetLoadAddress();
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::iterator iter = m_site_list.find(site_load_addr);
+
+    // Add site to the list.  However, if the element already exists in
+    // the list, then we don't add it, and return InvalidSiteID.
+    if (iter == m_site_list.end()) {
+      m_site_list[site_load_addr] = site_sp;
+      return site_sp->GetID();
+    } else {
+      return UINT32_MAX;
+    }
+  }
 
   /// Standard Dump routine, doesn't do anything at present.
   /// \param[in] s
   ///     Stream into which to dump the description.
-  void Dump(Stream *s) const;
+  void Dump(Stream *s) const {
+    s->Printf("%p: ", static_cast<const void *>(this));
+    s->Printf("StopPointSiteList with %u ConstituentSites:\n",
+              (uint32_t)m_site_list.size());
+    s->IndentMore();
+    typename collection::const_iterator pos;
+    typename collection::const_iterator end = m_site_list.end();
+    for (pos = m_site_list.begin(); pos != end; ++pos)
+      pos->second->Dump(s);
+    s->IndentLess();
+  }
 
   /// Returns a shared pointer to the site at address \a addr.
   ///
@@ -49,7 +73,14 @@ template <typename StopPointSite> class StopPointSiteList {
   /// \result
   ///     A shared pointer to the site. Nullptr if no site contains
   ///     the address.
-  StopPointSiteSP FindByAddress(lldb::addr_t addr);
+  StopPointSiteSP FindByAddress(lldb::addr_t addr) {
+    StopPointSiteSP found_sp;
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::iterator iter = m_site_list.find(addr);
+    if (iter != m_site_list.end())
+      found_sp = iter->second;
+    return found_sp;
+  }
 
   /// Returns a shared pointer to the site with id \a site_id.
   ///
@@ -58,7 +89,15 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \result
   ///   A shared pointer to the site. Nullptr if no matching site.
-  StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id);
+  StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    StopPointSiteSP stop_sp;
+    typename collection::iterator pos = GetIDIterator(site_id);
+    if (pos != m_site_list.end())
+      stop_sp = pos->second;
+
+    return stop_sp;
+  }
 
   /// Returns a shared pointer to the site with id \a site_id -
   /// const version.
@@ -68,7 +107,15 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \result
   ///   A shared pointer to the site. Nullptr if no matching site.
-  const StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) const;
+  const StopPointSiteSP FindByID(typename StopPointSite::SiteID site_id) const {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    StopPointSiteSP stop_sp;
+    typename collection::const_iterator pos = GetIDConstIterator(site_id);
+    if (pos != m_site_list.end())
+      stop_sp = pos->second;
+
+    return stop_sp;
+  }
 
   /// Returns the site id to the site at address \a addr.
   ///
@@ -77,7 +124,11 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \result
   ///   The ID of the site, or LLDB_INVALID_SITE_ID.
-  typename StopPointSite::SiteID FindIDByAddress(lldb::addr_t addr);
+  typename StopPointSite::SiteID FindIDByAddress(lldb::addr_t addr) {
+    if (StopPointSiteSP site = FindByAddress(addr))
+      return site->GetID();
+    return UINT32_MAX;
+  }
 
   /// Returns whether the BreakpointSite \a site_id has a BreakpointLocation
   /// that is part of Breakpoint \a bp_id.
@@ -97,7 +148,11 @@ template <typename StopPointSite> class StopPointSiteList {
   bool StopPointSiteContainsBreakpoint(typename StopPointSite::SiteID,
                                        lldb::break_id_t bp_id);
 
-  void ForEach(std::function<void(StopPointSite *)> const &callback);
+  void ForEach(std::function<void(StopPointSite *)> const &callback) {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    for (auto pair : m_site_list)
+      callback(pair.second.get());
+  }
 
   /// Removes the site given by \a site_id from this list.
   ///
@@ -106,7 +161,15 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \result
   ///   \b true if the site \a site_id was in the list.
-  bool Remove(typename StopPointSite::SiteID site_id);
+  bool Remove(typename StopPointSite::SiteID site_id) {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::iterator pos = GetIDIterator(site_id); // Predicate
+    if (pos != m_site_list.end()) {
+      m_site_list.erase(pos);
+      return true;
+    }
+    return false;
+  }
 
   /// Removes the site at address \a addr from this list.
   ///
@@ -115,10 +178,44 @@ template <typename StopPointSite> class StopPointSiteList {
   ///
   /// \result
   ///   \b true if \a addr had a site to remove from the list.
-  bool RemoveByAddress(lldb::addr_t addr);
+  bool RemoveByAddress(lldb::addr_t addr) {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::iterator pos = m_site_list.find(addr);
+    if (pos != m_site_list.end()) {
+      m_site_list.erase(pos);
+      return true;
+    }
+    return false;
+  }
 
   bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound,
-                   StopPointSiteList &bp_site_list) const;
+                   StopPointSiteList &bp_site_list) const {
+    if (lower_bound > upper_bound)
+      return false;
+
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::const_iterator lower, upper, pos;
+    lower = m_site_list.lower_bound(lower_bound);
+    if (lower == m_site_list.end() || (*lower).first >= upper_bound)
+      return false;
+
+    // This is one tricky bit.  The site might overlap the bottom end of
+    // the range.  So we grab the site prior to the lower bound, and check
+    // that that + its byte size isn't in our range.
+    if (lower != m_site_list.begin()) {
+      typename collection::const_iterator prev_pos = lower;
+      prev_pos--;
+      const StopPointSiteSP &prev_site = (*prev_pos).second;
+      if (prev_site->GetLoadAddress() + prev_site->GetByteSize() > lower_bound)
+        bp_site_list.Add(prev_site);
+    }
+
+    upper = m_site_list.upper_bound(upper_bound);
+
+    for (pos = lower; pos != upper; pos++)
+      bp_site_list.Add((*pos).second);
+    return true;
+  }
 
   typedef void (*StopPointSiteSPMapFunc)(StopPointSite &site, void *baton);
 
@@ -134,7 +231,17 @@ template <typename StopPointSite> class StopPointSiteList {
   /// \return
   ///    \b true if we should stop, \b false otherwise.
   bool ShouldStop(StoppointCallbackContext *context,
-                  typename StopPointSite::SiteID site_id);
+                  typename StopPointSite::SiteID site_id) {
+    if (StopPointSiteSP site_sp = FindByID(site_id)) {
+      // Let the site decide if it should stop here (could not have
+      // reached it's target hit count yet, or it could have a callback that
+      // decided it shouldn't stop (shared library loads/unloads).
+      return site_sp->ShouldStop(context);
+    }
+    // We should stop here since this site isn't valid anymore or it
+    // doesn't exist.
+    return true;
+  }
 
   /// Returns the number of elements in the list.
   ///
@@ -150,7 +257,17 @@ template <typename StopPointSite> class StopPointSiteList {
     return m_site_list.empty();
   }
 
-  std::vector<StopPointSiteSP> Sites();
+  std::vector<StopPointSiteSP> Sites() {
+    std::vector<StopPointSiteSP> sites;
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    typename collection::iterator iter = m_site_list.begin();
+    while (iter != m_site_list.end()) {
+      sites.push_back(iter->second);
+      ++iter;
+    }
+
+    return sites;
+  }
 
   void Clear() {
     std::lock_guard<std::recursive_mutex> guard(m_mutex);
@@ -161,10 +278,28 @@ template <typename StopPointSite> class StopPointSiteList {
   typedef std::map<lldb::addr_t, StopPointSiteSP> collection;
 
   typename collection::iterator
-  GetIDIterator(typename StopPointSite::SiteID site_id);
+  GetIDIterator(typename StopPointSite::SiteID site_id) {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    auto id_matches =
+        [site_id](const std::pair<lldb::addr_t, StopPointSiteSP> s) {
+          return site_id == s.second->GetID();
+        };
+    return std::find_if(m_site_list.begin(),
+                        m_site_list.end(), // Search full range
+                        id_matches);
+  }
 
   typename collection::const_iterator
-  GetIDConstIterator(typename StopPointSite::SiteID site_id) const;
+  GetIDConstIterator(typename StopPointSite::SiteID site_id) const {
+    std::lock_guard<std::recursive_mutex> guard(m_mutex);
+    auto id_matches =
+        [site_id](const std::pair<lldb::addr_t, StopPointSiteSP> s) {
+          return site_id == s.second->GetID();
+        };
+    return std::find_if(m_site_list.begin(),
+                        m_site_list.end(), // Search full range
+                        id_matches);
+  }
 
   mutable std::recursive_mutex m_mutex;
   collection m_site_list; // The site list.
diff --git a/lldb/source/Breakpoint/StopPointSiteList.cpp b/lldb/source/Breakpoint/StopPointSiteList.cpp
index da6a74f1c65b6df..275d0fbf265a653 100644
--- a/lldb/source/Breakpoint/StopPointSiteList.cpp
+++ b/lldb/source/Breakpoint/StopPointSiteList.cpp
@@ -16,139 +16,14 @@
 using namespace lldb;
 using namespace lldb_private;
 
-// Add site to the list.  However, if the element already exists in
-// the list, then we don't add it, and return InvalidSiteID.
-
-template <typename StopPointSite>
-typename StopPointSite::SiteID
-StopPointSiteList<StopPointSite>::Add(const StopPointSiteSP &site) {
-  lldb::addr_t site_load_addr = site->GetLoadAddress();
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::iterator iter = m_site_list.find(site_load_addr);
-
-  if (iter == m_site_list.end()) {
-    m_site_list[site_load_addr] = site;
-    return site->GetID();
-  } else {
-    return UINT32_MAX;
-  }
-}
-
-template <typename StopPointSite>
-bool StopPointSiteList<StopPointSite>::ShouldStop(
-    StoppointCallbackContext *context, typename StopPointSite::SiteID site_id) {
-  if (StopPointSiteSP site_sp = FindByID(site_id)) {
-    // Let the site decide if it should stop here (could not have
-    // reached it's target hit count yet, or it could have a callback that
-    // decided it shouldn't stop (shared library loads/unloads).
-    return site_sp->ShouldStop(context);
-  }
-  // We should stop here since this site isn't valid anymore or it
-  // doesn't exist.
-  return true;
-}
-
-template <typename StopPointSite>
-typename StopPointSite::SiteID
-StopPointSiteList<StopPointSite>::FindIDByAddress(lldb::addr_t addr) {
-  if (StopPointSiteSP site = FindByAddress(addr))
-    return site->GetID();
-  return UINT32_MAX;
-}
-
-template <typename StopPointSite>
-bool StopPointSiteList<StopPointSite>::Remove(
-    typename StopPointSite::SiteID site_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::iterator pos = GetIDIterator(site_id); // Predicate
-  if (pos != m_site_list.end()) {
-    m_site_list.erase(pos);
-    return true;
-  }
-  return false;
-}
-
-template <typename StopPointSite>
-bool StopPointSiteList<StopPointSite>::RemoveByAddress(lldb::addr_t address) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::iterator pos = m_site_list.find(address);
-  if (pos != m_site_list.end()) {
-    m_site_list.erase(pos);
-    return true;
-  }
-  return false;
-}
-
-template <typename StopPointSite>
-typename StopPointSiteList<StopPointSite>::collection::iterator
-StopPointSiteList<StopPointSite>::GetIDIterator(
-    typename StopPointSite::SiteID site_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  auto id_matches = [site_id](const std::pair<addr_t, StopPointSiteSP> s) {
-    return site_id == s.second->GetID();
-  };
-  return std::find_if(m_site_list.begin(),
-                      m_site_list.end(), // Search full range
-                      id_matches);
-}
-
-template <typename StopPointSite>
-typename StopPointSiteList<StopPointSite>::collection::const_iterator
-StopPointSiteList<StopPointSite>::GetIDConstIterator(
-    typename StopPointSite::SiteID site_id) const {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  auto id_matches = [site_id](const std::pair<addr_t, StopPointSiteSP> s) {
-    return site_id == s.second->GetID();
-  };
-  return std::find_if(m_site_list.begin(),
-                      m_site_list.end(), // Search full range
-                      id_matches);
-}
-
-template <typename StopPointSite>
-typename StopPointSiteList<StopPointSite>::StopPointSiteSP
-StopPointSiteList<StopPointSite>::FindByID(
-    typename StopPointSite::SiteID site_id) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  StopPointSiteSP stop_sp;
-  typename collection::iterator pos = GetIDIterator(site_id);
-  if (pos != m_site_list.end())
-    stop_sp = pos->second;
-
-  return stop_sp;
-}
-
-template <typename StopPointSite>
-const typename StopPointSiteList<StopPointSite>::StopPointSiteSP
-StopPointSiteList<StopPointSite>::FindByID(
-    typename StopPointSite::SiteID site_id) const {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  StopPointSiteSP stop_sp;
-  typename collection::const_iterator pos = GetIDConstIterator(site_id);
-  if (pos != m_site_list.end())
-    stop_sp = pos->second;
-
-  return stop_sp;
-}
-
-template <typename StopPointSite>
-typename StopPointSiteList<StopPointSite>::StopPointSiteSP
-StopPointSiteList<StopPointSite>::FindByAddress(lldb::addr_t addr) {
-  StopPointSiteSP found_sp;
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::iterator iter = m_site_list.find(addr);
-  if (iter != m_site_list.end())
-    found_sp = iter->second;
-  return found_sp;
-}
-
 // This method is only defined when we're specializing for
 // BreakpointSite / BreakpointLocation / Breakpoint.
 // Watchpoints don't have a similar structure, they are
 // WatchpointResource / Watchpoint
+
 template <>
 bool StopPointSiteList<BreakpointSite>::StopPointSiteContainsBreakpoint(
-    typename BreakpointSite::SiteID site_id, break_id_t bp_id) {
+    typename BreakpointSite::SiteID site_id, lldb::break_id_t bp_id) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   typename collection::const_iterator pos = GetIDConstIterator(site_id);
   if (pos != m_site_list.end())
@@ -157,73 +32,6 @@ bool StopPointSiteList<BreakpointSite>::StopPointSiteContainsBreakpoint(
   return false;
 }
 
-template <typename StopPointSite>
-void StopPointSiteList<StopPointSite>::Dump(Stream *s) const {
-  s->Printf("%p: ", static_cast<const void *>(this));
-  s->Printf("StopPointSiteList with %u ConstituentSites:\n",
-            (uint32_t)m_site_list.size());
-  s->IndentMore();
-  typename collection::const_iterator pos;
-  typename collection::const_iterator end = m_site_list.end();
-  for (pos = m_site_list.begin(); pos != end; ++pos)
-    pos->second->Dump(s);
-  s->IndentLess();
-}
-
-template <typename StopPointSite>
-void StopPointSiteList<StopPointSite>::ForEach(
-    std::function<void(StopPointSite *)> const &callback) {
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  for (auto pair : m_site_list)
-    callback(pair.second.get());
-}
-
-template <typename StopPointSite>
-bool StopPointSiteList<StopPointSite>::FindInRange(
-    lldb::addr_t lower_bound, lldb::addr_t upper_bound,
-    StopPointSiteList &site_list) const {
-  if (lower_bound > upper_bound)
-    return false;
-
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::const_iterator lower, upper, pos;
-  lower = m_site_list.lower_bound(lower_bound);
-  if (lower == m_site_list.end() || (*lower).first >= upper_bound)
-    return false;
-
-  // This is one tricky bit.  The site might overlap the bottom end of
-  // the range.  So we grab the site prior to the lower bound, and check
-  // that that + its byte size isn't in our range.
-  if (lower != m_site_list.begin()) {
-    typename collection::const_iterator prev_pos = lower;
-    prev_pos--;
-    const StopPointSiteSP &prev_site = (*prev_pos).second;
-    if (prev_site->GetLoadAddress() + prev_site->GetByteSize() > lower_bound)
-      site_list.Add(prev_site);
-  }
-
-  upper = m_site_list.upper_bound(upper_bound);
-
-  for (pos = lower; pos != upper; pos++)
-    site_list.Add((*pos).second);
-  return true;
-}
-
-template <typename StopPointSite>
-std::vector<typename StopPointSiteList<StopPointSite>::StopPointSiteSP>
-StopPointSiteList<StopPointSite>::Sites() {
-  std::vector<StopPointSiteSP> sites;
-  std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  typename collection::iterator iter = m_site_list.begin();
-  while (iter != m_site_list.end()) {
-    sites.push_back(iter->second);
-    ++iter;
-  }
-
-  return sites;
-}
-
 namespace lldb_private {
 template class StopPointSiteList<BreakpointSite>;
-template class StopPointSiteList<WatchpointResource>;
 } // namespace lldb_private

>From 0c5a738985833571dba8afcf2ac6cf8b3189fac0 Mon Sep 17 00:00:00 2001
From: Jason Molenda <jmolenda at apple.com>
Date: Thu, 16 Nov 2023 18:12:28 -0800
Subject: [PATCH 11/11] Fix WatchpointResource ID setting

I still had my original attempts to intuit the most likely hardware
index number when adding a WatchpointResource to the process resource
list.  I've dropped that whole scheme in a separate commit; this
commit correctly goes back to allocating the IDs sequentially for
the Resources.
---
 .../lldb/Breakpoint/WatchpointResource.h      |  2 ++
 lldb/source/Breakpoint/WatchpointResource.cpp |  7 +++-
 .../Breakpoint/WatchpointResourceList.cpp     | 32 -------------------
 3 files changed, 8 insertions(+), 33 deletions(-)

diff --git a/lldb/include/lldb/Breakpoint/WatchpointResource.h b/lldb/include/lldb/Breakpoint/WatchpointResource.h
index a4c648b131603de..e83ba0bbe8c6591 100644
--- a/lldb/include/lldb/Breakpoint/WatchpointResource.h
+++ b/lldb/include/lldb/Breakpoint/WatchpointResource.h
@@ -142,6 +142,8 @@ class WatchpointResource
   void BumpHitCounts();
 
 private:
+  static lldb::wp_resource_id_t GetNextID();
+
   lldb::wp_resource_id_t m_id;
 
   // Start address & size aligned & expanded to be a valid watchpoint
diff --git a/lldb/source/Breakpoint/WatchpointResource.cpp b/lldb/source/Breakpoint/WatchpointResource.cpp
index dc46d6c692a9efa..4b8fbe42c865e25 100644
--- a/lldb/source/Breakpoint/WatchpointResource.cpp
+++ b/lldb/source/Breakpoint/WatchpointResource.cpp
@@ -15,7 +15,7 @@ using namespace lldb_private;
 
 WatchpointResource::WatchpointResource(lldb::addr_t addr, size_t size,
                                        bool read, bool write)
-    : m_id(LLDB_INVALID_WATCHPOINT_RESOURCE_ID), m_addr(addr), m_size(size),
+    : m_id(GetNextID()), m_addr(addr), m_size(size),
       m_watch_read(read), m_watch_write(write) {}
 
 WatchpointResource::~WatchpointResource() {
@@ -115,3 +115,8 @@ bool WatchpointResource::ShouldStop(StoppointCallbackContext *context) {
 void WatchpointResource::Dump(Stream *s) const {
   return; // LWP_TODO
 }
+
+wp_resource_id_t WatchpointResource::GetNextID() {
+  static wp_resource_id_t g_next_id = 0;
+  return ++g_next_id;
+}
diff --git a/lldb/source/Breakpoint/WatchpointResourceList.cpp b/lldb/source/Breakpoint/WatchpointResourceList.cpp
index 49fca373b22332f..d1d364832098f4e 100644
--- a/lldb/source/Breakpoint/WatchpointResourceList.cpp
+++ b/lldb/source/Breakpoint/WatchpointResourceList.cpp
@@ -22,41 +22,9 @@ wp_resource_id_t
 WatchpointResourceList::Add(const WatchpointResourceSP &wp_res_sp) {
   Log *log = GetLog(LLDBLog::Watchpoints);
   std::lock_guard<std::mutex> guard(m_mutex);
-
   LLDB_LOGF(log, "WatchpointResourceList::Add(addr 0x%" PRIx64 " size %zu)",
             wp_res_sp->GetLoadAddress(), wp_res_sp->GetByteSize());
 
-  // The goal is to have the wp_resource_id_t match the actual hardware
-  // watchpoint register number.  If we assume that the remote stub is
-  // setting them in the register context in the same order that they
-  // are sent from lldb, and if a watchpoint is removed and then a new
-  // one is added and gets the same register number, then we can
-  // iterate over all used IDs looking for the first unused number.
-
-  // If the Process was able to find the actual hardware watchpoint register
-  // number that was used, it can set the ID for the WatchpointResource
-  // before we get here.
-
-  if (wp_res_sp->GetID() == LLDB_INVALID_WATCHPOINT_RESOURCE_ID) {
-    std::set<wp_resource_id_t> used_ids;
-    size_t size = m_resources.size();
-    for (size_t i = 0; i < size; ++i)
-      used_ids.insert(m_resources[i]->GetID());
-
-    wp_resource_id_t best = 0;
-    for (wp_resource_id_t id : used_ids)
-      if (id == best)
-        best++;
-      else
-        break;
-
-    LLDB_LOGF(log,
-              "WatchpointResourceList::Add assigning next "
-              "available WatchpointResource ID, %u",
-              best);
-    wp_res_sp->SetID(best);
-  }
-
   m_resources.push_back(wp_res_sp);
   return wp_res_sp->GetID();
 }



More information about the lldb-commits mailing list