//===-- MsvcStlSmartPointer.cpp -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "Generic.h" #include "MsvcStl.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" using namespace lldb; bool lldb_private::formatters::IsMsvcStlSmartPointer(ValueObject &valobj) { if (auto valobj_sp = valobj.GetNonSyntheticValue()) return valobj_sp->GetChildMemberWithName("_Ptr") != nullptr; return false; } bool lldb_private::formatters::MsvcStlSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); if (!valobj_sp) return false; ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_Ptr")); ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName("_Rep")); if (!ctrl_sp || !ptr_sp) return false; DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options); bool success; uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(0, &success); // Empty control field (expired) if (!success || ctrl_addr == 0) return true; uint64_t uses = 0; if (auto uses_sp = ctrl_sp->GetChildMemberWithName("_Uses")) { bool success; uses = uses_sp->GetValueAsUnsigned(0, &success); if (!success) return false; stream.Printf(" strong=%" PRIu64, uses); } // _Weaks is the number of weak references - (_Uses != 0). if (auto weak_count_sp = ctrl_sp->GetChildMemberWithName("_Weaks")) { bool success; uint64_t count = weak_count_sp->GetValueAsUnsigned(0, &success); if (!success) return false; stream.Printf(" weak=%" PRIu64, count - (uses != 0)); } return true; } namespace lldb_private { namespace formatters { class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); llvm::Expected CalculateNumChildren() override; lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; lldb::ChildCacheState Update() override; llvm::Expected GetIndexOfChildWithName(ConstString name) override; ~MsvcStlSmartPointerSyntheticFrontEnd() override; private: ValueObject *m_ptr_obj = nullptr; }; class MsvcStlUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); llvm::Expected CalculateNumChildren() override; lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; lldb::ChildCacheState Update() override; llvm::Expected GetIndexOfChildWithName(ConstString name) override; private: lldb::ValueObjectSP m_value_ptr_sp; lldb::ValueObjectSP m_deleter_sp; }; } // namespace formatters } // namespace lldb_private lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } llvm::Expected lldb_private::formatters:: MsvcStlSmartPointerSyntheticFrontEnd::CalculateNumChildren() { return (m_ptr_obj ? 1 : 0); } lldb::ValueObjectSP lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::GetChildAtIndex( uint32_t idx) { if (!m_ptr_obj) return lldb::ValueObjectSP(); ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) return lldb::ValueObjectSP(); if (idx == 0) return m_ptr_obj->GetSP(); if (idx == 1) { Status status; ValueObjectSP value_sp = m_ptr_obj->Dereference(status); if (status.Success()) return value_sp; } return lldb::ValueObjectSP(); } lldb::ChildCacheState lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::Update() { m_ptr_obj = nullptr; ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) return lldb::ChildCacheState::eRefetch; auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_Ptr"); if (!ptr_obj_sp) return lldb::ChildCacheState::eRefetch; auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp); if (!cast_ptr_sp) return lldb::ChildCacheState::eRefetch; m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get(); return lldb::ChildCacheState::eRefetch; } llvm::Expected lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { if (name == "pointer") return 0; if (name == "object" || name == "$$dereference$$") return 1; return llvm::createStringError("Type has no child named '%s'", name.AsCString()); } lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd:: ~MsvcStlSmartPointerSyntheticFrontEnd() = default; lldb_private::SyntheticChildrenFrontEnd * lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator( lldb::ValueObjectSP valobj_sp) { return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp); } bool lldb_private::formatters::IsMsvcStlUniquePtr(ValueObject &valobj) { if (auto valobj_sp = valobj.GetNonSyntheticValue()) return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr; return false; } bool lldb_private::formatters::MsvcStlUniquePtrSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); if (!valobj_sp) return false; ValueObjectSP ptr_sp(valobj_sp->GetChildAtNamePath({"_Mypair", "_Myval2"})); if (!ptr_sp) return false; DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options); return true; } lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd:: MsvcStlUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } llvm::Expected lldb_private::formatters:: MsvcStlUniquePtrSyntheticFrontEnd::CalculateNumChildren() { if (m_value_ptr_sp) return m_deleter_sp ? 2 : 1; return 0; } lldb::ValueObjectSP lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::GetChildAtIndex( uint32_t idx) { if (!m_value_ptr_sp) return lldb::ValueObjectSP(); if (idx == 0) return m_value_ptr_sp; if (idx == 1) return m_deleter_sp; if (idx == 2) { Status status; auto value_sp = m_value_ptr_sp->Dereference(status); if (status.Success()) { return value_sp; } } return lldb::ValueObjectSP(); } lldb::ChildCacheState lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) return lldb::ChildCacheState::eRefetch; ValueObjectSP pair_sp = valobj_sp->GetChildMemberWithName("_Mypair"); if (!pair_sp) return lldb::ChildCacheState::eRefetch; if (auto value_ptr_sp = pair_sp->GetChildMemberWithName("_Myval2")) m_value_ptr_sp = value_ptr_sp->Clone(ConstString("pointer")); // Only present if the deleter is non-empty if (auto deleter_sp = pair_sp->GetChildMemberWithName("_Myval1")) m_deleter_sp = deleter_sp->Clone(ConstString("deleter")); return lldb::ChildCacheState::eRefetch; } llvm::Expected lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { if (name == "pointer") return 0; if (name == "deleter") return 1; if (name == "obj" || name == "object" || name == "$$dereference$$") return 2; return llvm::createStringError("Type has no child named '%s'", name.AsCString()); } lldb_private::SyntheticChildrenFrontEnd * lldb_private::formatters::MsvcStlUniquePtrSyntheticFrontEndCreator( lldb::ValueObjectSP valobj_sp) { return new MsvcStlUniquePtrSyntheticFrontEnd(valobj_sp); }