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_self = 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_self = std::move(data);
278}
279
281 if (!m_impl.update)
283
284 FormatterBytecode::ControlStack control = {m_impl.update->getBuffer()};
287 control, data, FormatterBytecode::sig_update);
288 if (error) {
290 "@update failed: {0}");
292 }
293
294 if (data.size() > 0)
295 m_self = std::move(data);
296
298}
299
300llvm::Expected<uint32_t>
302 if (!m_impl.num_children)
303 return 0;
304
305 FormatterBytecode::ControlStack control = {m_impl.num_children->getBuffer()};
308 control, data, FormatterBytecode::sig_get_num_children);
309 if (error)
310 return error;
311
312 if (data.size() == 0) {
313 char message[] = "@get_num_children returned empty data stack";
315 return llvm::createStringError(message);
316 }
317
318 const FormatterBytecode::DataStackElement &top = data.back();
319 if (auto *u = std::get_if<uint64_t>(&top))
320 if (*u <= UINT32_MAX)
321 return *u;
322 if (auto *i = std::get_if<int64_t>(&top)) {
323 if (*i > 0 && *i <= UINT32_MAX)
324 return *i;
325 return UINT32_MAX;
326 }
327
328 return llvm::createStringError("@get_num_children returned invalid value");
329}
330
333 if (!m_impl.get_child_at_index)
334 return {};
335
337 m_impl.get_child_at_index->getBuffer()};
339 data.emplace_back((uint64_t)idx);
341 control, data, FormatterBytecode::sig_get_child_at_index);
342 if (error) {
344 "@get_child_at_index failed: {0}");
345 return {};
346 }
347
348 if (data.size() == 0) {
350 "@get_child_at_index returned empty data stack");
351 return {};
352 }
353
354 const FormatterBytecode::DataStackElement &top = data.back();
355 if (auto *child = std::get_if<ValueObjectSP>(&top))
356 return *child;
357
358 return {};
359}
360
361llvm::Expected<size_t>
363 if (m_impl.get_child_index)
364 return -1;
365
367 m_impl.get_child_index->getBuffer()};
369 data.emplace_back(name.GetString());
371 control, data, FormatterBytecode::sig_get_child_index);
372 if (error)
373 return error;
374
375 if (data.size() == 0) {
376 char message[] = "@get_child_index returned empty data stack";
378 return llvm::createStringError(message);
379 }
380
381 const FormatterBytecode::DataStackElement &top = data.back();
382 if (auto *u = std::get_if<uint64_t>(&top))
383 if (*u <= SIZE_MAX)
384 return *u;
385 if (auto *i = std::get_if<int64_t>(&top)) {
386 if (*i > 0 && static_cast<uint64_t>(*i) <= SIZE_MAX)
387 return *i;
388 return SIZE_MAX;
389 }
390
391 return llvm::createStringError("@get_child_index returned invalid value");
392}
393
395 StreamString sstr;
396 sstr.Printf("%s%s%s Bytecode synthetic", Cascades() ? "" : " (not cascading)",
397 SkipsPointers() ? " (skip pointers)" : "",
398 SkipsReferences() ? " (skip references)" : "");
399
400 return std::string(sstr.GetString());
401}
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:408
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
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