LLDB mainline
LibCxxVector.cpp
Go to the documentation of this file.
1//===-- LibCxxVector.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
14#include "lldb/lldb-forward.h"
15#include "llvm/Support/Error.h"
16#include "llvm/Support/ErrorExtras.h"
17#include <optional>
18
19using namespace lldb;
20using namespace lldb_private;
21using namespace lldb_private::formatters;
22
23namespace lldb_private {
24namespace formatters {
26public:
28
30
31 llvm::Expected<uint32_t> CalculateNumChildren() override;
32
33 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
34
36
37 llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name) override;
38
39private:
41
42 ValueObject *m_start = nullptr;
43
44 // m_finish may point to a pointer (`__end_`) or an integer (`__size_`)
45 // depending on how libc++'s vector is implemented. Interpreting what is
46 // pointed to is done using `m_layout`.
48 enum class VectorLayout : bool { Pointer, Size };
51 uint32_t m_element_size = 0;
52};
53
55public:
57
58 llvm::Expected<uint32_t> CalculateNumChildren() override;
59
60 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
61
63
64 llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name) override;
65
66private:
69 uint64_t m_count = 0;
71 std::map<size_t, lldb::ValueObjectSP> m_children;
72};
73
74} // namespace formatters
75} // namespace lldb_private
76
83
86 // these need to stay around because they are child objects who will follow
87 // their parent's life cycle
88 // delete m_start;
89 // delete m_finish;
90}
91
92static llvm::Expected<uint32_t>
94 uint64_t value_type_size) {
95 uint64_t start_val = begin->GetValueAsUnsigned(0);
96 uint64_t finish_val = end->GetValueAsUnsigned(0);
97
98 // A default-initialized empty vector.
99 if (start_val == 0 && finish_val == 0)
100 return 0;
101
102 if (start_val == 0)
103 return llvm::createStringError("invalid value for start of vector");
104
105 if (finish_val == 0)
106 return llvm::createStringError("invalid value for end of vector");
107
108 if (start_val > finish_val)
109 return llvm::createStringError(
110 "start of vector data begins after end pointer");
111
112 size_t num_children = (finish_val - start_val);
113 if (num_children % value_type_size)
114 return llvm::createStringError("size not multiple of element size");
115
116 return num_children / value_type_size;
117}
118
119static llvm::Expected<uint32_t> GetNumChildren(ValueObject *size) {
120 if (!size->GetCompilerType().IsInteger())
121 return llvm::createStringError(
122 "size data member must be a built-in integer type");
123 return size->GetValueAsUnsigned(0);
124}
125
126llvm::Expected<uint32_t> lldb_private::formatters::
128 if (!m_start || !m_finish)
129 return llvm::createStringError(
130 "failed to determine start/end of vector data");
131
132 switch (m_layout) {
137 return GetNumChildren(m_finish);
138 }
139
140 assert(false && "invalid vector layout");
141 return llvm::createStringError("invalid vector layout");
142}
143
146 uint32_t idx) {
147 if (!m_start || !m_finish)
148 return lldb::ValueObjectSP();
149
150 uint64_t offset = idx * m_element_size;
151 offset = offset + m_start->GetValueAsUnsigned(0);
152 StreamString name;
153 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
154 return CreateChildValueObjectFromAddress(name.GetString(), offset,
155 m_backend.GetExecutionContextRef(),
157}
158
161 m_start = m_finish = nullptr;
162
163 // Determine if this version of libc++'s `std::vector` uses `__vector_layout`.
164 ValueObjectSP layout_sp = m_backend.GetChildMemberWithName("__layout_");
165 ValueObject *target = layout_sp ? layout_sp.get() : &m_backend;
166
167 ValueObjectSP begin_sp = target->GetChildMemberWithName("__begin_");
168 if (!begin_sp)
170
171 m_element_type = begin_sp->GetCompilerType().GetPointeeType();
172 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
173 if (!size_or_err) {
174 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
175 "{0}");
177 }
178
179 m_element_size = *size_or_err;
180 if (m_element_size == 0) {
182 }
183
184 // store raw pointers or end up with a circular dependency
185 m_start = begin_sp.get();
186
187 if (ValueObjectSP end_sp = target->GetChildMemberWithName("__end_")) {
188 m_finish = end_sp.get();
191 }
192
193 ValueObjectSP size_sp = target->GetChildMemberWithName("__size_");
194 if (!size_sp)
196
197 m_finish = size_sp.get();
200}
201
202llvm::Expected<size_t>
204 GetIndexOfChildWithName(llvm::StringRef name) {
205 if (!m_start || !m_finish)
206 return llvm::createStringErrorV("type has no child named '{0}'", name);
207 auto optional_idx = formatters::ExtractIndexFromString(name);
208 if (!optional_idx) {
209 return llvm::createStringErrorV("type has no child named '{0}'", name);
210 }
211 return *optional_idx;
212}
213
217 m_children() {
218 if (valobj_sp) {
219 Update();
221 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
222 }
223}
224
229
232 uint32_t idx) {
233 auto iter = m_children.find(idx), end = m_children.end();
234 if (iter != end)
235 return iter->second;
236 if (idx >= m_count)
237 return {};
238 if (m_base_data_address == 0 || m_count == 0)
239 return {};
240 if (!m_bool_type)
241 return {};
242 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
243 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
244 lldb::addr_t byte_location = m_base_data_address + byte_idx;
245 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
246 if (!process_sp)
247 return {};
248 uint8_t byte = 0;
249 uint8_t mask = 0;
250 Status err;
251 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
252 if (err.Fail() || bytes_read == 0)
253 return {};
254 mask = 1 << bit_index;
255 bool bit_set = ((byte & mask) != 0);
256 std::optional<uint64_t> size =
257 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));
258 if (!size)
259 return {};
260 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
261 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
262 // regardless of endianness, anything non-zero is true
263 *(buffer_sp->GetBytes()) = 1;
264 }
265 StreamString name;
266 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
268 name.GetString(),
269 DataExtractor(buffer_sp, process_sp->GetByteOrder(),
270 process_sp->GetAddressByteSize()),
272 if (retval_sp)
273 m_children[idx] = retval_sp;
274 return retval_sp;
275}
276
279 m_children.clear();
280 ValueObjectSP valobj_sp = m_backend.GetSP();
281 if (!valobj_sp)
283 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
284 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
285 if (!size_sp)
287 m_count = size_sp->GetValueAsUnsigned(0);
288 if (!m_count)
290 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
291 if (!begin_sp) {
292 m_count = 0;
294 }
295 m_base_data_address = begin_sp->GetValueAsUnsigned(0);
296 if (!m_base_data_address) {
297 m_count = 0;
299 }
301}
302
303llvm::Expected<size_t>
305 GetIndexOfChildWithName(llvm::StringRef name) {
307 return llvm::createStringErrorV("type has no child named '{0}'", name);
308 auto optional_idx = ExtractIndexFromString(name);
309 if (!optional_idx) {
310 return llvm::createStringErrorV("type has no child named '{0}'", name);
311 }
312 uint32_t idx = *optional_idx;
314 return llvm::createStringErrorV("type has no child named '{0}'", name);
315 return idx;
316}
317
321 if (!valobj_sp)
322 return nullptr;
323 CompilerType type = valobj_sp->GetCompilerType();
324 if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
325 return nullptr;
326 CompilerType arg_type = type.GetTypeTemplateArgument(0);
327 if (arg_type.GetTypeName() == "bool")
328 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
329 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
330}
static llvm::Expected< uint32_t > CalculateNumChildrenUsingPointerArithmetic(ValueObject *begin, ValueObject *end, uint64_t value_type_size)
static llvm::Expected< uint32_t > GetNumChildren(ValueObject *size)
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:421
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
size_t GetNumTemplateArguments(bool expand_pack=false) const
Return the number of template arguments the type has.
ConstString GetTypeName(bool BaseOnly=false) const
bool IsInteger() const
This is used when you don't care about the signedness of the integer.
A subclass of DataBuffer that stores a data buffer on the heap.
An data extractor class.
Execution context objects refer to objects in the execution of the program that is being debugged.
An error handling class.
Definition Status.h:118
bool Fail() const
Test for error condition.
Definition Status.cpp:293
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
uint32_t CalculateNumChildrenIgnoringErrors(uint32_t max=UINT32_MAX)
lldb::ValueObjectSP CreateChildValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateChildValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
CompilerType GetCompilerType()
llvm::Expected< uint32_t > CalculateNumChildren() override
lldb::ChildCacheState UpdateVectorWithLayoutSubobject(ValueObject *layout)
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
llvm::Expected< size_t > GetIndexOfChildWithName(llvm::StringRef name) override
Determine the index of a named child.
LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
std::map< size_t, lldb::ValueObjectSP > m_children
llvm::Expected< uint32_t > CalculateNumChildren() override
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
llvm::Expected< size_t > GetIndexOfChildWithName(llvm::StringRef name) override
Determine the index of a named child.
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
std::optional< size_t > ExtractIndexFromString(llvm::StringRef item_name)
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
@ eReuse
Children did not change and don't need to be recomputed; re-use what we computed the last time we cal...
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80