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