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