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
12#include "lldb/Core/Address.h"
13#include "lldb/Core/Debugger.h"
14#include "lldb/Core/Module.h"
25#include "lldb/Target/Thread.h"
29#include "lldb/Utility/Log.h"
33
34using namespace lldb;
35using namespace lldb_private;
36
38
40 lldbassert(m_script_object_sp && "Invalid Script Object.");
41 lldbassert(GetInterface() && "Invalid Scripted Frame Interface.");
42}
43
44llvm::Expected<std::shared_ptr<ScriptedFrame>>
46 ScriptedThreadInterfaceSP scripted_thread_interface_sp,
48 StructuredData::Generic *script_object) {
49 if (!thread_sp || !thread_sp->IsValid())
50 return llvm::createStringError("invalid thread");
51
52 ProcessSP process_sp = thread_sp->GetProcess();
53 if (!process_sp || !process_sp->IsValid())
54 return llvm::createStringError("invalid process");
55
56 ScriptInterpreter *script_interp =
57 process_sp->GetTarget().GetDebugger().GetScriptInterpreter();
58 if (!script_interp)
59 return llvm::createStringError("no script interpreter");
60
61 auto scripted_frame_interface = script_interp->CreateScriptedFrameInterface();
62 if (!scripted_frame_interface)
63 return llvm::createStringError("failed to create scripted frame interface");
64
65 llvm::StringRef frame_class_name;
66 if (!script_object) {
67 // If no script object is provided and we have a scripted thread interface,
68 // try to get the frame class name from it.
69 if (scripted_thread_interface_sp) {
70 std::optional<std::string> class_name =
71 scripted_thread_interface_sp->GetScriptedFramePluginName();
72 if (!class_name || class_name->empty())
73 return llvm::createStringError(
74 "failed to get scripted frame class name");
75 frame_class_name = *class_name;
76 } else {
77 return llvm::createStringError(
78 "no script object provided and no scripted thread interface");
79 }
80 }
81
82 ExecutionContext exe_ctx(thread_sp);
83 auto obj_or_err = scripted_frame_interface->CreatePluginObject(
84 frame_class_name, exe_ctx, args_sp, script_object);
85
86 if (!obj_or_err)
87 return llvm::createStringError(
88 "failed to create script object: %s",
89 llvm::toString(obj_or_err.takeError()).c_str());
90
91 StructuredData::GenericSP owned_script_object_sp = *obj_or_err;
92
93 if (!owned_script_object_sp->IsValid())
94 return llvm::createStringError("created script object is invalid");
95
96 lldb::user_id_t frame_id = scripted_frame_interface->GetID();
97
98 lldb::addr_t pc = scripted_frame_interface->GetPC();
100 Address symbol_addr;
101 if (pc != LLDB_INVALID_ADDRESS) {
102 symbol_addr.SetLoadAddress(pc, &process_sp->GetTarget());
103 symbol_addr.CalculateSymbolContext(&sc);
104 }
105
106 std::optional<SymbolContext> maybe_sym_ctx =
107 scripted_frame_interface->GetSymbolContext();
108 if (maybe_sym_ctx)
109 sc = *maybe_sym_ctx;
110
111 lldb::RegisterContextSP reg_ctx_sp;
112 auto regs_or_err =
113 CreateRegisterContext(*scripted_frame_interface, *thread_sp, frame_id);
114 if (!regs_or_err)
115 LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), regs_or_err.takeError(), "{0}");
116 else
117 reg_ctx_sp = *regs_or_err;
118
119 return std::make_shared<ScriptedFrame>(thread_sp, scripted_frame_interface,
120 frame_id, pc, sc, reg_ctx_sp,
121 owned_script_object_sp);
122}
123
125 ScriptedFrameInterfaceSP interface_sp,
127 SymbolContext &sym_ctx,
128 lldb::RegisterContextSP reg_ctx_sp,
129 StructuredData::GenericSP script_object_sp)
130 : StackFrame(thread_sp, /*frame_idx=*/id,
131 /*concrete_frame_idx=*/id, /*reg_context_sp=*/reg_ctx_sp,
132 /*cfa=*/0, /*pc=*/pc,
133 /*behaves_like_zeroth_frame=*/!id, /*symbol_ctx=*/&sym_ctx),
134 m_scripted_frame_interface_sp(interface_sp),
135 m_script_object_sp(script_object_sp) {
136 // FIXME: This should be part of the base class constructor.
138}
139
141
144 std::optional<std::string> function_name = GetInterface()->GetFunctionName();
145 if (!function_name)
147 return ConstString(function_name->c_str()).AsCString();
148}
149
152 std::optional<std::string> function_name =
153 GetInterface()->GetDisplayFunctionName();
154 if (!function_name)
156 return ConstString(function_name->c_str()).AsCString();
157}
158
159bool ScriptedFrame::IsInlined() { return GetInterface()->IsInlined(); }
160
162 return GetInterface()->IsArtificial();
163}
164
165bool ScriptedFrame::IsHidden() { return GetInterface()->IsHidden(); }
166
170
171std::shared_ptr<DynamicRegisterInfo> ScriptedFrame::GetDynamicRegisterInfo() {
173
174 StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
175
177 if (!reg_info)
179 std::shared_ptr<DynamicRegisterInfo>>(
180 LLVM_PRETTY_FUNCTION, "failed to get scripted frame registers info",
182
183 ThreadSP thread_sp = m_thread_wp.lock();
184 if (!thread_sp || !thread_sp->IsValid())
186 std::shared_ptr<DynamicRegisterInfo>>(
187 LLVM_PRETTY_FUNCTION,
188 "failed to get scripted frame registers info: invalid thread", error,
190
191 ProcessSP process_sp = thread_sp->GetProcess();
192 if (!process_sp || !process_sp->IsValid())
194 std::shared_ptr<DynamicRegisterInfo>>(
195 LLVM_PRETTY_FUNCTION,
196 "failed to get scripted frame registers info: invalid process", error,
198
199 return DynamicRegisterInfo::Create(*reg_info,
200 process_sp->GetTarget().GetArchitecture());
201}
202
203llvm::Expected<lldb::RegisterContextSP>
205 Thread &thread, lldb::user_id_t frame_id) {
206 StructuredData::DictionarySP reg_info = interface.GetRegisterInfo();
207
208 if (!reg_info)
209 return llvm::createStringError(
210 "failed to get scripted frame registers info");
211
212 std::shared_ptr<DynamicRegisterInfo> register_info_sp =
214 *reg_info, thread.GetProcess()->GetTarget().GetArchitecture());
215
216 lldb::RegisterContextSP reg_ctx_sp;
217
218 std::optional<std::string> reg_data = interface.GetRegisterContext();
219 if (!reg_data)
220 return llvm::createStringError(
221 "failed to get scripted frame registers data");
222
223 DataBufferSP data_sp(
224 std::make_shared<DataBufferHeap>(reg_data->c_str(), reg_data->size()));
225
226 if (!data_sp->GetByteSize())
227 return llvm::createStringError("failed to copy raw registers data");
228
229 std::shared_ptr<RegisterContextMemory> reg_ctx_memory =
230 std::make_shared<RegisterContextMemory>(
231 thread, frame_id, *register_info_sp, LLDB_INVALID_ADDRESS);
232
233 reg_ctx_memory->SetAllRegisterData(data_sp);
234 reg_ctx_sp = reg_ctx_memory;
235
236 return reg_ctx_sp;
237}
238
240 if (!m_reg_context_sp) {
244 LLVM_PRETTY_FUNCTION,
245 "failed to get scripted frame registers context: invalid interface",
247
248 ThreadSP thread_sp = GetThread();
249 if (!thread_sp)
251 LLVM_PRETTY_FUNCTION,
252 "failed to get scripted frame registers context: invalid thread",
254
256 *thread_sp, GetFrameIndex());
257 if (!regs_or_err) {
258 error = Status::FromError(regs_or_err.takeError());
260 LLVM_PRETTY_FUNCTION,
261 "failed to get scripted frame registers context", error,
263 }
264
265 m_reg_context_sp = *regs_or_err;
266 }
267
268 return m_reg_context_sp;
269}
270
272 Status *error_ptr) {
274 return m_variable_list_sp.get();
275}
276
279 bool must_have_valid_location) {
281 return m_variable_list_sp;
282}
283
285 // Fetch values from the interface.
286 ValueObjectListSP value_list_sp = GetInterface()->GetVariables();
287 if (!value_list_sp)
288 return;
289
290 // Convert what we can into a variable.
291 m_variable_list_sp = std::make_shared<VariableList>();
292 for (uint32_t i = 0, e = value_list_sp->GetSize(); i < e; ++i) {
293 ValueObjectSP v = value_list_sp->GetValueObjectAtIndex(i);
294 if (!v)
295 continue;
296
297 VariableSP var = v->GetVariable();
298 // TODO: We could in theory ask the scripted frame to *produce* a
299 // variable for this value object.
300 if (!var)
301 continue;
302
303 m_variable_list_sp->AddVariable(var);
304 }
305}
306
308 const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic) {
309 // Fetch values from the interface.
310 ValueObjectListSP values = m_scripted_frame_interface_sp->GetVariables();
311 if (!values)
312 return {};
313
314 return values->FindValueObjectByValueName(variable_sp->GetName().AsCString());
315}
316
318 llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic,
319 uint32_t options, lldb::VariableSP &var_sp, Status &error) {
320 // Unless the frame implementation knows how to create variables (which it
321 // doesn't), we can't construct anything for the variable. This may seem
322 // somewhat out of place, but it's basically because of how this API is used -
323 // the print command uses this API to fill in var_sp; and this implementation
324 // can't do that!
325 // FIXME: We should make it possible for the frame implementation to create
326 // Variable objects.
327 (void)var_sp;
328 // Otherwise, delegate to the scripted frame interface pointer.
329 return m_scripted_frame_interface_sp->GetValueObjectForVariableExpression(
330 var_expr, options, error);
331}
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