172 lines · cpp
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-exception6//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 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 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 39private:40 // The lifetime of a ValueObject and all its derivative ValueObjects41 // (children, clones, etc.) is managed by a ClusterManager. These42 // objects are only destroyed when every shared pointer to any of them43 // is destroyed, so we must not store a shared pointer to any ValueObject44 // derived from our backend ValueObject (since we're in the same cluster).45 ValueObject *m_ptr_obj = nullptr;46 ValueObject* m_del_obj = nullptr;47 48 ValueObjectSP GetTuple();49};50 51} // end of anonymous namespace52 53LibStdcppUniquePtrSyntheticFrontEnd::LibStdcppUniquePtrSyntheticFrontEnd(54 lldb::ValueObjectSP valobj_sp)55 : SyntheticChildrenFrontEnd(*valobj_sp) {56 Update();57}58 59ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() {60 ValueObjectSP valobj_backend_sp = m_backend.GetSP();61 62 if (!valobj_backend_sp)63 return nullptr;64 65 ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();66 if (!valobj_sp)67 return nullptr;68 69 ValueObjectSP obj_child_sp = valobj_sp->GetChildMemberWithName("_M_t");70 if (!obj_child_sp)71 return nullptr;72 73 ValueObjectSP obj_subchild_sp = obj_child_sp->GetChildMemberWithName("_M_t");74 75 // if there is a _M_t subchild, the tuple is found in the obj_subchild_sp76 // (for libstdc++ 6.0.23).77 if (obj_subchild_sp) {78 return obj_subchild_sp;79 }80 81 return obj_child_sp;82}83 84lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() {85 ValueObjectSP tuple_sp = GetTuple();86 87 if (!tuple_sp)88 return lldb::ChildCacheState::eRefetch;89 90 std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend(91 LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp));92 93 ValueObjectSP ptr_obj = tuple_frontend->GetChildAtIndex(0);94 if (ptr_obj)95 m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get();96 97 // Add a 'deleter' child if there was a non-empty deleter type specified.98 //99 // The object might have size=1 in the TypeSystem but occupies no dedicated100 // storage due to no_unique_address, so infer the actual size from the total101 // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then102 // the deleter is empty and should be hidden.103 if (llvm::expectedToOptional(tuple_sp->GetByteSize()).value_or(0) >104 llvm::expectedToOptional(ptr_obj->GetByteSize()).value_or(0)) {105 ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1);106 if (del_obj)107 m_del_obj = del_obj->Clone(ConstString("deleter")).get();108 }109 110 return lldb::ChildCacheState::eRefetch;111}112 113lldb::ValueObjectSP114LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {115 if (idx == 0 && m_ptr_obj)116 return m_ptr_obj->GetSP();117 if (idx == 1 && m_del_obj)118 return m_del_obj->GetSP();119 if (idx == 2) {120 if (m_ptr_obj) {121 Status status;122 auto value_sp = m_ptr_obj->Dereference(status);123 if (status.Success()) {124 return value_sp;125 }126 }127 }128 return lldb::ValueObjectSP();129}130 131llvm::Expected<uint32_t>132LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() {133 if (m_del_obj)134 return 2;135 return 1;136}137 138llvm::Expected<size_t>139LibStdcppUniquePtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {140 if (name == "ptr" || name == "pointer")141 return 0;142 if (name == "del" || name == "deleter")143 return 1;144 if (name == "obj" || name == "object" || name == "$$dereference$$")145 return 2;146 return llvm::createStringError("Type has no child named '%s'",147 name.AsCString());148}149 150bool LibStdcppUniquePtrSyntheticFrontEnd::GetSummary(151 Stream &stream, const TypeSummaryOptions &options) {152 if (!m_ptr_obj)153 return false;154 155 DumpCxxSmartPtrPointerSummary(stream, *m_ptr_obj, options);156 157 return true;158}159 160SyntheticChildrenFrontEnd *161lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator(162 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {163 return (valobj_sp ? new LibStdcppUniquePtrSyntheticFrontEnd(valobj_sp)164 : nullptr);165}166 167bool lldb_private::formatters::LibStdcppUniquePointerSummaryProvider(168 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {169 LibStdcppUniquePtrSyntheticFrontEnd formatter(valobj.GetSP());170 return formatter.GetSummary(stream, options);171}172