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