xref: /llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (revision 624ea68cbc3ce422b3ee110c0c0af839eec2e278)
1566bfbb7SDanil Stefaniuc //===-- GenericBitset.cpp //-----------------------------------------------===//
2566bfbb7SDanil Stefaniuc //
3566bfbb7SDanil Stefaniuc // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4566bfbb7SDanil Stefaniuc // See https://llvm.org/LICENSE.txt for license information.
5566bfbb7SDanil Stefaniuc // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6566bfbb7SDanil Stefaniuc //
7566bfbb7SDanil Stefaniuc //===----------------------------------------------------------------------===//
8566bfbb7SDanil Stefaniuc 
9566bfbb7SDanil Stefaniuc #include "LibCxx.h"
10566bfbb7SDanil Stefaniuc #include "LibStdcpp.h"
11566bfbb7SDanil Stefaniuc #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12566bfbb7SDanil Stefaniuc #include "lldb/DataFormatters/FormattersHelpers.h"
13566bfbb7SDanil Stefaniuc #include "lldb/Target/Target.h"
14f190ce62SKazu Hirata #include <optional>
15566bfbb7SDanil Stefaniuc 
16566bfbb7SDanil Stefaniuc using namespace lldb;
17566bfbb7SDanil Stefaniuc using namespace lldb_private;
18566bfbb7SDanil Stefaniuc 
19566bfbb7SDanil Stefaniuc namespace {
20566bfbb7SDanil Stefaniuc 
21566bfbb7SDanil Stefaniuc /// This class can be used for handling bitsets from both libcxx and libstdcpp.
22566bfbb7SDanil Stefaniuc class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
23566bfbb7SDanil Stefaniuc public:
24566bfbb7SDanil Stefaniuc   enum class StdLib {
25566bfbb7SDanil Stefaniuc     LibCxx,
26566bfbb7SDanil Stefaniuc     LibStdcpp,
27566bfbb7SDanil Stefaniuc   };
28566bfbb7SDanil Stefaniuc 
29566bfbb7SDanil Stefaniuc   GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
30566bfbb7SDanil Stefaniuc 
GetIndexOfChildWithName(ConstString name)31566bfbb7SDanil Stefaniuc   size_t GetIndexOfChildWithName(ConstString name) override {
32566bfbb7SDanil Stefaniuc     return formatters::ExtractIndexFromString(name.GetCString());
33566bfbb7SDanil Stefaniuc   }
34566bfbb7SDanil Stefaniuc 
MightHaveChildren()35566bfbb7SDanil Stefaniuc   bool MightHaveChildren() override { return true; }
36d7fb94b6SMichael Buch   lldb::ChildCacheState Update() override;
CalculateNumChildren()37*624ea68cSAdrian Prantl   llvm::Expected<uint32_t> CalculateNumChildren() override {
38*624ea68cSAdrian Prantl     return m_elements.size();
39*624ea68cSAdrian Prantl   }
40e710523eSAdrian Prantl   ValueObjectSP GetChildAtIndex(uint32_t idx) override;
41566bfbb7SDanil Stefaniuc 
42566bfbb7SDanil Stefaniuc private:
4314d95b26SAlex Langford   llvm::StringRef GetDataContainerMemberName();
44566bfbb7SDanil Stefaniuc 
45566bfbb7SDanil Stefaniuc   // The lifetime of a ValueObject and all its derivative ValueObjects
46566bfbb7SDanil Stefaniuc   // (children, clones, etc.) is managed by a ClusterManager. These
47566bfbb7SDanil Stefaniuc   // objects are only destroyed when every shared pointer to any of them
48566bfbb7SDanil Stefaniuc   // is destroyed, so we must not store a shared pointer to any ValueObject
49566bfbb7SDanil Stefaniuc   // derived from our backend ValueObject (since we're in the same cluster).
50566bfbb7SDanil Stefaniuc   // Value objects created from raw data (i.e. in a different cluster) must
51566bfbb7SDanil Stefaniuc   // be referenced via shared pointer to keep them alive, however.
52566bfbb7SDanil Stefaniuc   std::vector<ValueObjectSP> m_elements;
53566bfbb7SDanil Stefaniuc   ValueObject *m_first = nullptr;
54566bfbb7SDanil Stefaniuc   CompilerType m_bool_type;
55566bfbb7SDanil Stefaniuc   ByteOrder m_byte_order = eByteOrderInvalid;
56566bfbb7SDanil Stefaniuc   uint8_t m_byte_size = 0;
57566bfbb7SDanil Stefaniuc   StdLib m_stdlib;
58566bfbb7SDanil Stefaniuc };
59566bfbb7SDanil Stefaniuc } // namespace
60566bfbb7SDanil Stefaniuc 
GenericBitsetFrontEnd(ValueObject & valobj,StdLib stdlib)61566bfbb7SDanil Stefaniuc GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
62566bfbb7SDanil Stefaniuc     : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
63566bfbb7SDanil Stefaniuc   m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
64566bfbb7SDanil Stefaniuc   if (auto target_sp = m_backend.GetTargetSP()) {
65566bfbb7SDanil Stefaniuc     m_byte_order = target_sp->GetArchitecture().GetByteOrder();
66566bfbb7SDanil Stefaniuc     m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
67566bfbb7SDanil Stefaniuc     Update();
68566bfbb7SDanil Stefaniuc   }
69566bfbb7SDanil Stefaniuc }
70566bfbb7SDanil Stefaniuc 
GetDataContainerMemberName()7114d95b26SAlex Langford llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() {
7214d95b26SAlex Langford   static constexpr llvm::StringLiteral s_libcxx_case("__first_");
7314d95b26SAlex Langford   static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w");
74566bfbb7SDanil Stefaniuc   switch (m_stdlib) {
75566bfbb7SDanil Stefaniuc   case StdLib::LibCxx:
7614d95b26SAlex Langford     return s_libcxx_case;
77566bfbb7SDanil Stefaniuc   case StdLib::LibStdcpp:
7814d95b26SAlex Langford     return s_libstdcpp_case;
79566bfbb7SDanil Stefaniuc   }
8049d38b1dSSimon Pilgrim   llvm_unreachable("Unknown StdLib enum");
81566bfbb7SDanil Stefaniuc }
82566bfbb7SDanil Stefaniuc 
Update()83d7fb94b6SMichael Buch lldb::ChildCacheState GenericBitsetFrontEnd::Update() {
84566bfbb7SDanil Stefaniuc   m_elements.clear();
85566bfbb7SDanil Stefaniuc   m_first = nullptr;
86566bfbb7SDanil Stefaniuc 
87566bfbb7SDanil Stefaniuc   TargetSP target_sp = m_backend.GetTargetSP();
88566bfbb7SDanil Stefaniuc   if (!target_sp)
89d7fb94b6SMichael Buch     return lldb::ChildCacheState::eRefetch;
90566bfbb7SDanil Stefaniuc 
91566bfbb7SDanil Stefaniuc   size_t size = 0;
92566bfbb7SDanil Stefaniuc 
93566bfbb7SDanil Stefaniuc   if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
94193bf2e8SDanil Stefaniuc     size = arg->value.getLimitedValue();
95566bfbb7SDanil Stefaniuc 
96566bfbb7SDanil Stefaniuc   m_elements.assign(size, ValueObjectSP());
977d4fcd41SDave Lee   m_first =
987d4fcd41SDave Lee       m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get();
99d7fb94b6SMichael Buch   return lldb::ChildCacheState::eRefetch;
100566bfbb7SDanil Stefaniuc }
101566bfbb7SDanil Stefaniuc 
GetChildAtIndex(uint32_t idx)102e710523eSAdrian Prantl ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {
103566bfbb7SDanil Stefaniuc   if (idx >= m_elements.size() || !m_first)
104566bfbb7SDanil Stefaniuc     return ValueObjectSP();
105566bfbb7SDanil Stefaniuc 
106566bfbb7SDanil Stefaniuc   if (m_elements[idx])
107566bfbb7SDanil Stefaniuc     return m_elements[idx];
108566bfbb7SDanil Stefaniuc 
109566bfbb7SDanil Stefaniuc   ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
110566bfbb7SDanil Stefaniuc   CompilerType type;
111566bfbb7SDanil Stefaniuc   ValueObjectSP chunk;
112566bfbb7SDanil Stefaniuc   // For small bitsets __first_ is not an array, but a plain size_t.
113566bfbb7SDanil Stefaniuc   if (m_first->GetCompilerType().IsArrayType(&type)) {
1142fe83274SKazu Hirata     std::optional<uint64_t> bit_size =
115566bfbb7SDanil Stefaniuc         type.GetBitSize(ctx.GetBestExecutionContextScope());
116566bfbb7SDanil Stefaniuc     if (!bit_size || *bit_size == 0)
117566bfbb7SDanil Stefaniuc       return {};
118a1a74f7cSDave Lee     chunk = m_first->GetChildAtIndex(idx / *bit_size);
119566bfbb7SDanil Stefaniuc   } else {
120566bfbb7SDanil Stefaniuc     type = m_first->GetCompilerType();
121566bfbb7SDanil Stefaniuc     chunk = m_first->GetSP();
122566bfbb7SDanil Stefaniuc   }
123566bfbb7SDanil Stefaniuc   if (!type || !chunk)
124566bfbb7SDanil Stefaniuc     return {};
125566bfbb7SDanil Stefaniuc 
1262fe83274SKazu Hirata   std::optional<uint64_t> bit_size =
127566bfbb7SDanil Stefaniuc       type.GetBitSize(ctx.GetBestExecutionContextScope());
128566bfbb7SDanil Stefaniuc   if (!bit_size || *bit_size == 0)
129566bfbb7SDanil Stefaniuc     return {};
130566bfbb7SDanil Stefaniuc   size_t chunk_idx = idx % *bit_size;
131566bfbb7SDanil Stefaniuc   uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
132566bfbb7SDanil Stefaniuc   DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
133566bfbb7SDanil Stefaniuc 
134566bfbb7SDanil Stefaniuc   m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
135566bfbb7SDanil Stefaniuc                                               data, ctx, m_bool_type);
136566bfbb7SDanil Stefaniuc 
137566bfbb7SDanil Stefaniuc   return m_elements[idx];
138566bfbb7SDanil Stefaniuc }
139566bfbb7SDanil Stefaniuc 
LibStdcppBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)140566bfbb7SDanil Stefaniuc SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
141566bfbb7SDanil Stefaniuc     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
142566bfbb7SDanil Stefaniuc   if (valobj_sp)
143566bfbb7SDanil Stefaniuc     return new GenericBitsetFrontEnd(*valobj_sp,
144566bfbb7SDanil Stefaniuc                                      GenericBitsetFrontEnd::StdLib::LibStdcpp);
145566bfbb7SDanil Stefaniuc   return nullptr;
146566bfbb7SDanil Stefaniuc }
147566bfbb7SDanil Stefaniuc 
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)148566bfbb7SDanil Stefaniuc SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
149566bfbb7SDanil Stefaniuc     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
150566bfbb7SDanil Stefaniuc   if (valobj_sp)
151566bfbb7SDanil Stefaniuc     return new GenericBitsetFrontEnd(*valobj_sp,
152566bfbb7SDanil Stefaniuc                                      GenericBitsetFrontEnd::StdLib::LibCxx);
153566bfbb7SDanil Stefaniuc   return nullptr;
154566bfbb7SDanil Stefaniuc }
155