xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1349cc55cSDimitry Andric //===-- GenericBitset.cpp //-----------------------------------------------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric 
9349cc55cSDimitry Andric #include "LibCxx.h"
10349cc55cSDimitry Andric #include "LibStdcpp.h"
11349cc55cSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12349cc55cSDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
13349cc55cSDimitry Andric #include "lldb/Target/Target.h"
14bdd1243dSDimitry Andric #include <optional>
15349cc55cSDimitry Andric 
16349cc55cSDimitry Andric using namespace lldb;
17349cc55cSDimitry Andric using namespace lldb_private;
18349cc55cSDimitry Andric 
19349cc55cSDimitry Andric namespace {
20349cc55cSDimitry Andric 
21349cc55cSDimitry Andric /// This class can be used for handling bitsets from both libcxx and libstdcpp.
22349cc55cSDimitry Andric class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd {
23349cc55cSDimitry Andric public:
24349cc55cSDimitry Andric   enum class StdLib {
25349cc55cSDimitry Andric     LibCxx,
26349cc55cSDimitry Andric     LibStdcpp,
27349cc55cSDimitry Andric   };
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric   GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib);
30349cc55cSDimitry Andric 
31349cc55cSDimitry Andric   size_t GetIndexOfChildWithName(ConstString name) override {
32349cc55cSDimitry Andric     return formatters::ExtractIndexFromString(name.GetCString());
33349cc55cSDimitry Andric   }
34349cc55cSDimitry Andric 
35349cc55cSDimitry Andric   bool MightHaveChildren() override { return true; }
36*0fca6ea1SDimitry Andric   lldb::ChildCacheState Update() override;
37*0fca6ea1SDimitry Andric   llvm::Expected<uint32_t> CalculateNumChildren() override {
38*0fca6ea1SDimitry Andric     return m_elements.size();
39*0fca6ea1SDimitry Andric   }
40*0fca6ea1SDimitry Andric   ValueObjectSP GetChildAtIndex(uint32_t idx) override;
41349cc55cSDimitry Andric 
42349cc55cSDimitry Andric private:
435f757f3fSDimitry Andric   llvm::StringRef GetDataContainerMemberName();
44349cc55cSDimitry Andric 
45349cc55cSDimitry Andric   // The lifetime of a ValueObject and all its derivative ValueObjects
46349cc55cSDimitry Andric   // (children, clones, etc.) is managed by a ClusterManager. These
47349cc55cSDimitry Andric   // objects are only destroyed when every shared pointer to any of them
48349cc55cSDimitry Andric   // is destroyed, so we must not store a shared pointer to any ValueObject
49349cc55cSDimitry Andric   // derived from our backend ValueObject (since we're in the same cluster).
50349cc55cSDimitry Andric   // Value objects created from raw data (i.e. in a different cluster) must
51349cc55cSDimitry Andric   // be referenced via shared pointer to keep them alive, however.
52349cc55cSDimitry Andric   std::vector<ValueObjectSP> m_elements;
53349cc55cSDimitry Andric   ValueObject *m_first = nullptr;
54349cc55cSDimitry Andric   CompilerType m_bool_type;
55349cc55cSDimitry Andric   ByteOrder m_byte_order = eByteOrderInvalid;
56349cc55cSDimitry Andric   uint8_t m_byte_size = 0;
57349cc55cSDimitry Andric   StdLib m_stdlib;
58349cc55cSDimitry Andric };
59349cc55cSDimitry Andric } // namespace
60349cc55cSDimitry Andric 
61349cc55cSDimitry Andric GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib)
62349cc55cSDimitry Andric     : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) {
63349cc55cSDimitry Andric   m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
64349cc55cSDimitry Andric   if (auto target_sp = m_backend.GetTargetSP()) {
65349cc55cSDimitry Andric     m_byte_order = target_sp->GetArchitecture().GetByteOrder();
66349cc55cSDimitry Andric     m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
67349cc55cSDimitry Andric     Update();
68349cc55cSDimitry Andric   }
69349cc55cSDimitry Andric }
70349cc55cSDimitry Andric 
715f757f3fSDimitry Andric llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() {
725f757f3fSDimitry Andric   static constexpr llvm::StringLiteral s_libcxx_case("__first_");
735f757f3fSDimitry Andric   static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w");
74349cc55cSDimitry Andric   switch (m_stdlib) {
75349cc55cSDimitry Andric   case StdLib::LibCxx:
765f757f3fSDimitry Andric     return s_libcxx_case;
77349cc55cSDimitry Andric   case StdLib::LibStdcpp:
785f757f3fSDimitry Andric     return s_libstdcpp_case;
79349cc55cSDimitry Andric   }
8004eeddc0SDimitry Andric   llvm_unreachable("Unknown StdLib enum");
81349cc55cSDimitry Andric }
82349cc55cSDimitry Andric 
83*0fca6ea1SDimitry Andric lldb::ChildCacheState GenericBitsetFrontEnd::Update() {
84349cc55cSDimitry Andric   m_elements.clear();
85349cc55cSDimitry Andric   m_first = nullptr;
86349cc55cSDimitry Andric 
87349cc55cSDimitry Andric   TargetSP target_sp = m_backend.GetTargetSP();
88349cc55cSDimitry Andric   if (!target_sp)
89*0fca6ea1SDimitry Andric     return lldb::ChildCacheState::eRefetch;
90349cc55cSDimitry Andric 
91349cc55cSDimitry Andric   size_t size = 0;
92349cc55cSDimitry Andric 
93349cc55cSDimitry Andric   if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
944824e7fdSDimitry Andric     size = arg->value.getLimitedValue();
95349cc55cSDimitry Andric 
96349cc55cSDimitry Andric   m_elements.assign(size, ValueObjectSP());
9706c3fb27SDimitry Andric   m_first =
9806c3fb27SDimitry Andric       m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get();
99*0fca6ea1SDimitry Andric   return lldb::ChildCacheState::eRefetch;
100349cc55cSDimitry Andric }
101349cc55cSDimitry Andric 
102*0fca6ea1SDimitry Andric ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) {
103349cc55cSDimitry Andric   if (idx >= m_elements.size() || !m_first)
104349cc55cSDimitry Andric     return ValueObjectSP();
105349cc55cSDimitry Andric 
106349cc55cSDimitry Andric   if (m_elements[idx])
107349cc55cSDimitry Andric     return m_elements[idx];
108349cc55cSDimitry Andric 
109349cc55cSDimitry Andric   ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
110349cc55cSDimitry Andric   CompilerType type;
111349cc55cSDimitry Andric   ValueObjectSP chunk;
112349cc55cSDimitry Andric   // For small bitsets __first_ is not an array, but a plain size_t.
113349cc55cSDimitry Andric   if (m_first->GetCompilerType().IsArrayType(&type)) {
114bdd1243dSDimitry Andric     std::optional<uint64_t> bit_size =
115349cc55cSDimitry Andric         type.GetBitSize(ctx.GetBestExecutionContextScope());
116349cc55cSDimitry Andric     if (!bit_size || *bit_size == 0)
117349cc55cSDimitry Andric       return {};
11806c3fb27SDimitry Andric     chunk = m_first->GetChildAtIndex(idx / *bit_size);
119349cc55cSDimitry Andric   } else {
120349cc55cSDimitry Andric     type = m_first->GetCompilerType();
121349cc55cSDimitry Andric     chunk = m_first->GetSP();
122349cc55cSDimitry Andric   }
123349cc55cSDimitry Andric   if (!type || !chunk)
124349cc55cSDimitry Andric     return {};
125349cc55cSDimitry Andric 
126bdd1243dSDimitry Andric   std::optional<uint64_t> bit_size =
127349cc55cSDimitry Andric       type.GetBitSize(ctx.GetBestExecutionContextScope());
128349cc55cSDimitry Andric   if (!bit_size || *bit_size == 0)
129349cc55cSDimitry Andric     return {};
130349cc55cSDimitry Andric   size_t chunk_idx = idx % *bit_size;
131349cc55cSDimitry Andric   uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
132349cc55cSDimitry Andric   DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
133349cc55cSDimitry Andric 
134349cc55cSDimitry Andric   m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
135349cc55cSDimitry Andric                                               data, ctx, m_bool_type);
136349cc55cSDimitry Andric 
137349cc55cSDimitry Andric   return m_elements[idx];
138349cc55cSDimitry Andric }
139349cc55cSDimitry Andric 
140349cc55cSDimitry Andric SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator(
141349cc55cSDimitry Andric     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
142349cc55cSDimitry Andric   if (valobj_sp)
143349cc55cSDimitry Andric     return new GenericBitsetFrontEnd(*valobj_sp,
144349cc55cSDimitry Andric                                      GenericBitsetFrontEnd::StdLib::LibStdcpp);
145349cc55cSDimitry Andric   return nullptr;
146349cc55cSDimitry Andric }
147349cc55cSDimitry Andric 
148349cc55cSDimitry Andric SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
149349cc55cSDimitry Andric     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
150349cc55cSDimitry Andric   if (valobj_sp)
151349cc55cSDimitry Andric     return new GenericBitsetFrontEnd(*valobj_sp,
152349cc55cSDimitry Andric                                      GenericBitsetFrontEnd::StdLib::LibCxx);
153349cc55cSDimitry Andric   return nullptr;
154349cc55cSDimitry Andric }
155