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

Jason Molenda via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 23 15:44:30 PDT 2023


================
@@ -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);
----------------
jasonmolenda wrote:

When the Process method is given a watchpoint request from the user, which must be broken into one or more WatchpointResources (or an existing WatchpointResource reused), we can only get the hardware register number by looking at the IDs of currently allocated WatchpointResources in the WatchpointResourceList, which start at 0.  I assume that the remote stub will allocate its watchpoints in the hardware registers starting at index 0, and when removing/disabling them, will leave that slot unused until another request comes along, at which point the stub will start from 0 and look for the first unused hardware register.

In the specific case of gdb remote serial protocol (ProcessGDBRemote), it has none of this.  The Z2/Z3/Z4 packets don't tell you what hardware register was used.  

Today, lldb sets the hardware watchpoint index based on the watchpoint access stop.  SOME ways of passing the watchpoint trap back to lldb can communicate the hardware watchpoint index.  The standard gdb remote serial protocol does not with its `watch/rwatch/awatch:address` key-value in the stop packet.  lldb-server has a different way of reporting watchpoints, `reason:watchpoint` and `description:addr[ index]` where the address is sent in the description: and it may be followed by a space and then the index number of the hardware watchpoint that was triggered.  For macOS systems, the mach exception data is sent at the stop, and the hardware index is encoded as a piece of data in that.

In reality, in both cases I believe, the stubs are actually getting an *address* of the access, and trying to figure out which one of the hardware watchpoints they have set was the actual one triggered.  Aarch64 will some day have a way reporting the actual hardware index triggered instead of the exception address (it may not even give an exception address at all), but today it's all a fiction.

So basically, today, you don't really know the hardware watchpoint index until it's been hit.  And even then, it's being deduced by the remote stub, which lldb could do just as well.  The idea to expose this piece of data we don't actually have was not a good one, IMO, but it's in SB API so I'm not tackling that for now.

If I wanted to have the Process plugin look at the IDs currently used in its WatchpointResourceList, use the available numbers for the WatchpointResources it is creating, and if they are set successfully in the inferior, add them to the WatchpointResourceList, I would need to lock the WatchpointResourceList for the duration of those operations, and I wasn't sure that was a good idea.

(sorry for the long reply, I spent so much time trying to decide what to do with these fictitious hardware index numbers we present in lldb)

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


More information about the lldb-commits mailing list