1 //===-- LibCxxBitset.cpp ----------------------------------------*- C++ -*-===// 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 "lldb/DataFormatters/FormattersHelpers.h" 11 #include "lldb/Symbol/ClangASTContext.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 std::vector<ValueObjectSP> m_elements; 34 ValueObjectSP m_first; 35 CompilerType m_bool_type; 36 ByteOrder m_byte_order = eByteOrderInvalid; 37 uint8_t m_byte_size = 0; 38 }; 39 } // namespace 40 41 BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj) 42 : SyntheticChildrenFrontEnd(valobj) { 43 m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool); 44 if (auto target_sp = m_backend.GetTargetSP()) { 45 m_byte_order = target_sp->GetArchitecture().GetByteOrder(); 46 m_byte_size = target_sp->GetArchitecture().GetAddressByteSize(); 47 Update(); 48 } 49 } 50 51 bool BitsetFrontEnd::Update() { 52 m_elements.clear(); 53 m_first.reset(); 54 55 TargetSP target_sp = m_backend.GetTargetSP(); 56 if (!target_sp) 57 return false; 58 size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay(); 59 60 size_t size = 0; 61 if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0)) 62 size = arg->value.getLimitedValue(capping_size); 63 64 m_elements.assign(size, ValueObjectSP()); 65 66 m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true); 67 return false; 68 } 69 70 ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) { 71 if (idx >= m_elements.size() || !m_first) 72 return ValueObjectSP(); 73 74 if (m_elements[idx]) 75 return m_elements[idx]; 76 77 ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false); 78 CompilerType type; 79 ValueObjectSP chunk; 80 // For small bitsets __first_ is not an array, but a plain size_t. 81 if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) { 82 llvm::Optional<uint64_t> bit_size = 83 type.GetBitSize(ctx.GetBestExecutionContextScope()); 84 if (!bit_size || *bit_size == 0) 85 return {}; 86 chunk = m_first->GetChildAtIndex(idx / *bit_size, true); 87 } else { 88 type = m_first->GetCompilerType(); 89 chunk = m_first; 90 } 91 if (!type || !chunk) 92 return {}; 93 94 llvm::Optional<uint64_t> bit_size = 95 type.GetBitSize(ctx.GetBestExecutionContextScope()); 96 if (!bit_size || *bit_size == 0) 97 return {}; 98 size_t chunk_idx = idx % *bit_size; 99 uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx)); 100 DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size); 101 102 m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), 103 data, ctx, m_bool_type); 104 105 return m_elements[idx]; 106 } 107 108 SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator( 109 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 110 if (valobj_sp) 111 return new BitsetFrontEnd(*valobj_sp); 112 return nullptr; 113 } 114