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