Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/bindings/python/python-swigsafecast.swig
Original file line number Diff line number Diff line change
Expand Up @@ -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
24 changes: 24 additions & 0 deletions lldb/bindings/python/python-wrapper.swig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion lldb/docs/use/python-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ The following tutorials and documentation demonstrate various Python capabilitie
tutorials/writing-custom-commands
tutorials/implementing-standalone-scripts
tutorials/custom-frame-recognizers
tutorials/extending-target-stop-hooks
tutorials/extending-target-stop-hooks
46 changes: 45 additions & 1 deletion lldb/docs/use/tutorials/creating-custom-breakpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,48 @@ you can use for this purpose. Your __init__ function gets passed this
SBStructuredData object. This API also allows you to directly provide the list
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.
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` `bp_loc`:`lldb.SBBreakpointLocation` | This will get called when one of the "real" locations set by your resolver is hit. `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` `desc_level`:`lldb.DescriptionLevel` `bp_loc` is the facade location to describe.| Use this to provide a helpful description of each facade location. ``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`.|

8 changes: 7 additions & 1 deletion lldb/include/lldb/API/SBBreakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,15 @@ 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();

Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/API/SBBreakpointLocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class SWIGBridge;
namespace lldb {

class LLDB_API SBBreakpointLocation {
friend class lldb_private::ScriptInterpreter;

public:
SBBreakpointLocation();

Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/API/SBFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ class LLDB_API SBFrame {
friend class SBThread;
friend class SBValue;

friend class lldb_private::ScriptInterpreter;
friend class lldb_private::python::SWIGBridge;
friend class lldb_private::lua::SWIGBridge;

Expand Down
59 changes: 54 additions & 5 deletions lldb/include/lldb/Breakpoint/Breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -268,27 +285,38 @@ 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.
///
Expand Down Expand Up @@ -409,9 +437,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.
///
Expand All @@ -421,9 +452,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.
///
Expand Down Expand Up @@ -529,6 +563,19 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
m_name_list.erase(name_to_remove);
}

/// This controls whether to display information about
/// the facade locations or the real locations.
enum DisplayType {
eDisplayFacade = 1, // Display facade locations
eDisplayReal = 1 << 1, // Display real locations
eDisplayHeader = 1 << 2 // Display compressed list of locations only
};

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();
Expand Down Expand Up @@ -657,6 +704,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;

Expand Down
Loading
Loading