[Go to site: main page, start]

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 assert(false && "invalid vector layout");
142 return llvm::createStringError("invalid vector layout");
143}
144
147 uint32_t idx) {
148 if (!m_start || !m_finish)
149 return lldb::ValueObjectSP();
150
151 uint64_t offset = idx * m_element_size;
152 offset = offset + m_start->GetValueAsUnsigned(0);
153 StreamString name;
154 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
155 return CreateChildValueObjectFromAddress(name.GetString(), offset,
156 m_backend.GetExecutionContextRef(),
158}
159
162 m_start = m_finish = nullptr;
163
164 // Determine if this version of libc++'s `std::vector` uses `__vector_layout`.
165 ValueObjectSP layout_sp = m_backend.GetChildMemberWithName("__layout_");
166 ValueObject *target = layout_sp ? layout_sp.get() : &m_backend;
167
168 ValueObjectSP begin_sp = target->GetChildMemberWithName("__begin_");
169 if (!begin_sp)
171
172 m_element_type = begin_sp->GetCompilerType().GetPointeeType();
173 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
174 if (!size_or_err) {
175 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
176 "{0}");
178 }
179
180 m_element_size = *size_or_err;
181 if (m_element_size == 0) {
183 }
184
185 // store raw pointers or end up with a circular dependency
186 m_start = begin_sp.get();
187
188 if (ValueObjectSP end_sp = target->GetChildMemberWithName("__end_")) {
189 m_finish = end_sp.get();
192 }
193
194 ValueObjectSP size_sp = target->GetChildMemberWithName("__size_");
195 if (!size_sp)
197
198 m_finish = size_sp.get();
201}
202
203llvm::Expected<size_t>
206 if (!m_start || !m_finish)
207 return llvm::createStringErrorV("type has no child named '{0}'", name);
208 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
209 if (!optional_idx) {
210 return llvm::createStringErrorV("type has no child named '{0}'", name);
211 }
212 return *optional_idx;
213}
214
218 m_children() {
219 if (valobj_sp) {
220 Update();
222 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
223 }
224}
225
230
233 uint32_t idx) {
234 auto iter = m_children.find(idx), end = m_children.end();
235 if (iter != end)
236 return iter->second;
237 if (idx >= m_count)
238 return {};
239 if (m_base_data_address == 0 || m_count == 0)
240 return {};
241 if (!m_bool_type)
242 return {};
243 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
244 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
245 lldb::addr_t byte_location = m_base_data_address + byte_idx;
246 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
247 if (!process_sp)
248 return {};
249 uint8_t byte = 0;
250 uint8_t mask = 0;
251 Status err;
252 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
253 if (err.Fail() || bytes_read == 0)
254 return {};
255 mask = 1 << bit_index;
256 bool bit_set = ((byte & mask) != 0);
257 std::optional<uint64_t> size =
258 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));
259 if (!size)
260 return {};
261 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
262 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
263 // regardless of endianness, anything non-zero is true
264 *(buffer_sp->GetBytes()) = 1;
265 }
266 StreamString name;
267 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
269 name.GetString(),
270 DataExtractor(buffer_sp, process_sp->GetByteOrder(),
271 process_sp->GetAddressByteSize()),
273 if (retval_sp)
274 m_children[idx] = retval_sp;
275 return retval_sp;
276}
277
280 m_children.clear();
281 ValueObjectSP valobj_sp = m_backend.GetSP();
282 if (!valobj_sp)
284 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
285 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
286 if (!size_sp)
288 m_count = size_sp->GetValueAsUnsigned(0);
289 if (!m_count)
291 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
292 if (!begin_sp) {
293 m_count = 0;
295 }
296 m_base_data_address = begin_sp->GetValueAsUnsigned(0);
297 if (!m_base_data_address) {
298 m_count = 0;
300 }
302}
303
304llvm::Expected<size_t>
308 return llvm::createStringErrorV("type has no child named '{0}'", name);
309 auto optional_idx = ExtractIndexFromString(name.AsCString(nullptr));
310 if (!optional_idx) {
311 return llvm::createStringErrorV("type has no child named '{0}'", name);
312 }
313 uint32_t idx = *optional_idx;
315 return llvm::createStringErrorV("type has no child named '{0}'", name);
316 return idx;
317}
318
322 if (!valobj_sp)
323 return nullptr;
324 CompilerType type = valobj_sp->GetCompilerType();
325 if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
326 return nullptr;
327 CompilerType arg_type = type.GetTypeTemplateArgument(0);
328 if (arg_type.GetTypeName() == "bool")
329 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
330 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
331}
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 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: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