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 19using namespace lldb; 20using namespace lldb_private; 21using namespace lldb_private::formatters; 22 23namespace { 24 25class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 26public: 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 41private: 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 56LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd( 57 lldb::ValueObjectSP valobj_sp) 58 : SyntheticChildrenFrontEnd(*valobj_sp) { 59 Update(); 60} 61 62ValueObjectSP 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 87bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { 88 ValueObjectSP tuple_sp = GetTuple(); 89 90 if (!tuple_sp) 91 return false; 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 false; 114} 115 116bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; } 117 118lldb::ValueObjectSP 119LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_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 138size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { 139 if (m_del_obj) 140 return 2; 141 return 1; 142} 143 144size_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 155bool 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 171SyntheticChildrenFrontEnd * 172lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator( 173 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 174 return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp) 175 : nullptr); 176} 177 178bool 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