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
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::createStringErrorV("type has no child named '{0}'", name);
229 return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp,
230 name.GetCString());
231}
232
234 if (!m_wrapper_sp || m_interpreter == nullptr)
235 return nullptr;
236
237 return m_interpreter->GetSyntheticValue(m_wrapper_sp);
238}
239
241 if (!m_wrapper_sp || m_interpreter == nullptr)
242 return ConstString();
243
244 return m_interpreter->GetSyntheticTypeName(m_wrapper_sp);
245}
246
248 StreamString sstr;
249 sstr.Printf("%s%s%s Python class %s", Cascades() ? "" : " (not cascading)",
250 SkipsPointers() ? " (skip pointers)" : "",
251 SkipsReferences() ? " (skip references)" : "",
252 m_python_class.c_str());
253
254 return std::string(sstr.GetString());
255}
256
259 : SyntheticChildrenFrontEnd(backend), m_impl(impl) {
260 FormatterBytecode::DataStack data = {backend.GetSP()};
261 if (!m_impl.init) {
262 m_init_results = std::move(data);
263 return;
264 }
265
266 FormatterBytecode::ControlStack control = {m_impl.init->getBuffer()};
267 llvm::Error error =
268 FormatterBytecode::Interpret(control, data, FormatterBytecode::sig_init);
269 if (error) {
271 "@init failed: {0}");
272 return;
273 }
274
275 if (data.size() > 0)
276 m_init_results = std::move(data);
277}
278
280 if (!m_impl.update) {
283 }
284
285 FormatterBytecode::ControlStack control = {m_impl.update->getBuffer()};
288 control, data, FormatterBytecode::sig_update);
289 if (error) {
291 "@update failed: {0}");
293 }
294
295 std::optional<ChildCacheState> can_reuse = std::nullopt;
296 const FormatterBytecode::DataStackElement &top = data.back();
297 if (auto *u = std::get_if<uint64_t>(&top))
298 if (*u == 0 || *u == 1)
299 can_reuse = static_cast<ChildCacheState>(*u);
300 if (auto *i = std::get_if<int64_t>(&top))
301 if (*i == 0 || *i == 1)
302 can_reuse = static_cast<ChildCacheState>(*i);
303
304 if (can_reuse) {
305 data.pop_back();
306 LLDB_LOG(
308 "Bytecode formatter can reuse @update: {0} (type: `{1}`, name: `{2}`)",
309 can_reuse ? "true" : "false", m_backend.GetDisplayTypeName(),
310 m_backend.GetName());
311 } else {
313 "Bytecode formatter did not return a valid reuse response from "
314 "@update (type: `{1}`, name: `{2}`)",
315 m_backend.GetDisplayTypeName(), m_backend.GetName());
316 }
317
318 if (data.size() > 0)
319 m_self = std::move(data);
320
321 return can_reuse.value_or(ChildCacheState::eRefetch);
322}
323
324llvm::Expected<uint32_t>
326 if (!m_impl.num_children)
327 return 0;
328
329 FormatterBytecode::ControlStack control = {m_impl.num_children->getBuffer()};
332 control, data, FormatterBytecode::sig_get_num_children);
333 if (error)
334 return error;
335
336 if (data.size() == 0) {
337 char message[] = "@get_num_children returned empty data stack";
339 return llvm::createStringError(message);
340 }
341
342 const FormatterBytecode::DataStackElement &top = data.back();
343 if (auto *u = std::get_if<uint64_t>(&top))
344 if (*u <= UINT32_MAX)
345 return *u;
346 if (auto *i = std::get_if<int64_t>(&top)) {
347 if (*i > 0 && *i <= UINT32_MAX)
348 return *i;
349 return UINT32_MAX;
350 }
351
352 return llvm::createStringError("@get_num_children returned invalid value");
353}
354
357 if (!m_impl.get_child_at_index)
358 return {};
359
361 m_impl.get_child_at_index->getBuffer()};
363 data.emplace_back((uint64_t)idx);
365 control, data, FormatterBytecode::sig_get_child_at_index);
366 if (error) {
368 "@get_child_at_index failed: {0}");
369 return {};
370 }
371
372 if (data.size() == 0) {
374 "@get_child_at_index returned empty data stack");
375 return {};
376 }
377
378 const FormatterBytecode::DataStackElement &top = data.back();
379 if (auto *child = std::get_if<ValueObjectSP>(&top))
380 return *child;
381
382 return {};
383}
384
385llvm::Expected<size_t>
387 if (m_impl.get_child_index)
388 return -1;
389
391 m_impl.get_child_index->getBuffer()};
393 data.emplace_back(name.GetString());
395 control, data, FormatterBytecode::sig_get_child_index);
396 if (error)
397 return error;
398
399 if (data.size() == 0) {
400 char message[] = "@get_child_index returned empty data stack";
402 return llvm::createStringError(message);
403 }
404
405 const FormatterBytecode::DataStackElement &top = data.back();
406 if (auto *u = std::get_if<uint64_t>(&top))
407 if (*u <= SIZE_MAX)
408 return *u;
409 if (auto *i = std::get_if<int64_t>(&top)) {
410 if (*i > 0 && static_cast<uint64_t>(*i) <= SIZE_MAX)
411 return *i;
412 return SIZE_MAX;
413 }
414
415 return llvm::createStringError("@get_child_index returned invalid value");
416}
417
419 StreamString sstr;
420 sstr.Printf("%s%s%s Bytecode synthetic", Cascades() ? "" : " (not cascading)",
421 SkipsPointers() ? " (skip pointers)" : "",
422 SkipsReferences() ? " (skip references)" : "");
423
424 return std::string(sstr.GetString());
425}
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:132
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: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