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