LLDB mainline
ScriptedFrame.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
9#include "ScriptedFrame.h"
11
13#include "lldb/Core/Address.h"
14#include "lldb/Core/Debugger.h"
15#include "lldb/Core/Module.h"
26#include "lldb/Target/Process.h"
28#include "lldb/Target/Thread.h"
31#include "lldb/Utility/Log.h"
35
36using namespace lldb;
37using namespace lldb_private;
38
40
42 lldbassert(m_script_object_sp && "Invalid Script Object.");
43 lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
44}
45
46llvm::Expected<std::shared_ptr<ScriptedFrame>>
48 ScriptedThreadInterfaceSP scripted_thread_interface_sp,
50 StructuredData::Generic *script_object) {
51 if (!thread_sp || !thread_sp->IsValid())
52 return llvm::createStringError("invalid thread");
53
54 ProcessSP process_sp = thread_sp->GetProcess();
55 if (!process_sp || !process_sp->IsValid())
56 return llvm::createStringError("invalid process");
57
58 ScriptInterpreter *script_interp =
59 process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
60 if (!script_interp)
61 return llvm::createStringError("no script interpreter");
62
63 auto scripted_frame_interface = script_interp->CreateScriptedFrameInterface();
64 if (!scripted_frame_interface)
65 return llvm::createStringError("failed to create scripted frame interface");
66
67 llvm::StringRef frame_class_name;
68 if (!script_object) {
69 // If no script object is provided and we have a scripted thread interface,
70 // try to get the frame class name from it.
71 if (scripted_thread_interface_sp) {
72 std::optional<std::string> class_name =
73 scripted_thread_interface_sp->GetScriptedFramePluginName();
74 if (!class_name || class_name->empty())
75 return llvm::createStringError(
76 "failed to get scripted frame class name");
77 frame_class_name = *class_name;
78 } else {
79 return llvm::createStringError(
80 "no script object provided and no scripted thread interface");
81 }
82 }
83
84 ExecutionContext exe_ctx(thread_sp);
85 auto obj_or_err = scripted_frame_interface->CreatePluginObject(
86 frame_class_name, exe_ctx, args_sp, script_object);
87
88 if (!obj_or_err)
89 return llvm::createStringError(
90 "failed to create script object: %s",
91 llvm::toString(obj_or_err.takeError()).c_str());
92
93 StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
94
95 if (!owned_script_object_sp->IsValid())
96 return llvm::createStringError("created script object is invalid");
97
98 lldb::user_id_t frame_id = scripted_frame_interface->GetID();
99
100 lldb::addr_t pc = scripted_frame_interface->GetPC();
101 SymbolContext sc;
102 Address symbol_addr;
103 if (pc != LLDB_INVALID_ADDRESS) {
104 symbol_addr.SetLoadAddress(pc, &process_sp->GetTarget());
105 symbol_addr.CalculateSymbolContext(&sc);
106 }
107
108 std::optional<SymbolContext> maybe_sym_ctx =
109 scripted_frame_interface->GetSymbolContext();
110 if (maybe_sym_ctx)
111 sc = *maybe_sym_ctx;
112
113 lldb::RegisterContextSP reg_ctx_sp;
114 auto regs_or_err =
115 CreateRegisterContext(*scripted_frame_interface, *thread_sp, frame_id);
116 if (!regs_or_err)
117 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), regs_or_err.takeError(), "{0}");
118 else
119 reg_ctx_sp = *regs_or_err;
120
121 return std::make_shared<ScriptedFrame>(thread_sp, scripted_frame_interface,
122 frame_id, pc, sc, reg_ctx_sp,
123 owned_script_object_sp);
124}
125
127 ScriptedFrameInterfaceSP interface_sp,
129 SymbolContext &sym_ctx,
130 lldb::RegisterContextSP reg_ctx_sp,
131 StructuredData::GenericSP script_object_sp)
132 : StackFrame(thread_sp, /*frame_idx=*/id,
133 /*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
134 /*cfa=*/0, /*pc=*/pc,
135 /*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
136 m_scripted_frame_interface_sp(interface_sp),
137 m_script_object_sp(script_object_sp) {
138 // FIXME: This should be part of the base class constructor.
140}
141
143
146 std::optional<std::string> function_name = GetInterface()->GetFunctionName();
147 if (!function_name)
149 return ConstString(function_name->c_str()).AsCString();
150}
151
154 std::optional<std::string> function_name =
155 GetInterface()->GetDisplayFunctionName();
156 if (!function_name)
158 return ConstString(function_name->c_str()).AsCString();
159}
160
161bool ScriptedFrame::IsInlined() { return GetInterface()->IsInlined(); }
162
164 return GetInterface()->IsArtificial();
165}
166
167bool ScriptedFrame::IsHidden() { return GetInterface()->IsHidden(); }
168
172
173std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
175
176 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
177
179 if (!reg_info)
181 std::shared_ptr<DynamicRegisterInfo>>(
182 LLVM_PRETTY_FUNCTION, "failed to get scripted frame registers info",
184
185 ThreadSP thread_sp = m_thread_wp.lock();
186 if (!thread_sp || !thread_sp->IsValid())
188 std::shared_ptr<DynamicRegisterInfo>>(
189 LLVM_PRETTY_FUNCTION,
190 "failed to get scripted frame registers info: invalid thread", error,
192
193 ProcessSP process_sp = thread_sp->GetProcess();
194 if (!process_sp || !process_sp->IsValid())
196 std::shared_ptr<DynamicRegisterInfo>>(
197 LLVM_PRETTY_FUNCTION,
198 "failed to get scripted frame registers info: invalid process", error,
200
201 return DynamicRegisterInfo::Create(*reg_info,
202 process_sp->GetTarget().GetArchitecture());
203}
204
205llvm::Expected<lldb::RegisterContextSP>
207 Thread &thread, lldb::user_id_t frame_id) {
208 StructuredData::DictionarySP reg_info = interface.GetRegisterInfo();
209
210 if (!reg_info)
211 return llvm::createStringError(
212 "failed to get scripted frame registers info");
213
214 std::shared_ptr<DynamicRegisterInfo> register_info_sp =
216 *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
217
218 lldb::RegisterContextSP reg_ctx_sp;
219
220 std::optional<std::string> reg_data = interface.GetRegisterContext();
221 if (!reg_data)
222 return llvm::createStringError(
223 "failed to get scripted frame registers data");
224
225 DataBufferSP data_sp(
226 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
227
228 if (!data_sp->GetByteSize())
229 return llvm::createStringError("failed to copy raw registers data");
230
231 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
232 std::make_shared<RegisterContextMemory>(
233 thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
234
235 reg_ctx_memory->SetAllRegisterData(data_sp);
236 reg_ctx_sp = reg_ctx_memory;
237
238 return reg_ctx_sp;
239}
240
242 if (!m_reg_context_sp) {
246 LLVM_PRETTY_FUNCTION,
247 "failed to get scripted frame registers context: invalid interface",
249
250 ThreadSP thread_sp = GetThread();
251 if (!thread_sp)
253 LLVM_PRETTY_FUNCTION,
254 "failed to get scripted frame registers context: invalid thread",
256
258 *thread_sp, GetFrameIndex());
259 if (!regs_or_err) {
260 error = Status::FromError(regs_or_err.takeError());
262 LLVM_PRETTY_FUNCTION,
263 "failed to get scripted frame registers context", error,
265 }
266
267 m_reg_context_sp = *regs_or_err;
268 }
269
270 return m_reg_context_sp;
271}
272
274 Status *error_ptr) {
276 return m_variable_list_sp.get();
277}
278
281 bool must_have_valid_location) {
283 return m_variable_list_sp;
284}
285
287 // Fetch values from the interface.
288 ValueObjectListSP value_list_sp = GetInterface()->GetVariables();
289 if (!value_list_sp)
290 return;
291
292 // Convert what we can into a variable.
293 m_variable_list_sp = std::make_shared<VariableList>();
294 for (uint32_t i = 0, e = value_list_sp->GetSize(); i < e; ++i) {
295 ValueObjectSP v = value_list_sp->GetValueObjectAtIndex(i);
296 if (!v)
297 continue;
298
299 VariableSP var = v->GetVariable();
300 // TODO: We could in theory ask the scripted frame to *produce* a
301 // variable for this value object.
302 if (!var)
303 continue;
304
305 m_variable_list_sp->AddVariable(var);
306 }
307}
308
310 const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic) {
311 // Fetch values from the interface.
312 ValueObjectListSP values = m_scripted_frame_interface_sp->GetVariables();
313 if (!values)
314 return {};
315
316 return values->FindValueObjectByValueName(variable_sp->GetName().AsCString());
317}
318
320 llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
321 uint32_t options, lldb::VariableSP &var_sp, Status &error) {
322 // Unless the frame implementation knows how to create variables (which it
323 // doesn't), we can't construct anything for the variable. This may seem
324 // somewhat out of place, but it's basically because of how this API is used -
325 // the print command uses this API to fill in var_sp; and this implementation
326 // can't do that!
327 // FIXME: We should make it possible for the frame implementation to create
328 // Variable objects.
329 (void)var_sp;
330 // Otherwise, delegate to the scripted frame interface pointer.
331 return m_scripted_frame_interface_sp->GetValueObjectForVariableExpression(
332 var_expr, options, error);
333}
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition LLDBAssert.h:16
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
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:1035
uint32_t CalculateSymbolContext(SymbolContext *sc, lldb::SymbolContextItem resolve_scope=lldb::eSymbolContextEverything) const
Reconstruct a symbol context from an address.
Definition Address.cpp:820
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
static std::unique_ptr< DynamicRegisterInfo > Create(const StructuredData::Dictionary &dict, const ArchSpec &arch)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
virtual lldb::ScriptedFrameInterfaceSP CreateScriptedFrameInterface()
virtual StructuredData::DictionarySP GetRegisterInfo()
virtual std::optional< std::string > GetRegisterContext()
lldb::VariableListSP m_variable_list_sp
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.
bool IsArtificial() const override
Query whether this frame is artificial (e.g a synthesized result of inferring missing tail call frame...
const char * GetFunctionName() override
Get the frame's demangled name.
VariableList * GetVariableList(bool get_file_globals, lldb_private::Status *error_ptr) override
Retrieve the list of variables whose scope either:
lldb::ScriptedFrameInterfaceSP GetInterface() const
lldb::VariableListSP GetInScopeVariableList(bool get_file_globals, bool must_have_valid_location=false) override
Retrieve the list of variables that are in scope at this StackFrame's pc.
void CheckInterpreterAndScriptObject() const
lldb::ScriptedFrameInterfaceSP m_scripted_frame_interface_sp
lldb::ValueObjectSP GetValueForVariableExpressionPath(llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, uint32_t options, lldb::VariableSP &var_sp, Status &error) override
Create a ValueObject for a variable name / pathname, possibly including simple dereference/child sele...
static llvm::Expected< lldb::RegisterContextSP > CreateRegisterContext(ScriptedFrameInterface &interface, Thread &thread, lldb::user_id_t frame_id)
ScriptedFrame(lldb::ThreadSP thread_sp, lldb::ScriptedFrameInterfaceSP interface_sp, lldb::user_id_t frame_idx, lldb::addr_t pc, SymbolContext &sym_ctx, lldb::RegisterContextSP reg_ctx_sp, StructuredData::GenericSP script_object_sp=nullptr)
lldb_private::StructuredData::GenericSP m_script_object_sp
lldb::RegisterContextSP GetRegisterContext() override
Get the RegisterContext for this frame, if possible.
bool IsHidden() override
Query whether this frame should be hidden from backtraces.
bool IsInlined() override
Query whether this frame is a concrete frame on the call stack, or if it is an inlined frame derived ...
const char * GetDisplayFunctionName() override
Get the frame's demangled display name.
lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic) override
Create a ValueObject for a given Variable in this StackFrame.
std::shared_ptr< DynamicRegisterInfo > GetDynamicRegisterInfo()
static Ret ErrorWithMessage(llvm::StringRef caller_name, llvm::StringRef error_msg, Status &error, LLDBLog log_category=LLDBLog::Process)
lldb::ThreadSP GetThread() const
Definition StackFrame.h:135
virtual const char * GetFunctionName()
Get the frame's demangled name.
lldb::ThreadWP m_thread_wp
For StackFrame and derived classes only.
Definition StackFrame.h:573
lldb::RegisterContextSP m_reg_context_sp
Definition StackFrame.h:576
@ Synthetic
An synthetic stack frame (e.g.
Definition StackFrame.h:72
virtual const char * GetDisplayFunctionName()
Get the frame's demangled display name.
virtual uint32_t GetFrameIndex() const
Query this frame to find what frame it is in this Thread's StackFrameList.
StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa, bool cfa_is_valid, lldb::addr_t pc, Kind frame_kind, bool artificial, bool behaves_like_zeroth_frame, const SymbolContext *sc_ptr)
Construct a StackFrame object without supplying a RegisterContextSP.
An error handling class.
Definition Status.h:118
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:137
std::shared_ptr< Generic > GenericSP
std::shared_ptr< Dictionary > DictionarySP
Defines a symbol context baton that can be handed other debug core functions.
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::ScriptedThreadInterface > ScriptedThreadInterfaceSP
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
std::shared_ptr< lldb_private::VariableList > VariableListSP
std::shared_ptr< lldb_private::Variable > VariableSP
uint64_t user_id_t
Definition lldb-types.h:82
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
std::shared_ptr< lldb_private::ScriptedFrameInterface > ScriptedFrameInterfaceSP