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