xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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   llvm::Expected<uint32_t> CalculateNumChildren() override;
30 
31   lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
32 
33   lldb::ChildCacheState 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 = valobj_sp->GetChildMemberWithName("_M_t");
73   if (!obj_child_sp)
74       return nullptr;
75 
76   ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName("_M_t");
77 
78   // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp
79   // (for libstdc++ 6.0.23).
80   if (obj_subchild_sp) {
81     return obj_subchild_sp;
82   }
83 
84   return obj_child_sp;
85 }
86 
Update()87 lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {
88   ValueObjectSP tuple_sp = GetTuple();
89 
90   if (!tuple_sp)
91     return lldb::ChildCacheState::eRefetch;
92 
93   std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(
94       LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));
95 
96   ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);
97   if (ptr_obj)
98     m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();
99 
100   // Add a 'deleter' child if there was a non-empty deleter type specified.
101   //
102   // The object might have size=1 in the TypeSystem but occupies no dedicated
103   // storage due to no_unique_address, so infer the actual size from the total
104   // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then
105   // the deleter is empty and should be hidden.
106   if (tuple_sp->GetByteSize() > ptr_obj->GetByteSize()) {
107     ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);
108     if (del_obj)
109       m_del_obj = del_obj->Clone(ConstString("deleter")).get();
110   }
111   m_obj_obj = nullptr;
112 
113   return lldb::ChildCacheState::eRefetch;
114 }
115 
MightHaveChildren()116 bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; }
117 
118 lldb::ValueObjectSP
GetChildAtIndex(uint32_t idx)119 LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
120   if (idx == 0 && m_ptr_obj)
121     return m_ptr_obj->GetSP();
122   if (idx == 1 && m_del_obj)
123     return m_del_obj->GetSP();
124   if (idx == 2) {
125     if (m_ptr_obj && !m_obj_obj) {
126       Status error;
127       ValueObjectSP obj_obj = m_ptr_obj->Dereference(error);
128       if (error.Success()) {
129         m_obj_obj = obj_obj->Clone(ConstString("object")).get();
130       }
131     }
132     if (m_obj_obj)
133       return m_obj_obj->GetSP();
134   }
135   return lldb::ValueObjectSP();
136 }
137 
138 llvm::Expected<uint32_t>
CalculateNumChildren()139 LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {
140   if (m_del_obj)
141     return 2;
142   return 1;
143 }
144 
GetIndexOfChildWithName(ConstString name)145 size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(
146     ConstString name) {
147   if (name == "ptr" || name == "pointer")
148     return 0;
149   if (name == "del" || name == "deleter")
150     return 1;
151   if (name == "obj" || name == "object" || name == "$$dereference$$")
152     return 2;
153   return UINT32_MAX;
154 }
155 
GetSummary(Stream & stream,const TypeSummaryOptions & options)156 bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(
157     Stream &stream, const TypeSummaryOptions &options) {
158   if (!m_ptr_obj)
159     return false;
160 
161   bool success;
162   uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(0, &success);
163   if (!success)
164     return false;
165   if (ptr_value == 0)
166     stream.Printf("nullptr");
167   else
168     stream.Printf("0x%" PRIx64, ptr_value);
169   return true;
170 }
171 
172 SyntheticChildrenFrontEnd *
LibStdcppUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)173 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(
174     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
175   return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)
176                     : nullptr);
177 }
178 
LibStdcppUniquePointerSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)179 bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(
180     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
181   LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());
182   return formatter.GetSummary(stream, options);
183 }
184