1 //===-- LibStdcpp.cpp -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
12 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
13 #include "lldb/DataFormatters/StringPrinter.h"
14 #include "lldb/DataFormatters/VectorIterator.h"
15 #include "lldb/Target/Target.h"
16 #include "lldb/Utility/DataBufferHeap.h"
17 #include "lldb/Utility/Endian.h"
18 #include "lldb/Utility/Status.h"
19 #include "lldb/Utility/Stream.h"
20 #include "lldb/ValueObject/ValueObject.h"
21 #include "lldb/ValueObject/ValueObjectConstResult.h"
25 using namespace lldb_private
;
26 using namespace lldb_private::formatters
;
30 class LibstdcppMapIteratorSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
32 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
33 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
34 (_Base_ptr) _M_node = 0x0000000100103910 {
35 (std::_Rb_tree_color) _M_color = _S_black
36 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
37 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
38 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
44 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
);
46 llvm::Expected
<uint32_t> CalculateNumChildren() override
;
48 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
;
50 lldb::ChildCacheState
Update() override
;
52 bool MightHaveChildren() override
;
54 size_t GetIndexOfChildWithName(ConstString name
) override
;
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
;
63 class LibStdcppSharedPtrSyntheticFrontEnd
: public SyntheticChildrenFrontEnd
{
65 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
);
67 llvm::Expected
<uint32_t> CalculateNumChildren() override
;
69 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx
) override
;
71 lldb::ChildCacheState
Update() override
;
73 bool MightHaveChildren() override
;
75 size_t GetIndexOfChildWithName(ConstString name
) override
;
78 // The lifetime of a ValueObject and all its derivative ValueObjects
79 // (children, clones, etc.) is managed by a ClusterManager. These
80 // objects are only destroyed when every shared pointer to any of them
81 // is destroyed, so we must not store a shared pointer to any ValueObject
82 // derived from our backend ValueObject (since we're in the same cluster).
83 ValueObject
* m_ptr_obj
= nullptr; // Underlying pointer (held, not owned)
84 ValueObject
* m_obj_obj
= nullptr; // Underlying object (held, not owned)
87 } // end of anonymous namespace
89 LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
90 lldb::ValueObjectSP valobj_sp
)
91 : SyntheticChildrenFrontEnd(*valobj_sp
), m_exe_ctx_ref(), m_pair_type(),
97 lldb::ChildCacheState
LibstdcppMapIteratorSyntheticFrontEnd::Update() {
98 ValueObjectSP valobj_sp
= m_backend
.GetSP();
100 return lldb::ChildCacheState::eRefetch
;
102 TargetSP
target_sp(valobj_sp
->GetTargetSP());
105 return lldb::ChildCacheState::eRefetch
;
107 bool is_64bit
= (target_sp
->GetArchitecture().GetAddressByteSize() == 8);
110 return lldb::ChildCacheState::eRefetch
;
111 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
113 ValueObjectSP
_M_node_sp(valobj_sp
->GetChildMemberWithName("_M_node"));
115 return lldb::ChildCacheState::eRefetch
;
117 m_pair_address
= _M_node_sp
->GetValueAsUnsigned(0);
118 if (m_pair_address
== 0)
119 return lldb::ChildCacheState::eRefetch
;
121 m_pair_address
+= (is_64bit
? 32 : 16);
123 CompilerType
my_type(valobj_sp
->GetCompilerType());
124 if (my_type
.GetNumTemplateArguments() >= 1) {
125 CompilerType pair_type
= my_type
.GetTypeTemplateArgument(0);
127 return lldb::ChildCacheState::eRefetch
;
128 m_pair_type
= pair_type
;
130 return lldb::ChildCacheState::eRefetch
;
132 return lldb::ChildCacheState::eReuse
;
135 llvm::Expected
<uint32_t>
136 LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
141 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx
) {
142 if (m_pair_address
!= 0 && m_pair_type
) {
144 m_pair_sp
= CreateValueObjectFromAddress("pair", m_pair_address
,
145 m_exe_ctx_ref
, m_pair_type
);
147 return m_pair_sp
->GetChildAtIndex(idx
);
149 return lldb::ValueObjectSP();
152 bool LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
154 size_t LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
158 if (name
== "second")
163 SyntheticChildrenFrontEnd
*
164 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator(
165 CXXSyntheticChildren
*, lldb::ValueObjectSP valobj_sp
) {
166 return (valobj_sp
? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp
)
171 (lldb) fr var ibeg --ptr-depth 1
172 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
174 _M_current = 0x00000001001037a0 {
180 SyntheticChildrenFrontEnd
*
181 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator(
182 CXXSyntheticChildren
*, lldb::ValueObjectSP valobj_sp
) {
183 return (valobj_sp
? new VectorIteratorSyntheticFrontEnd(
184 valobj_sp
, {ConstString("_M_current")})
188 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::
189 VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp
,
190 llvm::ArrayRef
<ConstString
> item_names
)
191 : SyntheticChildrenFrontEnd(*valobj_sp
), m_exe_ctx_ref(),
192 m_item_names(item_names
), m_item_sp() {
197 lldb::ChildCacheState
VectorIteratorSyntheticFrontEnd::Update() {
200 ValueObjectSP valobj_sp
= m_backend
.GetSP();
202 return lldb::ChildCacheState::eRefetch
;
205 return lldb::ChildCacheState::eRefetch
;
207 ValueObjectSP item_ptr
=
208 formatters::GetChildMemberWithName(*valobj_sp
, m_item_names
);
210 return lldb::ChildCacheState::eRefetch
;
211 if (item_ptr
->GetValueAsUnsigned(0) == 0)
212 return lldb::ChildCacheState::eRefetch
;
214 m_exe_ctx_ref
= valobj_sp
->GetExecutionContextRef();
215 m_item_sp
= CreateValueObjectFromAddress(
216 "item", item_ptr
->GetValueAsUnsigned(0), m_exe_ctx_ref
,
217 item_ptr
->GetCompilerType().GetPointeeType());
220 return lldb::ChildCacheState::eRefetch
;
223 llvm::Expected
<uint32_t>
224 VectorIteratorSyntheticFrontEnd::CalculateNumChildren() {
229 VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx
) {
232 return lldb::ValueObjectSP();
235 bool VectorIteratorSyntheticFrontEnd::MightHaveChildren() { return true; }
237 size_t VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
244 bool lldb_private::formatters::LibStdcppStringSummaryProvider(
245 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
246 const bool scalar_is_load_addr
= true;
247 AddressType addr_type
;
248 lldb::addr_t addr_of_string
= LLDB_INVALID_ADDRESS
;
249 if (valobj
.IsPointerOrReferenceType()) {
251 ValueObjectSP pointee_sp
= valobj
.Dereference(error
);
252 if (pointee_sp
&& error
.Success())
253 addr_of_string
= pointee_sp
->GetAddressOf(scalar_is_load_addr
, &addr_type
);
256 valobj
.GetAddressOf(scalar_is_load_addr
, &addr_type
);
257 if (addr_of_string
!= LLDB_INVALID_ADDRESS
) {
259 case eAddressTypeLoad
: {
260 ProcessSP
process_sp(valobj
.GetProcessSP());
264 StringPrinter::ReadStringAndDumpToStreamOptions
options(valobj
);
266 lldb::addr_t addr_of_data
=
267 process_sp
->ReadPointerFromMemory(addr_of_string
, error
);
268 if (error
.Fail() || addr_of_data
== 0 ||
269 addr_of_data
== LLDB_INVALID_ADDRESS
)
271 options
.SetLocation(addr_of_data
);
272 options
.SetTargetSP(valobj
.GetTargetSP());
273 options
.SetStream(&stream
);
274 options
.SetNeedsZeroTermination(false);
275 options
.SetBinaryZeroIsTerminator(true);
276 lldb::addr_t size_of_data
= process_sp
->ReadPointerFromMemory(
277 addr_of_string
+ process_sp
->GetAddressByteSize(), error
);
280 options
.SetSourceSize(size_of_data
);
281 options
.SetHasSourceSize(true);
283 if (!StringPrinter::ReadStringAndDumpToStream
<
284 StringPrinter::StringElementType::UTF8
>(options
)) {
285 stream
.Printf("Summary Unavailable");
290 case eAddressTypeHost
:
292 case eAddressTypeInvalid
:
293 case eAddressTypeFile
:
300 bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
301 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
302 const bool scalar_is_load_addr
= true;
303 AddressType addr_type
;
304 lldb::addr_t addr_of_string
=
305 valobj
.GetAddressOf(scalar_is_load_addr
, &addr_type
);
306 if (addr_of_string
!= LLDB_INVALID_ADDRESS
) {
308 case eAddressTypeLoad
: {
309 ProcessSP
process_sp(valobj
.GetProcessSP());
313 CompilerType wchar_compiler_type
=
314 valobj
.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar
);
316 if (!wchar_compiler_type
)
319 // Safe to pass nullptr for exe_scope here.
320 std::optional
<uint64_t> size
= wchar_compiler_type
.GetBitSize(nullptr);
323 const uint32_t wchar_size
= *size
;
325 StringPrinter::ReadStringAndDumpToStreamOptions
options(valobj
);
327 lldb::addr_t addr_of_data
=
328 process_sp
->ReadPointerFromMemory(addr_of_string
, error
);
329 if (error
.Fail() || addr_of_data
== 0 ||
330 addr_of_data
== LLDB_INVALID_ADDRESS
)
332 options
.SetLocation(addr_of_data
);
333 options
.SetTargetSP(valobj
.GetTargetSP());
334 options
.SetStream(&stream
);
335 options
.SetNeedsZeroTermination(false);
336 options
.SetBinaryZeroIsTerminator(false);
337 lldb::addr_t size_of_data
= process_sp
->ReadPointerFromMemory(
338 addr_of_string
+ process_sp
->GetAddressByteSize(), error
);
341 options
.SetSourceSize(size_of_data
);
342 options
.SetHasSourceSize(true);
343 options
.SetPrefixToken("L");
345 switch (wchar_size
) {
347 return StringPrinter::ReadStringAndDumpToStream
<
348 StringPrinter::StringElementType::UTF8
>(options
);
350 return StringPrinter::ReadStringAndDumpToStream
<
351 StringPrinter::StringElementType::UTF16
>(options
);
353 return StringPrinter::ReadStringAndDumpToStream
<
354 StringPrinter::StringElementType::UTF32
>(options
);
356 stream
.Printf("size for wchar_t is not valid");
361 case eAddressTypeHost
:
363 case eAddressTypeInvalid
:
364 case eAddressTypeFile
:
371 LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
372 lldb::ValueObjectSP valobj_sp
)
373 : SyntheticChildrenFrontEnd(*valobj_sp
) {
378 llvm::Expected
<uint32_t>
379 LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
384 LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx
) {
386 return m_ptr_obj
->GetSP();
388 if (m_ptr_obj
&& !m_obj_obj
) {
390 ValueObjectSP obj_obj
= m_ptr_obj
->Dereference(error
);
392 m_obj_obj
= obj_obj
->Clone(ConstString("object")).get();
395 return m_obj_obj
->GetSP();
397 return lldb::ValueObjectSP();
400 lldb::ChildCacheState
LibStdcppSharedPtrSyntheticFrontEnd::Update() {
401 auto backend
= m_backend
.GetSP();
403 return lldb::ChildCacheState::eRefetch
;
405 auto valobj_sp
= backend
->GetNonSyntheticValue();
407 return lldb::ChildCacheState::eRefetch
;
409 auto ptr_obj_sp
= valobj_sp
->GetChildMemberWithName("_M_ptr");
411 return lldb::ChildCacheState::eRefetch
;
413 m_ptr_obj
= ptr_obj_sp
->Clone(ConstString("pointer")).get();
416 return lldb::ChildCacheState::eRefetch
;
419 bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; }
421 size_t LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(
423 if (name
== "pointer")
425 if (name
== "object" || name
== "$$dereference$$")
430 SyntheticChildrenFrontEnd
*
431 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
432 CXXSyntheticChildren
*, lldb::ValueObjectSP valobj_sp
) {
433 return (valobj_sp
? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp
)
437 bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
438 ValueObject
&valobj
, Stream
&stream
, const TypeSummaryOptions
&options
) {
439 ValueObjectSP
valobj_sp(valobj
.GetNonSyntheticValue());
443 ValueObjectSP
ptr_sp(valobj_sp
->GetChildMemberWithName("_M_ptr"));
447 ValueObjectSP
usecount_sp(
448 valobj_sp
->GetChildAtNamePath({"_M_refcount", "_M_pi", "_M_use_count"}));
452 if (ptr_sp
->GetValueAsUnsigned(0) == 0 ||
453 usecount_sp
->GetValueAsUnsigned(0) == 0) {
454 stream
.Printf("nullptr");
459 ValueObjectSP pointee_sp
= ptr_sp
->Dereference(error
);
460 if (pointee_sp
&& error
.Success()) {
461 if (pointee_sp
->DumpPrintableRepresentation(
462 stream
, ValueObject::eValueObjectRepresentationStyleSummary
,
463 lldb::eFormatInvalid
,
464 ValueObject::PrintableRepresentationSpecialCases::eDisable
,
470 stream
.Printf("ptr = 0x%" PRIx64
, ptr_sp
->GetValueAsUnsigned(0));