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