Skip to content

Commit 0ea097e

Browse files
medismailbenkcloudy0717
authored andcommitted
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]>
1 parent 62302b5 commit 0ea097e

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
@@ -425,6 +425,18 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *
425425
return sb_ptr;
426426
}
427427

428+
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBThread(PyObject * data) {
429+
lldb::SBThread *sb_ptr = nullptr;
430+
431+
int valid_cast =
432+
SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBThread, 0);
433+
434+
if (valid_cast == -1)
435+
return NULL;
436+
437+
return sb_ptr;
438+
}
439+
428440
void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBFrame(PyObject * data) {
429441
lldb::SBFrame *sb_ptr = nullptr;
430442

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
@@ -243,6 +243,7 @@ def __init__(self, process, args):
243243
key/value pairs used by the scripted thread.
244244
"""
245245
self.target = None
246+
self.arch = None
246247
self.originating_process = None
247248
self.process = None
248249
self.args = None
@@ -264,6 +265,9 @@ def __init__(self, process, args):
264265
and process.IsValid()
265266
):
266267
self.target = process.target
268+
triple = self.target.triple
269+
if triple:
270+
self.arch = triple.split("-")[0]
267271
self.originating_process = process
268272
self.process = self.target.GetProcess()
269273
self.get_register_info()
@@ -350,17 +354,14 @@ def get_stackframes(self):
350354
def get_register_info(self):
351355
if self.register_info is None:
352356
self.register_info = dict()
353-
if "x86_64" in self.originating_process.arch:
357+
if "x86_64" in self.arch:
354358
self.register_info["sets"] = ["General Purpose Registers"]
355359
self.register_info["registers"] = INTEL64_GPR
356-
elif (
357-
"arm64" in self.originating_process.arch
358-
or self.originating_process.arch == "aarch64"
359-
):
360+
elif "arm64" in self.arch or self.arch == "aarch64":
360361
self.register_info["sets"] = ["General Purpose Registers"]
361362
self.register_info["registers"] = ARM64_GPR
362363
else:
363-
raise ValueError("Unknown architecture", self.originating_process.arch)
364+
raise ValueError("Unknown architecture", self.arch)
364365
return self.register_info
365366

366367
@abstractmethod
@@ -403,11 +404,12 @@ def __init__(self, thread, args):
403404
"""Construct a scripted frame.
404405
405406
Args:
406-
thread (ScriptedThread): The thread owning this frame.
407+
thread (ScriptedThread/lldb.SBThread): The thread owning this frame.
407408
args (lldb.SBStructuredData): A Dictionary holding arbitrary
408409
key/value pairs used by the scripted frame.
409410
"""
410411
self.target = None
412+
self.arch = None
411413
self.originating_thread = None
412414
self.thread = None
413415
self.args = None
@@ -417,15 +419,17 @@ def __init__(self, thread, args):
417419
self.register_ctx = {}
418420
self.variables = []
419421

420-
if (
421-
isinstance(thread, ScriptedThread)
422-
or isinstance(thread, lldb.SBThread)
423-
and thread.IsValid()
422+
if isinstance(thread, ScriptedThread) or (
423+
isinstance(thread, lldb.SBThread) and thread.IsValid()
424424
):
425-
self.target = thread.target
426425
self.process = thread.process
426+
self.target = self.process.target
427+
triple = self.target.triple
428+
if triple:
429+
self.arch = triple.split("-")[0]
430+
tid = thread.tid if isinstance(thread, ScriptedThread) else thread.id
427431
self.originating_thread = thread
428-
self.thread = self.process.GetThreadByIndexID(thread.tid)
432+
self.thread = self.process.GetThreadByIndexID(tid)
429433
self.get_register_info()
430434

431435
@abstractmethod
@@ -506,7 +510,18 @@ def get_variables(self, filters):
506510

507511
def get_register_info(self):
508512
if self.register_info is None:
509-
self.register_info = self.originating_thread.get_register_info()
513+
if isinstance(self.originating_thread, ScriptedThread):
514+
self.register_info = self.originating_thread.get_register_info()
515+
elif isinstance(self.originating_thread, lldb.SBThread):
516+
self.register_info = dict()
517+
if "x86_64" in self.arch:
518+
self.register_info["sets"] = ["General Purpose Registers"]
519+
self.register_info["registers"] = INTEL64_GPR
520+
elif "arm64" in self.arch or self.arch == "aarch64":
521+
self.register_info["sets"] = ["General Purpose Registers"]
522+
self.register_info["registers"] = ARM64_GPR
523+
else:
524+
raise ValueError("Unknown architecture", self.arch)
510525
return self.register_info
511526

512527
@abstractmethod
@@ -640,12 +655,12 @@ def get_stop_reason(self):
640655

641656
# TODO: Passthrough stop reason from driving process
642657
if self.driving_thread.GetStopReason() != lldb.eStopReasonNone:
643-
if "arm64" in self.originating_process.arch:
658+
if "arm64" in self.arch:
644659
stop_reason["type"] = lldb.eStopReasonException
645660
stop_reason["data"]["desc"] = (
646661
self.driving_thread.GetStopDescription(100)
647662
)
648-
elif self.originating_process.arch == "x86_64":
663+
elif self.arch == "x86_64":
649664
stop_reason["type"] = lldb.eStopReasonSignal
650665
stop_reason["data"]["signal"] = signal.SIGTRAP
651666
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"
@@ -1003,6 +1004,35 @@ class LLDB_API SBTarget {
10031004

10041005
lldb::SBMutex GetAPIMutex() const;
10051006

1007+
/// Register a scripted frame provider for this target.
1008+
/// If a scripted frame provider with the same name and same argument
1009+
/// dictionary is already registered on this target, it will be overwritten.
1010+
///
1011+
/// \param[in] class_name
1012+
/// The name of the Python class that implements the frame provider.
1013+
///
1014+
/// \param[in] args_dict
1015+
/// A dictionary of arguments to pass to the frame provider class.
1016+
///
1017+
/// \param[out] error
1018+
/// An error object indicating success or failure.
1019+
///
1020+
/// \return
1021+
/// A unique identifier for the frame provider descriptor that was
1022+
/// registered. 0 if the registration failed.
1023+
uint32_t RegisterScriptedFrameProvider(const char *class_name,
1024+
lldb::SBStructuredData args_dict,
1025+
lldb::SBError &error);
1026+
1027+
/// Remove a scripted frame provider from this target by name.
1028+
///
1029+
/// \param[in] provider_id
1030+
/// The id of the frame provider class to remove.
1031+
///
1032+
/// \return
1033+
/// An error object indicating success or failure.
1034+
lldb::SBError RemoveScriptedFrameProvider(uint32_t provider_id);
1035+
10061036
protected:
10071037
friend class SBAddress;
10081038
friend class SBAddressRange;

lldb/include/lldb/API/SBThread.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ class LLDB_API SBThread {
256256
friend class SBThreadPlan;
257257
friend class SBTrace;
258258

259+
friend class lldb_private::ScriptInterpreter;
259260
friend class lldb_private::python::SWIGBridge;
260261

261262
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
@@ -451,7 +451,7 @@ class StackFrame : public ExecutionContextScope,
451451
/// frames are included in this frame index count.
452452
virtual uint32_t GetFrameIndex() const;
453453

454-
/// Set this frame's synthetic frame index.
454+
/// Set this frame's frame index.
455455
void SetFrameIndex(uint32_t index) { m_frame_index = index; }
456456

457457
/// Query this frame to find what frame it is in this Thread's
@@ -558,6 +558,7 @@ class StackFrame : public ExecutionContextScope,
558558
protected:
559559
friend class BorrowedStackFrame;
560560
friend class StackFrameList;
561+
friend class SyntheticStackFrameList;
561562

562563
void SetSymbolContextScope(SymbolContextScope *symbol_scope);
563564

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
@@ -211,26 +212,51 @@ class StackFrameList : public std::enable_shared_from_this<StackFrameList> {
211212
/// Whether or not to show synthetic (inline) frames. Immutable.
212213
const bool m_show_inlined_frames;
213214

215+
/// Returns true if fetching frames was interrupted, false otherwise.
216+
virtual bool FetchFramesUpTo(uint32_t end_idx,
217+
InterruptionControl allow_interrupt);
218+
214219
private:
215220
uint32_t SetSelectedFrameNoLock(lldb_private::StackFrame *frame);
216221
lldb::StackFrameSP
217222
GetFrameAtIndexNoLock(uint32_t idx,
218223
std::shared_lock<std::shared_mutex> &guard);
219224

225+
/// @{
220226
/// These two Fetch frames APIs and SynthesizeTailCallFrames are called in
221227
/// GetFramesUpTo, they are the ones that actually add frames. They must be
222228
/// called with the writer end of the list mutex held.
223-
224-
/// Returns true if fetching frames was interrupted, false otherwise.
225-
bool FetchFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
229+
///
226230
/// Not currently interruptible so returns void.
231+
/// }@
227232
void FetchOnlyConcreteFramesUpTo(uint32_t end_idx);
228233
void SynthesizeTailCallFrames(StackFrame &next_frame);
229234

230235
StackFrameList(const StackFrameList &) = delete;
231236
const StackFrameList &operator=(const StackFrameList &) = delete;
232237
};
233238

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

236262
#endif // LLDB_TARGET_STACKFRAMELIST_H

0 commit comments

Comments
 (0)