LLDB mainline
ScriptedFrameProvider.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "lldb/Core/Debugger.h"
16#include "lldb/Target/Process.h"
18#include "lldb/Target/Thread.h"
20#include "lldb/Utility/Status.h"
21#include "llvm/Support/Error.h"
22#include <cstdint>
23
24using namespace lldb;
25using namespace lldb_private;
26
28
31 "Provides synthetic frames via scripting",
33}
34
38
39llvm::Expected<lldb::SyntheticFrameProviderSP>
41 lldb::StackFrameListSP input_frames,
42 const ScriptedFrameProviderDescriptor &descriptor) {
43 if (!input_frames)
44 return llvm::createStringError(
45 "failed to create scripted frame provider: invalid input frames");
46
47 Thread &thread = input_frames->GetThread();
48 ProcessSP process_sp = thread.GetProcess();
49 if (!process_sp)
50 return nullptr;
51
52 if (!descriptor.IsValid())
53 return llvm::createStringError(
54 "failed to create scripted frame provider: invalid scripted metadata");
55
56 if (!descriptor.AppliesToThread(thread))
57 return nullptr;
58
59 ScriptInterpreter *script_interp =
60 process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
61 if (!script_interp)
62 return llvm::createStringError("cannot create scripted frame provider: No "
63 "script interpreter installed");
64
67 if (!interface_sp)
68 return llvm::createStringError(
69 "cannot create scripted frame provider: script interpreter couldn't "
70 "create Scripted Frame Provider Interface");
71
72 const ScriptedMetadataSP scripted_metadata = descriptor.scripted_metadata_sp;
73
74 // If we shouldn't attach a frame provider to this thread, just exit early.
75 if (!interface_sp->AppliesToThread(scripted_metadata->GetClassName(),
76 thread.shared_from_this()))
77 return nullptr;
78
79 auto obj_or_err =
80 interface_sp->CreatePluginObject(*scripted_metadata, input_frames);
81 if (!obj_or_err)
82 return obj_or_err.takeError();
83
84 StructuredData::ObjectSP object_sp = *obj_or_err;
85 if (!object_sp || !object_sp->IsValid())
86 return llvm::createStringError(
87 "cannot create scripted frame provider: failed to create valid scripted"
88 "frame provider object");
89
90 return std::make_shared<ScriptedFrameProvider>(input_frames, interface_sp,
91 descriptor);
92}
93
100
102
104 if (!m_interface_sp)
105 return {};
106
107 return m_interface_sp->GetDescription(m_descriptor.GetName());
108}
109
110std::optional<uint32_t> ScriptedFrameProvider::GetPriority() const {
111 if (!m_interface_sp)
112 return std::nullopt;
113
114 return m_interface_sp->GetPriority(m_descriptor.GetName());
115}
116
117llvm::Expected<StackFrameSP>
119 if (!m_interface_sp)
120 return llvm::createStringError(
121 "cannot get stack frame: scripted frame provider not initialized");
122
123 auto create_frame_from_dict =
124 [this](StructuredData::Dictionary *dict,
125 uint32_t index) -> llvm::Expected<StackFrameSP> {
127 if (!dict->GetValueForKeyAsInteger("pc", pc))
128 return llvm::createStringError(
129 "missing 'pc' key from scripted frame dictionary");
130
131 Address symbol_addr;
132 symbol_addr.SetLoadAddress(pc, &GetThread().GetProcess()->GetTarget());
133
135 const bool cfa_is_valid = false;
136 const bool artificial = false;
137 const bool behaves_like_zeroth_frame = false;
138 SymbolContext sc;
139 symbol_addr.CalculateSymbolContext(&sc);
140
141 ThreadSP thread_sp = GetThread().shared_from_this();
142 return std::make_shared<StackFrame>(thread_sp, index, index, cfa,
143 cfa_is_valid, pc,
144 StackFrame::Kind::Synthetic, artificial,
145 behaves_like_zeroth_frame, &sc);
146 };
147
148 auto create_frame_from_script_object =
149 [this](
150 StructuredData::ObjectSP object_sp) -> llvm::Expected<StackFrameSP> {
152 if (!object_sp || !object_sp->GetAsGeneric())
153 return llvm::createStringError("invalid script object");
154
155 ThreadSP thread_sp = GetThread().shared_from_this();
156 auto frame_or_error = ScriptedFrame::Create(thread_sp, nullptr, nullptr,
157 object_sp->GetAsGeneric());
158
159 if (!frame_or_error) {
161 LLVM_PRETTY_FUNCTION, toString(frame_or_error.takeError()), error);
162 return error.ToError();
163 }
164
165 return *frame_or_error;
166 };
167
168 StructuredData::ObjectSP obj_sp = m_interface_sp->GetFrameAtIndex(idx);
169
170 // None/null means no more frames or error.
171 if (!obj_sp || !obj_sp->IsValid())
172 return llvm::createStringError("invalid script object returned for frame " +
173 llvm::Twine(idx));
174
175 StackFrameSP synth_frame_sp = nullptr;
177 obj_sp->GetAsUnsignedInteger()) {
178 uint32_t real_frame_index = int_obj->GetValue();
179 if (real_frame_index < m_input_frames->GetNumFrames()) {
180 StackFrameSP real_frame_sp =
181 m_input_frames->GetFrameAtIndex(real_frame_index);
182 synth_frame_sp =
183 (real_frame_index == idx)
184 ? real_frame_sp
185 : std::make_shared<BorrowedStackFrame>(real_frame_sp, idx);
186 }
187 } else if (StructuredData::Dictionary *dict = obj_sp->GetAsDictionary()) {
188 // Check if it's a dictionary describing a frame.
189 auto frame_from_dict_or_err = create_frame_from_dict(dict, idx);
190 if (!frame_from_dict_or_err) {
191 return llvm::createStringError(llvm::Twine(
192 "couldn't create frame from dictionary at index " + llvm::Twine(idx) +
193 ": " + toString(frame_from_dict_or_err.takeError())));
194 }
195 synth_frame_sp = *frame_from_dict_or_err;
196 } else if (obj_sp->GetAsGeneric()) {
197 // It's a ScriptedFrame object.
198 auto frame_from_script_obj_or_err = create_frame_from_script_object(obj_sp);
199 if (!frame_from_script_obj_or_err) {
200 return llvm::createStringError(
201 llvm::Twine("couldn't create frame from script object at index " +
202 llvm::Twine(idx) + ": " +
203 toString(frame_from_script_obj_or_err.takeError())));
204 }
205 synth_frame_sp = *frame_from_script_obj_or_err;
206 } else {
207 return llvm::createStringError(
208 llvm::Twine("invalid return type from get_frame_at_index at index " +
209 llvm::Twine(idx)));
210 }
211
212 if (!synth_frame_sp)
213 return llvm::createStringError(
214 llvm::Twine("failed to create frame at index " + llvm::Twine(idx)));
215
216 synth_frame_sp->SetFrameIndex(idx);
217
218 return synth_frame_sp;
219}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_PLUGIN_DEFINE(PluginName)
A section + offset based address class.
Definition Address.h:62
bool SetLoadAddress(lldb::addr_t load_addr, Target *target, bool allow_section_end=false)
Set the address to represent load_addr.
Definition Address.cpp:1034
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition Address.cpp:819
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
virtual lldb::ScriptedFrameProviderInterfaceSP CreateScriptedFrameProviderInterface()
lldb::ScriptedFrameProviderInterfaceSP m_interface_sp
static llvm::StringRef GetPluginNameStatic()
llvm::Expected< lldb::StackFrameSP > GetFrameAtIndex(uint32_t idx) override
Get a single stack frame at the specified index.
static llvm::Expected< lldb::SyntheticFrameProviderSP > CreateInstance(lldb::StackFrameListSP input_frames, const ScriptedFrameProviderDescriptor &descriptor)
ScriptedFrameProvider(lldb::StackFrameListSP input_frames, lldb::ScriptedFrameProviderInterfaceSP interface_sp, const ScriptedFrameProviderDescriptor &descriptor)
const ScriptedFrameProviderDescriptor & m_descriptor
std::optional< uint32_t > GetPriority() const override
Get the priority of this frame provider.
std::string GetDescription() const override
static llvm::Expected< std::shared_ptr< ScriptedFrame > > Create(lldb::ThreadSP thread_sp, lldb::ScriptedThreadInterfaceSP scripted_thread_interface_sp, StructuredData::DictionarySP args_sp, StructuredData::Generic *script_object=nullptr)
Create a ScriptedFrame from a object instanciated in the script interpreter.
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef error_msg, Status &error, LLDBLog log_category=LLDBLog::Process)
@ Synthetic
An synthetic stack frame (e.g.
Definition StackFrame.h:72
An error handling class.
Definition Status.h:118
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
std::shared_ptr< Object > ObjectSP
Integer< uint64_t > UnsignedInteger
Defines a symbol context baton that can be handed other debug core functions.
Thread & GetThread()
Get the thread associated with this provider.
SyntheticFrameProvider(lldb::StackFrameListSP input_frames)
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ScriptedMetadata > ScriptedMetadataSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::ScriptedFrameProviderInterface > ScriptedFrameProviderInterfaceSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::StackFrameList > StackFrameListSP
This struct contains the metadata needed to instantiate a frame provider and optional filters to cont...
lldb::ScriptedMetadataSP scripted_metadata_sp
Metadata for instantiating the provider (e.g. script class name and args).
bool AppliesToThread(Thread &thread) const
Check if this descriptor applies to the given thread.
bool IsValid() const
Check if this descriptor has valid metadata for script-based providers.