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