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