brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.4 KiB · f2521ec Raw
159 lines · cpp
1//===-- GenericBitset.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 "LibCxx.h"10#include "LibStdcpp.h"11#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"12#include "lldb/DataFormatters/FormattersHelpers.h"13#include "lldb/Target/Target.h"14#include <optional>15 16using namespace lldb;17using namespace lldb_private;18 19namespace {20 21/// This class can be used for handling bitsets from both libcxx and libstdcpp.22class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {23public:24  enum class StdLib {25    LibCxx,26    LibStdcpp,27  };28 29  GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);30 31  llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {32    auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());33    if (!optional_idx) {34      return llvm::createStringError("Type has no child named '%s'",35                                     name.AsCString());36    }37    return *optional_idx;38  }39 40  lldb::ChildCacheState Update() override;41  llvm::Expected<uint32_t> CalculateNumChildren() override {42    return m_elements.size();43  }44  ValueObjectSP GetChildAtIndex(uint32_t idx) override;45 46private:47  llvm::StringRef GetDataContainerMemberName();48 49  // The lifetime of a ValueObject and all its derivative ValueObjects50  // (children, clones, etc.) is managed by a ClusterManager. These51  // objects are only destroyed when every shared pointer to any of them52  // is destroyed, so we must not store a shared pointer to any ValueObject53  // derived from our backend ValueObject (since we're in the same cluster).54  // Value objects created from raw data (i.e. in a different cluster) must55  // be referenced via shared pointer to keep them alive, however.56  std::vector<ValueObjectSP> m_elements;57  ValueObject *m_first = nullptr;58  CompilerType m_bool_type;59  ByteOrder m_byte_order = eByteOrderInvalid;60  uint8_t m_byte_size = 0;61  StdLib m_stdlib;62};63} // namespace64 65GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)66    : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {67  m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);68  if (auto target_sp = m_backend.GetTargetSP()) {69    m_byte_order = target_sp->GetArchitecture().GetByteOrder();70    m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();71    Update();72  }73}74 75llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() {76  static constexpr llvm::StringLiteral s_libcxx_case("__first_");77  static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w");78  switch (m_stdlib) {79  case StdLib::LibCxx:80    return s_libcxx_case;81  case StdLib::LibStdcpp:82    return s_libstdcpp_case;83  }84  llvm_unreachable("Unknown StdLib enum");85}86 87lldb::ChildCacheState GenericBitsetFrontEnd::Update() {88  m_elements.clear();89  m_first = nullptr;90 91  TargetSP target_sp = m_backend.GetTargetSP();92  if (!target_sp)93    return lldb::ChildCacheState::eRefetch;94 95  size_t size = 0;96 97  if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))98    size = arg->value.GetAPSInt().getLimitedValue();99 100  m_elements.assign(size, ValueObjectSP());101  m_first =102      m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get();103  return lldb::ChildCacheState::eRefetch;104}105 106ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {107  if (idx >= m_elements.size() || !m_first)108    return ValueObjectSP();109 110  if (m_elements[idx])111    return m_elements[idx];112 113  ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);114  CompilerType type;115  ValueObjectSP chunk;116  // For small bitsets __first_ is not an array, but a plain size_t.117  if (m_first->GetCompilerType().IsArrayType(&type)) {118    std::optional<uint64_t> bit_size = llvm::expectedToOptional(119        type.GetBitSize(ctx.GetBestExecutionContextScope()));120    if (!bit_size || *bit_size == 0)121      return {};122    chunk = m_first->GetChildAtIndex(idx / *bit_size);123  } else {124    type = m_first->GetCompilerType();125    chunk = m_first->GetSP();126  }127  if (!type || !chunk)128    return {};129 130  std::optional<uint64_t> bit_size = llvm::expectedToOptional(131      type.GetBitSize(ctx.GetBestExecutionContextScope()));132  if (!bit_size || *bit_size == 0)133    return {};134  size_t chunk_idx = idx % *bit_size;135  uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));136  DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);137 138  m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),139                                              data, ctx, m_bool_type);140 141  return m_elements[idx];142}143 144SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(145    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {146  if (valobj_sp)147    return new GenericBitsetFrontEnd(*valobj_sp,148                                     GenericBitsetFrontEnd::StdLib::LibStdcpp);149  return nullptr;150}151 152SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(153    CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {154  if (valobj_sp)155    return new GenericBitsetFrontEnd(*valobj_sp,156                                     GenericBitsetFrontEnd::StdLib::LibCxx);157  return nullptr;158}159