1 //===-- ValueObjectSyntheticFilter.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/Core/ValueObjectSyntheticFilter.h"
10 
11 #include "lldb/Core/Value.h"
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/DataFormatters/TypeSynthetic.h"
14 #include "lldb/Target/ExecutionContext.h"
15 #include "lldb/Utility/LLDBLog.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/Status.h"
18 
19 #include "llvm/ADT/STLExtras.h"
20 #include <optional>
21 
22 namespace lldb_private {
23 class Declaration;
24 }
25 
26 using namespace lldb_private;
27 
28 class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
29 public:
30   DummySyntheticFrontEnd(ValueObject &backend)
31       : SyntheticChildrenFrontEnd(backend) {}
32 
33   size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); }
34 
35   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
36     return m_backend.GetChildAtIndex(idx, true);
37   }
38 
39   size_t GetIndexOfChildWithName(ConstString name) override {
40     return m_backend.GetIndexOfChildWithName(name);
41   }
42 
43   bool MightHaveChildren() override { return true; }
44 
45   bool Update() override { return false; }
46 };
47 
48 ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
49                                            lldb::SyntheticChildrenSP filter)
50     : ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(),
51       m_name_toindex(), m_synthetic_children_cache(),
52       m_synthetic_children_count(UINT32_MAX),
53       m_parent_type_name(parent.GetTypeName()),
54       m_might_have_children(eLazyBoolCalculate),
55       m_provides_value(eLazyBoolCalculate) {
56   SetName(parent.GetName());
57   // Copying the data of an incomplete type won't work as it has no byte size.
58   if (m_parent->GetCompilerType().IsCompleteType())
59     CopyValueData(m_parent);
60   CreateSynthFilter();
61 }
62 
63 ValueObjectSynthetic::~ValueObjectSynthetic() = default;
64 
65 CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
66   return m_parent->GetCompilerType();
67 }
68 
69 ConstString ValueObjectSynthetic::GetTypeName() {
70   return m_parent->GetTypeName();
71 }
72 
73 ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
74   return m_parent->GetQualifiedTypeName();
75 }
76 
77 ConstString ValueObjectSynthetic::GetDisplayTypeName() {
78   if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
79     return synth_name;
80 
81   return m_parent->GetDisplayTypeName();
82 }
83 
84 size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
85   Log *log = GetLog(LLDBLog::DataFormatters);
86 
87   UpdateValueIfNeeded();
88   if (m_synthetic_children_count < UINT32_MAX)
89     return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
90 
91   if (max < UINT32_MAX) {
92     size_t num_children = m_synth_filter_up->CalculateNumChildren(max);
93     LLDB_LOGF(log,
94               "[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
95               "%s and type %s, the filter returned %zu child values",
96               GetName().AsCString(), GetTypeName().AsCString(), num_children);
97     return num_children;
98   } else {
99     size_t num_children = (m_synthetic_children_count =
100                                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 %zu child values",
104               GetName().AsCString(), GetTypeName().AsCString(), num_children);
105     return num_children;
106   }
107 }
108 
109 lldb::ValueObjectSP
110 ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
111   if (!m_parent)
112     return lldb::ValueObjectSP();
113   if (IsDynamic() && GetDynamicValueType() == valueType)
114     return GetSP();
115   return m_parent->GetDynamicValue(valueType);
116 }
117 
118 bool ValueObjectSynthetic::MightHaveChildren() {
119   if (m_might_have_children == eLazyBoolCalculate)
120     m_might_have_children =
121         (m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
122   return (m_might_have_children != eLazyBoolNo);
123 }
124 
125 std::optional<uint64_t> ValueObjectSynthetic::GetByteSize() {
126   return m_parent->GetByteSize();
127 }
128 
129 lldb::ValueType ValueObjectSynthetic::GetValueType() const {
130   return m_parent->GetValueType();
131 }
132 
133 void ValueObjectSynthetic::CreateSynthFilter() {
134   ValueObject *valobj_for_frontend = m_parent;
135   if (m_synth_sp->WantsDereference())
136   {
137     CompilerType type = m_parent->GetCompilerType();
138     if (type.IsValid() && type.IsPointerOrReferenceType())
139     {
140       Status error;
141       lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
142       if (error.Success())
143         valobj_for_frontend = deref_sp.get();
144     }
145   }
146   m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
147   if (!m_synth_filter_up)
148     m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
149 }
150 
151 bool ValueObjectSynthetic::UpdateValue() {
152   Log *log = GetLog(LLDBLog::DataFormatters);
153 
154   SetValueIsValid(false);
155   m_error.Clear();
156 
157   if (!m_parent->UpdateValueIfNeeded(false)) {
158     // our parent could not update.. as we are meaningless without a parent,
159     // just stop
160     if (m_parent->GetError().Fail())
161       m_error = m_parent->GetError();
162     return false;
163   }
164 
165   // regenerate the synthetic filter if our typename changes
166   // <rdar://problem/12424824>
167   ConstString new_parent_type_name = m_parent->GetTypeName();
168   if (new_parent_type_name != m_parent_type_name) {
169     LLDB_LOGF(log,
170               "[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
171               "from %s to %s, recomputing synthetic filter",
172               GetName().AsCString(), m_parent_type_name.AsCString(),
173               new_parent_type_name.AsCString());
174     m_parent_type_name = new_parent_type_name;
175     CreateSynthFilter();
176   }
177 
178   // let our backend do its update
179   if (!m_synth_filter_up->Update()) {
180     LLDB_LOGF(log,
181               "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
182               "filter said caches are stale - clearing",
183               GetName().AsCString());
184     // filter said that cached values are stale
185     {
186       std::lock_guard<std::mutex> guard(m_child_mutex);
187       m_children_byindex.clear();
188       m_name_toindex.clear();
189     }
190     // usually, an object's value can change but this does not alter its
191     // children count for a synthetic VO that might indeed happen, so we need
192     // to tell the upper echelons that they need to come back to us asking for
193     // children
194     m_flags.m_children_count_valid = false;
195     {
196       std::lock_guard<std::mutex> guard(m_child_mutex);
197       m_synthetic_children_cache.clear();
198     }
199     m_synthetic_children_count = UINT32_MAX;
200     m_might_have_children = eLazyBoolCalculate;
201   } else {
202     LLDB_LOGF(log,
203               "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
204               "filter said caches are still valid",
205               GetName().AsCString());
206   }
207 
208   m_provides_value = eLazyBoolCalculate;
209 
210   lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
211 
212   if (synth_val && synth_val->CanProvideValue()) {
213     LLDB_LOGF(log,
214               "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
215               "filter said it can provide a value",
216               GetName().AsCString());
217 
218     m_provides_value = eLazyBoolYes;
219     CopyValueData(synth_val.get());
220   } else {
221     LLDB_LOGF(log,
222               "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
223               "filter said it will not provide a value",
224               GetName().AsCString());
225 
226     m_provides_value = eLazyBoolNo;
227     // Copying the data of an incomplete type won't work as it has no byte size.
228     if (m_parent->GetCompilerType().IsCompleteType())
229       CopyValueData(m_parent);
230   }
231 
232   SetValueIsValid(true);
233   return true;
234 }
235 
236 lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx,
237                                                           bool can_create) {
238   Log *log = GetLog(LLDBLog::DataFormatters);
239 
240   LLDB_LOGF(log,
241             "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
242             "child at index %zu",
243             GetName().AsCString(), idx);
244 
245   UpdateValueIfNeeded();
246 
247   ValueObject *valobj;
248   bool child_is_cached;
249   {
250     std::lock_guard<std::mutex> guard(m_child_mutex);
251     auto cached_child_it = m_children_byindex.find(idx);
252     child_is_cached = cached_child_it != m_children_byindex.end();
253     if (child_is_cached)
254       valobj = cached_child_it->second;
255   }
256 
257   if (!child_is_cached) {
258     if (can_create && m_synth_filter_up != nullptr) {
259       LLDB_LOGF(log,
260                 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
261                 "index %zu not cached and will be created",
262                 GetName().AsCString(), idx);
263 
264       lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
265 
266       LLDB_LOGF(
267           log,
268           "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
269           "%zu created as %p (is "
270           "synthetic: %s)",
271           GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
272           synth_guy.get()
273               ? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
274               : "no");
275 
276       if (!synth_guy)
277         return synth_guy;
278 
279       {
280         std::lock_guard<std::mutex> guard(m_child_mutex);
281         if (synth_guy->IsSyntheticChildrenGenerated())
282           m_synthetic_children_cache.push_back(synth_guy);
283         m_children_byindex[idx] = synth_guy.get();
284       }
285       synth_guy->SetPreferredDisplayLanguageIfNeeded(
286           GetPreferredDisplayLanguage());
287       return synth_guy;
288     } else {
289       LLDB_LOGF(log,
290                 "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
291                 "index %zu not cached and cannot "
292                 "be created (can_create = %s, synth_filter = %p)",
293                 GetName().AsCString(), idx, can_create ? "yes" : "no",
294                 static_cast<void *>(m_synth_filter_up.get()));
295 
296       return lldb::ValueObjectSP();
297     }
298   } else {
299     LLDB_LOGF(log,
300               "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
301               "index %zu cached as %p",
302               GetName().AsCString(), idx, static_cast<void *>(valobj));
303 
304     return valobj->GetSP();
305   }
306 }
307 
308 lldb::ValueObjectSP
309 ValueObjectSynthetic::GetChildMemberWithName(ConstString name,
310                                              bool can_create) {
311   UpdateValueIfNeeded();
312 
313   uint32_t index = GetIndexOfChildWithName(name);
314 
315   if (index == UINT32_MAX)
316     return lldb::ValueObjectSP();
317 
318   return GetChildAtIndex(index, can_create);
319 }
320 
321 size_t ValueObjectSynthetic::GetIndexOfChildWithName(ConstString name) {
322   UpdateValueIfNeeded();
323 
324   uint32_t found_index = UINT32_MAX;
325   bool did_find;
326   {
327     std::lock_guard<std::mutex> guard(m_child_mutex);
328     auto name_to_index = m_name_toindex.find(name.GetCString());
329     did_find = name_to_index != m_name_toindex.end();
330     if (did_find)
331       found_index = name_to_index->second;
332   }
333 
334   if (!did_find && m_synth_filter_up != nullptr) {
335     uint32_t index = m_synth_filter_up->GetIndexOfChildWithName(name);
336     if (index == UINT32_MAX)
337       return index;
338     std::lock_guard<std::mutex> guard(m_child_mutex);
339     m_name_toindex[name.GetCString()] = index;
340     return index;
341   } else if (!did_find && m_synth_filter_up == nullptr)
342     return UINT32_MAX;
343   else /*if (iter != m_name_toindex.end())*/
344     return found_index;
345 }
346 
347 bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
348 
349 lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
350   return m_parent->GetSP();
351 }
352 
353 void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
354   m_value = (source->UpdateValueIfNeeded(), source->GetValue());
355   ExecutionContext exe_ctx(GetExecutionContextRef());
356   m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
357 }
358 
359 bool ValueObjectSynthetic::CanProvideValue() {
360   if (!UpdateValueIfNeeded())
361     return false;
362   if (m_provides_value == eLazyBoolYes)
363     return true;
364   return m_parent->CanProvideValue();
365 }
366 
367 bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
368                                                Status &error) {
369   return m_parent->SetValueFromCString(value_str, error);
370 }
371 
372 void ValueObjectSynthetic::SetFormat(lldb::Format format) {
373   if (m_parent) {
374     m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
375     m_parent->SetFormat(format);
376   }
377   this->ValueObject::SetFormat(format);
378   this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
379 }
380 
381 void ValueObjectSynthetic::SetPreferredDisplayLanguage(
382     lldb::LanguageType lang) {
383   this->ValueObject::SetPreferredDisplayLanguage(lang);
384   if (m_parent)
385     m_parent->SetPreferredDisplayLanguage(lang);
386 }
387 
388 lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
389   if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
390     if (m_parent)
391       return m_parent->GetPreferredDisplayLanguage();
392     return lldb::eLanguageTypeUnknown;
393   } else
394     return m_preferred_display_language;
395 }
396 
397 bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
398   if (m_parent)
399     return m_parent->IsSyntheticChildrenGenerated();
400   return false;
401 }
402 
403 void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
404   if (m_parent)
405     m_parent->SetSyntheticChildrenGenerated(b);
406   this->ValueObject::SetSyntheticChildrenGenerated(b);
407 }
408 
409 bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
410   if (m_parent)
411     return m_parent->GetDeclaration(decl);
412 
413   return ValueObject::GetDeclaration(decl);
414 }
415 
416 uint64_t ValueObjectSynthetic::GetLanguageFlags() {
417   if (m_parent)
418     return m_parent->GetLanguageFlags();
419   return this->ValueObject::GetLanguageFlags();
420 }
421 
422 void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
423   if (m_parent)
424     m_parent->SetLanguageFlags(flags);
425   else
426     this->ValueObject::SetLanguageFlags(flags);
427 }
428