LLDB mainline
LibStdcpp.cpp
Go to the documentation of this file.
1//===-- LibStdcpp.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 "LibStdcpp.h"
10#include "LibCxx.h"
11
17#include "lldb/Target/Target.h"
19#include "lldb/Utility/Endian.h"
20#include "lldb/Utility/Status.h"
21#include "lldb/Utility/Stream.h"
24#include <optional>
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::formatters;
29
30namespace {
31
32class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
33 /*
34 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
35 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
36 (_Base_ptr) _M_node = 0x0000000100103910 {
37 (std::_Rb_tree_color) _M_color = _S_black
38 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
39 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
40 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
41 }
42 }
43 */
44
45public:
46 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
47
48 llvm::Expected<uint32_t> CalculateNumChildren() override;
49
50 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
51
52 lldb::ChildCacheState Update() override;
53
54 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
55
56private:
57 ExecutionContextRef m_exe_ctx_ref;
58 lldb::addr_t m_pair_address = 0;
59 CompilerType m_pair_type;
60 lldb::ValueObjectSP m_pair_sp;
61};
62
63class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
64public:
65 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
66
67 llvm::Expected<uint32_t> CalculateNumChildren() override;
68
69 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
70
71 lldb::ChildCacheState Update() override;
72
73 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
74
75private:
76
77 // The lifetime of a ValueObject and all its derivative ValueObjects
78 // (children, clones, etc.) is managed by a ClusterManager. These
79 // objects are only destroyed when every shared pointer to any of them
80 // is destroyed, so we must not store a shared pointer to any ValueObject
81 // derived from our backend ValueObject (since we're in the same cluster).
82 ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
83};
84
85} // end of anonymous namespace
86
87LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
88 lldb::ValueObjectSP valobj_sp)
89 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
90 m_pair_sp() {
91 if (valobj_sp)
92 Update();
93}
94
95lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
96 ValueObjectSP valobj_sp = m_backend.GetSP();
97 if (!valobj_sp)
99
100 TargetSP target_sp(valobj_sp->GetTargetSP());
101
102 if (!target_sp)
104
105 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
106
107 if (!valobj_sp)
109 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
110
111 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
112 if (!_M_node_sp)
114
115 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
116 if (m_pair_address == 0)
118
119 m_pair_address += (is_64bit ? 32 : 16);
120
121 CompilerType my_type(valobj_sp->GetCompilerType());
122 if (my_type.GetNumTemplateArguments() >= 1) {
123 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
124 if (!pair_type)
126 m_pair_type = pair_type;
127 } else
129
131}
132
133llvm::Expected<uint32_t>
134LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
135 return 2;
136}
137
139LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
140 if (m_pair_address != 0 && m_pair_type) {
141 if (!m_pair_sp)
142 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
143 m_exe_ctx_ref, m_pair_type);
144 if (m_pair_sp)
145 return m_pair_sp->GetChildAtIndex(idx);
146 }
147 return lldb::ValueObjectSP();
148}
149
150llvm::Expected<size_t>
151LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
152 ConstString name) {
153 if (name == "first")
154 return 0;
155 if (name == "second")
156 return 1;
157 return llvm::createStringError("Type has no child named '%s'",
158 name.AsCString());
159}
160
161SyntheticChildrenFrontEnd *
164 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
165 : nullptr);
166}
167
168/*
169 (lldb) fr var ibeg --ptr-depth 1
170 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
171 ibeg = {
172 _M_current = 0x00000001001037a0 {
173 *_M_current = 1
174 }
175 }
176 */
177
181 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
182 valobj_sp, {ConstString("_M_current")})
183 : nullptr);
184}
185
188 llvm::ArrayRef<ConstString> item_names)
190 m_item_names(item_names), m_item_sp() {
191 if (valobj_sp)
192 Update();
193}
194
196 m_item_sp.reset();
197
198 ValueObjectSP valobj_sp = m_backend.GetSP();
199 if (!valobj_sp)
201
202 if (!valobj_sp)
204
205 ValueObjectSP item_ptr =
207 if (!item_ptr)
209 if (item_ptr->GetValueAsUnsigned(0) == 0)
211 Status err;
212 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
214 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
215 item_ptr->GetCompilerType().GetPointeeType());
216 if (err.Fail())
217 m_item_sp.reset();
219}
220
221llvm::Expected<uint32_t>
225
228 if (idx == 0)
229 return m_item_sp;
230 return lldb::ValueObjectSP();
231}
232
233llvm::Expected<size_t>
235 if (name == "item")
236 return 0;
237 return llvm::createStringError("Type has no child named '%s'",
238 name.AsCString());
239}
240
242 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
243 ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
244 if (!ptr || !ptr->GetError().Success())
245 stream << "Summary Unavailable";
246 else
247 stream << ptr->GetSummaryAsCString();
248
249 return true;
250}
251
252LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
253 lldb::ValueObjectSP valobj_sp)
254 : SyntheticChildrenFrontEnd(*valobj_sp) {
255 if (valobj_sp)
256 Update();
257}
258
259llvm::Expected<uint32_t>
260LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
261 return 1;
262}
263
265LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
266 if (!m_ptr_obj)
267 return nullptr;
268
269 if (idx == 0)
270 return m_ptr_obj->GetSP();
271
272 if (idx == 1) {
273 ValueObjectSP valobj_sp = m_backend.GetSP();
274 if (!valobj_sp)
275 return nullptr;
276
277 Status status;
278 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
279 if (status.Success())
280 return value_sp;
281 }
282 return lldb::ValueObjectSP();
283}
284
285lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
286 auto backend = m_backend.GetSP();
287 if (!backend)
289
290 auto valobj_sp = backend->GetNonSyntheticValue();
291 if (!valobj_sp)
293
294 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
295 if (!ptr_obj_sp)
297
298 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
299 if (!cast_ptr_sp)
301
302 m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();
303
305}
306
307llvm::Expected<size_t>
308LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
309 if (name == "pointer")
310 return 0;
311
312 if (name == "object" || name == "$$dereference$$")
313 return 1;
314
315 return llvm::createStringError("Type has no child named '%s'",
316 name.AsCString());
317}
318
322 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
323 : nullptr);
324}
325
327 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
328 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
329 if (!valobj_sp)
330 return false;
331
332 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
333 if (!ptr_sp)
334 return false;
335
336 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
337
338 ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});
339 if (!pi_sp)
340 return false;
341
342 bool success;
343 uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);
344 // Empty control field. We're done.
345 if (!success || pi_addr == 0)
346 return true;
347
348 int64_t shared_count = 0;
349 if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {
350 bool success;
351 shared_count = count_sp->GetValueAsSigned(0, &success);
352 if (!success)
353 return false;
354
355 stream.Printf(" strong=%" PRId64, shared_count);
356 }
357
358 // _M_weak_count is the number of weak references + (_M_use_count != 0).
359 if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {
360 bool success;
361 int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
362 if (!success)
363 return false;
364
365 stream.Printf(" weak=%" PRId64, count - (shared_count != 0));
366 }
367
368 return true;
369}
370
371static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {
372 switch (index_byte_size) {
373 case 1:
374 return 0xff;
375 case 2:
376 return 0xffff;
377 default:
378 return 0xffff'ffff;
379 }
380}
381
383 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
384 ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();
385 if (!valobj_sp)
386 return false;
387
388 ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");
389 ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");
390 if (!index_obj || !data_obj)
391 return false;
392
393 auto index_bytes = index_obj->GetByteSize();
394 if (!index_bytes)
395 return false;
396 auto npos_value = LibStdcppVariantNposValue(*index_bytes);
397 auto index = index_obj->GetValueAsUnsigned(0);
398 if (index == npos_value) {
399 stream.Printf(" No Value");
400 return true;
401 }
402
403 auto variant_type =
404 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
405 if (!variant_type)
406 return false;
407 if (index >= variant_type.GetNumTemplateArguments(true)) {
408 stream.Printf(" <Invalid>");
409 return true;
410 }
411
412 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
413 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
414 return true;
415}
static uint64_t LibStdcppVariantNposValue(size_t index_byte_size)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
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.
An error handling class.
Definition Status.h:118
bool Fail() const
Test for error condition.
Definition Status.cpp:294
bool Success() const
Test for success condition.
Definition Status.cpp:304
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
llvm::Expected< uint32_t > CalculateNumChildren() override
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) 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...
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, llvm::ArrayRef< ConstString > item_names)
lldb::ValueObjectSP GetChildMemberWithName(ValueObject &obj, llvm::ArrayRef< ConstString > alternative_names)
Find a child member of obj_sp, trying all alternative names in order.
Definition LibCxx.cpp:63
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr, ValueObject &container)
Return the ValueObjectSP of the underlying pointer member whose type is a desugared 'std::shared_ptr:...
Definition Generic.cpp:13
bool LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
bool LibStdcppVariantSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
void DumpCxxSmartPtrPointerSummary(Stream &stream, ValueObject &ptr, const TypeSummaryOptions &options)
Prints the summary for the pointer value of a C++ std::unique_ptr/stdshared_ptr/stdweak_ptr.
A class that represents a running process on the host machine.
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
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP