Skip to content

Commit b5a0c08

Browse files
committed
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
1 parent b812e3d commit b5a0c08

36 files changed

+840
-134
lines changed

lldb/bindings/python/python-swigsafecast.swig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,5 +142,9 @@ PythonObject SWIGBridge::ToSWIGWrapper(
142142
return ToSWIGHelper(module_spec_sb.release(), SWIGTYPE_p_lldb__SBModuleSpec);
143143
}
144144

145+
PythonObject SWIGBridge::ToSWIGWrapper(lldb::DescriptionLevel level) {
146+
return PythonInteger((int64_t) level);
147+
}
148+
145149
} // namespace python
146150
} // namespace lldb_private

lldb/bindings/python/python-wrapper.swig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,30 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *
422422
return sb_ptr;
423423
}
424424

425+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBFrame(PyObject * data) {
426+
lldb::SBFrame *sb_ptr = nullptr;
427+
428+
int valid_cast =
429+
SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBFrame, 0);
430+
431+
if (valid_cast == -1)
432+
return NULL;
433+
434+
return sb_ptr;
435+
}
436+
437+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpointLocation(PyObject * data) {
438+
lldb::SBBreakpointLocation *sb_ptr = nullptr;
439+
440+
int valid_cast =
441+
SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBBreakpointLocation, 0);
442+
443+
if (valid_cast == -1)
444+
return NULL;
445+
446+
return sb_ptr;
447+
}
448+
425449
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject * data) {
426450
lldb::SBAttachInfo *sb_ptr = nullptr;
427451

lldb/docs/use/python-reference.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,67 @@ of Modules and the list of CompileUnits that will make up the SearchFilter. If
420420
you pass in empty lists, the breakpoint will use the default "search
421421
everywhere,accept everything" filter.
422422

423+
Providing Facade Locations:
424+
425+
The breakpoint resolver interface also allows you to present a separate set
426+
of locations for the breakpoint than the ones that actually implement the
427+
breakpoint in the target.
428+
429+
An example use case for this is if you are providing a debugging interface for a
430+
library that implements an interpreter for a language lldb can't debug. But
431+
while debugging that library at the level of the implementation language (e.g. C/C++, etc)
432+
you would like to offer the ability to "stop when a line in a source language
433+
file is executed".
434+
435+
You can do this if you know where new lines of code are dispatched in the
436+
interpreter. You would set a breakpoint there, and then look at the state
437+
when that breakpoint is hit to see if it is dispatching the source file and
438+
line that were requested, and stop appropriately.
439+
440+
Facade breakpoint locations are intended to make a more natural presentation
441+
of that sort of feature. The idea is that you would make a custom breakpoint
442+
resolver that sets actual locations in the places of interest in the interpreter.
443+
444+
Then your resolver would add "facade locations" that represent the places in the
445+
interpreted code that you want the breakpoint to stop at, using SBBreakpoint::AddFacadeLocation.
446+
When lldb describes the breakpoint, it will only show the Facade locations.
447+
Since facade breakpoint location's description is customizable, you can make these
448+
locations more descriptive. And when the "real" location is hit, lldb will call the
449+
"was_hit" method of your resolver. That will return the facade location you
450+
consider to have been hit this time around, or if you return None, the breakpoint
451+
will be considered not to have been hit.
452+
453+
Note, this feature is also useful if you don't intend to present facade
454+
locations since it essentially provides a scripted breakpoint condition. Every
455+
time one of the locations in your breakpoint is hit, you can run the code in
456+
your "was_hit" to determine whether to consider the breakpoint hit or not, and
457+
return the location you were passed in if you want it to be a hit, and None if not.
458+
459+
The Facade location adds these optional affordances to the Resolver class:
460+
461+
+------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
462+
| Name | Arguments | Description |
463+
+------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
464+
| ``was_hit`` | ``frame``:`lldb.SBFrame` | This will get called when one of the "real" locations set by your resolver is hit |
465+
| | ``bp_loc``:`lldb.SBBreakpointLocation` | |
466+
| | | |
467+
| | | ``frame`` is the stack frame that hit this location. |
468+
| | | |
469+
| | | |
470+
| | | ``bp_loc`` is the real location that was hit. |
471+
| | | |
472+
| | | Return either the facade location that you want to consider hit on this stop, or None if you don't consider |
473+
| | | any of your facade locations to have been hit. |
474+
+------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
475+
| ``get_location_description`` | ``bp_loc``:`lldb.SBBreakpointLocation` | Use this to provide a helpful description of each facade location. |
476+
| | ``desc_level``:`lldb.DescriptionLevel` | |
477+
| | | ``bp_loc`` is the facade location to describe. |
478+
| | | |
479+
| | | |
480+
| | | ``desc_level`` is the level of description requested. The Brief description is printed when the location is |
481+
| | | hit. Full is printed for `break list` and Verbose for `break list -v`. |
482+
+------------------------------+----------------------------------------+------------------------------------------------------------------------------------------------------------------+
483+
423484
Using the python API' to create custom stepping logic
424485
-----------------------------------------------------
425486

lldb/include/lldb/API/SBBreakpoint.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,16 @@ class LLDB_API SBBreakpoint {
153153
/// fails, e.g. when there aren't enough hardware resources available.
154154
lldb::SBError SetIsHardware(bool is_hardware);
155155

156-
// Can only be called from a ScriptedBreakpointResolver...
156+
/// Adds a location to the breakpoint at the address passed in.
157+
/// Can only be called from a ScriptedBreakpointResolver...
157158
SBError
158159
AddLocation(SBAddress &address);
160+
/// Add a "Facade location" to the breakpoint. This returns the Facade
161+
/// Location that was added, which you can then use in
162+
/// get_location_description and was_hit in your breakpoint resolver.
163+
/// Can only be called from a ScriptedBreakpointResolver.
164+
SBBreakpointLocation
165+
AddFacadeLocation();
159166

160167
SBStructuredData SerializeToStructuredData();
161168

lldb/include/lldb/API/SBBreakpointLocation.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class SWIGBridge;
2424
namespace lldb {
2525

2626
class LLDB_API SBBreakpointLocation {
27+
friend class lldb_private::ScriptInterpreter;
2728
public:
2829
SBBreakpointLocation();
2930

lldb/include/lldb/API/SBFrame.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ class LLDB_API SBFrame {
225225
friend class SBInstruction;
226226
friend class SBThread;
227227
friend class SBValue;
228-
228+
229+
friend class lldb_private::ScriptInterpreter;
229230
friend class lldb_private::python::SWIGBridge;
230231
friend class lldb_private::lua::SWIGBridge;
231232

lldb/include/lldb/Breakpoint/Breakpoint.h

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,23 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
248248
/// Returns a pointer to the new location.
249249
lldb::BreakpointLocationSP AddLocation(const Address &addr,
250250
bool *new_location = nullptr);
251+
/// Add a `facade` location to the breakpoint's collection of facade locations.
252+
/// This is only meant to be called by the breakpoint's resolver.
253+
/// Facade locations are placeholders that a scripted breakpoint can use to
254+
/// represent the stop locations provided by the breakpoint. The scripted
255+
/// breakpoint should record the id of the facade location, and provide
256+
/// the description of the location in the GetDescription method
257+
/// To emulate hitting a facade location, the breakpoint's WasHit should
258+
/// return the ID of the facade that was "hit".
259+
///
260+
/// \param[out] new_location
261+
/// Set to \b true if a new location was created, to \b false if there
262+
/// already was a location at this Address.
263+
/// \return
264+
/// Returns a pointer to the new location.
265+
lldb::BreakpointLocationSP AddFacadeLocation();
266+
267+
lldb::BreakpointLocationSP GetFacadeLocationByID(lldb::break_id_t);
251268

252269
/// Find a breakpoint location by Address.
253270
///
@@ -268,27 +285,36 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
268285
/// there is no breakpoint location at that address.
269286
lldb::break_id_t FindLocationIDByAddress(const Address &addr);
270287

271-
/// Find a breakpoint location for a given breakpoint location ID.
288+
/// Find a breakpoint location for a given breakpoint location ID. If there
289+
/// are Facade Locations in the breakpoint, the facade locations will be
290+
/// searched instead of the "real" ones.
272291
///
273292
/// \param[in] bp_loc_id
274293
/// The ID specifying the location.
294+
///
295+
/// \param[in] use_facade
296+
/// If \b true, then prefer facade locations over "real" ones if they exist.
297+
///
275298
/// \return
276299
/// Returns a shared pointer to the location with ID \a bp_loc_id. The
277300
/// pointer
278301
/// in the shared pointer will be nullptr if there is no location with that
279302
/// ID.
280-
lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id);
303+
lldb::BreakpointLocationSP FindLocationByID(lldb::break_id_t bp_loc_id, bool use_facade = true);
281304

282305
/// Get breakpoint locations by index.
283306
///
284307
/// \param[in] index
285308
/// The location index.
286309
///
310+
/// \param[in] use_facade
311+
/// If \b true, then prefer facade locations over "real" ones if they exist.
312+
///
287313
/// \return
288314
/// Returns a shared pointer to the location with index \a
289315
/// index. The shared pointer might contain nullptr if \a index is
290316
/// greater than then number of actual locations.
291-
lldb::BreakpointLocationSP GetLocationAtIndex(size_t index);
317+
lldb::BreakpointLocationSP GetLocationAtIndex(size_t index, bool use_facade = true);
292318

293319
/// Removes all invalid breakpoint locations.
294320
///
@@ -409,9 +435,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
409435
/// Return the number of breakpoint locations that have resolved to actual
410436
/// breakpoint sites.
411437
///
438+
/// \param[in] use_facade
439+
/// If \b true, then prefer facade locations over "real" ones if they exist.
440+
///
412441
/// \return
413442
/// The number locations resolved breakpoint sites.
414-
size_t GetNumResolvedLocations() const;
443+
size_t GetNumResolvedLocations(bool use_facade = true) const;
415444

416445
/// Return whether this breakpoint has any resolved locations.
417446
///
@@ -421,9 +450,12 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
421450

422451
/// Return the number of breakpoint locations.
423452
///
453+
/// \param[in] use_facade
454+
/// If \b true, then prefer facade locations over "real" ones if they exist.
455+
///
424456
/// \return
425457
/// The number breakpoint locations.
426-
size_t GetNumLocations() const;
458+
size_t GetNumLocations(bool use_facade = true) const;
427459

428460
/// Put a description of this breakpoint into the stream \a s.
429461
///
@@ -529,6 +561,20 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
529561
m_name_list.erase(name_to_remove);
530562
}
531563

564+
enum TypeDisplay {
565+
eDisplayFacade = 1,
566+
eDisplayReal = 1 << 1,
567+
eDisplayHeader = 1 << 2
568+
};
569+
570+
void GetDescriptionForType(Stream *s, lldb::DescriptionLevel level,
571+
uint8_t display_type, bool show_locations);
572+
573+
bool HasFacadeLocations() {
574+
return m_facade_locations.GetSize() != 0;
575+
}
576+
577+
532578
public:
533579
bool MatchesName(const char *name) {
534580
return m_name_list.find(name) != m_name_list.end();
@@ -657,6 +703,8 @@ class Breakpoint : public std::enable_shared_from_this<Breakpoint>,
657703
BreakpointOptions m_options; // Settable breakpoint options
658704
BreakpointLocationList
659705
m_locations; // The list of locations currently found for this breakpoint.
706+
BreakpointLocationCollection m_facade_locations;
707+
660708
std::string m_kind_description;
661709
bool m_resolve_indirect_symbols;
662710

lldb/include/lldb/Breakpoint/BreakpointLocation.h

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ namespace lldb_private {
3838

3939
class BreakpointLocation
4040
: public std::enable_shared_from_this<BreakpointLocation> {
41+
friend class BreakpointSite;
42+
friend class BreakpointLocationList;
43+
friend class Breakpoint;
44+
friend class Process;
45+
friend class StopInfoBreakpoint;
46+
4147
public:
4248
~BreakpointLocation();
4349

@@ -55,16 +61,39 @@ class BreakpointLocation
5561

5662
Target &GetTarget();
5763

64+
/// This is a programmatic version of a breakpoint "condition". When a
65+
/// breakpoint is hit, WasHit will get called before the synchronous ShouldStop
66+
/// callback is run, and if it returns an empty BreakpointLocationSP, lldb will
67+
/// act as if that breakpoint wasn't hit.
68+
///
69+
/// \param[in] context
70+
/// The context at the stop point
71+
///
72+
/// \return
73+
/// This will return the breakpoint location that was hit on this stop.
74+
/// If there was no facade location this will be the original location.
75+
/// If the shared pointer is empty, then we'll treat it as if the
76+
/// breakpoint was not hit.
77+
lldb::BreakpointLocationSP WasHit(StoppointCallbackContext *context);
78+
5879
/// Determines whether we should stop due to a hit at this breakpoint
5980
/// location.
6081
///
6182
/// Side Effects: This may evaluate the breakpoint condition, and run the
6283
/// callback. So this command may do a considerable amount of work.
6384
///
85+
/// \param[in] context
86+
/// The context at the stop point
87+
///
88+
/// \param[out] facade_loc_sp
89+
/// If this stop should be attributed not to the location that was hit, but
90+
/// to a facade location, it will be returned in this facade_loc_sp.
91+
///
6492
/// \return
6593
/// \b true if this breakpoint location thinks we should stop,
6694
/// \b false otherwise.
67-
bool ShouldStop(StoppointCallbackContext *context);
95+
bool ShouldStop(StoppointCallbackContext *context,
96+
lldb::BreakpointLocationSP &facade_loc_sp);
6897

6998
// The next section deals with various breakpoint options.
7099

@@ -292,11 +321,6 @@ class BreakpointLocation
292321
}
293322

294323
protected:
295-
friend class BreakpointSite;
296-
friend class BreakpointLocationList;
297-
friend class Process;
298-
friend class StopInfoBreakpoint;
299-
300324
/// Set the breakpoint site for this location to \a bp_site_sp.
301325
///
302326
/// \param[in] bp_site_sp
@@ -346,9 +370,11 @@ class BreakpointLocation
346370
// Constructors and Destructors
347371
//
348372
// Only the Breakpoint can make breakpoint locations, and it owns them.
349-
350373
/// Constructor.
351374
///
375+
/// \param[in] loc_id
376+
/// The location id of the new location.
377+
///
352378
/// \param[in] owner
353379
/// A back pointer to the breakpoint that owns this location.
354380
///
@@ -359,10 +385,25 @@ class BreakpointLocation
359385
/// The thread for which this breakpoint location is valid, or
360386
/// LLDB_INVALID_THREAD_ID if it is valid for all threads.
361387
///
362-
BreakpointLocation(lldb::break_id_t bid, Breakpoint &owner,
388+
BreakpointLocation(lldb::break_id_t loc_id, Breakpoint &owner,
363389
const Address &addr, lldb::tid_t tid,
364390
bool check_for_resolver = true);
365391

392+
/// This is the constructor for locations with no address. Currently this is
393+
/// just used for Facade locations.
394+
///
395+
/// \param[in] loc_id
396+
/// The location id of the new location.
397+
///
398+
/// \param[in] owner
399+
/// A back pointer to the breakpoint that owns this location.
400+
///
401+
///
402+
public:
403+
BreakpointLocation(lldb::break_id_t loc_id, Breakpoint &owner);
404+
bool IsValid() const { return m_is_valid; }
405+
bool IsFacade() const { return m_is_facade; }
406+
private:
366407
// Data members:
367408
bool m_should_resolve_indirect_functions;
368409
bool m_is_reexported;
@@ -390,6 +431,17 @@ class BreakpointLocation
390431
/// location was given somewhere in the virtual inlined call stack since the
391432
/// Address always resolves to the lowest entry in the stack.
392433
std::optional<LineEntry> m_preferred_line_entry;
434+
bool m_is_valid = true; /// Because Facade locations don't have sites
435+
/// we can't use the presence of the site to mean
436+
/// this breakpoint is valid, but must manage
437+
/// the state directly.
438+
bool m_is_facade = false; /// Facade locations aren't directly triggered
439+
/// and don't have a breakpoint site. They are
440+
/// a useful fiction when you want to represent
441+
/// the stop location as something lldb can't
442+
/// naturally stop at.
443+
444+
void SetInvalid() { m_is_valid = false; }
393445

394446
void SetShouldResolveIndirectFunctions(bool do_resolve) {
395447
m_should_resolve_indirect_functions = do_resolve;

lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class BreakpointLocationCollection {
111111
///
112112
/// \return
113113
/// \b true if we should stop, \b false otherwise.
114-
bool ShouldStop(StoppointCallbackContext *context);
114+
bool ShouldStop(StoppointCallbackContext *context, BreakpointLocationCollection &stopped_bp_locs);
115115

116116
/// Print a description of the breakpoint locations in this list
117117
/// to the stream \a s.

0 commit comments

Comments
 (0)