diff options
Diffstat (limited to 'lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp')
| -rw-r--r-- | lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp new file mode 100644 index 0000000..739963e --- /dev/null +++ b/lldb/source/Plugins/SyntheticFrameProvider/ScriptedFrameProvider/ScriptedFrameProvider.cpp @@ -0,0 +1,221 @@ +//===----------------------------------------------------------------------===// +// +// 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 "ScriptedFrameProvider.h" +#include "Plugins/Process/scripted/ScriptedFrame.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/BorrowedStackFrame.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ScriptedMetadata.h" +#include "lldb/Utility/Status.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +using namespace lldb; +using namespace lldb_private; + +void ScriptedFrameProvider::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Provides synthetic frames via scripting", + nullptr, ScriptedFrameProvider::CreateInstance); +} + +void ScriptedFrameProvider::Terminate() { + PluginManager::UnregisterPlugin(ScriptedFrameProvider::CreateInstance); +} + +llvm::Expected<lldb::SyntheticFrameProviderSP> +ScriptedFrameProvider::CreateInstance( + lldb::StackFrameListSP input_frames, + const ScriptedFrameProviderDescriptor &descriptor) { + if (!input_frames) + return llvm::createStringError( + "failed to create scripted frame provider: invalid input frames"); + + Thread &thread = input_frames->GetThread(); + ProcessSP process_sp = thread.GetProcess(); + if (!process_sp) + return nullptr; + + if (!descriptor.IsValid()) + return llvm::createStringError( + "failed to create scripted frame provider: invalid scripted metadata"); + + if (!descriptor.AppliesToThread(thread)) + return nullptr; + + ScriptInterpreter *script_interp = + process_sp->GetTarget().GetDebugger().GetScriptInterpreter(); + if (!script_interp) + return llvm::createStringError("cannot create scripted frame provider: No " + "script interpreter installed"); + + ScriptedFrameProviderInterfaceSP interface_sp = + script_interp->CreateScriptedFrameProviderInterface(); + if (!interface_sp) + return llvm::createStringError( + "cannot create scripted frame provider: script interpreter couldn't " + "create Scripted Frame Provider Interface"); + + const ScriptedMetadataSP scripted_metadata = descriptor.scripted_metadata_sp; + + // If we shouldn't attach a frame provider to this thread, just exit early. + if (!interface_sp->AppliesToThread(scripted_metadata->GetClassName(), + thread.shared_from_this())) + return nullptr; + + auto obj_or_err = interface_sp->CreatePluginObject( + scripted_metadata->GetClassName(), input_frames, + scripted_metadata->GetArgsSP()); + if (!obj_or_err) + return obj_or_err.takeError(); + + StructuredData::ObjectSP object_sp = *obj_or_err; + if (!object_sp || !object_sp->IsValid()) + return llvm::createStringError( + "cannot create scripted frame provider: failed to create valid scripted" + "frame provider object"); + + return std::make_shared<ScriptedFrameProvider>(input_frames, interface_sp, + descriptor); +} + +ScriptedFrameProvider::ScriptedFrameProvider( + StackFrameListSP input_frames, + lldb::ScriptedFrameProviderInterfaceSP interface_sp, + const ScriptedFrameProviderDescriptor &descriptor) + : SyntheticFrameProvider(input_frames), m_interface_sp(interface_sp), + m_descriptor(descriptor) {} + +ScriptedFrameProvider::~ScriptedFrameProvider() = default; + +std::string ScriptedFrameProvider::GetDescription() const { + if (!m_interface_sp) + return {}; + + return m_interface_sp->GetDescription(m_descriptor.GetName()); +} + +llvm::Expected<StackFrameSP> +ScriptedFrameProvider::GetFrameAtIndex(uint32_t idx) { + if (!m_interface_sp) + return llvm::createStringError( + "cannot get stack frame: scripted frame provider not initialized"); + + auto create_frame_from_dict = + [this](StructuredData::Dictionary *dict, + uint32_t index) -> llvm::Expected<StackFrameSP> { + lldb::addr_t pc; + if (!dict->GetValueForKeyAsInteger("pc", pc)) + return llvm::createStringError( + "missing 'pc' key from scripted frame dictionary"); + + Address symbol_addr; + symbol_addr.SetLoadAddress(pc, &GetThread().GetProcess()->GetTarget()); + + const lldb::addr_t cfa = LLDB_INVALID_ADDRESS; + const bool cfa_is_valid = false; + const bool artificial = false; + const bool behaves_like_zeroth_frame = false; + SymbolContext sc; + symbol_addr.CalculateSymbolContext(&sc); + + ThreadSP thread_sp = GetThread().shared_from_this(); + return std::make_shared<StackFrame>(thread_sp, index, index, cfa, + cfa_is_valid, pc, + StackFrame::Kind::Synthetic, artificial, + behaves_like_zeroth_frame, &sc); + }; + + auto create_frame_from_script_object = + [this]( + StructuredData::ObjectSP object_sp) -> llvm::Expected<StackFrameSP> { + Status error; + if (!object_sp || !object_sp->GetAsGeneric()) + return llvm::createStringError("invalid script object"); + + ThreadSP thread_sp = GetThread().shared_from_this(); + auto frame_or_error = ScriptedFrame::Create(thread_sp, nullptr, nullptr, + object_sp->GetAsGeneric()); + + if (!frame_or_error) { + ScriptedInterface::ErrorWithMessage<bool>( + LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error); + return error.ToError(); + } + + return *frame_or_error; + }; + + StructuredData::ObjectSP obj_sp = m_interface_sp->GetFrameAtIndex(idx); + + // None/null means no more frames or error. + if (!obj_sp || !obj_sp->IsValid()) + return llvm::createStringError("invalid script object returned for frame " + + llvm::Twine(idx)); + + StackFrameSP synth_frame_sp = nullptr; + if (StructuredData::UnsignedInteger *int_obj = + obj_sp->GetAsUnsignedInteger()) { + uint32_t real_frame_index = int_obj->GetValue(); + if (real_frame_index < m_input_frames->GetNumFrames()) { + StackFrameSP real_frame_sp = + m_input_frames->GetFrameAtIndex(real_frame_index); + synth_frame_sp = + (real_frame_index == idx) + ? real_frame_sp + : std::make_shared<BorrowedStackFrame>(real_frame_sp, idx); + } + } else if (StructuredData::Dictionary *dict = obj_sp->GetAsDictionary()) { + // Check if it's a dictionary describing a frame. + auto frame_from_dict_or_err = create_frame_from_dict(dict, idx); + if (!frame_from_dict_or_err) { + return llvm::createStringError(llvm::Twine( + "couldn't create frame from dictionary at index " + llvm::Twine(idx) + + ": " + toString(frame_from_dict_or_err.takeError()))); + } + synth_frame_sp = *frame_from_dict_or_err; + } else if (obj_sp->GetAsGeneric()) { + // It's a ScriptedFrame object. + auto frame_from_script_obj_or_err = create_frame_from_script_object(obj_sp); + if (!frame_from_script_obj_or_err) { + return llvm::createStringError( + llvm::Twine("couldn't create frame from script object at index " + + llvm::Twine(idx) + ": " + + toString(frame_from_script_obj_or_err.takeError()))); + } + synth_frame_sp = *frame_from_script_obj_or_err; + } else { + return llvm::createStringError( + llvm::Twine("invalid return type from get_frame_at_index at index " + + llvm::Twine(idx))); + } + + if (!synth_frame_sp) + return llvm::createStringError( + llvm::Twine("failed to create frame at index " + llvm::Twine(idx))); + + synth_frame_sp->SetFrameIndex(idx); + + return synth_frame_sp; +} + +namespace lldb_private { +void lldb_initialize_ScriptedFrameProvider() { + ScriptedFrameProvider::Initialize(); +} + +void lldb_terminate_ScriptedFrameProvider() { + ScriptedFrameProvider::Terminate(); +} +} // namespace lldb_private |
