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 <optional>
17
18using namespace lldb;
19using namespace lldb_private;
20using namespace lldb_private::formatters;
21
22namespace lldb_private {
23namespace formatters {
25public:
27
29
30 llvm::Expected<uint32_t> CalculateNumChildren() override;
31
32 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
33
35
36 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
37
38private:
39 ValueObject *m_start = nullptr;
42 uint32_t m_element_size = 0;
43};
44
46public:
48
49 llvm::Expected<uint32_t> CalculateNumChildren() override;
50
51 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
52
54
55 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
56
57private:
60 uint64_t m_count = 0;
62 std::map<size_t, lldb::ValueObjectSP> m_children;
63};
64
65} // namespace formatters
66} // namespace lldb_private
67
74
77 // these need to stay around because they are child objects who will follow
78 // their parent's life cycle
79 // delete m_start;
80 // delete m_finish;
81}
82
83llvm::Expected<uint32_t> lldb_private::formatters::
85 if (!m_start || !m_finish)
86 return llvm::createStringError(
87 "failed to determine start/end of vector data");
88
89 uint64_t start_val = m_start->GetValueAsUnsigned(0);
90 uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
91
92 // A default-initialized empty vector.
93 if (start_val == 0 && finish_val == 0)
94 return 0;
95
96 if (start_val == 0)
97 return llvm::createStringError("invalid value for start of vector");
98
99 if (finish_val == 0)
100 return llvm::createStringError("invalid value for end of vector");
101
102 if (start_val > finish_val)
103 return llvm::createStringError(
104 "start of vector data begins after end pointer");
105
106 size_t num_children = (finish_val - start_val);
107 if (num_children % m_element_size)
108 return llvm::createStringError("size not multiple of element size");
109
110 return num_children / m_element_size;
111}
112
115 uint32_t idx) {
116 if (!m_start || !m_finish)
117 return lldb::ValueObjectSP();
118
119 uint64_t offset = idx * m_element_size;
120 offset = offset + m_start->GetValueAsUnsigned(0);
121 StreamString name;
122 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
123 return CreateValueObjectFromAddress(name.GetString(), offset,
124 m_backend.GetExecutionContextRef(),
126}
127
129 auto [cap_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
130 root, /*anon_struct_idx=*/2, "__cap_", "__end_cap_");
131 if (!cap_sp)
132 return nullptr;
133
134 if (is_compressed_pair)
136
137 return cap_sp;
138}
139
142 m_start = m_finish = nullptr;
144
145 if (!data_sp)
147
148 m_element_type = data_sp->GetCompilerType().GetPointeeType();
149 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
150 if (!size_or_err)
151 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
152 "{0}");
153 else {
154 m_element_size = *size_or_err;
155
156 if (m_element_size > 0) {
157 // store raw pointers or end up with a circular dependency
158 m_start = m_backend.GetChildMemberWithName("__begin_").get();
159 m_finish = m_backend.GetChildMemberWithName("__end_").get();
160 }
161 }
163}
164
165llvm::Expected<size_t>
168 if (!m_start || !m_finish)
169 return llvm::createStringError("Type has no child named '%s'",
170 name.AsCString());
171 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
172 if (!optional_idx) {
173 return llvm::createStringError("Type has no child named '%s'",
174 name.AsCString());
175 }
176 return *optional_idx;
177}
178
182 m_children() {
183 if (valobj_sp) {
184 Update();
186 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
187 }
188}
189
194
197 uint32_t idx) {
198 auto iter = m_children.find(idx), end = m_children.end();
199 if (iter != end)
200 return iter->second;
201 if (idx >= m_count)
202 return {};
203 if (m_base_data_address == 0 || m_count == 0)
204 return {};
205 if (!m_bool_type)
206 return {};
207 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
208 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
209 lldb::addr_t byte_location = m_base_data_address + byte_idx;
210 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
211 if (!process_sp)
212 return {};
213 uint8_t byte = 0;
214 uint8_t mask = 0;
215 Status err;
216 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
217 if (err.Fail() || bytes_read == 0)
218 return {};
219 mask = 1 << bit_index;
220 bool bit_set = ((byte & mask) != 0);
221 std::optional<uint64_t> size =
222 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));
223 if (!size)
224 return {};
225 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
226 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
227 // regardless of endianness, anything non-zero is true
228 *(buffer_sp->GetBytes()) = 1;
229 }
230 StreamString name;
231 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
233 name.GetString(),
234 DataExtractor(buffer_sp, process_sp->GetByteOrder(),
235 process_sp->GetAddressByteSize()),
237 if (retval_sp)
238 m_children[idx] = retval_sp;
239 return retval_sp;
240}
241
244 m_children.clear();
245 ValueObjectSP valobj_sp = m_backend.GetSP();
246 if (!valobj_sp)
248 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
249 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
250 if (!size_sp)
252 m_count = size_sp->GetValueAsUnsigned(0);
253 if (!m_count)
255 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
256 if (!begin_sp) {
257 m_count = 0;
259 }
260 m_base_data_address = begin_sp->GetValueAsUnsigned(0);
261 if (!m_base_data_address) {
262 m_count = 0;
264 }
266}
267
268llvm::Expected<size_t>
272 return llvm::createStringError("Type has no child named '%s'",
273 name.AsCString());
274 auto optional_idx = ExtractIndexFromString(name.AsCString());
275 if (!optional_idx) {
276 return llvm::createStringError("Type has no child named '%s'",
277 name.AsCString());
278 }
279 uint32_t idx = *optional_idx;
281 return llvm::createStringError("Type has no child named '%s'",
282 name.AsCString());
283 return idx;
284}
285
289 if (!valobj_sp)
290 return nullptr;
291 CompilerType type = valobj_sp->GetCompilerType();
292 if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
293 return nullptr;
294 CompilerType arg_type = type.GetTypeTemplateArgument(0);
295 if (arg_type.GetTypeName() == "bool")
296 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
297 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
298}
static ValueObjectSP GetDataPointer(ValueObject &root)
#define LLDB_LOG_ERRORV(log, error,...)
Definition Log.h:408
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
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
const char * GetCString() 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:294
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 CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type)
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
llvm::Expected< uint32_t > CalculateNumChildren() override
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
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
std::optional< size_t > ExtractIndexFromString(const char *item_name)
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair)
Definition LibCxx.cpp:75
std::pair< lldb::ValueObjectSP, bool > GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name, llvm::StringRef compressed_pair_name)
Returns the ValueObjectSP of the child of obj.
Definition LibCxx.cpp:106
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:332
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