1dda28197Spatrick //===-- LibCxxVector.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "LibCxx.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/ValueObject.h"
12061da546Spatrick #include "lldb/DataFormatters/FormattersHelpers.h"
13061da546Spatrick #include "lldb/Utility/ConstString.h"
14*f6aab3d8Srobert #include <optional>
15061da546Spatrick
16061da546Spatrick using namespace lldb;
17061da546Spatrick using namespace lldb_private;
18061da546Spatrick using namespace lldb_private::formatters;
19061da546Spatrick
20061da546Spatrick namespace lldb_private {
21061da546Spatrick namespace formatters {
22061da546Spatrick class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
23061da546Spatrick public:
24061da546Spatrick LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
25061da546Spatrick
26061da546Spatrick ~LibcxxStdVectorSyntheticFrontEnd() override;
27061da546Spatrick
28061da546Spatrick size_t CalculateNumChildren() override;
29061da546Spatrick
30061da546Spatrick lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
31061da546Spatrick
32061da546Spatrick bool Update() override;
33061da546Spatrick
34061da546Spatrick bool MightHaveChildren() override;
35061da546Spatrick
36061da546Spatrick size_t GetIndexOfChildWithName(ConstString name) override;
37061da546Spatrick
38061da546Spatrick private:
39*f6aab3d8Srobert ValueObject *m_start = nullptr;
40*f6aab3d8Srobert ValueObject *m_finish = nullptr;
41061da546Spatrick CompilerType m_element_type;
42*f6aab3d8Srobert uint32_t m_element_size = 0;
43061da546Spatrick };
44061da546Spatrick
45061da546Spatrick class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
46061da546Spatrick public:
47061da546Spatrick LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
48061da546Spatrick
49061da546Spatrick size_t CalculateNumChildren() override;
50061da546Spatrick
51061da546Spatrick lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
52061da546Spatrick
53061da546Spatrick bool Update() override;
54061da546Spatrick
MightHaveChildren()55061da546Spatrick bool MightHaveChildren() override { return true; }
56061da546Spatrick
57061da546Spatrick size_t GetIndexOfChildWithName(ConstString name) override;
58061da546Spatrick
59061da546Spatrick private:
60061da546Spatrick CompilerType m_bool_type;
61061da546Spatrick ExecutionContextRef m_exe_ctx_ref;
62*f6aab3d8Srobert uint64_t m_count = 0;
63*f6aab3d8Srobert lldb::addr_t m_base_data_address = 0;
64061da546Spatrick std::map<size_t, lldb::ValueObjectSP> m_children;
65061da546Spatrick };
66061da546Spatrick
67061da546Spatrick } // namespace formatters
68061da546Spatrick } // namespace lldb_private
69061da546Spatrick
70061da546Spatrick lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)71061da546Spatrick LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
72*f6aab3d8Srobert : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {
73061da546Spatrick if (valobj_sp)
74061da546Spatrick Update();
75061da546Spatrick }
76061da546Spatrick
77061da546Spatrick lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
~LibcxxStdVectorSyntheticFrontEnd()78061da546Spatrick ~LibcxxStdVectorSyntheticFrontEnd() {
79061da546Spatrick // these need to stay around because they are child objects who will follow
80061da546Spatrick // their parent's life cycle
81061da546Spatrick // delete m_start;
82061da546Spatrick // delete m_finish;
83061da546Spatrick }
84061da546Spatrick
85061da546Spatrick size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
CalculateNumChildren()86061da546Spatrick CalculateNumChildren() {
87061da546Spatrick if (!m_start || !m_finish)
88061da546Spatrick return 0;
89061da546Spatrick uint64_t start_val = m_start->GetValueAsUnsigned(0);
90061da546Spatrick uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
91061da546Spatrick
92061da546Spatrick if (start_val == 0 || finish_val == 0)
93061da546Spatrick return 0;
94061da546Spatrick
95061da546Spatrick if (start_val >= finish_val)
96061da546Spatrick return 0;
97061da546Spatrick
98061da546Spatrick size_t num_children = (finish_val - start_val);
99061da546Spatrick if (num_children % m_element_size)
100061da546Spatrick return 0;
101061da546Spatrick return num_children / m_element_size;
102061da546Spatrick }
103061da546Spatrick
104061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)105061da546Spatrick lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex(
106061da546Spatrick size_t idx) {
107061da546Spatrick if (!m_start || !m_finish)
108061da546Spatrick return lldb::ValueObjectSP();
109061da546Spatrick
110061da546Spatrick uint64_t offset = idx * m_element_size;
111061da546Spatrick offset = offset + m_start->GetValueAsUnsigned(0);
112061da546Spatrick StreamString name;
113061da546Spatrick name.Printf("[%" PRIu64 "]", (uint64_t)idx);
114061da546Spatrick return CreateValueObjectFromAddress(name.GetString(), offset,
115061da546Spatrick m_backend.GetExecutionContextRef(),
116061da546Spatrick m_element_type);
117061da546Spatrick }
118061da546Spatrick
Update()119061da546Spatrick bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() {
120061da546Spatrick m_start = m_finish = nullptr;
121061da546Spatrick ValueObjectSP data_type_finder_sp(
122061da546Spatrick m_backend.GetChildMemberWithName(ConstString("__end_cap_"), true));
123061da546Spatrick if (!data_type_finder_sp)
124061da546Spatrick return false;
125061da546Spatrick
126061da546Spatrick switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) {
127061da546Spatrick case 1:
128061da546Spatrick // Assume a pre llvm r300140 __compressed_pair implementation:
129061da546Spatrick data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(
130061da546Spatrick ConstString("__first_"), true);
131061da546Spatrick break;
132061da546Spatrick case 2: {
133061da546Spatrick // Assume a post llvm r300140 __compressed_pair implementation:
134061da546Spatrick ValueObjectSP first_elem_parent_sp =
135061da546Spatrick data_type_finder_sp->GetChildAtIndex(0, true);
136061da546Spatrick data_type_finder_sp = first_elem_parent_sp->GetChildMemberWithName(
137061da546Spatrick ConstString("__value_"), true);
138061da546Spatrick break;
139061da546Spatrick }
140061da546Spatrick default:
141061da546Spatrick return false;
142061da546Spatrick }
143061da546Spatrick
144061da546Spatrick if (!data_type_finder_sp)
145061da546Spatrick return false;
146061da546Spatrick m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
147*f6aab3d8Srobert if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) {
148061da546Spatrick m_element_size = *size;
149061da546Spatrick
150061da546Spatrick if (m_element_size > 0) {
151061da546Spatrick // store raw pointers or end up with a circular dependency
152061da546Spatrick m_start =
153061da546Spatrick m_backend.GetChildMemberWithName(ConstString("__begin_"), true).get();
154061da546Spatrick m_finish =
155061da546Spatrick m_backend.GetChildMemberWithName(ConstString("__end_"), true).get();
156061da546Spatrick }
157061da546Spatrick }
158061da546Spatrick return false;
159061da546Spatrick }
160061da546Spatrick
161061da546Spatrick bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
MightHaveChildren()162061da546Spatrick MightHaveChildren() {
163061da546Spatrick return true;
164061da546Spatrick }
165061da546Spatrick
166061da546Spatrick size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)167061da546Spatrick GetIndexOfChildWithName(ConstString name) {
168061da546Spatrick if (!m_start || !m_finish)
169061da546Spatrick return UINT32_MAX;
170061da546Spatrick return ExtractIndexFromString(name.GetCString());
171061da546Spatrick }
172061da546Spatrick
173061da546Spatrick lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)174061da546Spatrick LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
175061da546Spatrick : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(),
176*f6aab3d8Srobert m_children() {
177061da546Spatrick if (valobj_sp) {
178061da546Spatrick Update();
179061da546Spatrick m_bool_type =
180061da546Spatrick valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
181061da546Spatrick }
182061da546Spatrick }
183061da546Spatrick
184061da546Spatrick size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
CalculateNumChildren()185061da546Spatrick CalculateNumChildren() {
186061da546Spatrick return m_count;
187061da546Spatrick }
188061da546Spatrick
189061da546Spatrick lldb::ValueObjectSP
GetChildAtIndex(size_t idx)190061da546Spatrick lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex(
191061da546Spatrick size_t idx) {
192061da546Spatrick auto iter = m_children.find(idx), end = m_children.end();
193061da546Spatrick if (iter != end)
194061da546Spatrick return iter->second;
195061da546Spatrick if (idx >= m_count)
196061da546Spatrick return {};
197061da546Spatrick if (m_base_data_address == 0 || m_count == 0)
198061da546Spatrick return {};
199061da546Spatrick if (!m_bool_type)
200061da546Spatrick return {};
201061da546Spatrick size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
202061da546Spatrick size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
203061da546Spatrick lldb::addr_t byte_location = m_base_data_address + byte_idx;
204061da546Spatrick ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
205061da546Spatrick if (!process_sp)
206061da546Spatrick return {};
207061da546Spatrick uint8_t byte = 0;
208061da546Spatrick uint8_t mask = 0;
209061da546Spatrick Status err;
210061da546Spatrick size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
211061da546Spatrick if (err.Fail() || bytes_read == 0)
212061da546Spatrick return {};
213061da546Spatrick mask = 1 << bit_index;
214061da546Spatrick bool bit_set = ((byte & mask) != 0);
215*f6aab3d8Srobert std::optional<uint64_t> size = m_bool_type.GetByteSize(nullptr);
216061da546Spatrick if (!size)
217061da546Spatrick return {};
218*f6aab3d8Srobert WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
219061da546Spatrick if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
220061da546Spatrick // regardless of endianness, anything non-zero is true
221061da546Spatrick *(buffer_sp->GetBytes()) = 1;
222061da546Spatrick }
223061da546Spatrick StreamString name;
224061da546Spatrick name.Printf("[%" PRIu64 "]", (uint64_t)idx);
225061da546Spatrick ValueObjectSP retval_sp(CreateValueObjectFromData(
226061da546Spatrick name.GetString(),
227061da546Spatrick DataExtractor(buffer_sp, process_sp->GetByteOrder(),
228061da546Spatrick process_sp->GetAddressByteSize()),
229061da546Spatrick m_exe_ctx_ref, m_bool_type));
230061da546Spatrick if (retval_sp)
231061da546Spatrick m_children[idx] = retval_sp;
232061da546Spatrick return retval_sp;
233061da546Spatrick }
234061da546Spatrick
235061da546Spatrick /*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
236061da546Spatrick __begin_ = 0x00000001001000e0
237061da546Spatrick __size_ = 56
238061da546Spatrick __cap_alloc_ = {
239061da546Spatrick std::__1::__libcpp_compressed_pair_imp<unsigned long,
240061da546Spatrick std::__1::allocator<unsigned long> > = {
241061da546Spatrick __first_ = 1
242061da546Spatrick }
243061da546Spatrick }
244061da546Spatrick }*/
245061da546Spatrick
Update()246061da546Spatrick bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() {
247061da546Spatrick m_children.clear();
248061da546Spatrick ValueObjectSP valobj_sp = m_backend.GetSP();
249061da546Spatrick if (!valobj_sp)
250061da546Spatrick return false;
251061da546Spatrick m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
252061da546Spatrick ValueObjectSP size_sp(
253061da546Spatrick valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
254061da546Spatrick if (!size_sp)
255061da546Spatrick return false;
256061da546Spatrick m_count = size_sp->GetValueAsUnsigned(0);
257061da546Spatrick if (!m_count)
258061da546Spatrick return true;
259061da546Spatrick ValueObjectSP begin_sp(
260061da546Spatrick valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
261061da546Spatrick if (!begin_sp) {
262061da546Spatrick m_count = 0;
263061da546Spatrick return false;
264061da546Spatrick }
265061da546Spatrick m_base_data_address = begin_sp->GetValueAsUnsigned(0);
266061da546Spatrick if (!m_base_data_address) {
267061da546Spatrick m_count = 0;
268061da546Spatrick return false;
269061da546Spatrick }
270061da546Spatrick return false;
271061da546Spatrick }
272061da546Spatrick
273061da546Spatrick size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)274061da546Spatrick GetIndexOfChildWithName(ConstString name) {
275061da546Spatrick if (!m_count || !m_base_data_address)
276061da546Spatrick return UINT32_MAX;
277061da546Spatrick const char *item_name = name.GetCString();
278061da546Spatrick uint32_t idx = ExtractIndexFromString(item_name);
279061da546Spatrick if (idx < UINT32_MAX && idx >= CalculateNumChildren())
280061da546Spatrick return UINT32_MAX;
281061da546Spatrick return idx;
282061da546Spatrick }
283061da546Spatrick
284061da546Spatrick lldb_private::SyntheticChildrenFrontEnd *
LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)285061da546Spatrick lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator(
286061da546Spatrick CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
287061da546Spatrick if (!valobj_sp)
288061da546Spatrick return nullptr;
289061da546Spatrick CompilerType type = valobj_sp->GetCompilerType();
290061da546Spatrick if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
291061da546Spatrick return nullptr;
292061da546Spatrick CompilerType arg_type = type.GetTypeTemplateArgument(0);
293061da546Spatrick if (arg_type.GetTypeName() == "bool")
294061da546Spatrick return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
295061da546Spatrick return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
296061da546Spatrick }
297