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