Skip to content

Commit 21ccd97

Browse files
committed
Reland "[lldb] Introduce ScriptedFrameProvider for real threads (llvm#161870)" (llvm#170236)
This patch re-lands llvm#161870 with fixes to the previous test failures. rdar://161834688 Signed-off-by: Med Ismail Bennani <[email protected]> (cherry picked from commit c50802c)
1 parent 39156e0 commit 21ccd97

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2290
-77
lines changed

lldb/bindings/python/python-wrapper.swig

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

425+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBThread(PyObject * data) {
426+
lldb::SBThread *sb_ptr = nullptr;
427+
428+
int valid_cast =
429+
SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBThread, 0);
430+
431+
if (valid_cast == -1)
432+
return NULL;
433+
434+
return sb_ptr;
435+
}
436+
425437
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBFrame(PyObject * data) {
426438
lldb::SBFrame *sb_ptr = nullptr;
427439

lldb/examples/python/templates/scripted_frame_provider.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,54 @@ class ScriptedFrameProvider(metaclass=ABCMeta):
3131
)
3232
"""
3333

34+
@staticmethod
35+
def applies_to_thread(thread):
36+
"""Determine if this frame provider should be used for a given thread.
37+
38+
This static method is called before creating an instance of the frame
39+
provider to determine if it should be applied to a specific thread.
40+
Override this method to provide custom filtering logic.
41+
42+
Args:
43+
thread (lldb.SBThread): The thread to check.
44+
45+
Returns:
46+
bool: True if this frame provider should be used for the thread,
47+
False otherwise. The default implementation returns True for
48+
all threads.
49+
50+
Example:
51+
52+
.. code-block:: python
53+
54+
@staticmethod
55+
def applies_to_thread(thread):
56+
# Only apply to thread 1
57+
return thread.GetIndexID() == 1
58+
"""
59+
return True
60+
61+
@staticmethod
3462
@abstractmethod
63+
def get_description():
64+
"""Get a description of this frame provider.
65+
66+
This method should return a human-readable string describing what
67+
this frame provider does. The description is used for debugging
68+
and display purposes.
69+
70+
Returns:
71+
str: A description of the frame provider.
72+
73+
Example:
74+
75+
.. code-block:: python
76+
77+
def get_description(self):
78+
return "Crash log frame provider for thread 1"
79+
"""
80+
pass
81+
3582
def __init__(self, input_frames, args):
3683
"""Construct a scripted frame provider.
3784

lldb/examples/python/templates/scripted_process.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ def __init__(self, process, args):
245245
key/value pairs used by the scripted thread.
246246
"""
247247
self.target = None
248+
self.arch = None
248249
self.originating_process = None
249250
self.process = None
250251
self.args = None
@@ -266,6 +267,9 @@ def __init__(self, process, args):
266267
and process.IsValid()
267268
):
268269
self.target = process.target
270+
triple = self.target.triple
271+
if triple:
272+
self.arch = triple.split("-")[0]
269273
self.originating_process = process
270274
self.process = self.target.GetProcess()
271275
self.get_register_info()
@@ -352,17 +356,14 @@ def get_stackframes(self):
352356
def get_register_info(self):
353357
if self.register_info is None:
354358
self.register_info = dict()
355-
if "x86_64" in self.originating_process.arch:
359+
if "x86_64" in self.arch:
356360
self.register_info["sets"] = ["General Purpose Registers"]
357361
self.register_info["registers"] = INTEL64_GPR
358-
elif (
359-
"arm64" in self.originating_process.arch
360-
or self.originating_process.arch == "aarch64"
361-
):
362+
elif "arm64" in self.arch or self.arch == "aarch64":
362363
self.register_info["sets"] = ["General Purpose Registers"]
363364
self.register_info["registers"] = ARM64_GPR
364365
else:
365-
raise ValueError("Unknown architecture", self.originating_process.arch)
366+
raise ValueError("Unknown architecture", self.arch)
366367
return self.register_info
367368

368369
@abstractmethod
@@ -405,11 +406,12 @@ def __init__(self, thread, args):
405406
"""Construct a scripted frame.
406407
407408
Args:
408-
thread (ScriptedThread): The thread owning this frame.
409+
thread (ScriptedThread/lldb.SBThread): The thread owning this frame.
409410
args (lldb.SBStructuredData): A Dictionary holding arbitrary
410411
key/value pairs used by the scripted frame.
411412
"""
412413
self.target = None
414+
self.arch = None
413415
self.originating_thread = None
414416
self.thread = None
415417
self.args = None
@@ -419,15 +421,17 @@ def __init__(self, thread, args):
419421
self.register_ctx = {}
420422
self.variables = []
421423

422-
if (
423-
isinstance(thread, ScriptedThread)
424-
or isinstance(thread, lldb.SBThread)
425-
and thread.IsValid()
424+
if isinstance(thread, ScriptedThread) or (
425+
isinstance(thread, lldb.SBThread) and thread.IsValid()
426426
):
427-
self.target = thread.target
428427
self.process = thread.process
428+
self.target = self.process.target
429+
triple = self.target.triple
430+
if triple:
431+
self.arch = triple.split("-")[0]
432+
tid = thread.tid if isinstance(thread, ScriptedThread) else thread.id
429433
self.originating_thread = thread
430-
self.thread = self.process.GetThreadByIndexID(thread.tid)
434+
self.thread = self.process.GetThreadByIndexID(tid)
431435
self.get_register_info()
432436

433437
@abstractmethod
@@ -508,7 +512,18 @@ def get_variables(self, filters):
508512

509513
def get_register_info(self):
510514
if self.register_info is None:
511-
self.register_info = self.originating_thread.get_register_info()
515+
if isinstance(self.originating_thread, ScriptedThread):
516+
self.register_info = self.originating_thread.get_register_info()
517+
elif isinstance(self.originating_thread, lldb.SBThread):
518+
self.register_info = dict()
519+
if "x86_64" in self.arch:
520+
self.register_info["sets"] = ["General Purpose Registers"]
521+
self.register_info["registers"] = INTEL64_GPR
522+
elif "arm64" in self.arch or self.arch == "aarch64":
523+
self.register_info["sets"] = ["General Purpose Registers"]
524+
self.register_info["registers"] = ARM64_GPR
525+
else:
526+
raise ValueError("Unknown architecture", self.arch)
512527
return self.register_info
513528

514529
@abstractmethod
@@ -642,12 +657,12 @@ def get_stop_reason(self):
642657

643658
# TODO: Passthrough stop reason from driving process
644659
if self.driving_thread.GetStopReason() != lldb.eStopReasonNone:
645-
if "arm64" in self.originating_process.arch:
660+
if "arm64" in self.arch:
646661
stop_reason["type"] = lldb.eStopReasonException
647662
stop_reason["data"]["desc"] = (
648663
self.driving_thread.GetStopDescription(100)
649664
)
650-
elif self.originating_process.arch == "x86_64":
665+
elif self.arch == "x86_64":
651666
stop_reason["type"] = lldb.eStopReasonSignal
652667
stop_reason["data"]["signal"] = signal.SIGTRAP
653668
else:

lldb/include/lldb/API/SBTarget.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "lldb/API/SBLaunchInfo.h"
2020
#include "lldb/API/SBStatisticsOptions.h"
2121
#include "lldb/API/SBSymbolContextList.h"
22+
#include "lldb/API/SBThreadCollection.h"
2223
#include "lldb/API/SBType.h"
2324
#include "lldb/API/SBValue.h"
2425
#include "lldb/API/SBWatchpoint.h"
@@ -979,6 +980,35 @@ class LLDB_API SBTarget {
979980

980981
lldb::SBMutex GetAPIMutex() const;
981982

983+
/// Register a scripted frame provider for this target.
984+
/// If a scripted frame provider with the same name and same argument
985+
/// dictionary is already registered on this target, it will be overwritten.
986+
///
987+
/// \param[in] class_name
988+
/// The name of the Python class that implements the frame provider.
989+
///
990+
/// \param[in] args_dict
991+
/// A dictionary of arguments to pass to the frame provider class.
992+
///
993+
/// \param[out] error
994+
/// An error object indicating success or failure.
995+
///
996+
/// \return
997+
/// A unique identifier for the frame provider descriptor that was
998+
/// registered. 0 if the registration failed.
999+
uint32_t RegisterScriptedFrameProvider(const char *class_name,
1000+
lldb::SBStructuredData args_dict,
1001+
lldb::SBError &error);
1002+
1003+
/// Remove a scripted frame provider from this target by name.
1004+
///
1005+
/// \param[in] provider_id
1006+
/// The id of the frame provider class to remove.
1007+
///
1008+
/// \return
1009+
/// An error object indicating success or failure.
1010+
lldb::SBError RemoveScriptedFrameProvider(uint32_t provider_id);
1011+
9821012
protected:
9831013
friend class SBAddress;
9841014
friend class SBAddressRange;

lldb/include/lldb/API/SBThread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ class LLDB_API SBThread {
252252
friend class SBThreadPlan;
253253
friend class SBTrace;
254254

255+
friend class lldb_private::ScriptInterpreter;
255256
friend class lldb_private::python::SWIGBridge;
256257

257258
SBThread(const lldb::ThreadSP &lldb_object_sp);

lldb/include/lldb/API/SBThreadCollection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class LLDB_API SBThreadCollection {
4646
void SetOpaque(const lldb::ThreadCollectionSP &threads);
4747

4848
private:
49+
friend class SBTarget;
4950
friend class SBProcess;
5051
friend class SBThread;
5152
friend class SBSaveCoreOptions;

lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,29 @@
1616
namespace lldb_private {
1717
class ScriptedFrameProviderInterface : public ScriptedInterface {
1818
public:
19+
virtual bool AppliesToThread(llvm::StringRef class_name,
20+
lldb::ThreadSP thread_sp) {
21+
return true;
22+
}
23+
1924
virtual llvm::Expected<StructuredData::GenericSP>
2025
CreatePluginObject(llvm::StringRef class_name,
2126
lldb::StackFrameListSP input_frames,
2227
StructuredData::DictionarySP args_sp) = 0;
2328

29+
/// Get a description string for the frame provider.
30+
///
31+
/// This is called by the descriptor to fetch a description from the
32+
/// scripted implementation. Implementations should call a static method
33+
/// on the scripting class to retrieve the description.
34+
///
35+
/// \param class_name The name of the scripting class implementing the
36+
/// provider.
37+
///
38+
/// \return A string describing what this frame provider does, or an
39+
/// empty string if no description is available.
40+
virtual std::string GetDescription(llvm::StringRef class_name) { return {}; }
41+
2442
virtual StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) {
2543
return {};
2644
}

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lldb/API/SBMemoryRegionInfo.h"
2222
#include "lldb/API/SBStream.h"
2323
#include "lldb/API/SBSymbolContext.h"
24+
#include "lldb/API/SBThread.h"
2425
#include "lldb/Breakpoint/BreakpointOptions.h"
2526
#include "lldb/Core/PluginInterface.h"
2627
#include "lldb/Core/SearchFilter.h"
@@ -580,6 +581,8 @@ class ScriptInterpreter : public PluginInterface {
580581

581582
lldb::StreamSP GetOpaqueTypeFromSBStream(const lldb::SBStream &stream) const;
582583

584+
lldb::ThreadSP GetOpaqueTypeFromSBThread(const lldb::SBThread &exe_ctx) const;
585+
583586
lldb::StackFrameSP GetOpaqueTypeFromSBFrame(const lldb::SBFrame &frame) const;
584587

585588
SymbolContext

lldb/include/lldb/Target/StackFrame.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ class StackFrame : public ExecutionContextScope,
455455
/// frames are included in this frame index count.
456456
virtual uint32_t GetFrameIndex() const;
457457

458-
/// Set this frame's synthetic frame index.
458+
/// Set this frame's frame index.
459459
void SetFrameIndex(uint32_t index) { m_frame_index = index; }
460460

461461
/// Query this frame to find what frame it is in this Thread's
@@ -573,6 +573,7 @@ class StackFrame : public ExecutionContextScope,
573573
protected:
574574
friend class BorrowedStackFrame;
575575
friend class StackFrameList;
576+
friend class SyntheticStackFrameList;
576577

577578
void SetSymbolContextScope(SymbolContextScope *symbol_scope);
578579

lldb/include/lldb/Target/StackFrameList.h

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class StackFrameList : public std::enable_shared_from_this<StackFrameList> {
2626
StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp,
2727
bool show_inline_frames);
2828

29-
~StackFrameList();
29+
virtual ~StackFrameList();
3030

3131
/// Get the number of visible frames. Frames may be created if \p can_create
3232
/// is true. Synthetic (inline) frames expanded from the concrete frame #0
@@ -106,6 +106,7 @@ class StackFrameList : public std::enable_shared_from_this<StackFrameList> {
106106

107107
protected:
108108
friend class Thread;
109+
friend class ScriptedFrameProvider;
109110
friend class ScriptedThread;
110111

111112
/// Use this API to build a stack frame list (used for scripted threads, for
@@ -206,26 +207,51 @@ class StackFrameList : public std::enable_shared_from_this<StackFrameList> {
206207
/// Whether or not to show synthetic (inline) frames. Immutable.
207208
const bool m_show_inlined_frames;
208209

210+
/// Returns true if fetching frames was interrupted, false otherwise.
211+
virtual bool FetchFramesUpTo(uint32_t end_idx,
212+
InterruptionControl allow_interrupt);
213+
209214
private:
210215
uint32_t SetSelectedFrameNoLock(lldb_private::StackFrame *frame);
211216
lldb::StackFrameSP
212217
GetFrameAtIndexNoLock(uint32_t idx,
213218
std::shared_lock<std::shared_mutex> &guard);
214219

220+
/// @{
215221
/// These two Fetch frames APIs and SynthesizeTailCallFrames are called in
216222
/// GetFramesUpTo, they are the ones that actually add frames. They must be
217223
/// called with the writer end of the list mutex held.
218-
219-
/// Returns true if fetching frames was interrupted, false otherwise.
220-
bool FetchFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
224+
///
221225
/// Not currently interruptible so returns void.
226+
/// }@
222227
void FetchOnlyConcreteFramesUpTo(uint32_t end_idx);
223228
void SynthesizeTailCallFrames(StackFrame &next_frame);
224229

225230
StackFrameList(const StackFrameList &) = delete;
226231
const StackFrameList &operator=(const StackFrameList &) = delete;
227232
};
228233

234+
/// A StackFrameList that wraps another StackFrameList and uses a
235+
/// SyntheticFrameProvider to lazily provide frames from either the provider
236+
/// or the underlying real stack frame list.
237+
class SyntheticStackFrameList : public StackFrameList {
238+
public:
239+
SyntheticStackFrameList(Thread &thread, lldb::StackFrameListSP input_frames,
240+
const lldb::StackFrameListSP &prev_frames_sp,
241+
bool show_inline_frames);
242+
243+
protected:
244+
/// Override FetchFramesUpTo to lazily return frames from the provider
245+
/// or from the actual stack frame list.
246+
bool FetchFramesUpTo(uint32_t end_idx,
247+
InterruptionControl allow_interrupt) override;
248+
249+
private:
250+
/// The input stack frame list that the provider transforms.
251+
/// This could be a real StackFrameList or another SyntheticStackFrameList.
252+
lldb::StackFrameListSP m_input_frames;
253+
};
254+
229255
} // namespace lldb_private
230256

231257
#endif // LLDB_TARGET_STACKFRAMELIST_H

0 commit comments

Comments
 (0)