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/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(ConstString name) override;
38
39private:
40 ValueObject *m_start = nullptr;
43 uint32_t m_element_size = 0;
44};
45
47public:
49
50 llvm::Expected<uint32_t> CalculateNumChildren() override;
51
52 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
53
55
56 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
57
58private:
61 uint64_t m_count = 0;
63 std::map<size_t, lldb::ValueObjectSP> m_children;
64};
65
66} // namespace formatters
67} // namespace lldb_private
68
75
78 // these need to stay around because they are child objects who will follow
79 // their parent's life cycle
80 // delete m_start;
81 // delete m_finish;
82}
83
84llvm::Expected<uint32_t> lldb_private::formatters::
86 if (!m_start || !m_finish)
87 return llvm::createStringError(
88 "failed to determine start/end of vector data");
89
90 uint64_t start_val = m_start->GetValueAsUnsigned(0);
91 uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
92
93 // A default-initialized empty vector.
94 if (start_val == 0 && finish_val == 0)
95 return 0;
96
97 if (start_val == 0)
98 return llvm::createStringError("invalid value for start of vector");
99
100 if (finish_val == 0)
101 return llvm::createStringError("invalid value for end of vector");
102
103 if (start_val > finish_val)
104 return llvm::createStringError(
105 "start of vector data begins after end pointer");
106
107 size_t num_children = (finish_val - start_val);
108 if (num_children % m_element_size)
109 return llvm::createStringError("size not multiple of element size");
110
111 return num_children / m_element_size;
112}
113
116 uint32_t idx) {
117 if (!m_start || !m_finish)
118 return lldb::ValueObjectSP();
119
120 uint64_t offset = idx * m_element_size;
121 offset = offset + m_start->GetValueAsUnsigned(0);
122 StreamString name;
123 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
124 return CreateValueObjectFromAddress(name.GetString(), offset,
125 m_backend.GetExecutionContextRef(),
127}
128
130 auto [cap_sp, is_compressed_pair] =
131 GetValueOrOldCompressedPair(root, "__cap_", "__end_cap_");
132 if (!cap_sp)
133 return nullptr;
134
135 if (is_compressed_pair)
137
138 return cap_sp;
139}
140
143 m_start = m_finish = nullptr;
145
146 if (!data_sp)
148
149 m_element_type = data_sp->GetCompilerType().GetPointeeType();
150 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);
151 if (!size_or_err)
152 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),
153 "{0}");
154 else {
155 m_element_size = *size_or_err;
156
157 if (m_element_size > 0) {
158 // store raw pointers or end up with a circular dependency
159 m_start = m_backend.GetChildMemberWithName("__begin_").get();
160 m_finish = m_backend.GetChildMemberWithName("__end_").get();
161 }
162 }
164}
165
166llvm::Expected<size_t>
169 if (!m_start || !m_finish)
170 return llvm::createStringErrorV("type has no child named '{0}'", name);
171 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
172 if (!optional_idx) {
173 return llvm::createStringErrorV("type has no child named '{0}'", name);
174 }
175 return *optional_idx;
176}
177
181 m_children() {
182 if (valobj_sp) {
183 Update();
185 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);
186 }
187}
188
193
196 uint32_t idx) {
197 auto iter = m_children.find(idx), end = m_children.end();
198 if (iter != end)
199 return iter->second;
200 if (idx >= m_count)
201 return {};
202 if (m_base_data_address == 0 || m_count == 0)
203 return {};
204 if (!m_bool_type)
205 return {};
206 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
207 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
208 lldb::addr_t byte_location = m_base_data_address + byte_idx;
209 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
210 if (!process_sp)
211 return {};
212 uint8_t byte = 0;
213 uint8_t mask = 0;
214 Status err;
215 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
216 if (err.Fail() || bytes_read == 0)
217 return {};
218 mask = 1 << bit_index;
219 bool bit_set = ((byte & mask) != 0);
220 std::optional<uint64_t> size =
221 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));
222 if (!size)
223 return {};
224 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
225 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {
226 // regardless of endianness, anything non-zero is true
227 *(buffer_sp->GetBytes()) = 1;
228 }
229 StreamString name;
230 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
232 name.GetString(),
233 DataExtractor(buffer_sp, process_sp->GetByteOrder(),
234 process_sp->GetAddressByteSize()),
236 if (retval_sp)
237 m_children[idx] = retval_sp;
238 return retval_sp;
239}
240
243 m_children.clear();
244 ValueObjectSP valobj_sp = m_backend.GetSP();
245 if (!valobj_sp)
247 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
248 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_"));
249 if (!size_sp)
251 m_count = size_sp->GetValueAsUnsigned(0);
252 if (!m_count)
254 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_"));
255 if (!begin_sp) {
256 m_count = 0;
258 }
259 m_base_data_address = begin_sp->GetValueAsUnsigned(0);
260 if (!m_base_data_address) {
261 m_count = 0;
263 }
265}
266
267llvm::Expected<size_t>
271 return llvm::createStringErrorV("type has no child named '{0}'", name);
272 auto optional_idx = ExtractIndexFromString(name.AsCString(nullptr));
273 if (!optional_idx) {
274 return llvm::createStringErrorV("type has no child named '{0}'", name);
275 }
276 uint32_t idx = *optional_idx;
278 return llvm::createStringErrorV("type has no child named '{0}'", name);
279 return idx;
280}
281
285 if (!valobj_sp)
286 return nullptr;
287 CompilerType type = valobj_sp->GetCompilerType();
288 if (!type.IsValid() || type.GetNumTemplateArguments() == 0)
289 return nullptr;
290 CompilerType arg_type = type.GetTypeTemplateArgument(0);
291 if (arg_type.GetTypeName() == "bool")
292 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp);
293 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp);
294}
static ValueObjectSP GetDataPointer(ValueObject &root)
#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
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:132
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
Determine the index of a named child.
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
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)
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair)
Definition LibCxx.cpp:75
std::pair< lldb::ValueObjectSP, bool > GetValueOrOldCompressedPair(ValueObject &obj, llvm::StringRef child_name, llvm::StringRef compressed_pair_name)
Returns the ValueObjectSP of the child of obj.
Definition LibCxx.cpp:106
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