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