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
15#include "lldb/lldb-forward.h"
16#include "llvm/Support/Error.h"
17#include "llvm/Support/ErrorExtras.h"
18#include <optional>
19
20using namespace lldb;
21using namespace lldb_private;
22using namespace lldb_private::formatters;
23
24namespace lldb_private {
25namespace formatters {
27public:
29
31
32 llvm::Expected<uint32_t> CalculateNumChildren() override;
33
34 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
35
37
38 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
39
40private:
42
43 ValueObject *m_start = nullptr;
44
45 // m_finish may point to a pointer (`__end_`) or an integer (`__size_`)
46 // depending on how libc++'s vector is implemented. Interpreting what is
47 // pointed to is done using `m_layout`.
49 enum class VectorLayout : bool { Pointer, Size };
52 uint32_t m_element_size = 0;
53};
54
56public:
58
59 llvm::Expected<uint32_t> CalculateNumChildren() override;
60
61 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
62
64
65 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
66
67private:
70 uint64_t m_count = 0;
72 std::map<size_t, lldb::ValueObjectSP> m_children;
73};
74
75} // namespace formatters
76} // namespace lldb_private
77
84
87 // these need to stay around because they are child objects who will follow
88 // their parent's life cycle
89 // delete m_start;
90 // delete m_finish;
91}
92
93static llvm::Expected<uint32_t>
95 uint64_t value_type_size) {
96 uint64_t start_val = begin->GetValueAsUnsigned(0);
97 uint64_t finish_val = end->GetValueAsUnsigned(0);
98
99 // A default-initialized empty vector.
100 if (start_val == 0 && finish_val == 0)
101 return 0;
102
103 if (start_val == 0)
104 return llvm::createStringError("invalid value for start of vector");
105
106 if (finish_val == 0)
107 return llvm::createStringError("invalid value for end of vector");
108
109 if (start_val > finish_val)
110 return llvm::createStringError(
111 "start of vector data begins after end pointer");
112
113 size_t num_children = (finish_val - start_val);
114 if (num_children % value_type_size)
115 return llvm::createStringError("size not multiple of element size");
116
117 return num_children / value_type_size;
118}
119
120static llvm::Expected<uint32_t> GetNumChildren(ValueObject *size) {
121 if (!size->GetCompilerType().IsInteger())
122 return llvm::createStringError(
123 "size data member must be a built-in integer type");
124 return size->GetValueAsUnsigned(0);
125}
126
127llvm::Expected<uint32_t> lldb_private::formatters::
129 if (!m_start || !m_finish)
130 return llvm::createStringError(
131 "failed to determine start/end of vector data");
132
133 switch (m_layout) {
138 return GetNumChildren(m_finish);
139 }
140}
141
144 uint32_t idx) {
145 if (!m_start || !m_finish)
146 return lldb::ValueObjectSP();
147
148 uint64_t offset = idx * m_element_size;
149 offset = offset + m_start->GetValueAsUnsigned(0);
150 StreamString name;
151 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
152 return CreateChildValueObjectFromAddress(name.GetString(), offset,
153 m_backend.GetExecutionContextRef(),
155}
156
159 m_start = m_finish = nullptr;
160
161 // Determine if this version of libc++'s `std::vector` uses `__vector_layout`.
162 ValueObjectSP layout_sp = m_backend.GetChildMemberWithName("__layout_");
163 ValueObject *target = layout_sp ? layout_sp.get() : &m_backend;
164
165 ValueObjectSP begin_sp = target->GetChildMemberWithName("__begin_");
166 if (!begin_sp)
168
169 m_element_type = begin_sp->GetCompilerType().GetPointeeType();
170 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
171 if (!size_or_err) {
172 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
173 "{0}");
175 }
176
177 m_element_size = *size_or_err;
178 if (m_element_size == 0) {
180 }
181
182 // store raw pointers or end up with a circular dependency
183 m_start = begin_sp.get();
184
185 if (ValueObjectSP end_sp = target->GetChildMemberWithName("__end_")) {
186 m_finish = end_sp.get();
189 }
190
191 ValueObjectSP size_sp = target->GetChildMemberWithName("__size_");
192 if (!size_sp)
194
195 m_finish = size_sp.get();
198}
199
200llvm::Expected<size_t>
203 if (!m_start || !m_finish)
204 return llvm::createStringErrorV("type has no child named '{0}'", name);
205 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
206 if (!optional_idx) {
207 return llvm::createStringErrorV("type has no child named '{0}'", name);
208 }
209 return *optional_idx;
210}
211
215 m_children() {
216 if (valobj_sp) {
217 Update();
219 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
220 }
221}
222
227
230 uint32_t idx) {
231 auto iter = m_children.find(idx), end = m_children.end();
232 if (iter != end)
233 return iter->second;
234 if (idx >= m_count)
235 return {};
236 if (m_base_data_address == 0 || m_count == 0)
237 return {};
238 if (!m_bool_type)
239 return {};
240 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
241 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
242 lldb::addr_t byte_location = m_base_data_address + byte_idx;
243 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
244 if (!process_sp)
245 return {};
246 uint8_t byte = 0;
247 uint8_t mask = 0;
248 Status err;
249 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
250 if (err.Fail() || bytes_read == 0)
251 return {};
252 mask = 1 << bit_index;
253 bool bit_set = ((byte & mask) != 0);
254 std::optional<uint64_t> size =
255 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));
256 if (!size)
257 return {};
258 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
259 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
260 // regardless of endianness, anything non-zero is true
261 *(buffer_sp->GetBytes()) = 1;
262 }
263 StreamString name;
264 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
266 name.GetString(),
267 DataExtractor(buffer_sp, process_sp->GetByteOrder(),
268 process_sp->GetAddressByteSize()),
270 if (retval_sp)
271 m_children[idx] = retval_sp;
272 return retval_sp;
273}
274
277 m_children.clear();
278 ValueObjectSP valobj_sp = m_backend.GetSP();
279 if (!valobj_sp)
281 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
282 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
283 if (!size_sp)
285 m_count = size_sp->GetValueAsUnsigned(0);
286 if (!m_count)
288 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
289 if (!begin_sp) {
290 m_count = 0;
292 }
293 m_base_data_address = begin_sp->GetValueAsUnsigned(0);
294 if (!m_base_data_address) {
295 m_count = 0;
297 }
299}
300
301llvm::Expected<size_t>
305 return llvm::createStringErrorV("type has no child named '{0}'", name);
306 auto optional_idx = ExtractIndexFromString(name.AsCString(nullptr));
307 if (!optional_idx) {
308 return llvm::createStringErrorV("type has no child named '{0}'", name);
309 }
310 uint32_t idx = *optional_idx;
312 return llvm::createStringErrorV("type has no child named '{0}'", name);
313 return idx;
314}
315
319 if (!valobj_sp)
320 return nullptr;
321 CompilerType type = valobj_sp->GetCompilerType();
322 if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
323 return nullptr;
324 CompilerType arg_type = type.GetTypeTemplateArgument(0);
325 if (arg_type.GetTypeName() == "bool")
326 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
327 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
328}
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:410
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 uniqued constant string class.
Definition ConstString.h:40
const char * GetCString() const
Get the string value as a C string.
const char * AsCString(const char *value_if_empty) const
Get the string value as a C string.
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< size_t > GetIndexOfChildWithName(ConstString name) override
Determine the index of a named child.
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...
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(ConstString name) override
Determine the index of a named child.
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
std::optional< size_t > ExtractIndexFromString(const char *item_name)
SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
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:327
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