xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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