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