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