[Lldb-commits] [lldb] Add a scripted way to re-present a stop location (PR #158128)

via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 11 14:27:42 PDT 2025


https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/158128

>From b5a0c082685a2d76d3eafcfa2b470bed8218aec6 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Thu, 14 Aug 2025 17:21:04 -0700
Subject: [PATCH 1/2] Add a way for scripted breakpoint resolvers to present
 "Facade" locations instead of the actual underlying breakpoint location for
 the breakpoint.  Also add a "was_hit" method to the scripted resolver that
 allows the breakpoint to say which of these "Facade" locations was hit, and
 "get_location_description" to provide a description for the facade locations.

rdar://152112327
---
 lldb/bindings/python/python-swigsafecast.swig |   4 +
 lldb/bindings/python/python-wrapper.swig      |  24 +++
 lldb/docs/use/python-reference.rst            |  61 ++++++
 lldb/include/lldb/API/SBBreakpoint.h          |   9 +-
 lldb/include/lldb/API/SBBreakpointLocation.h  |   1 +
 lldb/include/lldb/API/SBFrame.h               |   3 +-
 lldb/include/lldb/Breakpoint/Breakpoint.h     |  58 +++++-
 .../lldb/Breakpoint/BreakpointLocation.h      |  68 ++++++-
 .../Breakpoint/BreakpointLocationCollection.h |   2 +-
 .../lldb/Breakpoint/BreakpointLocationList.h  |   3 +-
 .../Breakpoint/BreakpointResolverScripted.h   |   6 +
 lldb/include/lldb/Breakpoint/BreakpointSite.h |   3 +-
 .../lldb/Breakpoint/StopPointSiteList.h       |  24 ---
 lldb/include/lldb/Breakpoint/StoppointSite.h  |   5 +-
 .../Interfaces/ScriptedBreakpointInterface.h  |  10 +
 .../lldb/Interpreter/ScriptInterpreter.h      |   6 +
 lldb/source/API/SBBreakpoint.cpp              |  10 +
 lldb/source/Breakpoint/Breakpoint.cpp         |  88 +++++++--
 lldb/source/Breakpoint/BreakpointLocation.cpp | 177 ++++++++++++++----
 .../BreakpointLocationCollection.cpp          |  16 +-
 .../Breakpoint/BreakpointLocationList.cpp     |  11 +-
 .../Breakpoint/BreakpointResolverScripted.cpp |  24 ++-
 lldb/source/Breakpoint/BreakpointSite.cpp     |   5 +-
 lldb/source/Interpreter/ScriptInterpreter.cpp |  13 ++
 .../ScriptedBreakpointPythonInterface.cpp     |  26 +++
 .../ScriptedBreakpointPythonInterface.h       |   6 +
 .../Interfaces/ScriptedPythonInterface.cpp    |  47 +++++
 .../Interfaces/ScriptedPythonInterface.h      |  27 +++
 .../Python/SWIGPythonBridge.h                 |   3 +
 lldb/source/Target/StopInfo.cpp               |  72 ++++---
 .../breakpoint/scripted_bkpt/resolver.py      |   1 -
 .../breakpoint/scripted_bkpt/was_hit/Makefile |   4 +
 .../scripted_bkpt/was_hit/TestWasHit.py       |  85 +++++++++
 .../scripted_bkpt/was_hit/bkpt_resolver.py    |  45 +++++
 .../breakpoint/scripted_bkpt/was_hit/main.c   |  17 ++
 .../Python/PythonTestSuite.cpp                |  10 +
 36 files changed, 840 insertions(+), 134 deletions(-)
 create mode 100644 lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile
 create mode 100644 lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
 create mode 100644 lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
 create mode 100644 lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c

diff --git a/lldb/bindings/python/python-swigsafecast.swig b/lldb/bindings/python/python-swigsafecast.swig
index 4721dfdc17e6a..3ea24f1a31414 100644
--- a/lldb/bindings/python/python-swigsafecast.swig
+++ b/lldb/bindings/python/python-swigsafecast.swig
@@ -142,5 +142,9 @@ PythonObject SWIGBridge::ToSWIGWrapper(
   return ToSWIGHelper(module_spec_sb.release(), SWIGTYPE_p_lldb__SBModuleSpec);
 }
 
+PythonObject SWIGBridge::ToSWIGWrapper(lldb::DescriptionLevel level) {
+  return PythonInteger((int64_t) level);
+}
+
 } // namespace python
 } // namespace lldb_private
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index 2c30d536a753d..64b7dc8381073 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -422,6 +422,30 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *
   return sb_ptr;
 }
 
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBFrame(PyObject * data) {
+  lldb::SBFrame *sb_ptr = nullptr;
+
+  int valid_cast =
+      SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBFrame, 0);
+
+  if (valid_cast == -1)
+    return NULL;
+
+  return sb_ptr;
+}
+
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(PyObject * data) {
+  lldb::SBBreakpointLocation *sb_ptr = nullptr;
+
+  int valid_cast =
+      SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBBreakpointLocation, 0);
+
+  if (valid_cast == -1)
+    return NULL;
+
+  return sb_ptr;
+}
+
 void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject * data) {
   lldb::SBAttachInfo *sb_ptr = nullptr;
 
diff --git a/lldb/docs/use/python-reference.rst b/lldb/docs/use/python-reference.rst
index 4292714c9c208..5f40526a7308e 100644
--- a/lldb/docs/use/python-reference.rst
+++ b/lldb/docs/use/python-reference.rst
@@ -420,6 +420,67 @@ of Modules and the list of CompileUnits that will make up the SearchFilter. If
 you pass in empty lists, the breakpoint will use the default "search
 everywhere,accept everything" filter.
 
+Providing Facade Locations:
+
+The breakpoint resolver interface also allows you to present a separate set
+of locations for the breakpoint than the ones that actually implement the
+breakpoint in the target.
+
+An example use case for this is if you are providing a debugging interface for a
+library that implements an interpreter for a language lldb can't debug.  But
+while debugging that library at the level of the implementation language (e.g. C/C++, etc)
+you would like to offer the ability to "stop when a line in a source language
+file is executed".
+
+You can do this if you know where new lines of code are dispatched in the
+interpreter.  You would set a breakpoint there, and then look at the state
+when that breakpoint is hit to see if it is dispatching the source file and
+line that were requested, and stop appropriately.
+
+Facade breakpoint locations are intended to make a more natural presentation
+of that sort of feature.  The idea is that you would make a custom breakpoint
+resolver that sets actual locations in the places of interest in the interpreter.
+
+Then your resolver would add "facade locations" that represent the places in the
+interpreted code that you want the breakpoint to stop at, using SBBreakpoint::AddFacadeLocation.
+When lldb describes the breakpoint, it will only show the Facade locations.
+Since facade breakpoint location's description is customizable, you can make these
+locations more descriptive.  And when the "real" location is hit, lldb will call the
+"was_hit" method of your resolver.  That will return the facade location you
+consider to have been hit this time around, or if you return None, the breakpoint
+will be considered not to have been hit.
+
+Note, this feature is also useful if you don't intend to present facade
+locations since it essentially provides a scripted breakpoint condition.  Every
+time one of the locations in your breakpoint is hit, you can run the code in
+your "was_hit" to determine whether to consider the breakpoint hit or not, and
+return the location you were passed in if you want it to be a hit, and None if not.
+
+The Facade location adds these optional affordances to the Resolver class:
+
++------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
+| Name                         | Arguments                              | Description                                                                                                      |
++------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
+| ``was_hit``                  | ``frame``:`lldb.SBFrame`               | This will get called when one of the "real" locations set by your resolver is hit                                |
+|                              | ``bp_loc``:`lldb.SBBreakpointLocation` |                                                                                                                  |
+|                              |                                        |                                                                                                                  |
+|                              |                                        | ``frame`` is the stack frame that hit this location.                                                             |
+|                              |                                        |                                                                                                                  |
+|                              |                                        |                                                                                                                  |
+|                              |                                        | ``bp_loc`` is the real location that was hit.                                                                    |
+|                              |                                        |                                                                                                                  |
+|                              |                                        | Return either the facade location that you want to consider hit on this stop, or None if you don't consider      |
+|                              |                                        | any of your facade locations to have been hit.                                                                   |
++------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
+| ``get_location_description`` | ``bp_loc``:`lldb.SBBreakpointLocation` | Use this to provide a helpful description of each facade location.                                               |
+|                              | ``desc_level``:`lldb.DescriptionLevel` |                                                                                                                  |
+|                              |                                        | ``bp_loc`` is the facade location to describe.                                                                   |
+|                              |                                        |                                                                                                                  |
+|                              |                                        |                                                                                                                  |
+|                              |                                        | ``desc_level`` is the level of description requested.  The Brief description is printed when the location is     |
+|                              |                                        | hit.  Full is printed for `break list` and Verbose for `break list -v`.                                          |
++------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
+
 Using the python API' to create custom stepping logic
 -----------------------------------------------------
 
diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h
index 18ed3e7226d3b..3bf87a1b7cc92 100644
--- a/lldb/include/lldb/API/SBBreakpoint.h
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -153,9 +153,16 @@ class LLDB_API SBBreakpoint {
   /// fails, e.g. when there aren't enough hardware resources available.
   lldb::SBError SetIsHardware(bool is_hardware);
 
-  // Can only be called from a ScriptedBreakpointResolver...
+  /// Adds a location to the breakpoint at the address passed in.
+  /// Can only be called from a ScriptedBreakpointResolver...
   SBError
   AddLocation(SBAddress &address);
+  /// Add a "Facade location" to the breakpoint.  This returns the Facade 
+  /// Location that was added, which you can then use in 
+  /// get_location_description and was_hit in your breakpoint resolver.
+  /// Can only be called from a ScriptedBreakpointResolver.
+  SBBreakpointLocation
+  AddFacadeLocation();
 
   SBStructuredData SerializeToStructuredData();
 
diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h
index fa823e2b518ac..deda4970cd0ed 100644
--- a/lldb/include/lldb/API/SBBreakpointLocation.h
+++ b/lldb/include/lldb/API/SBBreakpointLocation.h
@@ -24,6 +24,7 @@ class SWIGBridge;
 namespace lldb {
 
 class LLDB_API SBBreakpointLocation {
+  friend class lldb_private::ScriptInterpreter;
 public:
   SBBreakpointLocation();
 
diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h
index e4bbcd5ddcd9c..4abb44b4bb0e5 100644
--- a/lldb/include/lldb/API/SBFrame.h
+++ b/lldb/include/lldb/API/SBFrame.h
@@ -225,7 +225,8 @@ class LLDB_API SBFrame {
   friend class SBInstruction;
   friend class SBThread;
   friend class SBValue;
-
+  
+  friend class lldb_private::ScriptInterpreter;
   friend class lldb_private::python::SWIGBridge;
   friend class lldb_private::lua::SWIGBridge;
 
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
index 26a5e901a0d7e..2bef6a919d878 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -248,6 +248,23 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   ///    Returns a pointer to the new location.
   lldb::BreakpointLocationSP AddLocation(const Address &addr,
                                          bool *new_location = nullptr);
+  /// Add a `facade` location to the breakpoint's collection of facade locations.  
+  /// This is only meant to be called by the breakpoint's resolver.
+  /// Facade locations are placeholders that a scripted breakpoint can use to
+  /// represent the stop locations provided by the breakpoint.  The scripted
+  /// breakpoint should record the id of the facade location, and provide
+  /// the description of the location in the GetDescription method
+  /// To emulate hitting a facade location, the breakpoint's WasHit should
+  /// return the ID of the facade that was "hit".
+  ///
+  /// \param[out] new_location
+  ///    Set to \b true if a new location was created, to \b false if there
+  ///    already was a location at this Address.
+  /// \return
+  ///    Returns a pointer to the new location.
+  lldb::BreakpointLocationSP AddFacadeLocation();
+  
+  lldb::BreakpointLocationSP GetFacadeLocationByID(lldb::break_id_t);
 
   /// Find a breakpoint location by Address.
   ///
@@ -268,27 +285,36 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   ///    there is no breakpoint location at that address.
   lldb::break_id_t FindLocationIDByAddress(const Address &addr);
 
-  /// Find a breakpoint location for a given breakpoint location ID.
+  /// Find a breakpoint location for a given breakpoint location ID.  If there
+  /// are Facade Locations in the breakpoint, the facade locations will be
+  /// searched instead of the "real" ones.
   ///
   /// \param[in] bp_loc_id
   ///    The ID specifying the location.
+  ///
+  /// \param[in] use_facade
+  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  ///
   /// \return
   ///    Returns a shared pointer to the location with ID \a bp_loc_id.  The
   ///    pointer
   ///    in the shared pointer will be nullptr if there is no location with that
   ///    ID.
-  lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id);
+  lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id, bool use_facade = true);
 
   /// Get breakpoint locations by index.
   ///
   /// \param[in] index
   ///    The location index.
   ///
+  /// \param[in] use_facade
+  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  ///
   /// \return
   ///     Returns a shared pointer to the location with index \a
   ///     index. The shared pointer might contain nullptr if \a index is
   ///     greater than then number of actual locations.
-  lldb::BreakpointLocationSP GetLocationAtIndex(size_t index);
+  lldb::BreakpointLocationSP GetLocationAtIndex(size_t index, bool use_facade = true);
 
   /// Removes all invalid breakpoint locations.
   ///
@@ -409,9 +435,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   /// Return the number of breakpoint locations that have resolved to actual
   /// breakpoint sites.
   ///
+  /// \param[in] use_facade
+  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  ///
   /// \return
   ///     The number locations resolved breakpoint sites.
-  size_t GetNumResolvedLocations() const;
+  size_t GetNumResolvedLocations(bool use_facade = true) const;
 
   /// Return whether this breakpoint has any resolved locations.
   ///
@@ -421,9 +450,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
 
   /// Return the number of breakpoint locations.
   ///
+  /// \param[in] use_facade
+  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  ///
   /// \return
   ///     The number breakpoint locations.
-  size_t GetNumLocations() const;
+  size_t GetNumLocations(bool use_facade = true) const;
 
   /// Put a description of this breakpoint into the stream \a s.
   ///
@@ -529,6 +561,20 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
       m_name_list.erase(name_to_remove);
   }
 
+  enum TypeDisplay {
+    eDisplayFacade = 1,
+    eDisplayReal   = 1 << 1,
+    eDisplayHeader = 1 << 2
+  };
+
+  void GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
+                      uint8_t display_type, bool show_locations);
+                      
+  bool HasFacadeLocations() {
+    return m_facade_locations.GetSize() != 0;
+  }
+
+
 public:
   bool MatchesName(const char *name) {
     return m_name_list.find(name) != m_name_list.end();
@@ -657,6 +703,8 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   BreakpointOptions m_options; // Settable breakpoint options
   BreakpointLocationList
       m_locations; // The list of locations currently found for this breakpoint.
+  BreakpointLocationCollection m_facade_locations;
+
   std::string m_kind_description;
   bool m_resolve_indirect_symbols;
 
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
index ab2e5e170559d..c4fa9bec51aae 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -38,6 +38,12 @@ namespace lldb_private {
 
 class BreakpointLocation
     : public std::enable_shared_from_this<BreakpointLocation> {
+  friend class BreakpointSite;
+  friend class BreakpointLocationList;
+  friend class Breakpoint;
+  friend class Process;
+  friend class StopInfoBreakpoint;
+
 public:
   ~BreakpointLocation();
 
@@ -55,16 +61,39 @@ class BreakpointLocation
 
   Target &GetTarget();
 
+  /// This is a programmatic version of a breakpoint "condition".  When a
+  /// breakpoint is hit, WasHit will get called before the synchronous ShouldStop
+  /// callback is run, and if it returns an empty BreakpointLocationSP, lldb will
+  /// act as if that breakpoint wasn't hit.
+  ///
+  /// \param[in] context
+  ///   The context at the stop point
+  ///    
+  /// \return
+  ///    This will return the breakpoint location that was hit on this stop.
+  ///    If there was no facade location this will be the original location.
+  ///    If the shared pointer is empty, then we'll treat it as if the 
+  ///    breakpoint was not hit.
+  lldb::BreakpointLocationSP WasHit(StoppointCallbackContext *context);
+
   /// Determines whether we should stop due to a hit at this breakpoint
   /// location.
   ///
   /// Side Effects: This may evaluate the breakpoint condition, and run the
   /// callback.  So this command may do a considerable amount of work.
   ///
+  /// \param[in] context
+  ///   The context at the stop point
+  ///    
+  /// \param[out] facade_loc_sp
+  ///   If this stop should be attributed not to the location that was hit, but
+  ///   to a facade location, it will be returned in this facade_loc_sp.
+  ///    
   /// \return
   ///     \b true if this breakpoint location thinks we should stop,
   ///     \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context);
+  bool ShouldStop(StoppointCallbackContext *context, 
+          lldb::BreakpointLocationSP &facade_loc_sp);
 
   // The next section deals with various breakpoint options.
 
@@ -292,11 +321,6 @@ class BreakpointLocation
   }
 
 protected:
-  friend class BreakpointSite;
-  friend class BreakpointLocationList;
-  friend class Process;
-  friend class StopInfoBreakpoint;
-
   /// Set the breakpoint site for this location to \a bp_site_sp.
   ///
   /// \param[in] bp_site_sp
@@ -346,9 +370,11 @@ class BreakpointLocation
   // Constructors and Destructors
   //
   // Only the Breakpoint can make breakpoint locations, and it owns them.
-
   /// Constructor.
   ///
+  /// \param[in] loc_id
+  ///     The location id of the new location. 
+  ///
   /// \param[in] owner
   ///     A back pointer to the breakpoint that owns this location.
   ///
@@ -359,10 +385,25 @@ class BreakpointLocation
   ///     The thread for which this breakpoint location is valid, or
   ///     LLDB_INVALID_THREAD_ID if it is valid for all threads.
   ///
-  BreakpointLocation(lldb::break_id_t bid, Breakpoint &owner,
+  BreakpointLocation(lldb::break_id_t loc_id, Breakpoint &owner,
                      const Address &addr, lldb::tid_t tid,
                      bool check_for_resolver = true);
 
+  /// This is the constructor for locations with no address.  Currently this is
+  /// just used for Facade locations. 
+  ///
+  /// \param[in] loc_id
+  ///     The location id of the new location. 
+  ///
+  /// \param[in] owner
+  ///     A back pointer to the breakpoint that owns this location.
+  ///
+  ///
+public:
+  BreakpointLocation(lldb::break_id_t loc_id, Breakpoint &owner);
+  bool IsValid() const { return m_is_valid; }
+  bool IsFacade() const { return m_is_facade; }
+private:
   // Data members:
   bool m_should_resolve_indirect_functions;
   bool m_is_reexported;
@@ -390,6 +431,17 @@ class BreakpointLocation
   /// location was given somewhere in the virtual inlined call stack since the
   /// Address always resolves to the lowest entry in the stack.
   std::optional<LineEntry> m_preferred_line_entry;
+  bool m_is_valid = true;  /// Because Facade locations don't have sites
+                           /// we can't use the presence of the site to mean
+                           /// this breakpoint is valid, but must manage
+                           /// the state directly.
+  bool m_is_facade = false; /// Facade locations aren't directly triggered
+                            /// and don't have a breakpoint site.  They are
+                            /// a useful fiction when you want to represent
+                            /// the stop location as something lldb can't
+                            /// naturally stop at.
+
+  void SetInvalid() { m_is_valid = false; }
 
   void SetShouldResolveIndirectFunctions(bool do_resolve) {
     m_should_resolve_indirect_functions = do_resolve;
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
index 3aef1d658c0e5..8ef13d304d044 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
@@ -111,7 +111,7 @@ class BreakpointLocationCollection {
   ///
   /// \return
   ///    \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context);
+  bool ShouldStop(StoppointCallbackContext *context, BreakpointLocationCollection &stopped_bp_locs);
 
   /// Print a description of the breakpoint locations in this list
   /// to the stream \a s.
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
index 17dc0bfe03148..8c8309b731b6b 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
@@ -140,7 +140,8 @@ class BreakpointLocationList {
   ///
   /// \return
   ///     \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID);
+  bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID, 
+      lldb::BreakpointLocationSP &bp_loc_sp);
 
   /// Returns the number of elements in this breakpoint location list.
   ///
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
index 0322fd9f46ede..7e747ab0bdc1f 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
@@ -45,6 +45,12 @@ class BreakpointResolverScripted : public BreakpointResolver {
 
   void GetDescription(Stream *s) override;
 
+  lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
+                                    lldb::BreakpointLocationSP bp_loc_sp);
+  
+  std::optional<std::string> GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp,
+      lldb::DescriptionLevel level);
+
   void Dump(Stream *s) const override;
 
   /// Methods for support type inquiry through isa, cast, and dyn_cast:
diff --git a/lldb/include/lldb/Breakpoint/BreakpointSite.h b/lldb/include/lldb/Breakpoint/BreakpointSite.h
index 7b3f7be23639f..75b5ed9f4f531 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointSite.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -99,7 +99,8 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   ///
   /// \return
   ///    \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context) override;
+  bool ShouldStop(StoppointCallbackContext *context, 
+          BreakpointLocationCollection &stopping_bp_loc) override;
 
   /// Standard Dump method
   void Dump(Stream *s) const override;
diff --git a/lldb/include/lldb/Breakpoint/StopPointSiteList.h b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
index 7ed53e952dc8d..101eccda4616b 100644
--- a/lldb/include/lldb/Breakpoint/StopPointSiteList.h
+++ b/lldb/include/lldb/Breakpoint/StopPointSiteList.h
@@ -213,30 +213,6 @@ template <typename StopPointSite> class StopPointSiteList {
 
   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) {
-    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.
   ///
   /// \result
diff --git a/lldb/include/lldb/Breakpoint/StoppointSite.h b/lldb/include/lldb/Breakpoint/StoppointSite.h
index bef19f37908c6..a398aa838596c 100644
--- a/lldb/include/lldb/Breakpoint/StoppointSite.h
+++ b/lldb/include/lldb/Breakpoint/StoppointSite.h
@@ -38,7 +38,10 @@ class StoppointSite {
 
   virtual bool IsHardware() const = 0;
 
-  virtual bool ShouldStop(StoppointCallbackContext* context) = 0;
+  virtual bool ShouldStop(StoppointCallbackContext* context) { return false; };
+
+  virtual bool ShouldStop(StoppointCallbackContext* context,
+          BreakpointLocationCollection &stopping_bp_locs) { return false; };
 
   virtual void Dump(Stream* stream) const = 0;
 
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
index 28d6ed992b141..c203e7f15d279 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
@@ -26,6 +26,16 @@ class ScriptedBreakpointInterface : public ScriptedInterface {
   virtual bool ResolverCallback(SymbolContext sym_ctx) { return true; }
   virtual lldb::SearchDepth GetDepth() { return lldb::eSearchDepthModule; }
   virtual std::optional<std::string> GetShortHelp() { return nullptr; }
+  /// WasHit returns the breakpoint location SP for the location that was "hit".
+  virtual lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
+                          lldb::BreakpointLocationSP bp_loc_sp) { 
+      return LLDB_INVALID_BREAK_ID;
+  }
+  virtual std::optional<std::string> 
+      GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp, 
+                             lldb::DescriptionLevel level) { 
+      return {};
+  }
 };
 } // namespace lldb_private
 
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 024bbc90a9a39..554f8128344d9 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -11,6 +11,7 @@
 
 #include "lldb/API/SBAttachInfo.h"
 #include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBBreakpointLocation.h"
 #include "lldb/API/SBData.h"
 #include "lldb/API/SBError.h"
 #include "lldb/API/SBEvent.h"
@@ -572,12 +573,17 @@ class ScriptInterpreter : public PluginInterface {
 
   lldb::StreamSP GetOpaqueTypeFromSBStream(const lldb::SBStream &stream) const;
 
+  lldb::StackFrameSP GetOpaqueTypeFromSBFrame(const lldb::SBFrame &frame) const;
+
   SymbolContext
   GetOpaqueTypeFromSBSymbolContext(const lldb::SBSymbolContext &sym_ctx) const;
 
   lldb::BreakpointSP
   GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const;
 
+  lldb::BreakpointLocationSP
+  GetOpaqueTypeFromSBBreakpointLocation(const lldb::SBBreakpointLocation &break_loc) const;
+
   lldb::ProcessAttachInfoSP
   GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo &attach_info) const;
 
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 07c0a2ea907ba..93748dd46f69c 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -567,6 +567,16 @@ SBError SBBreakpoint::AddLocation(SBAddress &address) {
   return error;
 }
 
+SBBreakpointLocation
+SBBreakpoint::AddFacadeLocation() {
+  BreakpointSP bkpt_sp = GetSP();
+  if (!bkpt_sp) {
+    return {};
+  }
+  BreakpointLocationSP loc_sp = bkpt_sp->AddFacadeLocation();
+  return SBBreakpointLocation(loc_sp);
+}
+
 SBStructuredData SBBreakpoint::SerializeToStructuredData() {
   LLDB_INSTRUMENT_VA(this);
 
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
index 1544bf85fb859..d6d2f8aa17c19 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -58,7 +58,12 @@ Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp)
       m_hit_counter() {}
 
 // Destructor
-Breakpoint::~Breakpoint() = default;
+Breakpoint::~Breakpoint() {
+  for (BreakpointLocationSP location_sp : m_locations.BreakpointLocations())
+    location_sp->SetInvalid();
+  for (BreakpointLocationSP location_sp : m_facade_locations.BreakpointLocations())
+    location_sp->SetInvalid();
+}
 
 BreakpointSP Breakpoint::CopyFromBreakpoint(TargetSP new_target,
                                             const Breakpoint &bp_to_copy_from) {
@@ -302,6 +307,19 @@ BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,
                                  new_location);
 }
 
+BreakpointLocationSP Breakpoint::AddFacadeLocation() {
+  size_t next_id = m_facade_locations.GetSize() + 1;
+  BreakpointLocationSP break_loc_sp 
+      = std::make_shared<BreakpointLocation>(next_id, *this);
+  break_loc_sp->m_is_facade = true;
+  m_facade_locations.Add(break_loc_sp);
+  return break_loc_sp;
+}
+
+BreakpointLocationSP Breakpoint::GetFacadeLocationByID(lldb::break_id_t loc_id) {
+  return m_facade_locations.GetByIndex(loc_id - 1);
+}
+
 BreakpointLocationSP Breakpoint::FindLocationByAddress(const Address &addr) {
   return m_locations.FindByAddress(addr);
 }
@@ -310,15 +328,21 @@ break_id_t Breakpoint::FindLocationIDByAddress(const Address &addr) {
   return m_locations.FindIDByAddress(addr);
 }
 
-BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id) {
+BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id, bool use_facade) {
+  if (use_facade && m_facade_locations.GetSize())
+    return GetFacadeLocationByID(bp_loc_id);
   return m_locations.FindByID(bp_loc_id);
 }
 
-BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index) {
+BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index, bool use_facade) {
+  if (use_facade && m_facade_locations.GetSize() > 0)
+    return m_facade_locations.GetByIndex(index);
   return m_locations.GetByIndex(index);
 }
 
 void Breakpoint::RemoveInvalidLocations(const ArchSpec &arch) {
+  // FIXME: Should we ask the scripted resolver whether any of its facade
+  // locations are invalid?
   m_locations.RemoveInvalidLocations(arch);
 }
 
@@ -864,9 +888,15 @@ void Breakpoint::ModuleReplaced(ModuleSP old_module_sp,
 
 void Breakpoint::Dump(Stream *) {}
 
-size_t Breakpoint::GetNumResolvedLocations() const {
+size_t Breakpoint::GetNumResolvedLocations(bool use_facade) const {
   // Return the number of breakpoints that are actually resolved and set down
   // in the inferior process.
+  // All facade locations are considered to be resolved:
+  if (use_facade) {
+    size_t num_facade_locs = m_facade_locations.GetSize();
+    if (num_facade_locs)
+      return num_facade_locs;
+  }
   return m_locations.GetNumResolvedLocations();
 }
 
@@ -874,7 +904,14 @@ bool Breakpoint::HasResolvedLocations() const {
   return GetNumResolvedLocations() > 0;
 }
 
-size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); }
+size_t Breakpoint::GetNumLocations(bool use_facade) const { 
+  if (use_facade) {
+    size_t num_facade_locs = m_facade_locations.GetSize();
+    if (num_facade_locs > 0)
+      return num_facade_locs;
+  }
+  return m_locations.GetSize(); 
+}
 
 void Breakpoint::AddName(llvm::StringRef new_name) {
   m_name_list.insert(new_name.str());
@@ -899,8 +936,30 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
     s->Printf("Kind: %s\n", GetBreakpointKind());
   }
 
-  const size_t num_locations = GetNumLocations();
-  const size_t num_resolved_locations = GetNumResolvedLocations();
+  bool show_both_types = level == eDescriptionLevelVerbose 
+    && HasFacadeLocations() && show_locations;
+  uint8_t display_mask = eDisplayFacade;
+  if (show_both_types)
+    display_mask |= eDisplayHeader;
+    
+  GetDescriptionForType(s, level, display_mask, show_locations);
+  
+  if (show_both_types) {
+    display_mask = eDisplayReal | eDisplayHeader;
+    GetDescriptionForType(s, level, display_mask, show_locations);
+  }
+  // Reset the colors back to normal if they were previously greyed out.
+  if (dim_breakpoint_description)
+    s->Printf("%s", ansi::FormatAnsiTerminalCodes(
+                        GetTarget().GetDebugger().GetDisabledAnsiSuffix())
+                        .c_str());
+}
+  
+void Breakpoint::GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
+                                       uint8_t display_type, bool show_locations) {
+  bool use_facade = (display_type & eDisplayFacade) != 0;
+  const size_t num_locations = GetNumLocations(use_facade);
+  const size_t num_resolved_locations = GetNumResolvedLocations(use_facade);
 
   // They just made the breakpoint, they don't need to be told HOW they made
   // it... Also, we'll print the breakpoint number differently depending on
@@ -957,7 +1016,7 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
     } else if (num_locations == 1 && !show_locations) {
       // There is only one location, so we'll just print that location
       // information.
-      GetLocationAtIndex(0)->GetDescription(s, level);
+      GetLocationAtIndex(0, use_facade)->GetDescription(s, level);
     } else {
       s->Printf("%" PRIu64 " locations.", static_cast<uint64_t>(num_locations));
     }
@@ -979,20 +1038,21 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
   // The brief description is just the location name (1.2 or whatever).  That's
   // pointless to show in the breakpoint's description, so suppress it.
   if (show_locations && level != lldb::eDescriptionLevelBrief) {
+    if ((display_type & eDisplayHeader) != 0)
+      if ((display_type & eDisplayFacade) != 0)
+        s->Printf("Facade locations:\n");
+      else
+        s->Printf("Implementation Locations\n");
+
     s->IndentMore();
     for (size_t i = 0; i < num_locations; ++i) {
-      BreakpointLocation *loc = GetLocationAtIndex(i).get();
+      BreakpointLocation *loc = GetLocationAtIndex(i, use_facade).get();
       loc->GetDescription(s, level);
       s->EOL();
     }
     s->IndentLess();
   }
 
-  // Reset the colors back to normal if they were previously greyed out.
-  if (dim_breakpoint_description)
-    s->Printf("%s", ansi::FormatAnsiTerminalCodes(
-                        GetTarget().GetDebugger().GetDisabledAnsiSuffix())
-                        .c_str());
 }
 
 void Breakpoint::GetResolverDescription(Stream *s) {
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 443d4f50833d3..829ed03392999 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -8,6 +8,8 @@
 
 #include "lldb/Breakpoint/BreakpointLocation.h"
 #include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverScripted.h"
 #include "lldb/Breakpoint/StoppointCallbackContext.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
@@ -45,6 +47,13 @@ BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner,
   SetThreadIDInternal(tid);
 }
 
+BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner)
+    : m_should_resolve_indirect_functions(false), m_is_reexported(false),
+      m_is_indirect(false), m_address(LLDB_INVALID_ADDRESS), m_owner(owner),
+      m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() {
+  SetThreadIDInternal(LLDB_INVALID_THREAD_ID);
+}
+
 BreakpointLocation::~BreakpointLocation() {
   llvm::consumeError(ClearBreakpointSite());
 }
@@ -372,12 +381,41 @@ bool BreakpointLocation::ValidForThisThread(Thread &thread) {
           .GetThreadSpecNoCreate());
 }
 
+BreakpointLocationSP BreakpointLocation::WasHit(StoppointCallbackContext *context)
+{
+  // Only the BreakpointResolverScripted provides WasHit.
+  BreakpointResolverSP resolver_sp = GetBreakpoint().GetResolver();
+  BreakpointResolverScripted *scripted = llvm::dyn_cast<BreakpointResolverScripted>(resolver_sp.get());
+  if (!scripted)
+    return shared_from_this();
+
+  StackFrameSP frame_sp = context->exe_ctx_ref.GetFrameSP();
+  if (!frame_sp)
+    return shared_from_this();
+
+  BreakpointLocationSP return_loc_sp = scripted->WasHit(frame_sp, shared_from_this());
+  // If this is a facade location, then we won't have bumped its hit count
+  // while processing the original location hit.  Do so here.  We don't need
+  // to bump the breakpoint's hit count, however, since hitting the real
+  // location would have already done that.
+  // Also we have to check the enabled state here, since we would never have
+  // gotten here with a real location...
+  if (return_loc_sp && return_loc_sp->IsFacade()) {
+     if (return_loc_sp->IsEnabled())
+       return_loc_sp->m_hit_counter.Increment();
+     else
+       return {};
+  }
+  return return_loc_sp;
+}
+
 // RETURNS - true if we should stop at this breakpoint, false if we
 // should continue.  Note, we don't check the thread spec for the breakpoint
 // here, since if the breakpoint is not for this thread, then the event won't
 // even get reported, so the check is redundant.
 
-bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
+bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context, 
+        lldb::BreakpointLocationSP &facade_loc_sp) {
   bool should_stop = true;
   Log *log = GetLog(LLDBLog::Breakpoints);
 
@@ -386,6 +424,27 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
   if (!IsEnabled())
     return false;
 
+  // Next check WasHit:
+  BreakpointLocationSP loc_hit_sp = WasHit(context);
+  
+  if (!loc_hit_sp) {
+    // We bump the hit counts in StopInfoBreakpoint::ShouldStopSynchronous,
+    // before we call into each location's ShouldStop.  So we need to undo
+    // that here.
+    UndoBumpHitCount();
+    return false;
+  }
+  
+  // If the location hit was not us, it was a facade location, in which case
+  // we should use the facade location's callbacks, etc.  Those will all be
+  // run in the asynchronous phase, so for now we just have to record the fact
+  // that we should treat this as a facade hit.  This is strictly an out
+  // parameter, so clear it if this isn't a facade hit.
+  if (loc_hit_sp.get() != this)
+    facade_loc_sp = loc_hit_sp;
+  else
+    facade_loc_sp.reset();
+
   // We only run synchronous callbacks in ShouldStop:
   context->is_synchronous = true;
   should_stop = InvokeCallback(context);
@@ -395,6 +454,11 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) {
     GetDescription(&s, lldb::eDescriptionLevelVerbose);
     LLDB_LOGF(log, "Hit breakpoint location: %s, %s.\n", s.GetData(),
               should_stop ? "stopping" : "continuing");
+    if (facade_loc_sp) {
+      s.Clear();
+      facade_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+      LLDB_LOGF(log, "Attributing to facade location: %s.\n", s.GetData());
+    }
   }
 
   return should_stop;
@@ -417,7 +481,10 @@ void BreakpointLocation::UndoBumpHitCount() {
 }
 
 bool BreakpointLocation::IsResolved() const {
-  return m_bp_site_sp.get() != nullptr;
+
+  bool has_site = m_bp_site_sp.get() != nullptr;
+  // Facade locations are currently always considered resolved.
+  return has_site || IsFacade();
 }
 
 lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
@@ -425,7 +492,9 @@ lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
 }
 
 llvm::Error BreakpointLocation::ResolveBreakpointSite() {
-  if (m_bp_site_sp)
+  // This might be a facade location, which doesn't have an address.
+  // In that case, don't attempt to make a site.
+  if (m_bp_site_sp  || IsFacade())
     return llvm::Error::success();
 
   Process *process = m_owner.GetTarget().GetProcessSP().get();
@@ -454,8 +523,13 @@ bool BreakpointLocation::SetBreakpointSite(BreakpointSiteSP &bp_site_sp) {
 }
 
 llvm::Error BreakpointLocation::ClearBreakpointSite() {
-  if (!m_bp_site_sp)
-    return llvm::createStringError("no breakpoint site to clear");
+  if (!m_bp_site_sp) {
+    // This might be a Facade Location, which don't have sites or addresses
+    if (IsFacade())
+      return llvm::Error::success();
+    else
+      return llvm::createStringError("no breakpoint site to clear");
+  }
 
   // If the process exists, get it to remove the owner, it will remove the
   // physical implementation of the breakpoint as well if there are no more
@@ -473,6 +547,17 @@ llvm::Error BreakpointLocation::ClearBreakpointSite() {
 void BreakpointLocation::GetDescription(Stream *s,
                                         lldb::DescriptionLevel level) {
   SymbolContext sc;
+  
+  // If this is a scripted breakpoint, give it a chance to describe its
+  // locations:
+  std::optional<std::string> scripted_opt;
+  BreakpointResolverSP resolver_sp = GetBreakpoint().GetResolver();
+  BreakpointResolverScripted *scripted = 
+      llvm::dyn_cast<BreakpointResolverScripted>(resolver_sp.get());
+  if (scripted)
+        scripted_opt = scripted->GetLocationDescription(shared_from_this(), level);
+
+  bool is_scripted_desc = scripted_opt.has_value();
 
   // If the description level is "initial" then the breakpoint is printing out
   // our initial state, and we should let it decide how it wants to print our
@@ -491,7 +576,9 @@ void BreakpointLocation::GetDescription(Stream *s,
   if (level == lldb::eDescriptionLevelVerbose)
     s->IndentMore();
 
-  if (m_address.IsSectionOffset()) {
+  if (is_scripted_desc) {
+    s->PutCString(scripted_opt->c_str());
+  } else if (m_address.IsSectionOffset()) {
     m_address.CalculateSymbolContext(&sc);
 
     if (level == lldb::eDescriptionLevelFull ||
@@ -566,43 +653,51 @@ void BreakpointLocation::GetDescription(Stream *s,
     s->Indent();
   }
 
-  if (m_address.IsSectionOffset() &&
-      (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
-    s->Printf(", ");
-  s->Printf("address = ");
-
-  ExecutionContextScope *exe_scope = nullptr;
-  Target *target = &m_owner.GetTarget();
-  if (target)
-    exe_scope = target->GetProcessSP().get();
-  if (exe_scope == nullptr)
-    exe_scope = target;
-
-  if (level == eDescriptionLevelInitial)
-    m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
-                   Address::DumpStyleFileAddress);
-  else
-    m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
-                   Address::DumpStyleModuleWithFileAddress);
-
-  if (IsIndirect() && m_bp_site_sp) {
-    Address resolved_address;
-    resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
-    Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
-    if (resolved_symbol) {
-      if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
-        s->Printf(", ");
-      else if (level == lldb::eDescriptionLevelVerbose) {
-        s->EOL();
-        s->Indent();
+  if (!is_scripted_desc) {
+    if (m_address.IsSectionOffset() &&
+        (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
+      s->Printf(", ");
+    s->Printf("address = ");
+
+    ExecutionContextScope *exe_scope = nullptr;
+    Target *target = &m_owner.GetTarget();
+    if (target)
+      exe_scope = target->GetProcessSP().get();
+    if (exe_scope == nullptr)
+      exe_scope = target;
+
+    if (level == eDescriptionLevelInitial)
+      m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
+                     Address::DumpStyleFileAddress);
+    else
+      m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress,
+                     Address::DumpStyleModuleWithFileAddress);
+
+    if (IsIndirect() && m_bp_site_sp) {
+      Address resolved_address;
+      resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target);
+      Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol();
+      if (resolved_symbol) {
+        if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)
+          s->Printf(", ");
+        else if (level == lldb::eDescriptionLevelVerbose) {
+          s->EOL();
+          s->Indent();
+        }
+        s->Printf("indirect target = %s",
+                  resolved_symbol->GetName().GetCString());
       }
-      s->Printf("indirect target = %s",
-                resolved_symbol->GetName().GetCString());
     }
   }
 
-  bool is_resolved = IsResolved();
-  bool is_hardware = is_resolved && m_bp_site_sp->IsHardware();
+  // Scripted breakpoint are currently always resolved.  Does this seem right?
+  // If they don't add any scripted locations, we shouldn't consider them
+  // resolved.
+  bool is_resolved = is_scripted_desc || IsResolved();
+  // A scripted breakpoint might be resolved but not have a site.  Be sure to 
+  // check for that.
+  bool is_hardware = !is_scripted_desc && IsResolved() && m_bp_site_sp 
+      && m_bp_site_sp->IsHardware();
 
   if (level == lldb::eDescriptionLevelVerbose) {
     s->EOL();
@@ -717,9 +812,9 @@ void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) {
 }
 
 void BreakpointLocation::SetThreadIDInternal(lldb::tid_t thread_id) {
-  if (thread_id != LLDB_INVALID_THREAD_ID)
+  if (thread_id != LLDB_INVALID_THREAD_ID) {
     GetLocationOptions().SetThreadID(thread_id);
-  else {
+  } else {
     // If we're resetting this to an invalid thread id, then don't make an
     // options pointer just to do that.
     if (m_options_up != nullptr)
diff --git a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
index 81bec0bd7583d..1d052c5fc9bb6 100644
--- a/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -115,7 +115,8 @@ BreakpointLocationCollection::GetByIndex(size_t i) const {
 }
 
 bool BreakpointLocationCollection::ShouldStop(
-    StoppointCallbackContext *context) {
+    StoppointCallbackContext *context,
+    BreakpointLocationCollection &stopped_bp_locs) {
   bool shouldStop = false;
   size_t i = 0;
   size_t prev_size = GetSize();
@@ -123,9 +124,20 @@ bool BreakpointLocationCollection::ShouldStop(
     // ShouldStop can remove the breakpoint from the list, or even delete
     // it, so we should
     BreakpointLocationSP cur_loc_sp = GetByIndex(i);
+    BreakpointLocationSP reported_loc_sp;
     BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this();
-    if (cur_loc_sp->ShouldStop(context))
+    // We're building up the list or which locations claim responsibility for
+    // this stop.  If the location's ShouldStop defers to a facade location by
+    // returning a non-null reported location, we want to use that.  Otherwise
+    // use the original location.
+    if (cur_loc_sp->ShouldStop(context, reported_loc_sp)) {
+      if (reported_loc_sp)
+        stopped_bp_locs.Add(reported_loc_sp);
+      else
+        stopped_bp_locs.Add(cur_loc_sp);
+
       shouldStop = true;
+    }
 
     if (prev_size == GetSize())
       i++;
diff --git a/lldb/source/Breakpoint/BreakpointLocationList.cpp b/lldb/source/Breakpoint/BreakpointLocationList.cpp
index 44d1eb5bf7140..5a791d4364641 100644
--- a/lldb/source/Breakpoint/BreakpointLocationList.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocationList.cpp
@@ -32,22 +32,23 @@ BreakpointLocationList::Create(const Address &addr,
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   // The location ID is just the size of the location list + 1
   lldb::break_id_t bp_loc_id = ++m_next_id;
-  BreakpointLocationSP bp_loc_sp(
-      new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
-                             resolve_indirect_symbols));
+  BreakpointLocationSP bp_loc_sp(new 
+      BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, 
+      resolve_indirect_symbols));
   m_locations.push_back(bp_loc_sp);
   m_address_to_location[addr] = bp_loc_sp;
   return bp_loc_sp;
 }
 
 bool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
-                                        lldb::break_id_t break_id) {
+                                        lldb::break_id_t break_id,
+                                        lldb::BreakpointLocationSP &bp_loc_sp) {
   BreakpointLocationSP bp = FindByID(break_id);
   if (bp) {
     // Let the BreakpointLocation 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 bp->ShouldStop(context);
+    return bp->ShouldStop(context, bp_loc_sp);
   }
   // We should stop here since this BreakpointLocation isn't valid anymore or
   // it doesn't exist.
diff --git a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
index 701cabae3ee97..b1e45d761735b 100644
--- a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
@@ -50,7 +50,9 @@ void BreakpointResolverScripted::CreateImplementationIfNeeded(
   if (!script_interp)
     return;
 
-  m_interface_sp = script_interp->CreateScriptedBreakpointInterface();
+  if (!m_interface_sp)
+    m_interface_sp = script_interp->CreateScriptedBreakpointInterface();
+
   if (!m_interface_sp) {
     m_error = Status::FromErrorStringWithFormat(
         "BreakpointResolverScripted::%s () - ERROR: %s", __FUNCTION__,
@@ -61,6 +63,7 @@ void BreakpointResolverScripted::CreateImplementationIfNeeded(
   auto obj_or_err =
       m_interface_sp->CreatePluginObject(m_class_name, breakpoint_sp, m_args);
   if (!obj_or_err) {
+    m_interface_sp.reset();
     m_error = Status::FromError(obj_or_err.takeError());
     return;
   }
@@ -146,6 +149,8 @@ void BreakpointResolverScripted::GetDescription(Stream *s) {
   StructuredData::GenericSP generic_sp;
   std::optional<std::string> short_help;
 
+  CreateImplementationIfNeeded(GetBreakpoint());
+
   if (m_interface_sp) {
     short_help = m_interface_sp->GetShortHelp();
   }
@@ -155,6 +160,23 @@ void BreakpointResolverScripted::GetDescription(Stream *s) {
     s->Printf("python class = %s", m_class_name.c_str());
 }
 
+std::optional<std::string> 
+BreakpointResolverScripted::GetLocationDescription(
+    lldb::BreakpointLocationSP bp_loc_sp, lldb::DescriptionLevel level) {
+  CreateImplementationIfNeeded(GetBreakpoint());
+  if (m_interface_sp) 
+    return m_interface_sp->GetLocationDescription(bp_loc_sp, level);
+  return {};
+}
+
+lldb::BreakpointLocationSP
+BreakpointResolverScripted::WasHit(lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
+  if (m_interface_sp)
+    return m_interface_sp->WasHit(frame_sp, bp_loc_sp);
+
+  return {};
+}
+
 void BreakpointResolverScripted::Dump(Stream *s) const {}
 
 lldb::BreakpointResolverSP
diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp
index d430e3de788f0..52100b91de09c 100644
--- a/lldb/source/Breakpoint/BreakpointSite.cpp
+++ b/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -45,7 +45,8 @@ break_id_t BreakpointSite::GetNextID() {
 // RETURNS - true if we should stop at this breakpoint, false if we
 // should continue.
 
-bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
+bool BreakpointSite::ShouldStop(StoppointCallbackContext *context,
+        BreakpointLocationCollection &stopping_bp_locs) {
   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
@@ -56,7 +57,7 @@ bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
     std::lock_guard<std::recursive_mutex> guard(m_constituents_mutex);
     constituents_copy = m_constituents;
   }
-  return constituents_copy.ShouldStop(context);
+  return constituents_copy.ShouldStop(context, stopping_bp_locs);
 }
 
 bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) {
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 6a654a0dafe5b..51475db27269b 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -81,6 +81,11 @@ lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
   return breakpoint.m_opaque_wp.lock();
 }
 
+lldb::BreakpointLocationSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpointLocation(
+    const lldb::SBBreakpointLocation &break_loc) const {
+  return break_loc.m_opaque_wp.lock();
+}
+
 lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
     const lldb::SBAttachInfo &attach_info) const {
   return attach_info.m_opaque_sp;
@@ -100,6 +105,14 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
   return Status();
 }
 
+lldb::StackFrameSP
+ScriptInterpreter::GetOpaqueTypeFromSBFrame(const lldb::SBFrame &frame) const {
+  if (frame.m_opaque_sp) {
+    return frame.m_opaque_sp->GetFrameSP();
+  }
+  return nullptr;
+}
+
 Event *
 ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const {
   return event.m_opaque_ptr;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
index 660edaa0191f0..0c6d23b108fa1 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
@@ -81,6 +81,32 @@ std::optional<std::string> ScriptedBreakpointPythonInterface::GetShortHelp() {
   return obj->GetAsString()->GetValue().str();
 }
 
+lldb::BreakpointLocationSP
+ScriptedBreakpointPythonInterface::WasHit(lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
+  Status py_error;
+  lldb::BreakpointLocationSP loc_sp 
+    = Dispatch<lldb::BreakpointLocationSP>("was_hit", py_error, frame_sp, bp_loc_sp);
+
+  if (py_error.Fail())
+    return bp_loc_sp;
+
+  return loc_sp;
+}
+
+std::optional<std::string> 
+ScriptedBreakpointPythonInterface::GetLocationDescription(
+    lldb::BreakpointLocationSP bp_loc_sp, 
+    lldb::DescriptionLevel level) {
+  Status error;
+  StructuredData::ObjectSP obj = Dispatch("get_location_description", error, bp_loc_sp, level);
+
+  if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+                                                    error))
+    return {};
+
+  return obj->GetAsString()->GetValue().str();
+}
+
 void ScriptedBreakpointPythonInterface::Initialize() {
   const std::vector<llvm::StringRef> ci_usages = {
       "breakpoint set -P classname [-k key -v value ...]"};
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
index 27bdd8718ac0c..b8c1219279876 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
@@ -36,6 +36,12 @@ class ScriptedBreakpointPythonInterface : public ScriptedBreakpointInterface,
   bool ResolverCallback(SymbolContext sym_ctx) override;
   lldb::SearchDepth GetDepth() override;
   std::optional<std::string> GetShortHelp() override;
+  lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
+                  lldb::BreakpointLocationSP bp_loc_sp) override;
+  virtual std::optional<std::string> 
+      GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp, 
+                             lldb::DescriptionLevel level) override;
+
 
   static void Initialize();
 
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index 8083ccae04026..cda8185ef0a17 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -80,6 +80,19 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
   return nullptr;
 }
 
+template <>
+lldb::StackFrameSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
+    python::PythonObject &p, Status &error) {
+  if (lldb::SBFrame *sb_frame = reinterpret_cast<lldb::SBFrame *>(
+          python::LLDBSWIGPython_CastPyObjectToSBFrame(p.get())))
+    return m_interpreter.GetOpaqueTypeFromSBFrame(*sb_frame);
+  error = Status::FromErrorString(
+      "Couldn't cast lldb::SBFrame to lldb_private::StackFrame.");
+
+  return nullptr;
+}
+
 template <>
 SymbolContext
 ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>(
@@ -126,6 +139,22 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
   return m_interpreter.GetOpaqueTypeFromSBBreakpoint(*sb_breakpoint);
 }
 
+template <>
+lldb::BreakpointLocationSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointLocationSP>(
+    python::PythonObject &p, Status &error) {
+  lldb::SBBreakpointLocation *sb_break_loc = reinterpret_cast<lldb::SBBreakpointLocation *>(
+      python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(p.get()));
+
+  if (!sb_break_loc) {
+    error = Status::FromErrorStringWithFormat(
+        "Couldn't cast lldb::SBBreakpointLocation to lldb::BreakpointLocationSP.");
+    return nullptr;
+  }
+
+  return m_interpreter.GetOpaqueTypeFromSBBreakpointLocation(*sb_break_loc);
+}
+
 template <>
 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error) {
@@ -194,4 +223,22 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
   return m_interpreter.GetOpaqueTypeFromSBExecutionContext(*sb_exe_ctx);
 }
 
+template <>
+lldb::DescriptionLevel
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    lldb::DescriptionLevel>(python::PythonObject &p, Status &error) {
+    lldb::DescriptionLevel ret_val = lldb::eDescriptionLevelBrief;
+    llvm::Expected<unsigned long long> unsigned_or_err = p.AsUnsignedLongLong();
+    if (!unsigned_or_err) {
+      error = (Status::FromError(unsigned_or_err.takeError()));
+      return ret_val;
+    }
+    unsigned long long unsigned_val = *unsigned_or_err;
+    if (unsigned_val >= lldb::DescriptionLevel::kNumDescriptionLevels) {
+      error = Status("value too large for lldb::DescriptionLevel.");
+      return ret_val;
+    }
+    return static_cast<lldb::DescriptionLevel>(unsigned_val);
+}
+
 #endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index f769d3d29add7..57d22d44e565e 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -436,6 +436,10 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
     return python::SWIGBridge::ToSWIGWrapper(arg);
   }
 
+  python::PythonObject Transform(lldb::BreakpointLocationSP arg) {
+    return python::SWIGBridge::ToSWIGWrapper(arg);
+  }
+
   python::PythonObject Transform(lldb::ProcessSP arg) {
     return python::SWIGBridge::ToSWIGWrapper(arg);
   }
@@ -464,10 +468,18 @@ class ScriptedPythonInterface : virtual public ScriptedInterface {
     return python::SWIGBridge::ToSWIGWrapper(arg.get());
   }
 
+  python::PythonObject Transform(lldb::StackFrameSP arg) {
+    return python::SWIGBridge::ToSWIGWrapper(arg);
+  }
+
   python::PythonObject Transform(lldb::DataExtractorSP arg) {
     return python::SWIGBridge::ToSWIGWrapper(arg);
   }
 
+  python::PythonObject Transform(lldb::DescriptionLevel arg) {
+    return python::SWIGBridge::ToSWIGWrapper(arg);
+  }
+
   template <typename T, typename U>
   void ReverseTransform(T &original_arg, U transformed_arg, Status &error) {
     // If U is not a PythonObject, don't touch it!
@@ -573,11 +585,21 @@ lldb::StreamSP
 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>(
     python::PythonObject &p, Status &error);
 
+template <>
+lldb::StackFrameSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StackFrameSP>(
+    python::PythonObject &p, Status &error);
+
 template <>
 lldb::BreakpointSP
 ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
     python::PythonObject &p, Status &error);
 
+template <>
+lldb::BreakpointLocationSP
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointLocationSP>(
+    python::PythonObject &p, Status &error);
+
 template <>
 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
     lldb::ProcessAttachInfoSP>(python::PythonObject &p, Status &error);
@@ -601,6 +623,11 @@ lldb::ExecutionContextRefSP
 ScriptedPythonInterface::ExtractValueFromPythonObject<
     lldb::ExecutionContextRefSP>(python::PythonObject &p, Status &error);
 
+template <>
+lldb::DescriptionLevel
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    lldb::DescriptionLevel>(python::PythonObject &p, Status &error);
+
 } // namespace lldb_private
 
 #endif // LLDB_ENABLE_PYTHON
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
index 413778639c297..7b39d29ba2b20 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h
@@ -107,6 +107,7 @@ class SWIGBridge {
   static PythonObject ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp);
   static PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp);
   static PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_extractor_sp);
+  static PythonObject ToSWIGWrapper(lldb::DescriptionLevel level);
 
   static PythonObject
   ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb);
@@ -256,11 +257,13 @@ class SWIGBridge {
 
 void *LLDBSWIGPython_CastPyObjectToSBData(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data);
+void *LLDBSWIGPython_CastPyObjectToSBFrame(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data);
 void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data);
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index f47dae2b2465d..b864159ba7471 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -157,7 +157,7 @@ class StopInfoBreakpoint : public StopInfo {
           ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
           StoppointCallbackContext context(event_ptr, exe_ctx, true);
           bp_site_sp->BumpHitCounts();
-          m_should_stop = bp_site_sp->ShouldStop(&context);
+          m_should_stop = bp_site_sp->ShouldStop(&context, m_async_stopped_locs);
         } else {
           Log *log = GetLog(LLDBLog::Process);
 
@@ -180,6 +180,7 @@ class StopInfoBreakpoint : public StopInfo {
   }
 
   const char *GetDescription() override {
+    // FIXME: only print m_async_stopped_locs.
     if (m_description.empty()) {
       ThreadSP thread_sp(m_thread_wp.lock());
       if (thread_sp) {
@@ -202,7 +203,7 @@ class StopInfoBreakpoint : public StopInfo {
           }
 
           strm.Printf("breakpoint ");
-          bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
+          m_async_stopped_locs.GetDescription(&strm, eDescriptionLevelBrief);
           m_description = std::string(strm.GetString());
         } else {
           StreamString strm;
@@ -244,6 +245,12 @@ class StopInfoBreakpoint : public StopInfo {
   }
 
   uint32_t GetStopReasonDataCount() const override {
+    size_t num_async_locs = m_async_stopped_locs.GetSize();
+    // If we have async locations, they are the ones we should report:
+    if (num_async_locs > 0)
+      return num_async_locs * 2;
+
+    // Otherwise report the number of locations at this breakpoint's site.
     lldb::BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
     if (bp_site_sp)
       return bp_site_sp->GetNumberOfConstituents() * 2;
@@ -251,22 +258,25 @@ class StopInfoBreakpoint : public StopInfo {
   }
 
   uint64_t GetStopReasonDataAtIndex(uint32_t idx) override {
-    lldb::BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
-    if (bp_site_sp) {
-      uint32_t bp_index = idx / 2;
-      BreakpointLocationSP bp_loc_sp(
-          bp_site_sp->GetConstituentAtIndex(bp_index));
-      if (bp_loc_sp) {
-        if (idx & 1) {
-          // FIXME: This might be a Facade breakpoint, so we need to fetch
-          // the one that the thread actually hit, not the native loc ID.
-
-          // Odd idx, return the breakpoint location ID
-          return bp_loc_sp->GetID();
-        } else {
-          // Even idx, return the breakpoint ID
-          return bp_loc_sp->GetBreakpoint().GetID();
-        }
+    uint32_t bp_index = idx / 2;
+    BreakpointLocationSP loc_to_report_sp;
+
+    size_t num_async_locs = m_async_stopped_locs.GetSize();
+    if (num_async_locs > 0) {
+      // GetByIndex returns an empty SP if we ask past its contents:
+      loc_to_report_sp = m_async_stopped_locs.GetByIndex(bp_index);
+    } else {
+      lldb::BreakpointSiteSP bp_site_sp = GetBreakpointSiteSP();
+      if (bp_site_sp)
+        loc_to_report_sp = bp_site_sp->GetConstituentAtIndex(bp_index);
+    }
+    if (loc_to_report_sp) {
+      if (idx & 1) {
+        // Odd idx, return the breakpoint location ID
+        return loc_to_report_sp->GetID();
+      } else {
+        // Even idx, return the breakpoint ID
+        return loc_to_report_sp->GetBreakpoint().GetID();
       }
     }
     return LLDB_INVALID_BREAK_ID;
@@ -336,7 +346,7 @@ class StopInfoBreakpoint : public StopInfo {
         // site, then we won't be operating on a bad list.
         BreakpointLocationCollection site_locations;
         size_t num_constituents =
-            bp_site_sp->CopyConstituentsList(site_locations);
+            m_async_stopped_locs.GetSize();
 
         if (num_constituents == 0) {
           m_should_stop = true;
@@ -435,17 +445,28 @@ class StopInfoBreakpoint : public StopInfo {
           // 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.
-
+          
+          // We are holding onto the breakpoint locations that were hit
+          // by this stop info between the "synchonous" ShouldStop and now.
+          // But an intervening action might have deleted one of the breakpoints
+          // we hit before we get here.  So at the same time let's build a list
+          // of the still valid locations:
           std::vector<lldb::BreakpointSP> location_constituents;
 
+          BreakpointLocationCollection valid_locs;
           for (size_t j = 0; j < num_constituents; j++) {
-            BreakpointLocationSP loc(site_locations.GetByIndex(j));
-            location_constituents.push_back(
-                loc->GetBreakpoint().shared_from_this());
+            BreakpointLocationSP loc_sp(m_async_stopped_locs.GetByIndex(j));
+            if (loc_sp->IsValid()) {
+              location_constituents.push_back(
+                  loc_sp->GetBreakpoint().shared_from_this());
+              valid_locs.Add(loc_sp);
+            }
           }
 
-          for (size_t j = 0; j < num_constituents; j++) {
-            lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
+          size_t num_valid_locs = valid_locs.GetSize();
+          for (size_t j = 0; j < num_valid_locs; j++) {
+            lldb::BreakpointLocationSP bp_loc_sp 
+                = valid_locs.GetByIndex(j);
             StreamString loc_desc;
             if (log) {
               bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief);
@@ -679,6 +700,7 @@ class StopInfoBreakpoint : public StopInfo {
   lldb::break_id_t m_break_id;
   bool m_was_all_internal;
   bool m_was_one_shot;
+  BreakpointLocationCollection m_async_stopped_locs;
 };
 
 // StopInfoWatchpoint
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py
index 85c7340127615..95868486b8cba 100644
--- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py
@@ -51,7 +51,6 @@ def __callback__(self, sym_ctx):
     def get_short_help(self):
         return "I am a python breakpoint resolver"
 
-
 class ResolverModuleDepth(Resolver):
     def __get_depth__(self):
         return lldb.eSearchDepthModule
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile
new file mode 100644
index 0000000000000..695335e068c0c
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -std=c99
+
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
new file mode 100644
index 0000000000000..de178f5b04fc7
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
@@ -0,0 +1,85 @@
+"""
+Test the WasHit feature of scripted breakpoints
+"""
+
+import os
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class TestWasHit(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24528")
+    def test_was_hit_resolver(self):
+        """Use facade breakpoints to emulate hitting some locations"""
+        self.build()
+        self.do_test()
+
+    def make_target_and_import(self):
+        target = lldbutil.run_to_breakpoint_make_target(self)
+        self.import_resolver_script()
+        return target
+
+    def import_resolver_script(self):
+        interp = self.dbg.GetCommandInterpreter()
+        error = lldb.SBError()
+
+        script_name = os.path.join(self.getSourceDir(), "bkpt_resolver.py")
+
+        command = "command script import " + script_name
+        self.runCmd(command)
+
+    def make_extra_args(self, sym_name, num_locs, loc_to_miss):
+        return f' -k symbol -v {sym_name} -k num_locs -v {num_locs} -k loc_to_miss -v {loc_to_miss} '
+
+    def do_test(self):
+        """This reads in a python file and sets a breakpoint using it."""
+
+        target = self.make_target_and_import()
+        extra_args = self.make_extra_args("stop_symbol", 4, 2)
+
+        bkpt_no = lldbutil.run_break_set_by_script(self, "bkpt_resolver.FacadeExample", extra_args, 4)
+
+        # Make sure the help text shows up in the "break list" output:
+        self.expect(
+            "break list",
+            substrs=["I am a facade resolver - sym: stop_symbol - num_locs: 4"],
+            msg="Help is listed in break list",
+        )
+
+        bkpt = target.FindBreakpointByID(bkpt_no)
+        self.assertTrue(bkpt.IsValid(), "Found the right breakpoint")
+        
+        # Now continue.  We should hit locations 1, 3 and 4:
+        (target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run(self, target, bkpt)
+        # This location should be bkpt_no.1:
+        self.assertEqual(thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint")
+        self.assertEqual(thread.stop_reason_data[1], 1, "First location hit is 1")
+
+        for loc in [3, 4]:
+            process.Continue()
+            self.assertEqual(thread.stop_reason, lldb.eStopReasonBreakpoint, "Hit breakpoint")
+            self.assertEqual(thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint")
+            self.assertEqual(thread.stop_reason_data[1], loc, f"Hit the right location: {loc}")
+
+        # At this point we should have hit three of the four locations, and not location 1.2.
+        # Check that that is true, and that the descriptions for the location are the ones
+        # the resolver provided.
+        self.assertEqual(bkpt.hit_count, 3, "Hit three locations")
+        for loc_id in range(1,4):
+            bkpt_loc = bkpt.FindLocationByID(loc_id)
+            self.assertTrue(bkpt_loc.IsValid(), f"{loc_id} was invalid.")
+            if loc_id != 2:
+                self.assertEqual(bkpt_loc.hit_count, 1, f"Loc {loc_id} hit count was wrong")
+            else:
+                self.assertEqual(bkpt_loc.hit_count, 0, "We didn't skip loc 2")
+            stream = lldb.SBStream()
+            self.assertTrue(bkpt_loc.GetDescription(stream, lldb.eDescriptionLevelFull),
+                            f"Didn't get description for {loc_id}")
+            self.assertIn(f"Location index: {loc_id}", stream.GetData(),
+                             f"Wrong desciption for {loc_id}")
+
+                            
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
new file mode 100644
index 0000000000000..004ee18513f2f
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
@@ -0,0 +1,45 @@
+import lldb
+
+class FacadeExample:
+    def __init__(self, bkpt, extra_args, dict):
+        self.bkpt = bkpt
+        self.extra_args = extra_args
+        self.base_sym = None
+        self.facade_locs = []
+        self.facade_locs_desc = []
+        self.cur_facade_loc = 1
+
+        self.sym_name = extra_args.GetValueForKey("symbol").GetStringValue(100)
+        self.num_locs = extra_args.GetValueForKey("num_locs").GetIntegerValue(5)
+        self.loc_to_miss = extra_args.GetValueForKey("loc_to_miss").GetIntegerValue(10000)
+
+    def __callback__(self, sym_ctx):
+        self.base_sym = sym_ctx.module.FindSymbol(self.sym_name, lldb.eSymbolTypeCode)
+        if self.base_sym.IsValid():
+            self.bkpt.AddLocation(self.base_sym.GetStartAddress())
+            # Locations are 1 based, so to keep things simple, I'm making
+            # the array holding locations 1 based as well:
+            self.facade_locs_desc.append("This is the zero index, you shouldn't see this")
+            self.facade_locs.append(None)
+            for i in range(1, self.num_locs + 1):
+                self.facade_locs_desc.append(f"Location index: {i}")
+                self.facade_locs.append(self.bkpt.AddFacadeLocation())
+                
+    def get_short_help(self):
+        return f"I am a facade resolver - sym: {self.sym_name} - num_locs: {self.num_locs} - locs_to_miss: {self.loc_to_miss}"
+
+    def was_hit(self, frame, bp_loc):
+        tmp_loc = self.cur_facade_loc
+
+        self.cur_facade_loc = (self.cur_facade_loc + 1)
+        if self.cur_facade_loc == 5:
+          self.cur_facade_loc = 1
+
+        if tmp_loc == self.loc_to_miss:
+            return None
+
+        return self.facade_locs[tmp_loc]
+
+    def get_location_description(self, bp_loc, desc_level):
+        return self.facade_locs_desc[bp_loc.id]
+
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c
new file mode 100644
index 0000000000000..762553109f7f7
--- /dev/null
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c
@@ -0,0 +1,17 @@
+#include <stdio.h>
+
+int
+stop_symbol() {
+  static int s_cnt = 0;
+  printf("I am in the stop symbol: %d\n", s_cnt++);
+  return s_cnt;
+}
+
+int
+main()
+{
+  for (int i = 0; i < 100; i++) {
+    stop_symbol();
+  }
+  return 0;
+}
diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
index 068860ebc20f1..6f5d9fd97ee28 100644
--- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
+++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp
@@ -105,6 +105,11 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(
   return nullptr;
 }
 
+void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(
+    PyObject *data) {
+  return nullptr;
+}
+
 void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBAttachInfo(
     PyObject *data) {
   return nullptr;
@@ -130,6 +135,11 @@ lldb_private::python::LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data) {
   return nullptr;
 }
 
+void *
+lldb_private::python::LLDBSWIGPython_CastPyObjectToSBFrame(PyObject *data) {
+  return nullptr;
+}
+
 void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBSymbolContext(
     PyObject *data) {
   return nullptr;

>From 5001e68b96beae7596b2100bf275dac4eaa5d990 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Thu, 11 Sep 2025 14:27:21 -0700
Subject: [PATCH 2/2] Formatting.

---
 lldb/include/lldb/API/SBBreakpoint.h          |  7 ++-
 lldb/include/lldb/API/SBBreakpointLocation.h  |  1 +
 lldb/include/lldb/API/SBFrame.h               |  2 +-
 lldb/include/lldb/Breakpoint/Breakpoint.h     | 29 ++++++-----
 .../lldb/Breakpoint/BreakpointLocation.h      | 33 +++++++------
 .../Breakpoint/BreakpointLocationCollection.h |  3 +-
 .../lldb/Breakpoint/BreakpointLocationList.h  |  4 +-
 .../Breakpoint/BreakpointResolverScripted.h   |  9 ++--
 lldb/include/lldb/Breakpoint/BreakpointSite.h |  4 +-
 lldb/include/lldb/Breakpoint/StoppointSite.h  |  8 +--
 .../Interfaces/ScriptedBreakpointInterface.h  | 14 +++---
 .../lldb/Interpreter/ScriptInterpreter.h      |  4 +-
 lldb/source/API/SBBreakpoint.cpp              |  3 +-
 lldb/source/Breakpoint/Breakpoint.cpp         | 34 +++++++------
 lldb/source/Breakpoint/BreakpointLocation.cpp | 40 ++++++++-------
 .../Breakpoint/BreakpointLocationList.cpp     |  6 +--
 .../Breakpoint/BreakpointResolverScripted.cpp |  8 +--
 lldb/source/Breakpoint/BreakpointSite.cpp     |  5 +-
 lldb/source/Interpreter/ScriptInterpreter.cpp |  3 +-
 .../ScriptedBreakpointPythonInterface.cpp     | 16 +++---
 .../ScriptedBreakpointPythonInterface.h       | 12 ++---
 .../Interfaces/ScriptedPythonInterface.cpp    | 40 ++++++++-------
 .../Interfaces/ScriptedPythonInterface.h      |  8 +--
 lldb/source/Target/StopInfo.cpp               | 11 ++---
 .../scripted_bkpt/was_hit/TestWasHit.py       | 49 +++++++++++++------
 .../scripted_bkpt/was_hit/bkpt_resolver.py    | 16 +++---
 .../breakpoint/scripted_bkpt/was_hit/main.c   |  7 +--
 27 files changed, 203 insertions(+), 173 deletions(-)

diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h
index 3bf87a1b7cc92..fe19ba998ea67 100644
--- a/lldb/include/lldb/API/SBBreakpoint.h
+++ b/lldb/include/lldb/API/SBBreakpoint.h
@@ -157,12 +157,11 @@ class LLDB_API SBBreakpoint {
   /// Can only be called from a ScriptedBreakpointResolver...
   SBError
   AddLocation(SBAddress &address);
-  /// Add a "Facade location" to the breakpoint.  This returns the Facade 
-  /// Location that was added, which you can then use in 
+  /// Add a "Facade location" to the breakpoint.  This returns the Facade
+  /// Location that was added, which you can then use in
   /// get_location_description and was_hit in your breakpoint resolver.
   /// Can only be called from a ScriptedBreakpointResolver.
-  SBBreakpointLocation
-  AddFacadeLocation();
+  SBBreakpointLocation AddFacadeLocation();
 
   SBStructuredData SerializeToStructuredData();
 
diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h
index deda4970cd0ed..9b0d4839aca82 100644
--- a/lldb/include/lldb/API/SBBreakpointLocation.h
+++ b/lldb/include/lldb/API/SBBreakpointLocation.h
@@ -25,6 +25,7 @@ namespace lldb {
 
 class LLDB_API SBBreakpointLocation {
   friend class lldb_private::ScriptInterpreter;
+
 public:
   SBBreakpointLocation();
 
diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h
index 4abb44b4bb0e5..92917e57fc125 100644
--- a/lldb/include/lldb/API/SBFrame.h
+++ b/lldb/include/lldb/API/SBFrame.h
@@ -225,7 +225,7 @@ class LLDB_API SBFrame {
   friend class SBInstruction;
   friend class SBThread;
   friend class SBValue;
-  
+
   friend class lldb_private::ScriptInterpreter;
   friend class lldb_private::python::SWIGBridge;
   friend class lldb_private::lua::SWIGBridge;
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
index 2bef6a919d878..bcb5d0ea7622b 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -248,8 +248,8 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   ///    Returns a pointer to the new location.
   lldb::BreakpointLocationSP AddLocation(const Address &addr,
                                          bool *new_location = nullptr);
-  /// Add a `facade` location to the breakpoint's collection of facade locations.  
-  /// This is only meant to be called by the breakpoint's resolver.
+  /// Add a `facade` location to the breakpoint's collection of facade
+  /// locations. This is only meant to be called by the breakpoint's resolver.
   /// Facade locations are placeholders that a scripted breakpoint can use to
   /// represent the stop locations provided by the breakpoint.  The scripted
   /// breakpoint should record the id of the facade location, and provide
@@ -263,7 +263,7 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   /// \return
   ///    Returns a pointer to the new location.
   lldb::BreakpointLocationSP AddFacadeLocation();
-  
+
   lldb::BreakpointLocationSP GetFacadeLocationByID(lldb::break_id_t);
 
   /// Find a breakpoint location by Address.
@@ -293,14 +293,15 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   ///    The ID specifying the location.
   ///
   /// \param[in] use_facade
-  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  /// If \b true, then prefer facade locations over "real" ones if they exist.
   ///
   /// \return
   ///    Returns a shared pointer to the location with ID \a bp_loc_id.  The
   ///    pointer
   ///    in the shared pointer will be nullptr if there is no location with that
   ///    ID.
-  lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id, bool use_facade = true);
+  lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id,
+                                              bool use_facade = true);
 
   /// Get breakpoint locations by index.
   ///
@@ -308,13 +309,14 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   ///    The location index.
   ///
   /// \param[in] use_facade
-  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  /// If \b true, then prefer facade locations over "real" ones if they exist.
   ///
   /// \return
   ///     Returns a shared pointer to the location with index \a
   ///     index. The shared pointer might contain nullptr if \a index is
   ///     greater than then number of actual locations.
-  lldb::BreakpointLocationSP GetLocationAtIndex(size_t index, bool use_facade = true);
+  lldb::BreakpointLocationSP GetLocationAtIndex(size_t index,
+                                                bool use_facade = true);
 
   /// Removes all invalid breakpoint locations.
   ///
@@ -436,7 +438,7 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   /// breakpoint sites.
   ///
   /// \param[in] use_facade
-  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  /// If \b true, then prefer facade locations over "real" ones if they exist.
   ///
   /// \return
   ///     The number locations resolved breakpoint sites.
@@ -451,7 +453,7 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
   /// Return the number of breakpoint locations.
   ///
   /// \param[in] use_facade
-  /// If \b true, then prefer facade locations over "real" ones if they exist.  
+  /// If \b true, then prefer facade locations over "real" ones if they exist.
   ///
   /// \return
   ///     The number breakpoint locations.
@@ -563,17 +565,14 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
 
   enum TypeDisplay {
     eDisplayFacade = 1,
-    eDisplayReal   = 1 << 1,
+    eDisplayReal = 1 << 1,
     eDisplayHeader = 1 << 2
   };
 
   void GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
-                      uint8_t display_type, bool show_locations);
-                      
-  bool HasFacadeLocations() {
-    return m_facade_locations.GetSize() != 0;
-  }
+                             uint8_t display_type, bool show_locations);
 
+  bool HasFacadeLocations() { return m_facade_locations.GetSize() != 0; }
 
 public:
   bool MatchesName(const char *name) {
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
index c4fa9bec51aae..6557a23a47911 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocation.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocation.h
@@ -62,17 +62,17 @@ class BreakpointLocation
   Target &GetTarget();
 
   /// This is a programmatic version of a breakpoint "condition".  When a
-  /// breakpoint is hit, WasHit will get called before the synchronous ShouldStop
-  /// callback is run, and if it returns an empty BreakpointLocationSP, lldb will
-  /// act as if that breakpoint wasn't hit.
+  /// breakpoint is hit, WasHit will get called before the synchronous
+  /// ShouldStop callback is run, and if it returns an empty
+  /// BreakpointLocationSP, lldb will act as if that breakpoint wasn't hit.
   ///
   /// \param[in] context
   ///   The context at the stop point
-  ///    
+  ///
   /// \return
   ///    This will return the breakpoint location that was hit on this stop.
   ///    If there was no facade location this will be the original location.
-  ///    If the shared pointer is empty, then we'll treat it as if the 
+  ///    If the shared pointer is empty, then we'll treat it as if the
   ///    breakpoint was not hit.
   lldb::BreakpointLocationSP WasHit(StoppointCallbackContext *context);
 
@@ -84,16 +84,16 @@ class BreakpointLocation
   ///
   /// \param[in] context
   ///   The context at the stop point
-  ///    
+  ///
   /// \param[out] facade_loc_sp
   ///   If this stop should be attributed not to the location that was hit, but
   ///   to a facade location, it will be returned in this facade_loc_sp.
-  ///    
+  ///
   /// \return
   ///     \b true if this breakpoint location thinks we should stop,
   ///     \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, 
-          lldb::BreakpointLocationSP &facade_loc_sp);
+  bool ShouldStop(StoppointCallbackContext *context,
+                  lldb::BreakpointLocationSP &facade_loc_sp);
 
   // The next section deals with various breakpoint options.
 
@@ -373,7 +373,7 @@ class BreakpointLocation
   /// Constructor.
   ///
   /// \param[in] loc_id
-  ///     The location id of the new location. 
+  ///     The location id of the new location.
   ///
   /// \param[in] owner
   ///     A back pointer to the breakpoint that owns this location.
@@ -390,10 +390,10 @@ class BreakpointLocation
                      bool check_for_resolver = true);
 
   /// This is the constructor for locations with no address.  Currently this is
-  /// just used for Facade locations. 
+  /// just used for Facade locations.
   ///
   /// \param[in] loc_id
-  ///     The location id of the new location. 
+  ///     The location id of the new location.
   ///
   /// \param[in] owner
   ///     A back pointer to the breakpoint that owns this location.
@@ -403,6 +403,7 @@ class BreakpointLocation
   BreakpointLocation(lldb::break_id_t loc_id, Breakpoint &owner);
   bool IsValid() const { return m_is_valid; }
   bool IsFacade() const { return m_is_facade; }
+
 private:
   // Data members:
   bool m_should_resolve_indirect_functions;
@@ -431,10 +432,10 @@ class BreakpointLocation
   /// location was given somewhere in the virtual inlined call stack since the
   /// Address always resolves to the lowest entry in the stack.
   std::optional<LineEntry> m_preferred_line_entry;
-  bool m_is_valid = true;  /// Because Facade locations don't have sites
-                           /// we can't use the presence of the site to mean
-                           /// this breakpoint is valid, but must manage
-                           /// the state directly.
+  bool m_is_valid = true;   /// Because Facade locations don't have sites
+                            /// we can't use the presence of the site to mean
+                            /// this breakpoint is valid, but must manage
+                            /// the state directly.
   bool m_is_facade = false; /// Facade locations aren't directly triggered
                             /// and don't have a breakpoint site.  They are
                             /// a useful fiction when you want to represent
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
index 8ef13d304d044..1df4e074680f5 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h
@@ -111,7 +111,8 @@ class BreakpointLocationCollection {
   ///
   /// \return
   ///    \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, BreakpointLocationCollection &stopped_bp_locs);
+  bool ShouldStop(StoppointCallbackContext *context,
+                  BreakpointLocationCollection &stopped_bp_locs);
 
   /// Print a description of the breakpoint locations in this list
   /// to the stream \a s.
diff --git a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
index 8c8309b731b6b..952db559d6cc7 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointLocationList.h
@@ -140,8 +140,8 @@ class BreakpointLocationList {
   ///
   /// \return
   ///     \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID, 
-      lldb::BreakpointLocationSP &bp_loc_sp);
+  bool ShouldStop(StoppointCallbackContext *context, lldb::break_id_t breakID,
+                  lldb::BreakpointLocationSP &bp_loc_sp);
 
   /// Returns the number of elements in this breakpoint location list.
   ///
diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
index 7e747ab0bdc1f..c3c1c80f49043 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h
@@ -45,11 +45,12 @@ class BreakpointResolverScripted : public BreakpointResolver {
 
   void GetDescription(Stream *s) override;
 
-  lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
+  lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp,
                                     lldb::BreakpointLocationSP bp_loc_sp);
-  
-  std::optional<std::string> GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp,
-      lldb::DescriptionLevel level);
+
+  std::optional<std::string>
+  GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp,
+                         lldb::DescriptionLevel level);
 
   void Dump(Stream *s) const override;
 
diff --git a/lldb/include/lldb/Breakpoint/BreakpointSite.h b/lldb/include/lldb/Breakpoint/BreakpointSite.h
index 75b5ed9f4f531..a935b2441c02a 100644
--- a/lldb/include/lldb/Breakpoint/BreakpointSite.h
+++ b/lldb/include/lldb/Breakpoint/BreakpointSite.h
@@ -99,8 +99,8 @@ class BreakpointSite : public std::enable_shared_from_this<BreakpointSite>,
   ///
   /// \return
   ///    \b true if we should stop, \b false otherwise.
-  bool ShouldStop(StoppointCallbackContext *context, 
-          BreakpointLocationCollection &stopping_bp_loc) override;
+  bool ShouldStop(StoppointCallbackContext *context,
+                  BreakpointLocationCollection &stopping_bp_loc) override;
 
   /// Standard Dump method
   void Dump(Stream *s) const override;
diff --git a/lldb/include/lldb/Breakpoint/StoppointSite.h b/lldb/include/lldb/Breakpoint/StoppointSite.h
index a398aa838596c..2ceac403940ef 100644
--- a/lldb/include/lldb/Breakpoint/StoppointSite.h
+++ b/lldb/include/lldb/Breakpoint/StoppointSite.h
@@ -38,10 +38,12 @@ class StoppointSite {
 
   virtual bool IsHardware() const = 0;
 
-  virtual bool ShouldStop(StoppointCallbackContext* context) { return false; };
+  virtual bool ShouldStop(StoppointCallbackContext *context) { return false; };
 
-  virtual bool ShouldStop(StoppointCallbackContext* context,
-          BreakpointLocationCollection &stopping_bp_locs) { return false; };
+  virtual bool ShouldStop(StoppointCallbackContext *context,
+                          BreakpointLocationCollection &stopping_bp_locs) {
+    return false;
+  };
 
   virtual void Dump(Stream* stream) const = 0;
 
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
index c203e7f15d279..d29fd8126e0cc 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h
@@ -27,14 +27,14 @@ class ScriptedBreakpointInterface : public ScriptedInterface {
   virtual lldb::SearchDepth GetDepth() { return lldb::eSearchDepthModule; }
   virtual std::optional<std::string> GetShortHelp() { return nullptr; }
   /// WasHit returns the breakpoint location SP for the location that was "hit".
-  virtual lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
-                          lldb::BreakpointLocationSP bp_loc_sp) { 
-      return LLDB_INVALID_BREAK_ID;
+  virtual lldb::BreakpointLocationSP
+  WasHit(lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
+    return LLDB_INVALID_BREAK_ID;
   }
-  virtual std::optional<std::string> 
-      GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp, 
-                             lldb::DescriptionLevel level) { 
-      return {};
+  virtual std::optional<std::string>
+  GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp,
+                         lldb::DescriptionLevel level) {
+    return {};
   }
 };
 } // namespace lldb_private
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index 554f8128344d9..6c0054a1ec1d1 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -581,8 +581,8 @@ class ScriptInterpreter : public PluginInterface {
   lldb::BreakpointSP
   GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const;
 
-  lldb::BreakpointLocationSP
-  GetOpaqueTypeFromSBBreakpointLocation(const lldb::SBBreakpointLocation &break_loc) const;
+  lldb::BreakpointLocationSP GetOpaqueTypeFromSBBreakpointLocation(
+      const lldb::SBBreakpointLocation &break_loc) const;
 
   lldb::ProcessAttachInfoSP
   GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo &attach_info) const;
diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp
index 93748dd46f69c..3777cfc7a61b3 100644
--- a/lldb/source/API/SBBreakpoint.cpp
+++ b/lldb/source/API/SBBreakpoint.cpp
@@ -567,8 +567,7 @@ SBError SBBreakpoint::AddLocation(SBAddress &address) {
   return error;
 }
 
-SBBreakpointLocation
-SBBreakpoint::AddFacadeLocation() {
+SBBreakpointLocation SBBreakpoint::AddFacadeLocation() {
   BreakpointSP bkpt_sp = GetSP();
   if (!bkpt_sp) {
     return {};
diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp
index d6d2f8aa17c19..b665bfc4c47b9 100644
--- a/lldb/source/Breakpoint/Breakpoint.cpp
+++ b/lldb/source/Breakpoint/Breakpoint.cpp
@@ -61,7 +61,8 @@ Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp)
 Breakpoint::~Breakpoint() {
   for (BreakpointLocationSP location_sp : m_locations.BreakpointLocations())
     location_sp->SetInvalid();
-  for (BreakpointLocationSP location_sp : m_facade_locations.BreakpointLocations())
+  for (BreakpointLocationSP location_sp :
+       m_facade_locations.BreakpointLocations())
     location_sp->SetInvalid();
 }
 
@@ -309,14 +310,15 @@ BreakpointLocationSP Breakpoint::AddLocation(const Address &addr,
 
 BreakpointLocationSP Breakpoint::AddFacadeLocation() {
   size_t next_id = m_facade_locations.GetSize() + 1;
-  BreakpointLocationSP break_loc_sp 
-      = std::make_shared<BreakpointLocation>(next_id, *this);
+  BreakpointLocationSP break_loc_sp =
+      std::make_shared<BreakpointLocation>(next_id, *this);
   break_loc_sp->m_is_facade = true;
   m_facade_locations.Add(break_loc_sp);
   return break_loc_sp;
 }
 
-BreakpointLocationSP Breakpoint::GetFacadeLocationByID(lldb::break_id_t loc_id) {
+BreakpointLocationSP
+Breakpoint::GetFacadeLocationByID(lldb::break_id_t loc_id) {
   return m_facade_locations.GetByIndex(loc_id - 1);
 }
 
@@ -328,13 +330,15 @@ break_id_t Breakpoint::FindLocationIDByAddress(const Address &addr) {
   return m_locations.FindIDByAddress(addr);
 }
 
-BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id, bool use_facade) {
+BreakpointLocationSP Breakpoint::FindLocationByID(break_id_t bp_loc_id,
+                                                  bool use_facade) {
   if (use_facade && m_facade_locations.GetSize())
     return GetFacadeLocationByID(bp_loc_id);
   return m_locations.FindByID(bp_loc_id);
 }
 
-BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index, bool use_facade) {
+BreakpointLocationSP Breakpoint::GetLocationAtIndex(size_t index,
+                                                    bool use_facade) {
   if (use_facade && m_facade_locations.GetSize() > 0)
     return m_facade_locations.GetByIndex(index);
   return m_locations.GetByIndex(index);
@@ -904,13 +908,13 @@ bool Breakpoint::HasResolvedLocations() const {
   return GetNumResolvedLocations() > 0;
 }
 
-size_t Breakpoint::GetNumLocations(bool use_facade) const { 
+size_t Breakpoint::GetNumLocations(bool use_facade) const {
   if (use_facade) {
     size_t num_facade_locs = m_facade_locations.GetSize();
     if (num_facade_locs > 0)
       return num_facade_locs;
   }
-  return m_locations.GetSize(); 
+  return m_locations.GetSize();
 }
 
 void Breakpoint::AddName(llvm::StringRef new_name) {
@@ -936,14 +940,14 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
     s->Printf("Kind: %s\n", GetBreakpointKind());
   }
 
-  bool show_both_types = level == eDescriptionLevelVerbose 
-    && HasFacadeLocations() && show_locations;
+  bool show_both_types = level == eDescriptionLevelVerbose &&
+                         HasFacadeLocations() && show_locations;
   uint8_t display_mask = eDisplayFacade;
   if (show_both_types)
     display_mask |= eDisplayHeader;
-    
+
   GetDescriptionForType(s, level, display_mask, show_locations);
-  
+
   if (show_both_types) {
     display_mask = eDisplayReal | eDisplayHeader;
     GetDescriptionForType(s, level, display_mask, show_locations);
@@ -954,9 +958,10 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level,
                         GetTarget().GetDebugger().GetDisabledAnsiSuffix())
                         .c_str());
 }
-  
+
 void Breakpoint::GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
-                                       uint8_t display_type, bool show_locations) {
+                                       uint8_t display_type,
+                                       bool show_locations) {
   bool use_facade = (display_type & eDisplayFacade) != 0;
   const size_t num_locations = GetNumLocations(use_facade);
   const size_t num_resolved_locations = GetNumResolvedLocations(use_facade);
@@ -1052,7 +1057,6 @@ void Breakpoint::GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
     }
     s->IndentLess();
   }
-
 }
 
 void Breakpoint::GetResolverDescription(Stream *s) {
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 829ed03392999..2505fb26e8d45 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -381,11 +381,12 @@ bool BreakpointLocation::ValidForThisThread(Thread &thread) {
           .GetThreadSpecNoCreate());
 }
 
-BreakpointLocationSP BreakpointLocation::WasHit(StoppointCallbackContext *context)
-{
+BreakpointLocationSP
+BreakpointLocation::WasHit(StoppointCallbackContext *context) {
   // Only the BreakpointResolverScripted provides WasHit.
   BreakpointResolverSP resolver_sp = GetBreakpoint().GetResolver();
-  BreakpointResolverScripted *scripted = llvm::dyn_cast<BreakpointResolverScripted>(resolver_sp.get());
+  BreakpointResolverScripted *scripted =
+      llvm::dyn_cast<BreakpointResolverScripted>(resolver_sp.get());
   if (!scripted)
     return shared_from_this();
 
@@ -393,7 +394,8 @@ BreakpointLocationSP BreakpointLocation::WasHit(StoppointCallbackContext *contex
   if (!frame_sp)
     return shared_from_this();
 
-  BreakpointLocationSP return_loc_sp = scripted->WasHit(frame_sp, shared_from_this());
+  BreakpointLocationSP return_loc_sp =
+      scripted->WasHit(frame_sp, shared_from_this());
   // If this is a facade location, then we won't have bumped its hit count
   // while processing the original location hit.  Do so here.  We don't need
   // to bump the breakpoint's hit count, however, since hitting the real
@@ -401,10 +403,10 @@ BreakpointLocationSP BreakpointLocation::WasHit(StoppointCallbackContext *contex
   // Also we have to check the enabled state here, since we would never have
   // gotten here with a real location...
   if (return_loc_sp && return_loc_sp->IsFacade()) {
-     if (return_loc_sp->IsEnabled())
-       return_loc_sp->m_hit_counter.Increment();
-     else
-       return {};
+    if (return_loc_sp->IsEnabled())
+      return_loc_sp->m_hit_counter.Increment();
+    else
+      return {};
   }
   return return_loc_sp;
 }
@@ -414,8 +416,8 @@ BreakpointLocationSP BreakpointLocation::WasHit(StoppointCallbackContext *contex
 // here, since if the breakpoint is not for this thread, then the event won't
 // even get reported, so the check is redundant.
 
-bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context, 
-        lldb::BreakpointLocationSP &facade_loc_sp) {
+bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context,
+                                    lldb::BreakpointLocationSP &facade_loc_sp) {
   bool should_stop = true;
   Log *log = GetLog(LLDBLog::Breakpoints);
 
@@ -426,7 +428,7 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context,
 
   // Next check WasHit:
   BreakpointLocationSP loc_hit_sp = WasHit(context);
-  
+
   if (!loc_hit_sp) {
     // We bump the hit counts in StopInfoBreakpoint::ShouldStopSynchronous,
     // before we call into each location's ShouldStop.  So we need to undo
@@ -434,7 +436,7 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context,
     UndoBumpHitCount();
     return false;
   }
-  
+
   // If the location hit was not us, it was a facade location, in which case
   // we should use the facade location's callbacks, etc.  Those will all be
   // run in the asynchronous phase, so for now we just have to record the fact
@@ -494,7 +496,7 @@ lldb::BreakpointSiteSP BreakpointLocation::GetBreakpointSite() const {
 llvm::Error BreakpointLocation::ResolveBreakpointSite() {
   // This might be a facade location, which doesn't have an address.
   // In that case, don't attempt to make a site.
-  if (m_bp_site_sp  || IsFacade())
+  if (m_bp_site_sp || IsFacade())
     return llvm::Error::success();
 
   Process *process = m_owner.GetTarget().GetProcessSP().get();
@@ -547,15 +549,15 @@ llvm::Error BreakpointLocation::ClearBreakpointSite() {
 void BreakpointLocation::GetDescription(Stream *s,
                                         lldb::DescriptionLevel level) {
   SymbolContext sc;
-  
+
   // If this is a scripted breakpoint, give it a chance to describe its
   // locations:
   std::optional<std::string> scripted_opt;
   BreakpointResolverSP resolver_sp = GetBreakpoint().GetResolver();
-  BreakpointResolverScripted *scripted = 
+  BreakpointResolverScripted *scripted =
       llvm::dyn_cast<BreakpointResolverScripted>(resolver_sp.get());
   if (scripted)
-        scripted_opt = scripted->GetLocationDescription(shared_from_this(), level);
+    scripted_opt = scripted->GetLocationDescription(shared_from_this(), level);
 
   bool is_scripted_desc = scripted_opt.has_value();
 
@@ -694,10 +696,10 @@ void BreakpointLocation::GetDescription(Stream *s,
   // If they don't add any scripted locations, we shouldn't consider them
   // resolved.
   bool is_resolved = is_scripted_desc || IsResolved();
-  // A scripted breakpoint might be resolved but not have a site.  Be sure to 
+  // A scripted breakpoint might be resolved but not have a site.  Be sure to
   // check for that.
-  bool is_hardware = !is_scripted_desc && IsResolved() && m_bp_site_sp 
-      && m_bp_site_sp->IsHardware();
+  bool is_hardware = !is_scripted_desc && IsResolved() && m_bp_site_sp &&
+                     m_bp_site_sp->IsHardware();
 
   if (level == lldb::eDescriptionLevelVerbose) {
     s->EOL();
diff --git a/lldb/source/Breakpoint/BreakpointLocationList.cpp b/lldb/source/Breakpoint/BreakpointLocationList.cpp
index 5a791d4364641..ea431aa3bb953 100644
--- a/lldb/source/Breakpoint/BreakpointLocationList.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocationList.cpp
@@ -32,9 +32,9 @@ BreakpointLocationList::Create(const Address &addr,
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
   // The location ID is just the size of the location list + 1
   lldb::break_id_t bp_loc_id = ++m_next_id;
-  BreakpointLocationSP bp_loc_sp(new 
-      BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, 
-      resolve_indirect_symbols));
+  BreakpointLocationSP bp_loc_sp(
+      new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
+                             resolve_indirect_symbols));
   m_locations.push_back(bp_loc_sp);
   m_address_to_location[addr] = bp_loc_sp;
   return bp_loc_sp;
diff --git a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
index b1e45d761735b..a4969a07b396b 100644
--- a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
+++ b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp
@@ -160,17 +160,17 @@ void BreakpointResolverScripted::GetDescription(Stream *s) {
     s->Printf("python class = %s", m_class_name.c_str());
 }
 
-std::optional<std::string> 
-BreakpointResolverScripted::GetLocationDescription(
+std::optional<std::string> BreakpointResolverScripted::GetLocationDescription(
     lldb::BreakpointLocationSP bp_loc_sp, lldb::DescriptionLevel level) {
   CreateImplementationIfNeeded(GetBreakpoint());
-  if (m_interface_sp) 
+  if (m_interface_sp)
     return m_interface_sp->GetLocationDescription(bp_loc_sp, level);
   return {};
 }
 
 lldb::BreakpointLocationSP
-BreakpointResolverScripted::WasHit(lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
+BreakpointResolverScripted::WasHit(lldb::StackFrameSP frame_sp,
+                                   lldb::BreakpointLocationSP bp_loc_sp) {
   if (m_interface_sp)
     return m_interface_sp->WasHit(frame_sp, bp_loc_sp);
 
diff --git a/lldb/source/Breakpoint/BreakpointSite.cpp b/lldb/source/Breakpoint/BreakpointSite.cpp
index 52100b91de09c..fd7666be6b1bf 100644
--- a/lldb/source/Breakpoint/BreakpointSite.cpp
+++ b/lldb/source/Breakpoint/BreakpointSite.cpp
@@ -45,8 +45,9 @@ break_id_t BreakpointSite::GetNextID() {
 // RETURNS - true if we should stop at this breakpoint, false if we
 // should continue.
 
-bool BreakpointSite::ShouldStop(StoppointCallbackContext *context,
-        BreakpointLocationCollection &stopping_bp_locs) {
+bool BreakpointSite::ShouldStop(
+    StoppointCallbackContext *context,
+    BreakpointLocationCollection &stopping_bp_locs) {
   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
diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp
index 51475db27269b..b5ad85d265314 100644
--- a/lldb/source/Interpreter/ScriptInterpreter.cpp
+++ b/lldb/source/Interpreter/ScriptInterpreter.cpp
@@ -81,7 +81,8 @@ lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
   return breakpoint.m_opaque_wp.lock();
 }
 
-lldb::BreakpointLocationSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpointLocation(
+lldb::BreakpointLocationSP
+ScriptInterpreter::GetOpaqueTypeFromSBBreakpointLocation(
     const lldb::SBBreakpointLocation &break_loc) const {
   return break_loc.m_opaque_wp.lock();
 }
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
index 0c6d23b108fa1..c9bb38d213c99 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
@@ -81,11 +81,11 @@ std::optional<std::string> ScriptedBreakpointPythonInterface::GetShortHelp() {
   return obj->GetAsString()->GetValue().str();
 }
 
-lldb::BreakpointLocationSP
-ScriptedBreakpointPythonInterface::WasHit(lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
+lldb::BreakpointLocationSP ScriptedBreakpointPythonInterface::WasHit(
+    lldb::StackFrameSP frame_sp, lldb::BreakpointLocationSP bp_loc_sp) {
   Status py_error;
-  lldb::BreakpointLocationSP loc_sp 
-    = Dispatch<lldb::BreakpointLocationSP>("was_hit", py_error, frame_sp, bp_loc_sp);
+  lldb::BreakpointLocationSP loc_sp = Dispatch<lldb::BreakpointLocationSP>(
+      "was_hit", py_error, frame_sp, bp_loc_sp);
 
   if (py_error.Fail())
     return bp_loc_sp;
@@ -93,12 +93,12 @@ ScriptedBreakpointPythonInterface::WasHit(lldb::StackFrameSP frame_sp, lldb::Bre
   return loc_sp;
 }
 
-std::optional<std::string> 
+std::optional<std::string>
 ScriptedBreakpointPythonInterface::GetLocationDescription(
-    lldb::BreakpointLocationSP bp_loc_sp, 
-    lldb::DescriptionLevel level) {
+    lldb::BreakpointLocationSP bp_loc_sp, lldb::DescriptionLevel level) {
   Status error;
-  StructuredData::ObjectSP obj = Dispatch("get_location_description", error, bp_loc_sp, level);
+  StructuredData::ObjectSP obj =
+      Dispatch("get_location_description", error, bp_loc_sp, level);
 
   if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
                                                     error))
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
index b8c1219279876..72da0a195ee01 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
@@ -36,12 +36,12 @@ class ScriptedBreakpointPythonInterface : public ScriptedBreakpointInterface,
   bool ResolverCallback(SymbolContext sym_ctx) override;
   lldb::SearchDepth GetDepth() override;
   std::optional<std::string> GetShortHelp() override;
-  lldb::BreakpointLocationSP WasHit(lldb::StackFrameSP frame_sp, 
-                  lldb::BreakpointLocationSP bp_loc_sp) override;
-  virtual std::optional<std::string> 
-      GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp, 
-                             lldb::DescriptionLevel level) override;
-
+  lldb::BreakpointLocationSP
+  WasHit(lldb::StackFrameSP frame_sp,
+         lldb::BreakpointLocationSP bp_loc_sp) override;
+  virtual std::optional<std::string>
+  GetLocationDescription(lldb::BreakpointLocationSP bp_loc_sp,
+                         lldb::DescriptionLevel level) override;
 
   static void Initialize();
 
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index cda8185ef0a17..4fdf2b12a5500 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -141,14 +141,16 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
 
 template <>
 lldb::BreakpointLocationSP
-ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointLocationSP>(
-    python::PythonObject &p, Status &error) {
-  lldb::SBBreakpointLocation *sb_break_loc = reinterpret_cast<lldb::SBBreakpointLocation *>(
-      python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(p.get()));
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    lldb::BreakpointLocationSP>(python::PythonObject &p, Status &error) {
+  lldb::SBBreakpointLocation *sb_break_loc =
+      reinterpret_cast<lldb::SBBreakpointLocation *>(
+          python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(p.get()));
 
   if (!sb_break_loc) {
     error = Status::FromErrorStringWithFormat(
-        "Couldn't cast lldb::SBBreakpointLocation to lldb::BreakpointLocationSP.");
+        "Couldn't cast lldb::SBBreakpointLocation to "
+        "lldb::BreakpointLocationSP.");
     return nullptr;
   }
 
@@ -225,20 +227,20 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
 
 template <>
 lldb::DescriptionLevel
-ScriptedPythonInterface::ExtractValueFromPythonObject<
-    lldb::DescriptionLevel>(python::PythonObject &p, Status &error) {
-    lldb::DescriptionLevel ret_val = lldb::eDescriptionLevelBrief;
-    llvm::Expected<unsigned long long> unsigned_or_err = p.AsUnsignedLongLong();
-    if (!unsigned_or_err) {
-      error = (Status::FromError(unsigned_or_err.takeError()));
-      return ret_val;
-    }
-    unsigned long long unsigned_val = *unsigned_or_err;
-    if (unsigned_val >= lldb::DescriptionLevel::kNumDescriptionLevels) {
-      error = Status("value too large for lldb::DescriptionLevel.");
-      return ret_val;
-    }
-    return static_cast<lldb::DescriptionLevel>(unsigned_val);
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
+    python::PythonObject &p, Status &error) {
+  lldb::DescriptionLevel ret_val = lldb::eDescriptionLevelBrief;
+  llvm::Expected<unsigned long long> unsigned_or_err = p.AsUnsignedLongLong();
+  if (!unsigned_or_err) {
+    error = (Status::FromError(unsigned_or_err.takeError()));
+    return ret_val;
+  }
+  unsigned long long unsigned_val = *unsigned_or_err;
+  if (unsigned_val >= lldb::DescriptionLevel::kNumDescriptionLevels) {
+    error = Status("value too large for lldb::DescriptionLevel.");
+    return ret_val;
+  }
+  return static_cast<lldb::DescriptionLevel>(unsigned_val);
 }
 
 #endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
index 57d22d44e565e..2335b2ef0f171 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
@@ -597,8 +597,8 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>(
 
 template <>
 lldb::BreakpointLocationSP
-ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointLocationSP>(
-    python::PythonObject &p, Status &error);
+ScriptedPythonInterface::ExtractValueFromPythonObject<
+    lldb::BreakpointLocationSP>(python::PythonObject &p, Status &error);
 
 template <>
 lldb::ProcessAttachInfoSP ScriptedPythonInterface::ExtractValueFromPythonObject<
@@ -625,8 +625,8 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
 
 template <>
 lldb::DescriptionLevel
-ScriptedPythonInterface::ExtractValueFromPythonObject<
-    lldb::DescriptionLevel>(python::PythonObject &p, Status &error);
+ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DescriptionLevel>(
+    python::PythonObject &p, Status &error);
 
 } // namespace lldb_private
 
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index b864159ba7471..7fa1fc5d71f13 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -157,7 +157,8 @@ class StopInfoBreakpoint : public StopInfo {
           ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
           StoppointCallbackContext context(event_ptr, exe_ctx, true);
           bp_site_sp->BumpHitCounts();
-          m_should_stop = bp_site_sp->ShouldStop(&context, m_async_stopped_locs);
+          m_should_stop =
+              bp_site_sp->ShouldStop(&context, m_async_stopped_locs);
         } else {
           Log *log = GetLog(LLDBLog::Process);
 
@@ -345,8 +346,7 @@ class StopInfoBreakpoint : public StopInfo {
         // 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_constituents =
-            m_async_stopped_locs.GetSize();
+        size_t num_constituents = m_async_stopped_locs.GetSize();
 
         if (num_constituents == 0) {
           m_should_stop = true;
@@ -445,7 +445,7 @@ class StopInfoBreakpoint : public StopInfo {
           // 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.
-          
+
           // We are holding onto the breakpoint locations that were hit
           // by this stop info between the "synchonous" ShouldStop and now.
           // But an intervening action might have deleted one of the breakpoints
@@ -465,8 +465,7 @@ class StopInfoBreakpoint : public StopInfo {
 
           size_t num_valid_locs = valid_locs.GetSize();
           for (size_t j = 0; j < num_valid_locs; j++) {
-            lldb::BreakpointLocationSP bp_loc_sp 
-                = valid_locs.GetByIndex(j);
+            lldb::BreakpointLocationSP bp_loc_sp = valid_locs.GetByIndex(j);
             StreamString loc_desc;
             if (log) {
               bp_loc_sp->GetDescription(&loc_desc, eDescriptionLevelBrief);
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
index de178f5b04fc7..2e176239facf0 100644
--- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py
@@ -33,7 +33,7 @@ def import_resolver_script(self):
         self.runCmd(command)
 
     def make_extra_args(self, sym_name, num_locs, loc_to_miss):
-        return f' -k symbol -v {sym_name} -k num_locs -v {num_locs} -k loc_to_miss -v {loc_to_miss} '
+        return f" -k symbol -v {sym_name} -k num_locs -v {num_locs} -k loc_to_miss -v {loc_to_miss} "
 
     def do_test(self):
         """This reads in a python file and sets a breakpoint using it."""
@@ -41,7 +41,9 @@ def do_test(self):
         target = self.make_target_and_import()
         extra_args = self.make_extra_args("stop_symbol", 4, 2)
 
-        bkpt_no = lldbutil.run_break_set_by_script(self, "bkpt_resolver.FacadeExample", extra_args, 4)
+        bkpt_no = lldbutil.run_break_set_by_script(
+            self, "bkpt_resolver.FacadeExample", extra_args, 4
+        )
 
         # Make sure the help text shows up in the "break list" output:
         self.expect(
@@ -52,34 +54,49 @@ def do_test(self):
 
         bkpt = target.FindBreakpointByID(bkpt_no)
         self.assertTrue(bkpt.IsValid(), "Found the right breakpoint")
-        
+
         # Now continue.  We should hit locations 1, 3 and 4:
-        (target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run(self, target, bkpt)
+        (target, process, thread, bkpt) = lldbutil.run_to_breakpoint_do_run(
+            self, target, bkpt
+        )
         # This location should be bkpt_no.1:
-        self.assertEqual(thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint")
+        self.assertEqual(
+            thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint"
+        )
         self.assertEqual(thread.stop_reason_data[1], 1, "First location hit is 1")
 
         for loc in [3, 4]:
             process.Continue()
-            self.assertEqual(thread.stop_reason, lldb.eStopReasonBreakpoint, "Hit breakpoint")
-            self.assertEqual(thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint")
-            self.assertEqual(thread.stop_reason_data[1], loc, f"Hit the right location: {loc}")
+            self.assertEqual(
+                thread.stop_reason, lldb.eStopReasonBreakpoint, "Hit breakpoint"
+            )
+            self.assertEqual(
+                thread.stop_reason_data[0], bkpt_no, "Hit the right breakpoint"
+            )
+            self.assertEqual(
+                thread.stop_reason_data[1], loc, f"Hit the right location: {loc}"
+            )
 
         # At this point we should have hit three of the four locations, and not location 1.2.
         # Check that that is true, and that the descriptions for the location are the ones
         # the resolver provided.
         self.assertEqual(bkpt.hit_count, 3, "Hit three locations")
-        for loc_id in range(1,4):
+        for loc_id in range(1, 4):
             bkpt_loc = bkpt.FindLocationByID(loc_id)
             self.assertTrue(bkpt_loc.IsValid(), f"{loc_id} was invalid.")
             if loc_id != 2:
-                self.assertEqual(bkpt_loc.hit_count, 1, f"Loc {loc_id} hit count was wrong")
+                self.assertEqual(
+                    bkpt_loc.hit_count, 1, f"Loc {loc_id} hit count was wrong"
+                )
             else:
                 self.assertEqual(bkpt_loc.hit_count, 0, "We didn't skip loc 2")
             stream = lldb.SBStream()
-            self.assertTrue(bkpt_loc.GetDescription(stream, lldb.eDescriptionLevelFull),
-                            f"Didn't get description for {loc_id}")
-            self.assertIn(f"Location index: {loc_id}", stream.GetData(),
-                             f"Wrong desciption for {loc_id}")
-
-                            
+            self.assertTrue(
+                bkpt_loc.GetDescription(stream, lldb.eDescriptionLevelFull),
+                f"Didn't get description for {loc_id}",
+            )
+            self.assertIn(
+                f"Location index: {loc_id}",
+                stream.GetData(),
+                f"Wrong desciption for {loc_id}",
+            )
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
index 004ee18513f2f..b8cc3fb8eb07e 100644
--- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py
@@ -1,5 +1,6 @@
 import lldb
 
+
 class FacadeExample:
     def __init__(self, bkpt, extra_args, dict):
         self.bkpt = bkpt
@@ -11,7 +12,9 @@ def __init__(self, bkpt, extra_args, dict):
 
         self.sym_name = extra_args.GetValueForKey("symbol").GetStringValue(100)
         self.num_locs = extra_args.GetValueForKey("num_locs").GetIntegerValue(5)
-        self.loc_to_miss = extra_args.GetValueForKey("loc_to_miss").GetIntegerValue(10000)
+        self.loc_to_miss = extra_args.GetValueForKey("loc_to_miss").GetIntegerValue(
+            10000
+        )
 
     def __callback__(self, sym_ctx):
         self.base_sym = sym_ctx.module.FindSymbol(self.sym_name, lldb.eSymbolTypeCode)
@@ -19,21 +22,23 @@ def __callback__(self, sym_ctx):
             self.bkpt.AddLocation(self.base_sym.GetStartAddress())
             # Locations are 1 based, so to keep things simple, I'm making
             # the array holding locations 1 based as well:
-            self.facade_locs_desc.append("This is the zero index, you shouldn't see this")
+            self.facade_locs_desc.append(
+                "This is the zero index, you shouldn't see this"
+            )
             self.facade_locs.append(None)
             for i in range(1, self.num_locs + 1):
                 self.facade_locs_desc.append(f"Location index: {i}")
                 self.facade_locs.append(self.bkpt.AddFacadeLocation())
-                
+
     def get_short_help(self):
         return f"I am a facade resolver - sym: {self.sym_name} - num_locs: {self.num_locs} - locs_to_miss: {self.loc_to_miss}"
 
     def was_hit(self, frame, bp_loc):
         tmp_loc = self.cur_facade_loc
 
-        self.cur_facade_loc = (self.cur_facade_loc + 1)
+        self.cur_facade_loc = self.cur_facade_loc + 1
         if self.cur_facade_loc == 5:
-          self.cur_facade_loc = 1
+            self.cur_facade_loc = 1
 
         if tmp_loc == self.loc_to_miss:
             return None
@@ -42,4 +47,3 @@ def was_hit(self, frame, bp_loc):
 
     def get_location_description(self, bp_loc, desc_level):
         return self.facade_locs_desc[bp_loc.id]
-
diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c
index 762553109f7f7..b8f977e493513 100644
--- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c
+++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c
@@ -1,15 +1,12 @@
 #include <stdio.h>
 
-int
-stop_symbol() {
+int stop_symbol() {
   static int s_cnt = 0;
   printf("I am in the stop symbol: %d\n", s_cnt++);
   return s_cnt;
 }
 
-int
-main()
-{
+int main() {
   for (int i = 0; i < 100; i++) {
     stop_symbol();
   }



More information about the lldb-commits mailing list