LLDB mainline
ValueObjectSynthetic.cpp
Go to the documentation of this file.
1//===-- ValueObjectSynthetic.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
10
11#include "lldb/Core/Value.h"
17#include "lldb/Utility/Log.h"
18#include "lldb/Utility/Status.h"
20
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/Support/Error.h"
23#include <optional>
24
25namespace lldb_private {
26class Declaration;
27}
28
29using namespace lldb_private;
30
32public:
35
36 llvm::Expected<uint32_t> CalculateNumChildren() override {
37 return m_backend.GetNumChildren();
38 }
39
40 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
41 return m_backend.GetChildAtIndex(idx);
42 }
43
44 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
45 return m_backend.GetIndexOfChildWithName(name);
46 }
47
48 bool MightHaveChildren() override { return m_backend.MightHaveChildren(); }
49
53};
54
57 : ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(),
63 SetName(parent.GetName());
64 // Copying the data of an incomplete type won't work as it has no byte size.
65 if (m_parent->GetCompilerType().IsCompleteType())
68}
69
71
75
77 return m_parent->GetTypeName();
78}
79
81 return m_parent->GetQualifiedTypeName();
82}
83
85 if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
86 return synth_name;
87
88 return m_parent->GetDisplayTypeName();
89}
90
91llvm::Expected<uint32_t>
94
98
99 if (max < UINT32_MAX) {
100 auto num_children = m_synth_filter_up->CalculateNumChildren(max);
101 LLDB_LOGF(log,
102 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
103 "%s and type %s, the filter returned %u child values",
104 GetName().AsCString(), GetTypeName().AsCString(),
105 num_children ? *num_children : 0);
106 return num_children;
107 } else {
108 auto num_children_or_err = m_synth_filter_up->CalculateNumChildren(max);
109 if (!num_children_or_err) {
111 return num_children_or_err;
112 }
113 auto num_children = (m_synthetic_children_count = *num_children_or_err);
114 LLDB_LOGF(log,
115 "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
116 "%s and type %s, the filter returned %u child values",
117 GetName().AsCString(), GetTypeName().AsCString(), num_children);
118 return num_children;
119 }
120}
121
124 if (!m_parent)
125 return lldb::ValueObjectSP();
126 if (IsDynamic() && GetDynamicValueType() == valueType)
127 return GetSP();
128 return m_parent->GetDynamicValue(valueType);
129}
130
137
138llvm::Expected<uint64_t> ValueObjectSynthetic::GetByteSize() {
139 return m_parent->GetByteSize();
140}
141
143 return m_parent->GetValueType();
144}
145
147 ValueObject *valobj_for_frontend = m_parent;
148 if (m_synth_sp->WantsDereference()) {
149 CompilerType type = m_parent->GetCompilerType();
150 if (type.IsValid() && type.IsPointerOrReferenceType()) {
152 lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
153 if (error.Success())
154 valobj_for_frontend = deref_sp.get();
155 }
156 }
157 m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
159 m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
160}
161
164
165 SetValueIsValid(false);
166 m_error.Clear();
167
168 if (!m_parent->UpdateValueIfNeeded(false)) {
169 // our parent could not update.. as we are meaningless without a parent,
170 // just stop
171 if (m_parent->GetError().Fail())
172 m_error = m_parent->GetError().Clone();
173 return false;
174 }
175
176 // Regenerate the synthetic filter if our typename changes. When the (dynamic)
177 // type of an object changes, so does their synthetic filter of choice.
178 ConstString new_parent_type_name = m_parent->GetTypeName();
179 if (new_parent_type_name != m_parent_type_name) {
180 LLDB_LOGF(log,
181 "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
182 "from %s to %s, recomputing synthetic filter",
183 GetName().AsCString(), m_parent_type_name.AsCString(),
184 new_parent_type_name.AsCString());
185 m_parent_type_name = new_parent_type_name;
187 }
188
189 // let our backend do its update
191 LLDB_LOGF(log,
192 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
193 "filter said caches are stale - clearing",
194 GetName().AsCString());
195 // filter said that cached values are stale
196 {
197 std::lock_guard<std::mutex> guard(m_child_mutex);
198 m_children_byindex.clear();
199 m_name_toindex.clear();
200 }
201 // usually, an object's value can change but this does not alter its
202 // children count for a synthetic VO that might indeed happen, so we need
203 // to tell the upper echelons that they need to come back to us asking for
204 // children
205 m_flags.m_children_count_valid = false;
206 {
207 std::lock_guard<std::mutex> guard(m_child_mutex);
209 }
212 } else {
213 LLDB_LOGF(log,
214 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
215 "filter said caches are still valid",
216 GetName().AsCString());
217 }
218
220
221 lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
222
223 if (synth_val && synth_val->CanProvideValue()) {
224 LLDB_LOGF(log,
225 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
226 "filter said it can provide a value",
227 GetName().AsCString());
228
230 CopyValueData(synth_val.get());
231 } else {
232 LLDB_LOGF(log,
233 "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
234 "filter said it will not provide a value",
235 GetName().AsCString());
236
238 // Copying the data of an incomplete type won't work as it has no byte size.
239 if (m_parent->GetCompilerType().IsCompleteType())
241 }
242
243 SetValueIsValid(true);
244 return true;
245}
246
248 bool can_create) {
250
251 LLDB_LOGF(log,
252 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
253 "child at index %u",
254 GetName().AsCString(), idx);
255
257
258 ValueObject *valobj;
259 bool child_is_cached;
260 {
261 std::lock_guard<std::mutex> guard(m_child_mutex);
262 auto cached_child_it = m_children_byindex.find(idx);
263 child_is_cached = cached_child_it != m_children_byindex.end();
264 if (child_is_cached)
265 valobj = cached_child_it->second;
266 }
267
268 if (!child_is_cached) {
269 if (can_create && m_synth_filter_up != nullptr) {
270 LLDB_LOGF(log,
271 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
272 "index %u not cached and will be created",
273 GetName().AsCString(), idx);
274
275 lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
276
277 LLDB_LOGF(
278 log,
279 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
280 "%u created as %p (is "
281 "synthetic: %s)",
282 GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
283 synth_guy.get()
284 ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
285 : "no");
286
287 if (!synth_guy)
288 return synth_guy;
289
290 {
291 std::lock_guard<std::mutex> guard(m_child_mutex);
292 if (synth_guy->IsSyntheticChildrenGenerated())
293 m_synthetic_children_cache.push_back(synth_guy);
294 m_children_byindex[idx] = synth_guy.get();
295 }
296 synth_guy->SetPreferredDisplayLanguageIfNeeded(
298 return synth_guy;
299 } else {
300 LLDB_LOGF(log,
301 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
302 "index %u not cached and cannot "
303 "be created (can_create = %s, synth_filter = %p)",
304 GetName().AsCString(), idx, can_create ? "yes" : "no",
305 static_cast<void *>(m_synth_filter_up.get()));
306
307 return lldb::ValueObjectSP();
308 }
309 } else {
310 LLDB_LOGF(log,
311 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
312 "index %u cached as %p",
313 GetName().AsCString(), idx, static_cast<void *>(valobj));
314
315 return valobj->GetSP();
316 }
317}
318
321 bool can_create) {
323
324 auto index_or_err = GetIndexOfChildWithName(name);
325
326 if (!index_or_err) {
327 llvm::consumeError(index_or_err.takeError());
328 return lldb::ValueObjectSP();
329 }
330
331 return GetChildAtIndex(*index_or_err, can_create);
332}
333
334llvm::Expected<size_t>
337
338 ConstString name(name_ref);
339
340 std::optional<uint32_t> found_index = std::nullopt;
341 {
342 std::lock_guard<std::mutex> guard(m_child_mutex);
343 auto name_to_index = m_name_toindex.find(name.GetCString());
344 if (name_to_index != m_name_toindex.end())
345 found_index = name_to_index->second;
346 }
347
348 if (!found_index && m_synth_filter_up != nullptr) {
349 size_t index = SIZE_MAX;
350 if (auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name)) {
351 index = *index_or_err;
352 } else if (!m_synth_sp->CustomSubscripting()) {
353 // Provide automatic support for subscript child names ("[N]").
354 auto maybe_index = formatters::ExtractIndexFromString(name.GetCString());
355 if (!maybe_index)
356 // The child name was not of the form "[N]", return the original error.
357 return index_or_err.takeError();
358
359 // Subscripting succeeded, ignore the original error.
360 llvm::consumeError(index_or_err.takeError());
361 index = *maybe_index;
362
363 // Prevent unnecessary work by limiting max to one past the index.
364 uint32_t max = index + 1;
365 auto num_children = GetNumChildrenIgnoringErrors(max);
366 if (index >= num_children)
367 return llvm::createStringError("Subscript index out of range: %zu",
368 index);
369 }
370 std::lock_guard<std::mutex> guard(m_child_mutex);
371 m_name_toindex[name.GetCString()] = index;
372 return index;
373 } else if (!found_index && m_synth_filter_up == nullptr) {
374 return llvm::createStringError("Type has no child named '%s'",
375 name.AsCString());
376 } else if (found_index)
377 return *found_index;
378
379 return llvm::createStringError("Type has no child named '%s'",
380 name.AsCString());
381}
382
383bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
384
388
390 if (!source->UpdateValueIfNeeded())
391 return;
392 m_value = source->GetValue();
394 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
395}
396
398 if (!UpdateValueIfNeeded())
399 return false;
401 return true;
402 return m_parent->CanProvideValue();
403}
404
406 Status &error) {
407 return m_parent->SetValueFromCString(value_str, error);
408}
409
411 if (m_parent) {
412 m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
413 m_parent->SetFormat(format);
414 }
415 this->ValueObject::SetFormat(format);
417}
418
420 lldb::LanguageType lang) {
422 if (m_parent)
423 m_parent->SetPreferredDisplayLanguage(lang);
424}
425
434
436 if (m_parent)
437 return m_parent->IsSyntheticChildrenGenerated();
438 return false;
439}
440
442 if (m_parent)
443 m_parent->SetSyntheticChildrenGenerated(b);
445}
446
448 if (m_parent)
449 return m_parent->GetDeclaration(decl);
450
451 return ValueObject::GetDeclaration(decl);
452}
453
455 if (m_parent)
456 return m_parent->GetLanguageFlags();
457 return this->ValueObject::GetLanguageFlags();
458}
459
461 if (m_parent)
462 m_parent->SetLanguageFlags(flags);
463 else
465}
466
468 GetExpressionPathFormat epformat) {
469 // A synthetic ValueObject may wrap an underlying Register or RegisterSet
470 // ValueObject, which requires a different approach to generating the
471 // expression path. In such cases, delegate to the non-synthetic value object.
472 if (const lldb::ValueType obj_value_type = GetValueType();
473 IsSynthetic() && (obj_value_type == lldb::eValueTypeRegister ||
474 obj_value_type == lldb::eValueTypeRegisterSet)) {
475
476 if (const lldb::ValueObjectSP raw_value = GetNonSyntheticValue())
477 return raw_value->GetExpressionPath(stream, epformat);
478 }
479 return ValueObject::GetExpressionPath(stream, epformat);
480}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:376
llvm::Expected< uint32_t > CalculateNumChildren() override
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
Determine the index of a named child.
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::ValueObjectSP GetChildAtIndex(uint32_t idx) override
DummySyntheticFrontEnd(ValueObject &backend)
Generic representation of a type in a programming language.
bool IsPointerOrReferenceType(CompilerType *pointee_type=nullptr) const
A uniqued constant string class.
Definition ConstString.h:40
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.
A class that describes the declaration location of a lldb object.
Definition Declaration.h:24
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
An error handling class.
Definition Status.h:118
A stream class that can stream formatted output to a file.
Definition Stream.h:28
SyntheticChildrenFrontEnd(ValueObject &backend)
virtual lldb::DynamicValueType GetDynamicValueType()
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx, bool can_create=true) override
bool SetValueFromCString(const char *value_str, Status &error) override
lldb::ValueType GetValueType() const override
lldb::LanguageType GetPreferredDisplayLanguage() override
void GetExpressionPath(Stream &stream, GetExpressionPathFormat epformat=eGetExpressionPathFormatDereferencePointers) override
void SetFormat(lldb::Format format) override
NameToIndexMap m_name_toindex
Guarded by m_child_mutex;.
ByIndexMap m_children_byindex
Guarded by m_child_mutex;.
std::unique_ptr< SyntheticChildrenFrontEnd > m_synth_filter_up
lldb::ValueObjectSP GetDynamicValue(lldb::DynamicValueType valueType) override
void SetSyntheticChildrenGenerated(bool b) override
void SetPreferredDisplayLanguage(lldb::LanguageType)
lldb::ValueObjectSP GetNonSyntheticValue() override
SyntheticChildrenCache m_synthetic_children_cache
Guarded by m_child_mutex;.
llvm::Expected< size_t > GetIndexOfChildWithName(llvm::StringRef name) override
bool GetDeclaration(Declaration &decl) override
bool MightHaveChildren() override
Find out if a ValueObject might have children.
lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true) override
llvm::Expected< uint64_t > GetByteSize() override
ValueObjectSynthetic(ValueObject &parent, lldb::SyntheticChildrenSP filter)
void SetLanguageFlags(uint64_t flags) override
llvm::Expected< uint32_t > CalculateNumChildren(uint32_t max) override
Should only be called by ValueObject::GetNumChildren().
void SetValueIsValid(bool valid)
void ClearUserVisibleData(uint32_t items=ValueObject::eClearUserVisibleDataItemsAllStrings)
void SetPreferredDisplayLanguage(lldb::LanguageType lt)
struct lldb_private::ValueObject::Bitflags m_flags
lldb::ValueObjectSP GetSP()
virtual void SetLanguageFlags(uint64_t flags)
Status m_error
An error object that can describe any errors that occur when updating values.
virtual uint64_t GetLanguageFlags()
virtual void SetSyntheticChildrenGenerated(bool b)
DataExtractor m_data
A data extractor that can be used to extract the value.
virtual void GetExpressionPath(Stream &s, GetExpressionPathFormat=eGetExpressionPathFormatDereferencePointers)
virtual lldb::ModuleSP GetModule()
Return the module associated with this value object in case the value is from an executable file and ...
lldb::LanguageType m_preferred_display_language
ValueObject * m_parent
The parent value object, or nullptr if this has no parent.
virtual bool GetDeclaration(Declaration &decl)
bool UpdateValueIfNeeded(bool update_format=true)
void SetName(ConstString name)
Change the name of the current ValueObject.
ConstString GetName() const
virtual void SetFormat(lldb::Format format)
const ExecutionContextRef & GetExecutionContextRef() const
uint32_t GetNumChildrenIgnoringErrors(uint32_t max=UINT32_MAX)
Like GetNumChildren but returns 0 on error.
const Value & GetValue() const
#define UINT32_MAX
std::optional< size_t > ExtractIndexFromString(const char *item_name)
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.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Format
Display format definitions.
LanguageType
Programming language type.
@ eLanguageTypeUnknown
Unknown or invalid language value.
std::shared_ptr< lldb_private::SyntheticChildren > SyntheticChildrenSP
@ eValueTypeRegister
stack frame register value
@ eValueTypeRegisterSet
A collection of stack frame register values.