Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibStdcppTuple.cpp
LibStdcppUniquePointer.cpp
MsvcStl.cpp
MsvcStlSmartPointer.cpp
MSVCUndecoratedNameParser.cpp

LINK_COMPONENTS
Expand Down
36 changes: 18 additions & 18 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1540,16 +1540,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
"std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$",
stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
"std::shared_ptr synthetic children", "^std::shared_ptr<.+>(( )?&)?$",
stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
"std::weak_ptr synthetic children", "^std::weak_ptr<.+>(( )?&)?$",
stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
Expand Down Expand Up @@ -1580,14 +1570,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
"libstdc++ std::unique_ptr summary provider",
"^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
"libstdc++ std::shared_ptr summary provider",
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
"libstdc++ std::weak_ptr summary provider",
"^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
"libstdc++ std::coroutine_handle summary provider",
Expand All @@ -1611,6 +1593,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
.SetDontShowValue(false)
.SetShowMembersOneLiner(false)
.SetHideItemNames(false);
SyntheticChildren::Flags stl_synth_flags;
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
false);

using StringElementType = StringPrinter::StringElementType;

RegisterStdStringSummaryProvider(
Expand All @@ -1636,6 +1622,20 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
return LibStdcppStringSummaryProvider(valobj, stream, options);
},
"MSVC STL/libstdc++ std::wstring summary provider"));

AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
"std::shared_ptr synthetic children",
"^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true);
AddCXXSynthetic(cpp_category_sp, GenericSmartPointerSyntheticFrontEndCreator,
"std::weak_ptr synthetic children",
"^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true);

AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::shared_ptr summary provider",
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider,
"MSVC STL/libstdc++ std::weak_ptr summary provider",
"^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
}

static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
Expand Down
20 changes: 19 additions & 1 deletion lldb/source/Plugins/Language/CPlusPlus/Generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//===---------------------------------------------------------------------===//

#include "Generic.h"
#include "LibStdcpp.h"
#include "MsvcStl.h"

lldb::ValueObjectSP lldb_private::formatters::GetDesugaredSmartPointerValue(
ValueObject &ptr, ValueObject &container) {
Expand All @@ -16,7 +18,23 @@ lldb::ValueObjectSP lldb_private::formatters::GetDesugaredSmartPointerValue(

auto arg = container_type.GetTypeTemplateArgument(0);
if (!arg)
return nullptr;
// If there isn't enough debug info, use the pointer type as is
return ptr.GetSP();

return ptr.Cast(arg.GetPointerType());
}

lldb_private::SyntheticChildrenFrontEnd *
lldb_private::formatters::GenericSmartPointerSyntheticFrontEndCreator(
CXXSyntheticChildren *children, lldb::ValueObjectSP valobj_sp) {
if (auto *msvc = MsvcStlSmartPointerSyntheticFrontEndCreator(valobj_sp))
return msvc;

return LibStdcppSharedPtrSyntheticFrontEndCreator(children, valobj_sp);
}

bool lldb_private::formatters::GenericSmartPointerSummaryProvider(
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
return MsvcStlSmartPointerSummaryProvider(valobj, stream, options) ||
LibStdcppSmartPointerSummaryProvider(valobj, stream, options);
}
7 changes: 7 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/Generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ bool GenericOptionalSummaryProvider(ValueObject &valobj, Stream &stream,
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr,
ValueObject &container);

// std::shared_ptr<>/std::weak_ptr<>
SyntheticChildrenFrontEnd *
GenericSmartPointerSyntheticFrontEndCreator(CXXSyntheticChildren *children,
lldb::ValueObjectSP valobj_sp);
bool GenericSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);

} // namespace formatters
} // namespace lldb_private

Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ bool MsvcStlWStringSummaryProvider(
ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options); // VC 2015+ std::wstring

// MSVC STL std::shared_ptr<> and std::weak_ptr<>
bool IsMsvcStlSmartPointer(ValueObject &valobj);
bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
const TypeSummaryOptions &options);

lldb_private::SyntheticChildrenFrontEnd *
MsvcStlSmartPointerSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp);

} // namespace formatters
} // namespace lldb_private

Expand Down
168 changes: 168 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/MsvcStlSmartPointer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//===-- 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) {
return valobj.GetChildMemberWithName("_Ptr") != nullptr;
}

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<uint32_t> CalculateNumChildren() override;

lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;

lldb::ChildCacheState Update() override;

llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;

~MsvcStlSmartPointerSyntheticFrontEnd() override;

private:
ValueObject *m_ptr_obj = nullptr;
};

} // namespace formatters
} // namespace lldb_private

lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {
if (valobj_sp)
Update();
}

llvm::Expected<uint32_t> 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<size_t>
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name) {
if (name == "_Ptr" || 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) {
if (!valobj_sp)
return nullptr;

if (!IsMsvcStlSmartPointer(*valobj_sp))
return nullptr;

return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ def test_libcxx(self):
def test_libstdcxx(self):
self.build(dictionary={"USE_LIBSTDCPP": 1})
self.do_test()

@add_test_categories(["msvcstl"])
def test_msvcstl(self):
# No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
self.build()
self.do_test()
Loading