brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.5 KiB · f673c51 Raw
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