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