LLDB mainline
TypeSynthetic.cpp
Go to the documentation of this file.
1//===-- TypeSynthetic.cpp -------------------------------------------------===//
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 "lldb/Utility/Log.h"
12#include "lldb/lldb-forward.h"
13#include "lldb/lldb-public.h"
14
15#include "lldb/Core/Debugger.h"
22#include "lldb/Target/Target.h"
24#include "llvm/Support/Error.h"
25#include "llvm/Support/ErrorExtras.h"
26#include <cstdint>
27
28using namespace lldb;
29using namespace lldb_private;
30
31void TypeFilterImpl::AddExpressionPath(const std::string &path) {
32 bool need_add_dot = true;
33 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
34 need_add_dot = false;
35 // add a '.' symbol to help forgetful users
36 if (!need_add_dot)
37 m_expression_paths.push_back(path);
38 else
39 m_expression_paths.push_back(std::string(".") + path);
40}
41
43 const std::string &path) {
44 if (i >= GetCount())
45 return false;
46 bool need_add_dot = true;
47 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
48 need_add_dot = false;
49 // add a '.' symbol to help forgetful users
50 if (!need_add_dot)
51 m_expression_paths[i] = path;
52 else
53 m_expression_paths[i] = std::string(".") + path;
54 return true;
55}
56
57llvm::Expected<size_t>
59 const char *name_cstr = name.GetCString();
60 if (name_cstr) {
61 for (size_t i = 0; i < filter->GetCount(); i++) {
62 const char *expr_cstr = filter->GetExpressionPathAtIndex(i);
63 if (expr_cstr) {
64 if (*expr_cstr == '.')
65 expr_cstr++;
66 else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>')
67 expr_cstr += 2;
68 }
69 if (expr_cstr) {
70 if (!::strcmp(name_cstr, expr_cstr))
71 return i;
72 }
73 }
74 }
75 return llvm::createStringErrorV("type has no child named '{0}'", name);
76}
77
79 StreamString sstr;
80 sstr.Printf("%s%s%s {\n", Cascades() ? "" : " (not cascading)",
81 SkipsPointers() ? " (skip pointers)" : "",
82 SkipsReferences() ? " (skip references)" : "");
83
84 for (size_t i = 0; i < GetCount(); i++) {
85 sstr.Printf(" %s\n", GetExpressionPathAtIndex(i));
86 }
87
88 sstr.PutCString("}");
89 return std::string(sstr.GetString());
90}
91
93
95
97 const SyntheticChildren::Flags &flags, const char *description,
99 : SyntheticChildren(flags), m_create_callback(std::move(callback)),
100 m_description(description ? description : "") {}
101
103
104bool SyntheticChildren::IsScripted() { return false; }
105
106std::string SyntheticChildren::GetDescription() { return ""; }
107
110 return nullptr;
111}
112
114 StreamString sstr;
115 sstr.Printf("%s%s%s %s", Cascades() ? "" : " (not cascading)",
116 SkipsPointers() ? " (skip pointers)" : "",
117 SkipsReferences() ? " (skip references)" : "",
118 m_description.c_str());
119
120 return std::string(sstr.GetString());
121}
122
123uint32_t
125 auto value_or_err = CalculateNumChildren(max);
126 if (value_or_err)
127 return *value_or_err;
128 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(),
129 "{0}");
130 return 0;
131}
132
135 llvm::StringRef name, llvm::StringRef expression,
136 const ExecutionContext &exe_ctx) {
138 ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromExpression(
139 name, expression, exe_ctx, options);
140 if (valobj_sp)
141 valobj_sp->SetSyntheticChildrenGenerated(true);
142 return valobj_sp;
143}
144
147 llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
148 CompilerType type, bool do_deref) {
149 ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromAddress(
150 name, address, exe_ctx, type, do_deref);
151 if (valobj_sp)
152 valobj_sp->SetSyntheticChildrenGenerated(true);
153 return valobj_sp;
154}
155
157 llvm::StringRef name, const DataExtractor &data,
158 const ExecutionContext &exe_ctx, CompilerType type) {
159 ValueObjectSP valobj_sp =
160 m_backend.CreateChildValueObjectFromData(name, data, exe_ctx, type);
161 if (valobj_sp)
162 valobj_sp->SetSyntheticChildrenGenerated(true);
163 return valobj_sp;
164}
165
167 ValueObject &backend)
168 : SyntheticChildrenFrontEnd(backend), m_python_class(pclass) {
169 if (backend.GetID() == LLDB_INVALID_UID)
170 return;
171
172 TargetSP target_sp = backend.GetTargetSP();
173
174 if (!target_sp)
175 return;
176
177 ScriptInterpreter *interpreter =
178 target_sp->GetDebugger().GetScriptInterpreter();
179
180 if (!interpreter)
181 return;
182
184 if (!m_interface_sp)
185 return;
186
187 auto obj_or_err = m_interface_sp->CreatePluginObject(m_python_class, backend);
188 if (!obj_or_err) {
189 llvm::consumeError(obj_or_err.takeError());
190 m_interface_sp.reset();
191 }
192}
193
195
198 if (!m_interface_sp)
199 return lldb::ValueObjectSP();
200
201 return m_interface_sp->GetChildAtIndex(idx);
202}
203
207
208llvm::Expected<uint32_t>
210 if (!m_interface_sp)
211 return 0;
212 return m_interface_sp->CalculateNumChildren(UINT32_MAX);
213}
214
215llvm::Expected<uint32_t>
217 if (!m_interface_sp)
218 return 0;
219 return m_interface_sp->CalculateNumChildren(max);
220}
221
228
230 if (!m_interface_sp)
231 return false;
232
233 return m_interface_sp->MightHaveChildren();
234}
235
236llvm::Expected<size_t>
238 if (!m_interface_sp)
239 return llvm::createStringErrorV("type has no child named '{0}'", name);
240 return m_interface_sp->GetIndexOfChildWithName(name);
241}
242
244 if (!m_interface_sp)
245 return nullptr;
246
247 return m_interface_sp->GetSyntheticValue();
248}
249
251 if (!m_interface_sp)
252 return ConstString();
253
254 return m_interface_sp->GetSyntheticTypeName();
255}
256
258 if (!m_interface_sp)
259 return nullptr;
260
261 StructuredData::GenericSP obj = m_interface_sp->GetScriptObjectInstance();
262 if (!obj)
263 return nullptr;
264
265 return obj->GetValue();
266}
267
269 StreamString sstr;
270 sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
271 SkipsPointers() ? " (skip pointers)" : "",
272 SkipsReferences() ? " (skip references)" : "",
273 m_python_class.c_str());
274
275 return std::string(sstr.GetString());
276}
277
280 : SyntheticChildrenFrontEnd(backend), m_impl(impl) {
281 FormatterBytecode::DataStack data = {backend.GetSP()};
282 if (!m_impl.init) {
283 m_init_results = std::move(data);
284 return;
285 }
286
287 FormatterBytecode::ControlStack control = {m_impl.init->getBuffer()};
288 llvm::Error error =
289 FormatterBytecode::Interpret(control, data, FormatterBytecode::sig_init);
290 if (error) {
292 "@init failed: {0}");
293 return;
294 }
295
296 if (data.size() > 0)
297 m_init_results = std::move(data);
298}
299
301 if (!m_impl.update) {
304 }
305
306 FormatterBytecode::ControlStack control = {m_impl.update->getBuffer()};
309 control, data, FormatterBytecode::sig_update);
310 if (error) {
312 "@update failed: {0}");
314 }
315
316 std::optional<ChildCacheState> can_reuse = std::nullopt;
317 const FormatterBytecode::DataStackElement &top = data.back();
318 if (auto *u = std::get_if<uint64_t>(&top))
319 if (*u == 0 || *u == 1)
320 can_reuse = static_cast<ChildCacheState>(*u);
321 if (auto *i = std::get_if<int64_t>(&top))
322 if (*i == 0 || *i == 1)
323 can_reuse = static_cast<ChildCacheState>(*i);
324
325 if (can_reuse) {
326 data.pop_back();
327 LLDB_LOG(
329 "Bytecode formatter can reuse @update: {0} (type: `{1}`, name: `{2}`)",
330 can_reuse ? "true" : "false", m_backend.GetDisplayTypeName(),
331 m_backend.GetName());
332 } else {
334 "Bytecode formatter did not return a valid reuse response from "
335 "@update (type: `{}`, name: `{}`)",
336 m_backend.GetDisplayTypeName(), m_backend.GetName());
337 }
338
339 if (data.size() > 0)
340 m_self = std::move(data);
341
342 return can_reuse.value_or(ChildCacheState::eRefetch);
343}
344
345llvm::Expected<uint32_t>
347 if (!m_impl.num_children)
348 return 0;
349
350 FormatterBytecode::ControlStack control = {m_impl.num_children->getBuffer()};
353 control, data, FormatterBytecode::sig_get_num_children);
354 if (error)
355 return error;
356
357 if (data.size() == 0) {
358 char message[] = "@get_num_children returned empty data stack";
360 return llvm::createStringError(message);
361 }
362
363 const FormatterBytecode::DataStackElement &top = data.back();
364 if (auto *u = std::get_if<uint64_t>(&top))
365 if (*u <= UINT32_MAX)
366 return *u;
367 if (auto *i = std::get_if<int64_t>(&top)) {
368 if (*i > 0 && *i <= UINT32_MAX)
369 return *i;
370 return UINT32_MAX;
371 }
372
373 return llvm::createStringError("@get_num_children returned invalid value");
374}
375
378 if (!m_impl.get_child_at_index)
379 return {};
380
382 m_impl.get_child_at_index->getBuffer()};
384 data.emplace_back((uint64_t)idx);
386 control, data, FormatterBytecode::sig_get_child_at_index);
387 if (error) {
389 "@get_child_at_index failed: {0}");
390 return {};
391 }
392
393 if (data.size() == 0) {
395 "@get_child_at_index returned empty data stack");
396 return {};
397 }
398
399 const FormatterBytecode::DataStackElement &top = data.back();
400 if (auto *child = std::get_if<ValueObjectSP>(&top))
401 return *child;
402
403 return {};
404}
405
406llvm::Expected<size_t>
408 if (m_impl.get_child_index)
409 return -1;
410
412 m_impl.get_child_index->getBuffer()};
414 data.emplace_back(name.GetString());
416 control, data, FormatterBytecode::sig_get_child_index);
417 if (error)
418 return error;
419
420 if (data.size() == 0) {
421 char message[] = "@get_child_index returned empty data stack";
423 return llvm::createStringError(message);
424 }
425
426 const FormatterBytecode::DataStackElement &top = data.back();
427 if (auto *u = std::get_if<uint64_t>(&top))
428 if (*u <= SIZE_MAX)
429 return *u;
430 if (auto *i = std::get_if<int64_t>(&top)) {
431 if (*i > 0 && static_cast<uint64_t>(*i) <= SIZE_MAX)
432 return *i;
433 return SIZE_MAX;
434 }
435
436 return llvm::createStringError("@get_child_index returned invalid value");
437}
438
440 StreamString sstr;
441 sstr.Printf("%s%s%s Bytecode synthetic", Cascades() ? "" : " (not cascading)",
442 SkipsPointers() ? " (skip pointers)" : "",
443 SkipsReferences() ? " (skip references)" : "");
444
445 return std::string(sstr.GetString());
446}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:421
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
FrontEnd(ValueObject &backend, SyntheticBytecodeImplementation &impl)
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
Determine the index of a named child.
llvm::Expected< uint32_t > CalculateNumChildren() override
const SyntheticBytecodeImplementation & m_impl
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
CreateFrontEndCallback m_create_callback
std::string GetDescription() override
CXXSyntheticChildren(const SyntheticChildren::Flags &flags, const char *description, CreateFrontEndCallback callback)
std::function< SyntheticChildrenFrontEnd *(CXXSyntheticChildren *, lldb::ValueObjectSP)> CreateFrontEndCallback
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
std::string GetString() const
Get the string value as a std::string.
const char * GetCString() const
Get the string value as a C string.
An data extractor class.
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
virtual lldb::ScriptedSyntheticChildrenInterfaceSP CreateScriptedSyntheticChildrenInterface()
Debugger & GetDebugger()
Get the debugger associated with this script interpreter.
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
lldb::ScriptedSyntheticChildrenInterfaceSP m_interface_sp
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
Determine the index of a named child.
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
FrontEnd(std::string pclass, ValueObject &backend)
llvm::Expected< uint32_t > CalculateNumChildren() override
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
std::shared_ptr< Generic > GenericSP
uint32_t CalculateNumChildrenIgnoringErrors(uint32_t max=UINT32_MAX)
lldb::ValueObjectSP CreateChildValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
std::unique_ptr< SyntheticChildrenFrontEnd > UniquePointer
lldb::ValueObjectSP CreateChildValueObjectFromExpression(llvm::StringRef name, llvm::StringRef expression, const ExecutionContext &exe_ctx)
virtual llvm::Expected< uint32_t > CalculateNumChildren()=0
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateChildValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
virtual std::string GetDescription()=0
virtual SyntheticChildrenFrontEnd::UniquePointer GetFrontEnd(ValueObject &backend)=0
SyntheticChildren(const Flags &flags)
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
Determine the index of a named child.
bool SetExpressionPathAtIndex(size_t i, const char *path)
const char * GetExpressionPathAtIndex(size_t i) const
void AddExpressionPath(const char *path)
std::string GetDescription() override
std::vector< std::string > m_expression_paths
lldb::ValueObjectSP GetSP()
lldb::user_id_t GetID() const
Returns a unique id for this ValueObject.
lldb::TargetSP GetTargetSP() const
#define LLDB_INVALID_UID
#define UINT32_MAX
std::vector< ControlStackElement > ControlStack
llvm::Error Interpret(ControlStack &control, DataStack &data, Signatures sig)
std::variant< std::string, uint64_t, int64_t, lldb::ValueObjectSP, CompilerType, Selectors > DataStackElement
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:338
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
@ eReuse
Children did not change and don't need to be recomputed; re-use what we computed the last time we cal...
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Target > TargetSP