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