Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
39644 views
//===-- GenericBitset.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 "LibCxx.h"9#include "LibStdcpp.h"10#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"11#include "lldb/DataFormatters/FormattersHelpers.h"12#include "lldb/Target/Target.h"13#include <optional>1415using namespace lldb;16using namespace lldb_private;1718namespace {1920/// This class can be used for handling bitsets from both libcxx and libstdcpp.21class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {22public:23enum class StdLib {24LibCxx,25LibStdcpp,26};2728GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);2930size_t GetIndexOfChildWithName(ConstString name) override {31return formatters::ExtractIndexFromString(name.GetCString());32}3334bool MightHaveChildren() override { return true; }35lldb::ChildCacheState Update() override;36llvm::Expected<uint32_t> CalculateNumChildren() override {37return m_elements.size();38}39ValueObjectSP GetChildAtIndex(uint32_t idx) override;4041private:42llvm::StringRef GetDataContainerMemberName();4344// The lifetime of a ValueObject and all its derivative ValueObjects45// (children, clones, etc.) is managed by a ClusterManager. These46// objects are only destroyed when every shared pointer to any of them47// is destroyed, so we must not store a shared pointer to any ValueObject48// derived from our backend ValueObject (since we're in the same cluster).49// Value objects created from raw data (i.e. in a different cluster) must50// be referenced via shared pointer to keep them alive, however.51std::vector<ValueObjectSP> m_elements;52ValueObject *m_first = nullptr;53CompilerType m_bool_type;54ByteOrder m_byte_order = eByteOrderInvalid;55uint8_t m_byte_size = 0;56StdLib m_stdlib;57};58} // namespace5960GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)61: SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {62m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);63if (auto target_sp = m_backend.GetTargetSP()) {64m_byte_order = target_sp->GetArchitecture().GetByteOrder();65m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();66Update();67}68}6970llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() {71static constexpr llvm::StringLiteral s_libcxx_case("__first_");72static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w");73switch (m_stdlib) {74case StdLib::LibCxx:75return s_libcxx_case;76case StdLib::LibStdcpp:77return s_libstdcpp_case;78}79llvm_unreachable("Unknown StdLib enum");80}8182lldb::ChildCacheState GenericBitsetFrontEnd::Update() {83m_elements.clear();84m_first = nullptr;8586TargetSP target_sp = m_backend.GetTargetSP();87if (!target_sp)88return lldb::ChildCacheState::eRefetch;8990size_t size = 0;9192if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))93size = arg->value.getLimitedValue();9495m_elements.assign(size, ValueObjectSP());96m_first =97m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get();98return lldb::ChildCacheState::eRefetch;99}100101ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {102if (idx >= m_elements.size() || !m_first)103return ValueObjectSP();104105if (m_elements[idx])106return m_elements[idx];107108ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);109CompilerType type;110ValueObjectSP chunk;111// For small bitsets __first_ is not an array, but a plain size_t.112if (m_first->GetCompilerType().IsArrayType(&type)) {113std::optional<uint64_t> bit_size =114type.GetBitSize(ctx.GetBestExecutionContextScope());115if (!bit_size || *bit_size == 0)116return {};117chunk = m_first->GetChildAtIndex(idx / *bit_size);118} else {119type = m_first->GetCompilerType();120chunk = m_first->GetSP();121}122if (!type || !chunk)123return {};124125std::optional<uint64_t> bit_size =126type.GetBitSize(ctx.GetBestExecutionContextScope());127if (!bit_size || *bit_size == 0)128return {};129size_t chunk_idx = idx % *bit_size;130uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));131DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);132133m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),134data, ctx, m_bool_type);135136return m_elements[idx];137}138139SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(140CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {141if (valobj_sp)142return new GenericBitsetFrontEnd(*valobj_sp,143GenericBitsetFrontEnd::StdLib::LibStdcpp);144return nullptr;145}146147SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(148CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {149if (valobj_sp)150return new GenericBitsetFrontEnd(*valobj_sp,151GenericBitsetFrontEnd::StdLib::LibCxx);152return nullptr;153}154155156