1 | //===-- LibStdcppUniquePointer.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 | |
11 | #include "lldb/DataFormatters/FormattersHelpers.h" |
12 | #include "lldb/DataFormatters/TypeSynthetic.h" |
13 | #include "lldb/Utility/ConstString.h" |
14 | #include "lldb/ValueObject/ValueObject.h" |
15 | |
16 | #include <memory> |
17 | #include <vector> |
18 | |
19 | using namespace lldb; |
20 | using namespace lldb_private; |
21 | using namespace lldb_private::formatters; |
22 | |
23 | namespace { |
24 | |
25 | class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { |
26 | public: |
27 | explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); |
28 | |
29 | llvm::Expected<uint32_t> CalculateNumChildren() override; |
30 | |
31 | lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; |
32 | |
33 | lldb::ChildCacheState Update() override; |
34 | |
35 | llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; |
36 | |
37 | bool GetSummary(Stream &stream, const TypeSummaryOptions &options); |
38 | |
39 | private: |
40 | // The lifetime of a ValueObject and all its derivative ValueObjects |
41 | // (children, clones, etc.) is managed by a ClusterManager. These |
42 | // objects are only destroyed when every shared pointer to any of them |
43 | // is destroyed, so we must not store a shared pointer to any ValueObject |
44 | // derived from our backend ValueObject (since we're in the same cluster). |
45 | ValueObject* m_ptr_obj = nullptr; |
46 | ValueObject* m_obj_obj = nullptr; |
47 | ValueObject* m_del_obj = nullptr; |
48 | |
49 | ValueObjectSP GetTuple(); |
50 | }; |
51 | |
52 | } // end of anonymous namespace |
53 | |
54 | LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd( |
55 | lldb::ValueObjectSP valobj_sp) |
56 | : SyntheticChildrenFrontEnd(*valobj_sp) { |
57 | Update(); |
58 | } |
59 | |
60 | ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() { |
61 | ValueObjectSP valobj_backend_sp = m_backend.GetSP(); |
62 | |
63 | if (!valobj_backend_sp) |
64 | return nullptr; |
65 | |
66 | ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue(); |
67 | if (!valobj_sp) |
68 | return nullptr; |
69 | |
70 | ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName(name: "_M_t" ); |
71 | if (!obj_child_sp) |
72 | return nullptr; |
73 | |
74 | ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName(name: "_M_t" ); |
75 | |
76 | // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp |
77 | // (for libstdc++ 6.0.23). |
78 | if (obj_subchild_sp) { |
79 | return obj_subchild_sp; |
80 | } |
81 | |
82 | return obj_child_sp; |
83 | } |
84 | |
85 | lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() { |
86 | ValueObjectSP tuple_sp = GetTuple(); |
87 | |
88 | if (!tuple_sp) |
89 | return lldb::ChildCacheState::eRefetch; |
90 | |
91 | std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend( |
92 | LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp)); |
93 | |
94 | ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(idx: 0); |
95 | if (ptr_obj) |
96 | m_ptr_obj = ptr_obj->Clone(new_name: ConstString("pointer" )).get(); |
97 | |
98 | // Add a 'deleter' child if there was a non-empty deleter type specified. |
99 | // |
100 | // The object might have size=1 in the TypeSystem but occupies no dedicated |
101 | // storage due to no_unique_address, so infer the actual size from the total |
102 | // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then |
103 | // the deleter is empty and should be hidden. |
104 | if (llvm::expectedToOptional(E: tuple_sp->GetByteSize()).value_or(u: 0) > |
105 | llvm::expectedToOptional(E: ptr_obj->GetByteSize()).value_or(u: 0)) { |
106 | ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(idx: 1); |
107 | if (del_obj) |
108 | m_del_obj = del_obj->Clone(new_name: ConstString("deleter" )).get(); |
109 | } |
110 | m_obj_obj = nullptr; |
111 | |
112 | return lldb::ChildCacheState::eRefetch; |
113 | } |
114 | |
115 | lldb::ValueObjectSP |
116 | LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { |
117 | if (idx == 0 && m_ptr_obj) |
118 | return m_ptr_obj->GetSP(); |
119 | if (idx == 1 && m_del_obj) |
120 | return m_del_obj->GetSP(); |
121 | if (idx == 2) { |
122 | if (m_ptr_obj && !m_obj_obj) { |
123 | Status error; |
124 | ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); |
125 | if (error.Success()) { |
126 | m_obj_obj = obj_obj->Clone(new_name: ConstString("object" )).get(); |
127 | } |
128 | } |
129 | if (m_obj_obj) |
130 | return m_obj_obj->GetSP(); |
131 | } |
132 | return lldb::ValueObjectSP(); |
133 | } |
134 | |
135 | llvm::Expected<uint32_t> |
136 | LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { |
137 | if (m_del_obj) |
138 | return 2; |
139 | return 1; |
140 | } |
141 | |
142 | llvm::Expected<size_t> |
143 | LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) { |
144 | if (name == "ptr" || name == "pointer" ) |
145 | return 0; |
146 | if (name == "del" || name == "deleter" ) |
147 | return 1; |
148 | if (name == "obj" || name == "object" || name == "$$dereference$$" ) |
149 | return 2; |
150 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , |
151 | Vals: name.AsCString()); |
152 | } |
153 | |
154 | bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary( |
155 | Stream &stream, const TypeSummaryOptions &options) { |
156 | if (!m_ptr_obj) |
157 | return false; |
158 | |
159 | bool success; |
160 | uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(fail_value: 0, success: &success); |
161 | if (!success) |
162 | return false; |
163 | if (ptr_value == 0) |
164 | stream.Printf(format: "nullptr" ); |
165 | else |
166 | stream.Printf(format: "0x%" PRIx64, ptr_value); |
167 | return true; |
168 | } |
169 | |
170 | SyntheticChildrenFrontEnd * |
171 | lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator( |
172 | CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
173 | return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp) |
174 | : nullptr); |
175 | } |
176 | |
177 | bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider( |
178 | ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { |
179 | LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP()); |
180 | return formatter.GetSummary(stream, options); |
181 | } |
182 | |