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