llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: None (jimingham)

<details>
<summary>Changes</summary>

This patch adds the notion of "Facade" locations which can be reported from a 
ScriptedResolver 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.

I apologize in advance for the size of the patch.  Almost all of what's here 
was necessary to (a) make the feature testable and (b) not break any of the 
current behavior.

The motivation for this feature is given in the "Providing Facade Locations" 
section that I added to the python-reference.rst so I won't repeat it here.

rdar://152112327

---

Patch is 77.02 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/158128.diff


36 Files Affected:

- (modified) lldb/bindings/python/python-swigsafecast.swig (+4) 
- (modified) lldb/bindings/python/python-wrapper.swig (+24) 
- (modified) lldb/docs/use/python-reference.rst (+61) 
- (modified) lldb/include/lldb/API/SBBreakpoint.h (+8-1) 
- (modified) lldb/include/lldb/API/SBBreakpointLocation.h (+1) 
- (modified) lldb/include/lldb/API/SBFrame.h (+2-1) 
- (modified) lldb/include/lldb/Breakpoint/Breakpoint.h (+53-5) 
- (modified) lldb/include/lldb/Breakpoint/BreakpointLocation.h (+60-8) 
- (modified) lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h (+1-1) 
- (modified) lldb/include/lldb/Breakpoint/BreakpointLocationList.h (+2-1) 
- (modified) lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h (+6) 
- (modified) lldb/include/lldb/Breakpoint/BreakpointSite.h (+2-1) 
- (modified) lldb/include/lldb/Breakpoint/StopPointSiteList.h (-24) 
- (modified) lldb/include/lldb/Breakpoint/StoppointSite.h (+4-1) 
- (modified) 
lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h (+10) 
- (modified) lldb/include/lldb/Interpreter/ScriptInterpreter.h (+6) 
- (modified) lldb/source/API/SBBreakpoint.cpp (+10) 
- (modified) lldb/source/Breakpoint/Breakpoint.cpp (+74-14) 
- (modified) lldb/source/Breakpoint/BreakpointLocation.cpp (+136-41) 
- (modified) lldb/source/Breakpoint/BreakpointLocationCollection.cpp (+14-2) 
- (modified) lldb/source/Breakpoint/BreakpointLocationList.cpp (+6-5) 
- (modified) lldb/source/Breakpoint/BreakpointResolverScripted.cpp (+23-1) 
- (modified) lldb/source/Breakpoint/BreakpointSite.cpp (+3-2) 
- (modified) lldb/source/Interpreter/ScriptInterpreter.cpp (+13) 
- (modified) 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp
 (+26) 
- (modified) 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h
 (+6) 
- (modified) 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
 (+47) 
- (modified) 
lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h
 (+27) 
- (modified) lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h 
(+3) 
- (modified) lldb/source/Target/StopInfo.cpp (+47-25) 
- (modified) lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py 
(-1) 
- (added) 
lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/Makefile (+4) 
- (added) 
lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/TestWasHit.py 
(+85) 
- (added) 
lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/bkpt_resolver.py 
(+45) 
- (added) lldb/test/API/functionalities/breakpoint/scripted_bkpt/was_hit/main.c 
(+17) 
- (modified) lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp (+10) 


``````````diff
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 ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/158128
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to