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 56 LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd( 57 lldb::ValueObjectSP valobj_sp) 58 : SyntheticChildrenFrontEnd(*valobj_sp) { 59 Update(); 60 } 61 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 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 ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); 103 if (del_obj) 104 m_del_obj = del_obj->Clone(ConstString("deleter")).get(); 105 106 if (m_ptr_obj) { 107 Status error; 108 ValueObjectSP obj_obj = m_ptr_obj->Dereference(error); 109 if (error.Success()) { 110 m_obj_obj = obj_obj->Clone(ConstString("object")).get(); 111 } 112 } 113 114 return false; 115 } 116 117 bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; } 118 119 lldb::ValueObjectSP 120 LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { 121 if (idx == 0 && m_ptr_obj) 122 return m_ptr_obj->GetSP(); 123 if (idx == 1 && m_del_obj) 124 return m_del_obj->GetSP(); 125 if (idx == 2 && m_obj_obj) 126 return m_obj_obj->GetSP(); 127 return lldb::ValueObjectSP(); 128 } 129 130 size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { 131 if (m_del_obj) 132 return 2; 133 return 1; 134 } 135 136 size_t LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName( 137 ConstString name) { 138 if (name == "ptr" || name == "pointer") 139 return 0; 140 if (name == "del" || name == "deleter") 141 return 1; 142 if (name == "obj" || name == "object" || name == "$$dereference$$") 143 return 2; 144 return UINT32_MAX; 145 } 146 147 bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary( 148 Stream &stream, const TypeSummaryOptions &options) { 149 if (!m_ptr_obj) 150 return false; 151 152 bool success; 153 uint64_t ptr_value = m_ptr_obj->GetValueAsUnsigned(0, &success); 154 if (!success) 155 return false; 156 if (ptr_value == 0) 157 stream.Printf("nullptr"); 158 else 159 stream.Printf("0x%" PRIx64, ptr_value); 160 return true; 161 } 162 163 SyntheticChildrenFrontEnd * 164 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator( 165 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 166 return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp) 167 : nullptr); 168 } 169 170 bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider( 171 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 172 LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP()); 173 return formatter.GetSummary(stream, options); 174 } 175