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"
21#include "lldb/Target/Target.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/ErrorExtras.h"
25#include <cstdint>
26
27using namespace lldb;
28using namespace lldb_private;
29
30void TypeFilterImpl::AddExpressionPath(const std::string &path) {
31 bool need_add_dot = true;
32 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
33 need_add_dot = false;
34 // add a '.' symbol to help forgetful users
35 if (!need_add_dot)
36 m_expression_paths.push_back(path);
37 else
38 m_expression_paths.push_back(std::string(".") + path);
39}
40
42 const std::string &path) {
43 if (i >= GetCount())
44 return false;
45 bool need_add_dot = true;
46 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
47 need_add_dot = false;
48 // add a '.' symbol to help forgetful users
49 if (!need_add_dot)
50 m_expression_paths[i] = path;
51 else
52 m_expression_paths[i] = std::string(".") + path;
53 return true;
54}
55
56llvm::Expected<size_t>
58 const char *name_cstr = name.GetCString();
59 if (name_cstr) {
60 for (size_t i = 0; i < filter->GetCount(); i++) {
61 const char *expr_cstr = filter->GetExpressionPathAtIndex(i);
62 if (expr_cstr) {
63 if (*expr_cstr == '.')
64 expr_cstr++;
65 else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>')
66 expr_cstr += 2;
67 }
68 if (expr_cstr) {
69 if (!::strcmp(name_cstr, expr_cstr))
70 return i;
71 }
72 }
73 }
74 return llvm::createStringErrorV("type has no child named '{0}'", name);
75}
76
78 StreamString sstr;
79 sstr.Printf("%s%s%s {\n", Cascades() ? "" : " (not cascading)",
80 SkipsPointers() ? " (skip pointers)" : "",
81 SkipsReferences() ? " (skip references)" : "");
82
83 for (size_t i = 0; i < GetCount(); i++) {
84 sstr.Printf(" %s\n", GetExpressionPathAtIndex(i));
85 }
86
87 sstr.Printf("}");
88 return std::string(sstr.GetString());
89}
90
92
94
96 const SyntheticChildren::Flags &flags, const char *description,
98 : SyntheticChildren(flags), m_create_callback(std::move(callback)),
99 m_description(description ? description : "") {}
100
102
103bool SyntheticChildren::IsScripted() { return false; }
104
105std::string SyntheticChildren::GetDescription() { return ""; }
106
109 return nullptr;
110}
111
113 StreamString sstr;
114 sstr.Printf("%s%s%s %s", Cascades() ? "" : " (not cascading)",
115 SkipsPointers() ? " (skip pointers)" : "",
116 SkipsReferences() ? " (skip references)" : "",
117 m_description.c_str());
118
119 return std::string(sstr.GetString());
120}
121
122uint32_t
124 auto value_or_err = CalculateNumChildren(max);
125 if (value_or_err)
126 return *value_or_err;
127 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(),
128 "{0}");
129 return 0;
130}
131
134 llvm::StringRef name, llvm::StringRef expression,
135 const ExecutionContext &exe_ctx) {
137 ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromExpression(
138 name, expression, exe_ctx, options);
139 if (valobj_sp)
140 valobj_sp->SetSyntheticChildrenGenerated(true);
141 return valobj_sp;
142}
143
146 llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
147 CompilerType type, bool do_deref) {
148 ValueObjectSP valobj_sp = m_backend.CreateChildValueObjectFromAddress(
149 name, address, exe_ctx, type, do_deref);
150 if (valobj_sp)
151 valobj_sp->SetSyntheticChildrenGenerated(true);
152 return valobj_sp;
153}
154
156 llvm::StringRef name, const DataExtractor &data,
157 const ExecutionContext &exe_ctx, CompilerType type) {
158 ValueObjectSP valobj_sp =
159 m_backend.CreateChildValueObjectFromData(name, data, exe_ctx, type);
160 if (valobj_sp)
161 valobj_sp->SetSyntheticChildrenGenerated(true);
162 return valobj_sp;
163}
164
166 ValueObject &backend)
167 : SyntheticChildrenFrontEnd(backend), m_python_class(pclass),
168 m_wrapper_sp(), m_interpreter(nullptr) {
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 m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
178
179 if (m_interpreter != nullptr)
180 m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(
181 m_python_class.c_str(), backend.GetSP());
182}
183
185
189 return lldb::ValueObjectSP();
190
191 return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
192}
193
197
198llvm::Expected<uint32_t>
200 if (!m_wrapper_sp || m_interpreter == nullptr)
201 return 0;
202 return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX);
203}
204
205llvm::Expected<uint32_t>
207 if (!m_wrapper_sp || m_interpreter == nullptr)
208 return 0;
209 return m_interpreter->CalculateNumChildren(m_wrapper_sp, max);
210}
211
220
222 if (!m_wrapper_sp || m_interpreter == nullptr)
223 return false;
224
225 return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
226}
227
228llvm::Expected<size_t>
230 if (!m_wrapper_sp || m_interpreter == nullptr)
231 return llvm::createStringErrorV("type has no child named '{0}'", name);
232 return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp,
233 name.GetCString());
234}
235
237 if (!m_wrapper_sp || m_interpreter == nullptr)
238 return nullptr;
239
240 return m_interpreter->GetSyntheticValue(m_wrapper_sp);
241}
242
244 if (!m_wrapper_sp || m_interpreter == nullptr)
245 return ConstString();
246
247 return m_interpreter->GetSyntheticTypeName(m_wrapper_sp);
248}
249
251 StreamString sstr;
252 sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
253 SkipsPointers() ? " (skip pointers)" : "",
254 SkipsReferences() ? " (skip references)" : "",
255 m_python_class.c_str());
256
257 return std::string(sstr.GetString());
258}
259
262 : SyntheticChildrenFrontEnd(backend), m_impl(impl) {
263 FormatterBytecode::DataStack data = {backend.GetSP()};
264 if (!m_impl.init) {
265 m_init_results = std::move(data);
266 return;
267 }
268
269 FormatterBytecode::ControlStack control = {m_impl.init->getBuffer()};
270 llvm::Error error =
271 FormatterBytecode::Interpret(control, data, FormatterBytecode::sig_init);
272 if (error) {
274 "@init failed: {0}");
275 return;
276 }
277
278 if (data.size() > 0)
279 m_init_results = std::move(data);
280}
281
283 if (!m_impl.update) {
286 }
287
288 FormatterBytecode::ControlStack control = {m_impl.update->getBuffer()};
291 control, data, FormatterBytecode::sig_update);
292 if (error) {
294 "@update failed: {0}");
296 }
297
298 std::optional<ChildCacheState> can_reuse = std::nullopt;
299 const FormatterBytecode::DataStackElement &top = data.back();
300 if (auto *u = std::get_if<uint64_t>(&top))
301 if (*u == 0 || *u == 1)
302 can_reuse = static_cast<ChildCacheState>(*u);
303 if (auto *i = std::get_if<int64_t>(&top))
304 if (*i == 0 || *i == 1)
305 can_reuse = static_cast<ChildCacheState>(*i);
306
307 if (can_reuse) {
308 data.pop_back();
309 LLDB_LOG(
311 "Bytecode formatter can reuse @update: {0} (type: `{1}`, name: `{2}`)",
312 can_reuse ? "true" : "false", m_backend.GetDisplayTypeName(),
313 m_backend.GetName());
314 } else {
316 "Bytecode formatter did not return a valid reuse response from "
317 "@update (type: `{}`, name: `{}`)",
318 m_backend.GetDisplayTypeName(), m_backend.GetName());
319 }
320
321 if (data.size() > 0)
322 m_self = std::move(data);
323
324 return can_reuse.value_or(ChildCacheState::eRefetch);
325}
326
327llvm::Expected<uint32_t>
329 if (!m_impl.num_children)
330 return 0;
331
332 FormatterBytecode::ControlStack control = {m_impl.num_children->getBuffer()};
335 control, data, FormatterBytecode::sig_get_num_children);
336 if (error)
337 return error;
338
339 if (data.size() == 0) {
340 char message[] = "@get_num_children returned empty data stack";
342 return llvm::createStringError(message);
343 }
344
345 const FormatterBytecode::DataStackElement &top = data.back();
346 if (auto *u = std::get_if<uint64_t>(&top))
347 if (*u <= UINT32_MAX)
348 return *u;
349 if (auto *i = std::get_if<int64_t>(&top)) {
350 if (*i > 0 && *i <= UINT32_MAX)
351 return *i;
352 return UINT32_MAX;
353 }
354
355 return llvm::createStringError("@get_num_children returned invalid value");
356}
357
360 if (!m_impl.get_child_at_index)
361 return {};
362
364 m_impl.get_child_at_index->getBuffer()};
366 data.emplace_back((uint64_t)idx);
368 control, data, FormatterBytecode::sig_get_child_at_index);
369 if (error) {
371 "@get_child_at_index failed: {0}");
372 return {};
373 }
374
375 if (data.size() == 0) {
377 "@get_child_at_index returned empty data stack");
378 return {};
379 }
380
381 const FormatterBytecode::DataStackElement &top = data.back();
382 if (auto *child = std::get_if<ValueObjectSP>(&top))
383 return *child;
384
385 return {};
386}
387
388llvm::Expected<size_t>
390 if (m_impl.get_child_index)
391 return -1;
392
394 m_impl.get_child_index->getBuffer()};
396 data.emplace_back(name.GetString());
398 control, data, FormatterBytecode::sig_get_child_index);
399 if (error)
400 return error;
401
402 if (data.size() == 0) {
403 char message[] = "@get_child_index returned empty data stack";
405 return llvm::createStringError(message);
406 }
407
408 const FormatterBytecode::DataStackElement &top = data.back();
409 if (auto *u = std::get_if<uint64_t>(&top))
410 if (*u <= SIZE_MAX)
411 return *u;
412 if (auto *i = std::get_if<int64_t>(&top)) {
413 if (*i > 0 && static_cast<uint64_t>(*i) <= SIZE_MAX)
414 return *i;
415 return SIZE_MAX;
416 }
417
418 return llvm::createStringError("@get_child_index returned invalid value");
419}
420
422 StreamString sstr;
423 sstr.Printf("%s%s%s Bytecode synthetic", Cascades() ? "" : " (not cascading)",
424 SkipsPointers() ? " (skip pointers)" : "",
425 SkipsReferences() ? " (skip references)" : "");
426
427 return std::string(sstr.GetString());
428}
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:364
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:410
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:394
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.
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
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
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:327
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