[Lldb-commits] [lldb] [lldb] Introduce ScriptedFrame affordance (PR #149622)
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Thu Sep 4 15:00:01 PDT 2025
https://github.com/medismailben updated https://github.com/llvm/llvm-project/pull/149622
>From d5d9e01134e0cf78974cd5f50f028bd71756c24f Mon Sep 17 00:00:00 2001
From: Med Ismail Bennani <ismail at bennani.ma>
Date: Thu, 4 Sep 2025 14:59:44 -0700
Subject: [PATCH] [lldb] Introduce ScriptedFrame affordance
This patch introduces a new scripting affordance in lldb: `ScriptedFrame`.
This allows user to produce mock stackframes in scripted threads and
scripted processes from a python script.
With this change, StackFrame can be synthetized from different sources:
- Either from a dictionary containing a load address, and a frame index,
which is the legacy way.
- Or by creating a ScriptedFrame python object.
One particularity of synthezising stackframes from the ScriptedFrame
python object, is that these frame have an optional PC, meaning that
they don't have a report a valid PC and they can act as shells that just
contain static information, like the frame function name, the list of
variables or registers, etc. It can also provide a symbol context.
rdar://157260006
Signed-off-by: Med Ismail Bennani <ismail at bennani.ma>
---
.../python/templates/scripted_process.py | 136 +++++++++++++
lldb/include/lldb/API/SBSymbolContext.h | 1 +
.../Interfaces/ScriptedFrameInterface.h | 55 +++++
.../Interfaces/ScriptedThreadInterface.h | 10 +
.../lldb/Interpreter/ScriptInterpreter.h | 5 +
lldb/include/lldb/Target/StackFrame.h | 34 ++--
lldb/include/lldb/lldb-forward.h | 3 +
lldb/source/Core/FormatEntity.cpp | 2 +-
.../Plugins/Process/scripted/CMakeLists.txt | 1 +
.../Process/scripted/ScriptedFrame.cpp | 191 ++++++++++++++++++
.../Plugins/Process/scripted/ScriptedFrame.h | 63 ++++++
.../Process/scripted/ScriptedThread.cpp | 82 +++++++-
.../Plugins/Process/scripted/ScriptedThread.h | 5 +-
.../Python/Interfaces/CMakeLists.txt | 1 +
.../ScriptInterpreterPythonInterfaces.h | 1 +
.../ScriptedFramePythonInterface.cpp | 157 ++++++++++++++
.../Interfaces/ScriptedFramePythonInterface.h | 59 ++++++
.../Interfaces/ScriptedPythonInterface.cpp | 3 +-
.../ScriptedThreadPythonInterface.cpp | 17 ++
.../ScriptedThreadPythonInterface.h | 5 +
.../Python/ScriptInterpreterPython.cpp | 5 +
.../Python/ScriptInterpreterPythonImpl.h | 2 +
.../dummy_scripted_process.py | 65 +++++-
23 files changed, 871 insertions(+), 32 deletions(-)
create mode 100644 lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
create mode 100644 lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
create mode 100644 lldb/source/Plugins/Process/scripted/ScriptedFrame.h
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
create mode 100644 lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
diff --git a/lldb/examples/python/templates/scripted_process.py b/lldb/examples/python/templates/scripted_process.py
index b6360b8519077..49059d533f38a 100644
--- a/lldb/examples/python/templates/scripted_process.py
+++ b/lldb/examples/python/templates/scripted_process.py
@@ -383,6 +383,142 @@ def get_extended_info(self):
"""
return self.extended_info
+ def get_scripted_frame_plugin(self):
+ """Get scripted frame plugin name.
+
+ Returns:
+ str: Name of the scripted frame plugin.
+ """
+ return None
+
+
+class ScriptedFrame(metaclass=ABCMeta):
+ """
+ The base class for a scripted frame.
+
+ Most of the base class methods are `@abstractmethod` that need to be
+ overwritten by the inheriting class.
+ """
+
+ @abstractmethod
+ def __init__(self, thread, args):
+ """Construct a scripted frame.
+
+ Args:
+ thread (ScriptedThread): The thread owning this frame.
+ args (lldb.SBStructuredData): A Dictionary holding arbitrary
+ key/value pairs used by the scripted frame.
+ """
+ self.target = None
+ self.originating_thread = None
+ self.thread = None
+ self.args = None
+ self.id = None
+ self.name = None
+ self.register_info = None
+ self.register_ctx = {}
+ self.variables = []
+
+ if (
+ isinstance(thread, ScriptedThread)
+ or isinstance(thread, lldb.SBThread)
+ and thread.IsValid()
+ ):
+ self.target = thread.target
+ self.process = thread.process
+ self.originating_thread = thread
+ self.thread = self.process.GetThreadByIndexID(thread.tid)
+ self.get_register_info()
+
+ @abstractmethod
+ def get_id(self):
+ """Get the scripted frame identifier.
+
+ Returns:
+ int: The identifier of the scripted frame in the scripted thread.
+ """
+ pass
+
+ def get_pc(self):
+ """Get the scripted frame address.
+
+ Returns:
+ int: The optional address of the scripted frame in the scripted thread.
+ """
+ return None
+
+ def get_symbol_context(self):
+ """Get the scripted frame symbol context.
+
+ Returns:
+ lldb.SBSymbolContext: The symbol context of the scripted frame in the scripted thread.
+ """
+ return None
+
+ def is_inlined(self):
+ """Check if the scripted frame is inlined.
+
+ Returns:
+ bool: True if scripted frame is inlined. False otherwise.
+ """
+ return False
+
+ def is_artificial(self):
+ """Check if the scripted frame is artificial.
+
+ Returns:
+ bool: True if scripted frame is artificial. False otherwise.
+ """
+ return True
+
+ def is_hidden(self):
+ """Check if the scripted frame is hidden.
+
+ Returns:
+ bool: True if scripted frame is hidden. False otherwise.
+ """
+ return False
+
+ def get_function_name(self):
+ """Get the scripted frame function name.
+
+ Returns:
+ str: The function name of the scripted frame.
+ """
+ return self.name
+
+ def get_display_function_name(self):
+ """Get the scripted frame display function name.
+
+ Returns:
+ str: The display function name of the scripted frame.
+ """
+ return self.get_function_name()
+
+ def get_variables(self, filters):
+ """Get the scripted thread state type.
+
+ Args:
+ filter (lldb.SBVariablesOptions): The filter used to resolve the variables
+ Returns:
+ lldb.SBValueList: The SBValueList containing the SBValue for each resolved variable.
+ Returns None by default.
+ """
+ return None
+
+ def get_register_info(self):
+ if self.register_info is None:
+ self.register_info = self.originating_thread.get_register_info()
+ return self.register_info
+
+ @abstractmethod
+ def get_register_context(self):
+ """Get the scripted thread register context
+
+ Returns:
+ str: A byte representing all register's value.
+ """
+ pass
class PassthroughScriptedProcess(ScriptedProcess):
driving_target = None
diff --git a/lldb/include/lldb/API/SBSymbolContext.h b/lldb/include/lldb/API/SBSymbolContext.h
index 128b0b65b7860..19f29c629d094 100644
--- a/lldb/include/lldb/API/SBSymbolContext.h
+++ b/lldb/include/lldb/API/SBSymbolContext.h
@@ -66,6 +66,7 @@ class LLDB_API SBSymbolContext {
friend class SBTarget;
friend class SBSymbolContextList;
+ friend class lldb_private::ScriptInterpreter;
friend class lldb_private::python::SWIGBridge;
SBSymbolContext(const lldb_private::SymbolContext &sc_ptr);
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
new file mode 100644
index 0000000000000..8ef4b37d6ba12
--- /dev/null
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameInterface.h
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEINTERFACE_H
+#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEINTERFACE_H
+
+#include "ScriptedInterface.h"
+#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/lldb-private.h"
+#include <optional>
+#include <string>
+
+namespace lldb_private {
+class ScriptedFrameInterface : virtual public ScriptedInterface {
+public:
+ virtual llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_obj = nullptr) = 0;
+
+ virtual lldb::user_id_t GetID() { return LLDB_INVALID_FRAME_ID; }
+
+ virtual lldb::addr_t GetPC() { return LLDB_INVALID_ADDRESS; }
+
+ virtual std::optional<SymbolContext> GetSymbolContext() {
+ return std::nullopt;
+ }
+
+ virtual std::optional<std::string> GetFunctionName() { return std::nullopt; }
+
+ virtual std::optional<std::string> GetDisplayFunctionName() {
+ return std::nullopt;
+ }
+
+ virtual bool IsInlined() { return false; }
+
+ virtual bool IsArtificial() { return false; }
+
+ virtual bool IsHidden() { return false; }
+
+ virtual StructuredData::DictionarySP GetRegisterInfo() { return {}; }
+
+ virtual std::optional<std::string> GetRegisterContext() {
+ return std::nullopt;
+ }
+};
+} // namespace lldb_private
+
+#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEINTERFACE_H
diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadInterface.h
index a7cfc690b67dc..bc58f344d36f8 100644
--- a/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadInterface.h
+++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadInterface.h
@@ -44,6 +44,16 @@ class ScriptedThreadInterface : virtual public ScriptedInterface {
}
virtual StructuredData::ArraySP GetExtendedInfo() { return {}; }
+
+ virtual std::optional<std::string> GetScriptedFramePluginName() {
+ return std::nullopt;
+ }
+
+protected:
+ friend class ScriptedFrame;
+ virtual lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() {
+ return {};
+ }
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
index dffb9b82abf3d..024bbc90a9a39 100644
--- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h
+++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h
@@ -26,6 +26,7 @@
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/StreamFile.h"
#include "lldb/Interpreter/Interfaces/OperatingSystemInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
#include "lldb/Interpreter/Interfaces/ScriptedPlatformInterface.h"
#include "lldb/Interpreter/Interfaces/ScriptedProcessInterface.h"
#include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h"
@@ -531,6 +532,10 @@ class ScriptInterpreter : public PluginInterface {
return {};
}
+ virtual lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() {
+ return {};
+ }
+
virtual lldb::ScriptedThreadPlanInterfaceSP
CreateScriptedThreadPlanInterface() {
return {};
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index 4ffbf97ce6e90..cdbe8ae3c6779 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -398,7 +398,7 @@ class StackFrame : public ExecutionContextScope,
///
/// \return
/// true if this is an inlined frame.
- bool IsInlined();
+ virtual bool IsInlined();
/// Query whether this frame is synthetic.
bool IsSynthetic() const;
@@ -409,12 +409,12 @@ class StackFrame : public ExecutionContextScope,
/// Query whether this frame is artificial (e.g a synthesized result of
/// inferring missing tail call frames from a backtrace). Artificial frames
/// may have limited support for inspecting variables.
- bool IsArtificial() const;
+ virtual bool IsArtificial() const;
/// Query whether this frame should be hidden from backtraces. Frame
/// recognizers can customize this behavior and hide distracting
/// system implementation details this way.
- bool IsHidden();
+ virtual bool IsHidden();
/// Language plugins can use this API to report language-specific
/// runtime information about this compile unit, such as additional
@@ -425,13 +425,13 @@ class StackFrame : public ExecutionContextScope,
///
/// /// \return
/// A C-String containing the function demangled name. Can be null.
- const char *GetFunctionName();
+ virtual const char *GetFunctionName();
/// Get the frame's demangled display name.
///
/// /// \return
/// A C-String containing the function demangled display name. Can be null.
- const char *GetDisplayFunctionName();
+ virtual const char *GetDisplayFunctionName();
/// Query this frame to find what frame it is in this Thread's
/// StackFrameList.
@@ -543,18 +543,7 @@ class StackFrame : public ExecutionContextScope,
bool HasCachedData() const;
-private:
- /// Private methods, called from GetValueForVariableExpressionPath.
- /// See that method for documentation of parameters and return value.
- lldb::ValueObjectSP LegacyGetValueForVariableExpressionPath(
- llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
- uint32_t options, lldb::VariableSP &var_sp, Status &error);
-
- lldb::ValueObjectSP DILGetValueForVariableExpressionPath(
- llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
- uint32_t options, lldb::VariableSP &var_sp, Status &error);
-
- /// For StackFrame only.
+ /// For StackFrame and derived classes only.
/// \{
lldb::ThreadWP m_thread_wp;
uint32_t m_frame_index;
@@ -591,6 +580,17 @@ class StackFrame : public ExecutionContextScope,
StreamString m_disassembly;
std::recursive_mutex m_mutex;
+private:
+ /// Private methods, called from GetValueForVariableExpressionPath.
+ /// See that method for documentation of parameters and return value.
+ lldb::ValueObjectSP LegacyGetValueForVariableExpressionPath(
+ llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
+ uint32_t options, lldb::VariableSP &var_sp, Status &error);
+
+ lldb::ValueObjectSP DILGetValueForVariableExpressionPath(
+ llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
+ uint32_t options, lldb::VariableSP &var_sp, Status &error);
+
StackFrame(const StackFrame &) = delete;
const StackFrame &operator=(const StackFrame &) = delete;
};
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 483dce98ea427..af5656b3dcad1 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -187,6 +187,7 @@ class SaveCoreOptions;
class Scalar;
class ScriptInterpreter;
class ScriptInterpreterLocker;
+class ScriptedFrameInterface;
class ScriptedMetadata;
class ScriptedBreakpointInterface;
class ScriptedPlatformInterface;
@@ -408,6 +409,8 @@ typedef std::shared_ptr<lldb_private::RecognizedStackFrame>
typedef std::shared_ptr<lldb_private::ScriptSummaryFormat>
ScriptSummaryFormatSP;
typedef std::shared_ptr<lldb_private::ScriptInterpreter> ScriptInterpreterSP;
+typedef std::shared_ptr<lldb_private::ScriptedFrameInterface>
+ ScriptedFrameInterfaceSP;
typedef std::shared_ptr<lldb_private::ScriptedMetadata> ScriptedMetadataSP;
typedef std::unique_ptr<lldb_private::ScriptedPlatformInterface>
ScriptedPlatformInterfaceUP;
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 2ff73979e4976..491f5c6320d97 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -1681,7 +1681,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
StackFrame *frame = exe_ctx->GetFramePtr();
if (frame) {
const Address &pc_addr = frame->GetFrameCodeAddress();
- if (pc_addr.IsValid()) {
+ if (pc_addr.IsValid() || frame->IsSynthetic()) {
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
return true;
}
diff --git a/lldb/source/Plugins/Process/scripted/CMakeLists.txt b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
index 590166591a41e..1516ad3132e3b 100644
--- a/lldb/source/Plugins/Process/scripted/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/scripted/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_library(lldbPluginScriptedProcess PLUGIN
ScriptedProcess.cpp
ScriptedThread.cpp
+ ScriptedFrame.cpp
LINK_COMPONENTS
BinaryFormat
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
new file mode 100644
index 0000000000000..6519df9185df0
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.cpp
@@ -0,0 +1,191 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptedFrame.h"
+
+#include "lldb/Utility/DataBufferHeap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void ScriptedFrame::CheckInterpreterAndScriptObject() const {
+ lldbassert(m_script_object_sp && "Invalid Script Object.");
+ lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
+}
+
+llvm::Expected<std::shared_ptr<ScriptedFrame>>
+ScriptedFrame::Create(ScriptedThread &thread,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object) {
+ if (!thread.IsValid())
+ return llvm::createStringError("Invalid scripted thread.");
+
+ thread.CheckInterpreterAndScriptObject();
+
+ auto scripted_frame_interface =
+ thread.GetInterface()->CreateScriptedFrameInterface();
+ if (!scripted_frame_interface)
+ return llvm::createStringError("failed to create scripted frame interface");
+
+ llvm::StringRef frame_class_name;
+ if (!script_object) {
+ std::optional<std::string> class_name =
+ thread.GetInterface()->GetScriptedFramePluginName();
+ if (!class_name || class_name->empty())
+ return llvm::createStringError(
+ "failed to get scripted thread class name");
+ frame_class_name = *class_name;
+ }
+
+ ExecutionContext exe_ctx(thread);
+ auto obj_or_err = scripted_frame_interface->CreatePluginObject(
+ frame_class_name, exe_ctx, args_sp, script_object);
+
+ if (!obj_or_err)
+ return llvm::createStringError(
+ "failed to create script object: %s",
+ llvm::toString(obj_or_err.takeError()).c_str());
+
+ StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
+
+ if (!owned_script_object_sp->IsValid())
+ return llvm::createStringError("created script object is invalid");
+
+ lldb::user_id_t frame_id = scripted_frame_interface->GetID();
+
+ lldb::addr_t pc = scripted_frame_interface->GetPC();
+ SymbolContext sc;
+ Address symbol_addr;
+ if (pc != LLDB_INVALID_ADDRESS) {
+ symbol_addr.SetLoadAddress(pc, &thread.GetProcess()->GetTarget());
+ symbol_addr.CalculateSymbolContext(&sc);
+ }
+
+ std::optional<SymbolContext> maybe_sym_ctx =
+ scripted_frame_interface->GetSymbolContext();
+ if (maybe_sym_ctx) {
+ sc = *maybe_sym_ctx;
+ }
+
+ StructuredData::DictionarySP reg_info =
+ scripted_frame_interface->GetRegisterInfo();
+
+ if (!reg_info)
+ return llvm::createStringError(
+ "failed to get scripted thread registers info");
+
+ std::shared_ptr<DynamicRegisterInfo> register_info_sp =
+ DynamicRegisterInfo::Create(
+ *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
+
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ std::optional<std::string> reg_data =
+ scripted_frame_interface->GetRegisterContext();
+ if (reg_data) {
+ DataBufferSP data_sp(
+ std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
+
+ if (!data_sp->GetByteSize())
+ return llvm::createStringError("failed to copy raw registers data");
+
+ std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
+ std::make_shared<RegisterContextMemory>(
+ thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
+ if (!reg_ctx_memory)
+ return llvm::createStringError("failed to create a register context.");
+
+ reg_ctx_memory->SetAllRegisterData(data_sp);
+ reg_ctx_sp = reg_ctx_memory;
+ }
+
+ return std::make_shared<ScriptedFrame>(
+ thread, scripted_frame_interface, frame_id, pc, sc, reg_ctx_sp,
+ register_info_sp, owned_script_object_sp);
+}
+
+ScriptedFrame::ScriptedFrame(ScriptedThread &thread,
+ ScriptedFrameInterfaceSP interface_sp,
+ lldb::user_id_t id, lldb::addr_t pc,
+ SymbolContext &sym_ctx,
+ lldb::RegisterContextSP reg_ctx_sp,
+ std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
+ StructuredData::GenericSP script_object_sp)
+ : StackFrame(thread.shared_from_this(), /*frame_idx=*/id,
+ /*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
+ /*cfa=*/0, /*pc=*/pc,
+ /*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
+ m_scripted_frame_interface_sp(interface_sp),
+ m_script_object_sp(script_object_sp), m_register_info_sp(reg_info_sp) {}
+
+ScriptedFrame::~ScriptedFrame() {}
+
+const char *ScriptedFrame::GetFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name = GetInterface()->GetFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+const char *ScriptedFrame::GetDisplayFunctionName() {
+ CheckInterpreterAndScriptObject();
+ std::optional<std::string> function_name =
+ GetInterface()->GetDisplayFunctionName();
+ if (!function_name)
+ return nullptr;
+ return ConstString(function_name->c_str()).AsCString();
+}
+
+bool ScriptedFrame::IsInlined() { return GetInterface()->IsInlined(); }
+
+bool ScriptedFrame::IsArtificial() const {
+ return GetInterface()->IsArtificial();
+}
+
+bool ScriptedFrame::IsHidden() { return GetInterface()->IsHidden(); }
+
+lldb::ScriptedFrameInterfaceSP ScriptedFrame::GetInterface() const {
+ return m_scripted_frame_interface_sp;
+}
+
+std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
+ CheckInterpreterAndScriptObject();
+
+ if (!m_register_info_sp) {
+ StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
+
+ Status error;
+ if (!reg_info)
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION, "Failed to get scripted frame registers info.",
+ error, LLDBLog::Thread);
+
+ ThreadSP thread_sp = m_thread_wp.lock();
+ if (!thread_sp || !thread_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "Failed to get scripted frame registers info: invalid thread.", error,
+ LLDBLog::Thread);
+
+ ProcessSP process_sp = thread_sp->GetProcess();
+ if (!process_sp || !process_sp->IsValid())
+ return ScriptedInterface::ErrorWithMessage<
+ std::shared_ptr<DynamicRegisterInfo>>(
+ LLVM_PRETTY_FUNCTION,
+ "Failed to get scripted frame registers info: invalid process.",
+ error, LLDBLog::Thread);
+
+ m_register_info_sp = DynamicRegisterInfo::Create(
+ *reg_info, process_sp->GetTarget().GetArchitecture());
+ }
+
+ return m_register_info_sp;
+}
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedFrame.h b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
new file mode 100644
index 0000000000000..6e01e2fd7653e
--- /dev/null
+++ b/lldb/source/Plugins/Process/scripted/ScriptedFrame.h
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
+#define LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
+
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "ScriptedThread.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
+#include "lldb/Target/StackFrame.h"
+#include <string>
+
+namespace lldb_private {
+class ScriptedThread;
+}
+
+namespace lldb_private {
+
+class ScriptedFrame : public lldb_private::StackFrame {
+
+public:
+ ScriptedFrame(ScriptedThread &thread,
+ lldb::ScriptedFrameInterfaceSP interface_sp,
+ lldb::user_id_t frame_idx, lldb::addr_t pc,
+ SymbolContext &sym_ctx, lldb::RegisterContextSP reg_ctx_sp,
+ std::shared_ptr<DynamicRegisterInfo> reg_info_sp,
+ StructuredData::GenericSP script_object_sp = nullptr);
+
+ ~ScriptedFrame() override;
+
+ static llvm::Expected<std::shared_ptr<ScriptedFrame>>
+ Create(ScriptedThread &thread, StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_object = nullptr);
+
+ bool IsInlined() override;
+ bool IsArtificial() const override;
+ bool IsHidden() override;
+ const char *GetFunctionName() override;
+ const char *GetDisplayFunctionName() override;
+
+private:
+ void CheckInterpreterAndScriptObject() const;
+ lldb::ScriptedFrameInterfaceSP GetInterface() const;
+
+ ScriptedFrame(const ScriptedFrame &) = delete;
+ const ScriptedFrame &operator=(const ScriptedFrame &) = delete;
+
+ std::shared_ptr<DynamicRegisterInfo> GetDynamicRegisterInfo();
+
+ lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp;
+ lldb_private::StructuredData::GenericSP m_script_object_sp;
+ std::shared_ptr<DynamicRegisterInfo> m_register_info_sp;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_FRAME_H
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index 45ad83e4ed671..491efac5aadef 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ScriptedThread.h"
+#include "ScriptedFrame.h"
#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
@@ -173,27 +174,31 @@ bool ScriptedThread::LoadArtificialStackFrames() {
.str(),
error, LLDBLog::Thread);
- StackFrameListSP frames = GetStackFrameList();
-
- for (size_t idx = 0; idx < arr_size; idx++) {
+ auto create_frame_from_dict =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
std::optional<StructuredData::Dictionary *> maybe_dict =
arr_sp->GetItemAtIndexAsDictionary(idx);
- if (!maybe_dict)
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!maybe_dict) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
llvm::Twine(
"Couldn't get artificial stackframe dictionary at index (" +
llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
.str(),
error, LLDBLog::Thread);
+ return error.ToError();
+ }
StructuredData::Dictionary *dict = *maybe_dict;
lldb::addr_t pc;
- if (!dict->GetValueForKeyAsInteger("pc", pc))
- return ScriptedInterface::ErrorWithMessage<bool>(
+ if (!dict->GetValueForKeyAsInteger("pc", pc)) {
+ ScriptedInterface::ErrorWithMessage<bool>(
LLVM_PRETTY_FUNCTION,
"Couldn't find value for key 'pc' in stackframe dictionary.", error,
LLDBLog::Thread);
+ return error.ToError();
+ }
Address symbol_addr;
symbol_addr.SetLoadAddress(pc, &this->GetProcess()->GetTarget());
@@ -205,10 +210,65 @@ bool ScriptedThread::LoadArtificialStackFrames() {
SymbolContext sc;
symbol_addr.CalculateSymbolContext(&sc);
- StackFrameSP synth_frame_sp = std::make_shared<StackFrame>(
- this->shared_from_this(), idx, idx, cfa, cfa_is_valid, pc,
- StackFrame::Kind::Synthetic, artificial, behaves_like_zeroth_frame,
- &sc);
+ return std::make_shared<StackFrame>(this->shared_from_this(), idx, idx, cfa,
+ cfa_is_valid, pc,
+ StackFrame::Kind::Synthetic, artificial,
+ behaves_like_zeroth_frame, &sc);
+ };
+
+ auto create_frame_from_script_object =
+ [this, arr_sp](size_t idx) -> llvm::Expected<StackFrameSP> {
+ Status error;
+ StructuredData::ObjectSP object_sp = arr_sp->GetItemAtIndex(idx);
+ if (!object_sp || !object_sp->GetAsGeneric()) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't get artificial stackframe object at index (" +
+ llvm::Twine(idx) +
+ llvm::Twine(") from stackframe array."))
+ .str(),
+ error, LLDBLog::Thread);
+ return error.ToError();
+ }
+
+ auto frame_or_error =
+ ScriptedFrame::Create(*this, nullptr, object_sp->GetAsGeneric());
+
+ if (!frame_or_error) {
+ ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
+ return error.ToError();
+ }
+
+ StackFrameSP frame_sp = frame_or_error.get();
+ lldbassert(frame_sp && "Couldn't initialize scripted frame.");
+
+ return frame_sp;
+ };
+
+ StackFrameListSP frames = GetStackFrameList();
+
+ for (size_t idx = 0; idx < arr_size; idx++) {
+ StackFrameSP synth_frame_sp = nullptr;
+
+ auto frame_from_dict_or_err = create_frame_from_dict(idx);
+ if (!frame_from_dict_or_err) {
+ auto frame_from_script_obj_or_err = create_frame_from_script_object(idx);
+
+ if (!frame_from_script_obj_or_err) {
+ return ScriptedInterface::ErrorWithMessage<bool>(
+ LLVM_PRETTY_FUNCTION,
+ llvm::Twine("Couldn't add artificial frame (" + llvm::Twine(idx) +
+ llvm::Twine(") to ScriptedThread StackFrameList."))
+ .str(),
+ error, LLDBLog::Thread);
+ } else {
+ llvm::consumeError(frame_from_dict_or_err.takeError());
+ synth_frame_sp = *frame_from_script_obj_or_err;
+ }
+ } else {
+ synth_frame_sp = *frame_from_dict_or_err;
+ }
if (!frames->SetFrameAtIndex(static_cast<uint32_t>(idx), synth_frame_sp))
return ScriptedInterface::ErrorWithMessage<bool>(
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.h b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
index cd224d60ceef8..ee5ace4059673 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.h
@@ -15,11 +15,12 @@
#include "Plugins/Process/Utility/RegisterContextMemory.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Target//DynamicRegisterInfo.h"
+#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/Thread.h"
namespace lldb_private {
class ScriptedProcess;
+class ScriptedFrame;
}
namespace lldb_private {
@@ -61,6 +62,8 @@ class ScriptedThread : public lldb_private::Thread {
StructuredData::ObjectSP FetchThreadExtendedInfo() override;
private:
+ friend class ScriptedFrame;
+
void CheckInterpreterAndScriptObject() const;
lldb::ScriptedThreadInterfaceSP GetInterface() const;
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
index 04370940423ae..09103573b89c5 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt
@@ -22,6 +22,7 @@ endif()
add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN
OperatingSystemPythonInterface.cpp
ScriptInterpreterPythonInterfaces.cpp
+ ScriptedFramePythonInterface.cpp
ScriptedPlatformPythonInterface.cpp
ScriptedProcessPythonInterface.cpp
ScriptedPythonInterface.cpp
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
index 02dc06507caf2..3814f46615078 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h
@@ -17,6 +17,7 @@
#include "OperatingSystemPythonInterface.h"
#include "ScriptedBreakpointPythonInterface.h"
+#include "ScriptedFramePythonInterface.h"
#include "ScriptedPlatformPythonInterface.h"
#include "ScriptedProcessPythonInterface.h"
#include "ScriptedStopHookPythonInterface.h"
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
new file mode 100644
index 0000000000000..20ca7a2c01356
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.cpp
@@ -0,0 +1,157 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/lldb-enumerations.h"
+
+#if LLDB_ENABLE_PYTHON
+
+// LLDB Python header must be included first
+#include "../lldb-python.h"
+
+#include "../SWIGPythonBridge.h"
+#include "../ScriptInterpreterPythonImpl.h"
+#include "ScriptedFramePythonInterface.h"
+#include <optional>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::python;
+using Locker = ScriptInterpreterPythonImpl::Locker;
+
+ScriptedFramePythonInterface::ScriptedFramePythonInterface(
+ ScriptInterpreterPythonImpl &interpreter)
+ : ScriptedFrameInterface(), ScriptedPythonInterface(interpreter) {}
+
+llvm::Expected<StructuredData::GenericSP>
+ScriptedFramePythonInterface::CreatePluginObject(
+ const llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp, StructuredData::Generic *script_obj) {
+ ExecutionContextRefSP exe_ctx_ref_sp =
+ std::make_shared<ExecutionContextRef>(exe_ctx);
+ StructuredDataImpl sd_impl(args_sp);
+ return ScriptedPythonInterface::CreatePluginObject(class_name, script_obj,
+ exe_ctx_ref_sp, sd_impl);
+}
+
+lldb::user_id_t ScriptedFramePythonInterface::GetID() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_id", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return LLDB_INVALID_FRAME_ID;
+
+ return obj->GetUnsignedIntegerValue(LLDB_INVALID_FRAME_ID);
+}
+
+lldb::addr_t ScriptedFramePythonInterface::GetPC() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_pc", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return LLDB_INVALID_ADDRESS;
+
+ return obj->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
+}
+
+std::optional<SymbolContext> ScriptedFramePythonInterface::GetSymbolContext() {
+ Status error;
+ auto sym_ctx = Dispatch<SymbolContext>("get_symbol_context", error);
+
+ if (error.Fail()) {
+ return ErrorWithMessage<SymbolContext>(LLVM_PRETTY_FUNCTION,
+ error.AsCString(), error);
+ }
+
+ return sym_ctx;
+}
+
+std::optional<std::string> ScriptedFramePythonInterface::GetFunctionName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_function_name", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+std::optional<std::string>
+ScriptedFramePythonInterface::GetDisplayFunctionName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_display_function_name", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+bool ScriptedFramePythonInterface::IsInlined() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_inlined", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+bool ScriptedFramePythonInterface::IsArtificial() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_artificial", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+bool ScriptedFramePythonInterface::IsHidden() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("is_hidden", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return false;
+
+ return obj->GetBooleanValue();
+}
+
+StructuredData::DictionarySP ScriptedFramePythonInterface::GetRegisterInfo() {
+ Status error;
+ StructuredData::DictionarySP dict =
+ Dispatch<StructuredData::DictionarySP>("get_register_info", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict,
+ error))
+ return {};
+
+ return dict;
+}
+
+std::optional<std::string> ScriptedFramePythonInterface::GetRegisterContext() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_register_context", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetAsString()->GetValue().str();
+}
+
+#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
new file mode 100644
index 0000000000000..3aff237ae65d5
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFramePythonInterface.h
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPYTHONINTERFACE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPYTHONINTERFACE_H
+
+#include "lldb/Host/Config.h"
+
+#if LLDB_ENABLE_PYTHON
+
+#include "ScriptedPythonInterface.h"
+#include "lldb/Interpreter/Interfaces/ScriptedFrameInterface.h"
+#include <optional>
+
+namespace lldb_private {
+class ScriptedFramePythonInterface : public ScriptedFrameInterface,
+ public ScriptedPythonInterface {
+public:
+ ScriptedFramePythonInterface(ScriptInterpreterPythonImpl &interpreter);
+
+ llvm::Expected<StructuredData::GenericSP>
+ CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
+ StructuredData::DictionarySP args_sp,
+ StructuredData::Generic *script_obj = nullptr) override;
+
+ llvm::SmallVector<AbstractMethodRequirement>
+ GetAbstractMethodRequirements() const override {
+ return llvm::SmallVector<AbstractMethodRequirement>({{"get_id"}});
+ }
+
+ lldb::user_id_t GetID() override;
+
+ lldb::addr_t GetPC() override;
+
+ std::optional<SymbolContext> GetSymbolContext() override;
+
+ std::optional<std::string> GetFunctionName() override;
+
+ std::optional<std::string> GetDisplayFunctionName() override;
+
+ bool IsInlined() override;
+
+ bool IsArtificial() override;
+
+ bool IsHidden() override;
+
+ StructuredData::DictionarySP GetRegisterInfo() override;
+
+ std::optional<std::string> GetRegisterContext() override;
+};
+} // namespace lldb_private
+
+#endif // LLDB_ENABLE_PYTHON
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDFRAMEPYTHONINTERFACE_H
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
index b49d1d82fe535..8083ccae04026 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp
@@ -167,7 +167,8 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<
if (!sb_mem_reg_info) {
error = Status::FromErrorStringWithFormat(
- "Couldn't cast lldb::SBMemoryRegionInfo to lldb::MemoryRegionInfoSP.");
+ "Couldn't cast lldb::SBMemoryRegionInfo to "
+ "lldb_private::MemoryRegionInfo.");
return {};
}
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
index 8af89d761764b..fd4d231a747fe 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp
@@ -144,4 +144,21 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetExtendedInfo() {
return arr;
}
+std::optional<std::string>
+ScriptedThreadPythonInterface::GetScriptedFramePluginName() {
+ Status error;
+ StructuredData::ObjectSP obj = Dispatch("get_scripted_frame_plugin", error);
+
+ if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
+ error))
+ return {};
+
+ return obj->GetStringValue().str();
+}
+
+lldb::ScriptedFrameInterfaceSP
+ScriptedThreadPythonInterface::CreateScriptedFrameInterface() {
+ return m_interpreter.CreateScriptedFrameInterface();
+}
+
#endif
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
index 1fb23b39c7076..043557a827461 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.h
@@ -51,6 +51,11 @@ class ScriptedThreadPythonInterface : public ScriptedThreadInterface,
std::optional<std::string> GetRegisterContext() override;
StructuredData::ArraySP GetExtendedInfo() override;
+
+ std::optional<std::string> GetScriptedFramePluginName() override;
+
+protected:
+ lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index 9330a634489a2..73c5c72932ff1 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -1521,6 +1521,11 @@ ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() {
return std::make_shared<ScriptedThreadPythonInterface>(*this);
}
+ScriptedFrameInterfaceSP
+ScriptInterpreterPythonImpl::CreateScriptedFrameInterface() {
+ return std::make_shared<ScriptedFramePythonInterface>(*this);
+}
+
ScriptedThreadPlanInterfaceSP
ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() {
return std::make_shared<ScriptedThreadPlanPythonInterface>(*this);
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
index 83b64b85faebd..dedac280788f4 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h
@@ -99,6 +99,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override;
+ lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface() override;
+
lldb::ScriptedThreadPlanInterfaceSP
CreateScriptedThreadPlanInterface() override;
diff --git a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
index 2721d961bcb9d..835267221ddb4 100644
--- a/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
+++ b/lldb/test/API/functionalities/scripted_process/dummy_scripted_process.py
@@ -5,6 +5,7 @@
import lldb
from lldb.plugins.scripted_process import ScriptedProcess
from lldb.plugins.scripted_process import ScriptedThread
+from lldb.plugins.scripted_process import ScriptedFrame
class DummyStopHook:
@@ -22,7 +23,7 @@ class DummyScriptedProcess(ScriptedProcess):
def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData):
super().__init__(exe_ctx, args)
- self.threads[0] = DummyScriptedThread(self, None)
+ self.threads[0] = DummyScriptedThread(self, args)
self.memory = {}
addr = 0x500000000
debugger = self.target.GetDebugger()
@@ -69,6 +70,9 @@ class DummyScriptedThread(ScriptedThread):
def __init__(self, process, args):
super().__init__(process, args)
self.frames.append({"pc": 0x0100001B00})
+ self.frames.append(DummyScriptedFrame(self, args, len(self.frames), "baz123"))
+ self.frames.append(DummyScriptedFrame(self, args, len(self.frames), "bar"))
+ self.frames.append(DummyScriptedFrame(self, args, len(self.frames), "foo"))
def get_thread_id(self) -> int:
return 0x19
@@ -109,6 +113,65 @@ def get_register_context(self) -> str:
)
+class DummyScriptedFrame(ScriptedFrame):
+ def __init__(self, thread, args, id, name, sym_ctx=None):
+ super().__init__(thread, args)
+ self.id = id
+ self.name = name
+ self.sym_ctx = sym_ctx
+
+ def get_id(self):
+ return self.id
+
+ def get_function_name(self):
+ return self.name
+
+ def get_register_context(self) -> str:
+ return struct.pack(
+ "21Q",
+ 0x10001,
+ 0x10002,
+ 0x10003,
+ 0x10004,
+ 0x10005,
+ 0x10006,
+ 0x10007,
+ 0x10008,
+ 0x10009,
+ 0x100010,
+ 0x100011,
+ 0x100012,
+ 0x100013,
+ 0x100014,
+ 0x100015,
+ 0x100016,
+ 0x100017,
+ 0x100018,
+ 0x100019,
+ 0x100020,
+ 0x100021,
+ )
+
+ def get_symbol_context(self):
+ def get_symbol_context_for_function(func_name):
+ module = self.target.FindModule(self.target.GetExecutable())
+ if not module.IsValid():
+ return None
+
+ sym_ctx_list = module.FindFunctions(func_name)
+ if not sym_ctx_list.IsValid() or sym_ctx_list.GetSize() == 0:
+ return None
+
+ return sym_ctx_list.GetContextAtIndex(0)
+
+ return (
+ self.sym_ctx if self.sym_ctx else get_symbol_context_for_function(self.name)
+ )
+
+ def get_scripted_frame_plugin(self):
+ return DummyScriptedFrame.__module__ + "." + DummyScriptedFrame.__name__
+
+
def __lldb_init_module(debugger, dict):
# This is used when loading the script in an interactive debug session to
# automatically, register the stop-hook and launch the scripted process.
More information about the lldb-commits
mailing list