Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectSynthetic.cpp
213764 views
//===-- ValueObjectSynthetic.cpp ------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/ValueObject/ValueObjectSynthetic.h"910#include "lldb/Core/Value.h"11#include "lldb/DataFormatters/TypeSynthetic.h"12#include "lldb/Target/ExecutionContext.h"13#include "lldb/Utility/ConstString.h"14#include "lldb/Utility/LLDBLog.h"15#include "lldb/Utility/Log.h"16#include "lldb/Utility/Status.h"17#include "lldb/ValueObject/ValueObject.h"1819#include "llvm/ADT/STLExtras.h"20#include <optional>2122namespace lldb_private {23class Declaration;24}2526using namespace lldb_private;2728class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {29public:30DummySyntheticFrontEnd(ValueObject &backend)31: SyntheticChildrenFrontEnd(backend) {}3233llvm::Expected<uint32_t> CalculateNumChildren() override {34return m_backend.GetNumChildren();35}3637lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {38return m_backend.GetChildAtIndex(idx);39}4041llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {42return m_backend.GetIndexOfChildWithName(name);43}4445bool MightHaveChildren() override { return m_backend.MightHaveChildren(); }4647lldb::ChildCacheState Update() override {48return lldb::ChildCacheState::eRefetch;49}50};5152ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,53lldb::SyntheticChildrenSP filter)54: ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(),55m_name_toindex(), m_synthetic_children_cache(),56m_synthetic_children_count(UINT32_MAX),57m_parent_type_name(parent.GetTypeName()),58m_might_have_children(eLazyBoolCalculate),59m_provides_value(eLazyBoolCalculate) {60SetName(parent.GetName());61// Copying the data of an incomplete type won't work as it has no byte size.62if (m_parent->GetCompilerType().IsCompleteType())63CopyValueData(m_parent);64CreateSynthFilter();65}6667ValueObjectSynthetic::~ValueObjectSynthetic() = default;6869CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {70return m_parent->GetCompilerType();71}7273ConstString ValueObjectSynthetic::GetTypeName() {74return m_parent->GetTypeName();75}7677ConstString ValueObjectSynthetic::GetQualifiedTypeName() {78return m_parent->GetQualifiedTypeName();79}8081ConstString ValueObjectSynthetic::GetDisplayTypeName() {82if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())83return synth_name;8485return m_parent->GetDisplayTypeName();86}8788llvm::Expected<uint32_t>89ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {90Log *log = GetLog(LLDBLog::DataFormatters);9192UpdateValueIfNeeded();93if (m_synthetic_children_count < UINT32_MAX)94return m_synthetic_children_count <= max ? m_synthetic_children_count : max;9596if (max < UINT32_MAX) {97auto num_children = m_synth_filter_up->CalculateNumChildren(max);98LLDB_LOGF(log,99"[ValueObjectSynthetic::CalculateNumChildren] for VO of name "100"%s and type %s, the filter returned %u child values",101GetName().AsCString(), GetTypeName().AsCString(),102num_children ? *num_children : 0);103return num_children;104} else {105auto num_children_or_err = m_synth_filter_up->CalculateNumChildren(max);106if (!num_children_or_err) {107m_synthetic_children_count = 0;108return num_children_or_err;109}110auto num_children = (m_synthetic_children_count = *num_children_or_err);111LLDB_LOGF(log,112"[ValueObjectSynthetic::CalculateNumChildren] for VO of name "113"%s and type %s, the filter returned %u child values",114GetName().AsCString(), GetTypeName().AsCString(), num_children);115return num_children;116}117}118119lldb::ValueObjectSP120ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {121if (!m_parent)122return lldb::ValueObjectSP();123if (IsDynamic() && GetDynamicValueType() == valueType)124return GetSP();125return m_parent->GetDynamicValue(valueType);126}127128bool ValueObjectSynthetic::MightHaveChildren() {129if (m_might_have_children == eLazyBoolCalculate)130m_might_have_children =131(m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);132return (m_might_have_children != eLazyBoolNo);133}134135llvm::Expected<uint64_t> ValueObjectSynthetic::GetByteSize() {136return m_parent->GetByteSize();137}138139lldb::ValueType ValueObjectSynthetic::GetValueType() const {140return m_parent->GetValueType();141}142143void ValueObjectSynthetic::CreateSynthFilter() {144ValueObject *valobj_for_frontend = m_parent;145if (m_synth_sp->WantsDereference()) {146CompilerType type = m_parent->GetCompilerType();147if (type.IsValid() && type.IsPointerOrReferenceType()) {148Status error;149lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);150if (error.Success())151valobj_for_frontend = deref_sp.get();152}153}154m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));155if (!m_synth_filter_up)156m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);157}158159bool ValueObjectSynthetic::UpdateValue() {160Log *log = GetLog(LLDBLog::DataFormatters);161162SetValueIsValid(false);163m_error.Clear();164165if (!m_parent->UpdateValueIfNeeded(false)) {166// our parent could not update.. as we are meaningless without a parent,167// just stop168if (m_parent->GetError().Fail())169m_error = m_parent->GetError().Clone();170return false;171}172173// Regenerate the synthetic filter if our typename changes. When the (dynamic)174// type of an object changes, so does their synthetic filter of choice.175ConstString new_parent_type_name = m_parent->GetTypeName();176if (new_parent_type_name != m_parent_type_name) {177LLDB_LOGF(log,178"[ValueObjectSynthetic::UpdateValue] name=%s, type changed "179"from %s to %s, recomputing synthetic filter",180GetName().AsCString(), m_parent_type_name.AsCString(),181new_parent_type_name.AsCString());182m_parent_type_name = new_parent_type_name;183CreateSynthFilter();184}185186// let our backend do its update187if (m_synth_filter_up->Update() == lldb::ChildCacheState::eRefetch) {188LLDB_LOGF(log,189"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "190"filter said caches are stale - clearing",191GetName().AsCString());192// filter said that cached values are stale193{194std::lock_guard<std::mutex> guard(m_child_mutex);195m_children_byindex.clear();196m_name_toindex.clear();197}198// usually, an object's value can change but this does not alter its199// children count for a synthetic VO that might indeed happen, so we need200// to tell the upper echelons that they need to come back to us asking for201// children202m_flags.m_children_count_valid = false;203{204std::lock_guard<std::mutex> guard(m_child_mutex);205m_synthetic_children_cache.clear();206}207m_synthetic_children_count = UINT32_MAX;208m_might_have_children = eLazyBoolCalculate;209} else {210LLDB_LOGF(log,211"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "212"filter said caches are still valid",213GetName().AsCString());214}215216m_provides_value = eLazyBoolCalculate;217218lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());219220if (synth_val && synth_val->CanProvideValue()) {221LLDB_LOGF(log,222"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "223"filter said it can provide a value",224GetName().AsCString());225226m_provides_value = eLazyBoolYes;227CopyValueData(synth_val.get());228} else {229LLDB_LOGF(log,230"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "231"filter said it will not provide a value",232GetName().AsCString());233234m_provides_value = eLazyBoolNo;235// Copying the data of an incomplete type won't work as it has no byte size.236if (m_parent->GetCompilerType().IsCompleteType())237CopyValueData(m_parent);238}239240SetValueIsValid(true);241return true;242}243244lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(uint32_t idx,245bool can_create) {246Log *log = GetLog(LLDBLog::DataFormatters);247248LLDB_LOGF(log,249"[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "250"child at index %u",251GetName().AsCString(), idx);252253UpdateValueIfNeeded();254255ValueObject *valobj;256bool child_is_cached;257{258std::lock_guard<std::mutex> guard(m_child_mutex);259auto cached_child_it = m_children_byindex.find(idx);260child_is_cached = cached_child_it != m_children_byindex.end();261if (child_is_cached)262valobj = cached_child_it->second;263}264265if (!child_is_cached) {266if (can_create && m_synth_filter_up != nullptr) {267LLDB_LOGF(log,268"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "269"index %u not cached and will be created",270GetName().AsCString(), idx);271272lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);273274LLDB_LOGF(275log,276"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "277"%u created as %p (is "278"synthetic: %s)",279GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),280synth_guy.get()281? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")282: "no");283284if (!synth_guy)285return synth_guy;286287{288std::lock_guard<std::mutex> guard(m_child_mutex);289if (synth_guy->IsSyntheticChildrenGenerated())290m_synthetic_children_cache.push_back(synth_guy);291m_children_byindex[idx] = synth_guy.get();292}293synth_guy->SetPreferredDisplayLanguageIfNeeded(294GetPreferredDisplayLanguage());295return synth_guy;296} else {297LLDB_LOGF(log,298"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "299"index %u not cached and cannot "300"be created (can_create = %s, synth_filter = %p)",301GetName().AsCString(), idx, can_create ? "yes" : "no",302static_cast<void *>(m_synth_filter_up.get()));303304return lldb::ValueObjectSP();305}306} else {307LLDB_LOGF(log,308"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "309"index %u cached as %p",310GetName().AsCString(), idx, static_cast<void *>(valobj));311312return valobj->GetSP();313}314}315316lldb::ValueObjectSP317ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,318bool can_create) {319UpdateValueIfNeeded();320321auto index_or_err = GetIndexOfChildWithName(name);322323if (!index_or_err) {324llvm::consumeError(index_or_err.takeError());325return lldb::ValueObjectSP();326}327328return GetChildAtIndex(*index_or_err, can_create);329}330331llvm::Expected<size_t>332ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {333UpdateValueIfNeeded();334335ConstString name(name_ref);336337std::optional<uint32_t> found_index = std::nullopt;338{339std::lock_guard<std::mutex> guard(m_child_mutex);340auto name_to_index = m_name_toindex.find(name.GetCString());341if (name_to_index != m_name_toindex.end())342found_index = name_to_index->second;343}344345if (!found_index && m_synth_filter_up != nullptr) {346auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name);347if (!index_or_err)348return index_or_err.takeError();349std::lock_guard<std::mutex> guard(m_child_mutex);350m_name_toindex[name.GetCString()] = *index_or_err;351return *index_or_err;352} else if (!found_index && m_synth_filter_up == nullptr) {353return llvm::createStringError("Type has no child named '%s'",354name.AsCString());355} else if (found_index)356return *found_index;357358return llvm::createStringError("Type has no child named '%s'",359name.AsCString());360}361362bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }363364lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {365return m_parent->GetSP();366}367368void ValueObjectSynthetic::CopyValueData(ValueObject *source) {369if (!source->UpdateValueIfNeeded())370return;371m_value = source->GetValue();372ExecutionContext exe_ctx(GetExecutionContextRef());373m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());374}375376bool ValueObjectSynthetic::CanProvideValue() {377if (!UpdateValueIfNeeded())378return false;379if (m_provides_value == eLazyBoolYes)380return true;381return m_parent->CanProvideValue();382}383384bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,385Status &error) {386return m_parent->SetValueFromCString(value_str, error);387}388389void ValueObjectSynthetic::SetFormat(lldb::Format format) {390if (m_parent) {391m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);392m_parent->SetFormat(format);393}394this->ValueObject::SetFormat(format);395this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);396}397398void ValueObjectSynthetic::SetPreferredDisplayLanguage(399lldb::LanguageType lang) {400this->ValueObject::SetPreferredDisplayLanguage(lang);401if (m_parent)402m_parent->SetPreferredDisplayLanguage(lang);403}404405lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {406if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {407if (m_parent)408return m_parent->GetPreferredDisplayLanguage();409return lldb::eLanguageTypeUnknown;410} else411return m_preferred_display_language;412}413414bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {415if (m_parent)416return m_parent->IsSyntheticChildrenGenerated();417return false;418}419420void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {421if (m_parent)422m_parent->SetSyntheticChildrenGenerated(b);423this->ValueObject::SetSyntheticChildrenGenerated(b);424}425426bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {427if (m_parent)428return m_parent->GetDeclaration(decl);429430return ValueObject::GetDeclaration(decl);431}432433uint64_t ValueObjectSynthetic::GetLanguageFlags() {434if (m_parent)435return m_parent->GetLanguageFlags();436return this->ValueObject::GetLanguageFlags();437}438439void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {440if (m_parent)441m_parent->SetLanguageFlags(flags);442else443this->ValueObject::SetLanguageFlags(flags);444}445446447