1 //===-- LibCxxVector.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 #include "lldb/DataFormatters/FormattersHelpers.h"
12 #include "lldb/Utility/ConstString.h"
13 #include "lldb/ValueObject/ValueObject.h"
14 #include "lldb/lldb-enumerations.h"
15 #include "lldb/lldb-forward.h"
19 using namespace lldb_private
;
20 using namespace lldb_private::formatters
;
22 namespace lldb_private
{
23 namespace formatters
{
24 class LibcxxStdVectorSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
26 LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
);
28 ~LibcxxStdVectorSyntheticFrontEnd() override
;
30 llvm::Expected
<uint32_t> CalculateNumChildren() override
;
32 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
;
34 lldb::ChildCacheState
Update() override
;
36 bool MightHaveChildren() override
;
38 size_t GetIndexOfChildWithName(ConstString name
) override
;
41 ValueObject
*m_start
= nullptr;
42 ValueObject
*m_finish
= nullptr;
43 CompilerType m_element_type
;
44 uint32_t m_element_size
= 0;
47 class LibcxxVectorBoolSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
49 LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
);
51 llvm::Expected
<uint32_t> CalculateNumChildren() override
;
53 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
;
55 lldb::ChildCacheState
Update() override
;
57 bool MightHaveChildren() override
{ return true; }
59 size_t GetIndexOfChildWithName(ConstString name
) override
;
62 CompilerType m_bool_type
;
63 ExecutionContextRef m_exe_ctx_ref
;
65 lldb::addr_t m_base_data_address
= 0;
66 std::map
<size_t, lldb::ValueObjectSP
> m_children
;
69 } // namespace formatters
70 } // namespace lldb_private
72 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
73 LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
)
74 : SyntheticChildrenFrontEnd(*valobj_sp
), m_element_type() {
79 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
80 ~LibcxxStdVectorSyntheticFrontEnd() {
81 // these need to stay around because they are child objects who will follow
82 // their parent's life cycle
87 llvm::Expected
<uint32_t> lldb_private::formatters::
88 LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() {
89 if (!m_start
|| !m_finish
)
91 uint64_t start_val
= m_start
->GetValueAsUnsigned(0);
92 uint64_t finish_val
= m_finish
->GetValueAsUnsigned(0);
94 if (start_val
== 0 || finish_val
== 0)
97 if (start_val
>= finish_val
)
100 size_t num_children
= (finish_val
- start_val
);
101 if (num_children
% m_element_size
)
103 return num_children
/ m_element_size
;
107 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
109 if (!m_start
|| !m_finish
)
110 return lldb::ValueObjectSP();
112 uint64_t offset
= idx
* m_element_size
;
113 offset
= offset
+ m_start
->GetValueAsUnsigned(0);
115 name
.Printf("[%" PRIu64
"]", (uint64_t)idx
);
116 return CreateValueObjectFromAddress(name
.GetString(), offset
,
117 m_backend
.GetExecutionContextRef(),
121 static ValueObjectSP
GetDataPointer(ValueObject
&root
) {
122 if (auto cap_sp
= root
.GetChildMemberWithName("__cap_"))
125 ValueObjectSP cap_sp
= root
.GetChildMemberWithName("__end_cap_");
129 if (!isOldCompressedPairLayout(*cap_sp
))
132 return GetFirstValueOfLibCXXCompressedPair(*cap_sp
);
135 lldb::ChildCacheState
136 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
137 m_start
= m_finish
= nullptr;
138 ValueObjectSP
data_sp(GetDataPointer(m_backend
));
141 return lldb::ChildCacheState::eRefetch
;
143 m_element_type
= data_sp
->GetCompilerType().GetPointeeType();
144 if (std::optional
<uint64_t> size
= m_element_type
.GetByteSize(nullptr)) {
145 m_element_size
= *size
;
147 if (m_element_size
> 0) {
148 // store raw pointers or end up with a circular dependency
149 m_start
= m_backend
.GetChildMemberWithName("__begin_").get();
150 m_finish
= m_backend
.GetChildMemberWithName("__end_").get();
153 return lldb::ChildCacheState::eRefetch
;
156 bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
157 MightHaveChildren() {
161 size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
162 GetIndexOfChildWithName(ConstString name
) {
163 if (!m_start
|| !m_finish
)
165 return ExtractIndexFromString(name
.GetCString());
168 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
169 LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
)
170 : SyntheticChildrenFrontEnd(*valobj_sp
), m_bool_type(), m_exe_ctx_ref(),
175 valobj_sp
->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool
);
179 llvm::Expected
<uint32_t> lldb_private::formatters::
180 LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren() {
185 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
187 auto iter
= m_children
.find(idx
), end
= m_children
.end();
192 if (m_base_data_address
== 0 || m_count
== 0)
196 size_t byte_idx
= (idx
>> 3); // divide by 8 to get byte index
197 size_t bit_index
= (idx
& 7); // efficient idx % 8 for bit index
198 lldb::addr_t byte_location
= m_base_data_address
+ byte_idx
;
199 ProcessSP
process_sp(m_exe_ctx_ref
.GetProcessSP());
205 size_t bytes_read
= process_sp
->ReadMemory(byte_location
, &byte
, 1, err
);
206 if (err
.Fail() || bytes_read
== 0)
208 mask
= 1 << bit_index
;
209 bool bit_set
= ((byte
& mask
) != 0);
210 std::optional
<uint64_t> size
= m_bool_type
.GetByteSize(nullptr);
213 WritableDataBufferSP
buffer_sp(new DataBufferHeap(*size
, 0));
214 if (bit_set
&& buffer_sp
&& buffer_sp
->GetBytes()) {
215 // regardless of endianness, anything non-zero is true
216 *(buffer_sp
->GetBytes()) = 1;
219 name
.Printf("[%" PRIu64
"]", (uint64_t)idx
);
220 ValueObjectSP
retval_sp(CreateValueObjectFromData(
222 DataExtractor(buffer_sp
, process_sp
->GetByteOrder(),
223 process_sp
->GetAddressByteSize()),
224 m_exe_ctx_ref
, m_bool_type
));
226 m_children
[idx
] = retval_sp
;
230 lldb::ChildCacheState
231 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
233 ValueObjectSP valobj_sp
= m_backend
.GetSP();
235 return lldb::ChildCacheState::eRefetch
;
236 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
237 ValueObjectSP
size_sp(valobj_sp
->GetChildMemberWithName("__size_"));
239 return lldb::ChildCacheState::eRefetch
;
240 m_count
= size_sp
->GetValueAsUnsigned(0);
242 return lldb::ChildCacheState::eReuse
;
243 ValueObjectSP
begin_sp(valobj_sp
->GetChildMemberWithName("__begin_"));
246 return lldb::ChildCacheState::eRefetch
;
248 m_base_data_address
= begin_sp
->GetValueAsUnsigned(0);
249 if (!m_base_data_address
) {
251 return lldb::ChildCacheState::eRefetch
;
253 return lldb::ChildCacheState::eRefetch
;
256 size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
257 GetIndexOfChildWithName(ConstString name
) {
258 if (!m_count
|| !m_base_data_address
)
260 const char *item_name
= name
.GetCString();
261 uint32_t idx
= ExtractIndexFromString(item_name
);
262 if (idx
< UINT32_MAX
&& idx
>= CalculateNumChildrenIgnoringErrors())
267 lldb_private::SyntheticChildrenFrontEnd
*
268 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator(
269 CXXSyntheticChildren
*, lldb::ValueObjectSP valobj_sp
) {
272 CompilerType type
= valobj_sp
->GetCompilerType();
273 if (!type
.IsValid() || type
.GetNumTemplateArguments() == 0)
275 CompilerType arg_type
= type
.GetTypeTemplateArgument(0);
276 if (arg_type
.GetTypeName() == "bool")
277 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp
);
278 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp
);