1 //===-- LibCxxBitset.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 "Plugins/TypeSystem/Clang/TypeSystemClang.h" 11 #include "lldb/DataFormatters/FormattersHelpers.h" 12 #include "lldb/Target/Target.h" 13 14 using namespace lldb; 15 using namespace lldb_private; 16 17 namespace { 18 19 class BitsetFrontEnd : public SyntheticChildrenFrontEnd { 20 public: 21 BitsetFrontEnd(ValueObject &valobj); 22 23 size_t GetIndexOfChildWithName(ConstString name) override { 24 return formatters::ExtractIndexFromString(name.GetCString()); 25 } 26 27 bool MightHaveChildren() override { return true; } 28 bool Update() override; 29 size_t CalculateNumChildren() override { return m_elements.size(); } 30 ValueObjectSP GetChildAtIndex(size_t idx) override; 31 32 private: 33 // The lifetime of a ValueObject and all its derivative ValueObjects 34 // (children, clones, etc.) is managed by a ClusterManager. These 35 // objects are only destroyed when every shared pointer to any of them 36 // is destroyed, so we must not store a shared pointer to any ValueObject 37 // derived from our backend ValueObject (since we're in the same cluster). 38 // Value objects created from raw data (i.e. in a different cluster) must 39 // be referenced via shared pointer to keep them alive, however. 40 std::vector<ValueObjectSP> m_elements; 41 ValueObject* m_first = nullptr; 42 CompilerType m_bool_type; 43 ByteOrder m_byte_order = eByteOrderInvalid; 44 uint8_t m_byte_size = 0; 45 }; 46 } // namespace 47 48 BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj) 49 : SyntheticChildrenFrontEnd(valobj) { 50 m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool); 51 if (auto target_sp = m_backend.GetTargetSP()) { 52 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 53 m_byte_size = target_sp->GetArchitecture().GetAddressByteSize(); 54 Update(); 55 } 56 } 57 58 bool BitsetFrontEnd::Update() { 59 m_elements.clear(); 60 m_first = nullptr; 61 62 TargetSP target_sp = m_backend.GetTargetSP(); 63 if (!target_sp) 64 return false; 65 size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay(); 66 67 size_t size = 0; 68 if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0)) 69 size = arg->value.getLimitedValue(capping_size); 70 71 m_elements.assign(size, ValueObjectSP()); 72 73 m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true).get(); 74 return false; 75 } 76 77 ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) { 78 if (idx >= m_elements.size() || !m_first) 79 return ValueObjectSP(); 80 81 if (m_elements[idx]) 82 return m_elements[idx]; 83 84 ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false); 85 CompilerType type; 86 ValueObjectSP chunk; 87 // For small bitsets __first_ is not an array, but a plain size_t. 88 if (m_first->GetCompilerType().IsArrayType(&type)) { 89 llvm::Optional<uint64_t> bit_size = 90 type.GetBitSize(ctx.GetBestExecutionContextScope()); 91 if (!bit_size || *bit_size == 0) 92 return {}; 93 chunk = m_first->GetChildAtIndex(idx / *bit_size, true); 94 } else { 95 type = m_first->GetCompilerType(); 96 chunk = m_first->GetSP(); 97 } 98 if (!type || !chunk) 99 return {}; 100 101 llvm::Optional<uint64_t> bit_size = 102 type.GetBitSize(ctx.GetBestExecutionContextScope()); 103 if (!bit_size || *bit_size == 0) 104 return {}; 105 size_t chunk_idx = idx % *bit_size; 106 uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx)); 107 DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size); 108 109 m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), 110 data, ctx, m_bool_type); 111 112 return m_elements[idx]; 113 } 114 115 SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator( 116 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 117 if (valobj_sp) 118 return new BitsetFrontEnd(*valobj_sp); 119 return nullptr; 120 } 121