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 <cstdint>
25
26using namespace lldb;
27using namespace lldb_private;
28
29void TypeFilterImpl::AddExpressionPath(const std::string &path) {
30 bool need_add_dot = true;
31 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
32 need_add_dot = false;
33 // add a '.' symbol to help forgetful users
34 if (!need_add_dot)
35 m_expression_paths.push_back(path);
36 else
37 m_expression_paths.push_back(std::string(".") + path);
38}
39
41 const std::string &path) {
42 if (i >= GetCount())
43 return false;
44 bool need_add_dot = true;
45 if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[')
46 need_add_dot = false;
47 // add a '.' symbol to help forgetful users
48 if (!need_add_dot)
49 m_expression_paths[i] = path;
50 else
51 m_expression_paths[i] = std::string(".") + path;
52 return true;
53}
54
55llvm::Expected<size_t>
57 const char *name_cstr = name.GetCString();
58 if (name_cstr) {
59 for (size_t i = 0; i < filter->GetCount(); i++) {
60 const char *expr_cstr = filter->GetExpressionPathAtIndex(i);
61 if (expr_cstr) {
62 if (*expr_cstr == '.')
63 expr_cstr++;
64 else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>')
65 expr_cstr += 2;
66 }
67 if (expr_cstr) {
68 if (!::strcmp(name_cstr, expr_cstr))
69 return i;
70 }
71 }
72 }
73 return llvm::createStringError("Type has no child named '%s'",
74 name.AsCString());
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
133 llvm::StringRef name, llvm::StringRef expression,
134 const ExecutionContext &exe_ctx) {
135 ValueObjectSP valobj_sp(
136 ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx));
137 if (valobj_sp)
138 valobj_sp->SetSyntheticChildrenGenerated(true);
139 return valobj_sp;
140}
141
143 llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
144 CompilerType type, bool do_deref) {
146 name, address, exe_ctx, type, do_deref));
147 if (valobj_sp)
148 valobj_sp->SetSyntheticChildrenGenerated(true);
149 return valobj_sp;
150}
151
153 llvm::StringRef name, const DataExtractor &data,
154 const ExecutionContext &exe_ctx, CompilerType type) {
155 ValueObjectSP valobj_sp(
156 ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type));
157 if (valobj_sp)
158 valobj_sp->SetSyntheticChildrenGenerated(true);
159 return valobj_sp;
160}
161
163 ValueObject &backend)
164 : SyntheticChildrenFrontEnd(backend), m_python_class(pclass),
165 m_wrapper_sp(), m_interpreter(nullptr) {
166 if (backend.GetID() == LLDB_INVALID_UID)
167 return;
168
169 TargetSP target_sp = backend.GetTargetSP();
170
171 if (!target_sp)
172 return;
173
174 m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
175
176 if (m_interpreter != nullptr)
177 m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(
178 m_python_class.c_str(), backend.GetSP());
179}
180
182
186 return lldb::ValueObjectSP();
187
188 return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
189}
190
194
195llvm::Expected<uint32_t>
197 if (!m_wrapper_sp || m_interpreter == nullptr)
198 return 0;
199 return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX);
200}
201
202llvm::Expected<uint32_t>
204 if (!m_wrapper_sp || m_interpreter == nullptr)
205 return 0;
206 return m_interpreter->CalculateNumChildren(m_wrapper_sp, max);
207}
208
217
219 if (!m_wrapper_sp || m_interpreter == nullptr)
220 return false;
221
222 return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
223}
224
225llvm::Expected<size_t>
227 if (!m_wrapper_sp || m_interpreter == nullptr)
228 return llvm::createStringError("Type has no child named '%s'",
229 name.AsCString());
230 return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp,
231 name.GetCString());
232}
233
235 if (!m_wrapper_sp || m_interpreter == nullptr)
236 return nullptr;
237
238 return m_interpreter->GetSyntheticValue(m_wrapper_sp);
239}
240
242 if (!m_wrapper_sp || m_interpreter == nullptr)
243 return ConstString();
244
245 return m_interpreter->GetSyntheticTypeName(m_wrapper_sp);
246}
247
249 StreamString sstr;
250 sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
251 SkipsPointers() ? " (skip pointers)" : "",
252 SkipsReferences() ? " (skip references)" : "",
253 m_python_class.c_str());
254
255 return std::string(sstr.GetString());
256}
257
260 : SyntheticChildrenFrontEnd(backend), m_impl(impl) {
261 FormatterBytecode::DataStack data = {backend.GetSP()};
262 if (!m_impl.init) {
263 m_init_results = std::move(data);
264 return;
265 }
266
267 FormatterBytecode::ControlStack control = {m_impl.init->getBuffer()};
268 llvm::Error error =
269 FormatterBytecode::Interpret(control, data, FormatterBytecode::sig_init);
270 if (error) {
272 "@init failed: {0}");
273 return;
274 }
275
276 if (data.size() > 0)
277 m_init_results = std::move(data);
278}
279
281 if (!m_impl.update) {
284 }
285
286 FormatterBytecode::ControlStack control = {m_impl.update->getBuffer()};
289 control, data, FormatterBytecode::sig_update);
290 if (error) {
292 "@update failed: {0}");
294 }
295
296 std::optional<ChildCacheState> can_reuse = std::nullopt;
297 const FormatterBytecode::DataStackElement &top = data.back();
298 if (auto *u = std::get_if<uint64_t>(&top))
299 if (*u == 0 || *u == 1)
300 can_reuse = static_cast<ChildCacheState>(*u);
301 if (auto *i = std::get_if<int64_t>(&top))
302 if (*i == 0 || *i == 1)
303 can_reuse = static_cast<ChildCacheState>(*i);
304
305 if (can_reuse) {
306 data.pop_back();
307 LLDB_LOG(
309 "Bytecode formatter can reuse @update: {0} (type: `{1}`, name: `{2}`)",
310 can_reuse ? "true" : "false", m_backend.GetDisplayTypeName(),
311 m_backend.GetName());
312 } else {
314 "Bytecode formatter did not return a valid reuse response from "
315 "@update (type: `{1}`, name: `{2}`)",
316 m_backend.GetDisplayTypeName(), m_backend.GetName());
317 }
318
319 if (data.size() > 0)
320 m_self = std::move(data);
321
322 return can_reuse.value_or(ChildCacheState::eRefetch);
323}
324
325llvm::Expected<uint32_t>
327 if (!m_impl.num_children)
328 return 0;
329
330 FormatterBytecode::ControlStack control = {m_impl.num_children->getBuffer()};
333 control, data, FormatterBytecode::sig_get_num_children);
334 if (error)
335 return error;
336
337 if (data.size() == 0) {
338 char message[] = "@get_num_children returned empty data stack";
340 return llvm::createStringError(message);
341 }
342
343 const FormatterBytecode::DataStackElement &top = data.back();
344 if (auto *u = std::get_if<uint64_t>(&top))
345 if (*u <= UINT32_MAX)
346 return *u;
347 if (auto *i = std::get_if<int64_t>(&top)) {
348 if (*i > 0 && *i <= UINT32_MAX)
349 return *i;
350 return UINT32_MAX;
351 }
352
353 return llvm::createStringError("@get_num_children returned invalid value");
354}
355
358 if (!m_impl.get_child_at_index)
359 return {};
360
362 m_impl.get_child_at_index->getBuffer()};
364 data.emplace_back((uint64_t)idx);
366 control, data, FormatterBytecode::sig_get_child_at_index);
367 if (error) {
369 "@get_child_at_index failed: {0}");
370 return {};
371 }
372
373 if (data.size() == 0) {
375 "@get_child_at_index returned empty data stack");
376 return {};
377 }
378
379 const FormatterBytecode::DataStackElement &top = data.back();
380 if (auto *child = std::get_if<ValueObjectSP>(&top))
381 return *child;
382
383 return {};
384}
385
386llvm::Expected<size_t>
388 if (m_impl.get_child_index)
389 return -1;
390
392 m_impl.get_child_index->getBuffer()};
394 data.emplace_back(name.GetString());
396 control, data, FormatterBytecode::sig_get_child_index);
397 if (error)
398 return error;
399
400 if (data.size() == 0) {
401 char message[] = "@get_child_index returned empty data stack";
403 return llvm::createStringError(message);
404 }
405
406 const FormatterBytecode::DataStackElement &top = data.back();
407 if (auto *u = std::get_if<uint64_t>(&top))
408 if (*u <= SIZE_MAX)
409 return *u;
410 if (auto *i = std::get_if<int64_t>(&top)) {
411 if (*i > 0 && static_cast<uint64_t>(*i) <= SIZE_MAX)
412 return *i;
413 return SIZE_MAX;
414 }
415
416 return llvm::createStringError("@get_child_index returned invalid value");
417}
418
420 StreamString sstr;
421 sstr.Printf("%s%s%s Bytecode synthetic", Cascades() ? "" : " (not cascading)",
422 SkipsPointers() ? " (skip pointers)" : "",
423 SkipsReferences() ? " (skip references)" : "");
424
425 return std::string(sstr.GetString());
426}
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:369
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:415
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:399
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 * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C 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 CreateValueObjectFromExpression(llvm::StringRef name, llvm::StringRef expression, const ExecutionContext &exe_ctx)
std::unique_ptr< SyntheticChildrenFrontEnd > UniquePointer
lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
virtual llvm::Expected< uint32_t > CalculateNumChildren()=0
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
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
static lldb::ValueObjectSP CreateValueObjectFromExpression(llvm::StringRef name, llvm::StringRef expression, const ExecutionContext &exe_ctx)
lldb::ValueObjectSP GetSP()
lldb::user_id_t GetID() const
Returns a unique id for this ValueObject.
static lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
Given an address either create a value object containing the value at that address,...
static lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
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:332
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