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/LLDBLog.h" 16 #include "lldb/Utility/Log.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 = GetLog(LLDBLog::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 = GetLog(LLDBLog::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_flags.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 = GetLog(LLDBLog::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