Skip to content

Commit 8894b65

Browse files
committed
[LLDB] Add formatters for MSVC STL std::shared_ptr
1 parent bbefd33 commit 8894b65

File tree

6 files changed

+220
-19
lines changed

6 files changed

+220
-19
lines changed

lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
3434
LibStdcppTuple.cpp
3535
LibStdcppUniquePointer.cpp
3636
MsvcStl.cpp
37+
MsvcStlSmartPointer.cpp
3738
MSVCUndecoratedNameParser.cpp
3839

3940
LINK_COMPONENTS

lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,16 +1540,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
15401540
lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator,
15411541
"std::unique_ptr synthetic children", "^std::unique_ptr<.+>(( )?&)?$",
15421542
stl_synth_flags, true);
1543-
AddCXXSynthetic(
1544-
cpp_category_sp,
1545-
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1546-
"std::shared_ptr synthetic children", "^std::shared_ptr<.+>(( )?&)?$",
1547-
stl_synth_flags, true);
1548-
AddCXXSynthetic(
1549-
cpp_category_sp,
1550-
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
1551-
"std::weak_ptr synthetic children", "^std::weak_ptr<.+>(( )?&)?$",
1552-
stl_synth_flags, true);
15531543
AddCXXSynthetic(
15541544
cpp_category_sp,
15551545
lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
@@ -1580,14 +1570,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
15801570
lldb_private::formatters::LibStdcppUniquePointerSummaryProvider,
15811571
"libstdc++ std::unique_ptr summary provider",
15821572
"^std::unique_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1583-
AddCXXSummary(cpp_category_sp,
1584-
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1585-
"libstdc++ std::shared_ptr summary provider",
1586-
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1587-
AddCXXSummary(cpp_category_sp,
1588-
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
1589-
"libstdc++ std::weak_ptr summary provider",
1590-
"^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
15911573
AddCXXSummary(cpp_category_sp,
15921574
lldb_private::formatters::StdlibCoroutineHandleSummaryProvider,
15931575
"libstdc++ std::coroutine_handle summary provider",
@@ -1611,6 +1593,10 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16111593
.SetDontShowValue(false)
16121594
.SetShowMembersOneLiner(false)
16131595
.SetHideItemNames(false);
1596+
SyntheticChildren::Flags stl_synth_flags;
1597+
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
1598+
false);
1599+
16141600
using StringElementType = StringPrinter::StringElementType;
16151601

16161602
RegisterStdStringSummaryProvider(
@@ -1636,6 +1622,36 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16361622
return LibStdcppStringSummaryProvider(valobj, stream, options);
16371623
},
16381624
"MSVC STL/libstdc++ std::wstring summary provider"));
1625+
1626+
auto smart_ptr_creator =
1627+
[](CXXSyntheticChildren *children,
1628+
ValueObjectSP valobj_sp) -> SyntheticChildrenFrontEnd * {
1629+
if (!valobj_sp)
1630+
return nullptr;
1631+
1632+
if (auto *msvc = MsvcStlSmartPointerSyntheticFrontEndCreator(valobj_sp))
1633+
return msvc;
1634+
1635+
return LibStdcppSharedPtrSyntheticFrontEndCreator(children, valobj_sp);
1636+
};
1637+
AddCXXSynthetic(cpp_category_sp, smart_ptr_creator,
1638+
"std::shared_ptr synthetic children",
1639+
"^std::shared_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1640+
AddCXXSynthetic(cpp_category_sp, smart_ptr_creator,
1641+
"std::weak_ptr synthetic children",
1642+
"^std::weak_ptr<.+>(( )?&)?$", stl_synth_flags, true);
1643+
1644+
auto smart_ptr_summary = [](ValueObject &valobj, Stream &stream,
1645+
const TypeSummaryOptions &options) {
1646+
return MsvcStlSmartPointerSummaryProvider(valobj, stream, options) ||
1647+
LibStdcppSmartPointerSummaryProvider(valobj, stream, options);
1648+
};
1649+
AddCXXSummary(cpp_category_sp, smart_ptr_summary,
1650+
"MSVC STL/libstdc++ std::shared_ptr summary provider",
1651+
"^std::shared_ptr<.+>(( )?&)?$", stl_summary_flags, true);
1652+
AddCXXSummary(cpp_category_sp, smart_ptr_summary,
1653+
"MSVC STL/libstdc++ std::weak_ptr summary provider",
1654+
"^std::weak_ptr<.+>(( )?&)?$", stl_summary_flags, true);
16391655
}
16401656

16411657
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {

lldb/source/Plugins/Language/CPlusPlus/Generic.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ lldb::ValueObjectSP lldb_private::formatters::GetDesugaredSmartPointerValue(
1616

1717
auto arg = container_type.GetTypeTemplateArgument(0);
1818
if (!arg)
19-
return nullptr;
19+
return ptr.GetSP(); // FIXME: PDB doesn't have info about template arguments
2020

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

lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ bool MsvcStlWStringSummaryProvider(
2929
ValueObject &valobj, Stream &stream,
3030
const TypeSummaryOptions &options); // VC 2015+ std::wstring
3131

32+
// MSVC STL std::shared_ptr<> and std::weak_ptr<>
33+
bool IsMsvcStlSmartPointer(ValueObject &valobj);
34+
bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
35+
const TypeSummaryOptions &options);
36+
37+
lldb_private::SyntheticChildrenFrontEnd *
38+
MsvcStlSmartPointerSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp);
39+
3240
} // namespace formatters
3341
} // namespace lldb_private
3442

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
//===-- MsvcStlSmartPointer.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 "Generic.h"
10+
#include "MsvcStl.h"
11+
12+
#include "lldb/DataFormatters/FormattersHelpers.h"
13+
#include "lldb/DataFormatters/TypeSynthetic.h"
14+
15+
using namespace lldb;
16+
17+
bool lldb_private::formatters::IsMsvcStlSmartPointer(ValueObject &valobj) {
18+
std::vector<uint32_t> indexes;
19+
return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Ptr", true,
20+
indexes) > 0;
21+
}
22+
23+
bool lldb_private::formatters::MsvcStlSmartPointerSummaryProvider(
24+
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
25+
ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
26+
if (!valobj_sp)
27+
return false;
28+
29+
ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_Ptr"));
30+
ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName("_Rep"));
31+
if (!ctrl_sp || !ptr_sp)
32+
return false;
33+
34+
DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
35+
36+
bool success;
37+
uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(0, &success);
38+
// Empty control field (expired)
39+
if (!success || ctrl_addr == 0)
40+
return true;
41+
42+
uint64_t uses = 0;
43+
if (auto uses_sp = ctrl_sp->GetChildMemberWithName("_Uses")) {
44+
bool success;
45+
uses = uses_sp->GetValueAsUnsigned(0, &success);
46+
if (!success)
47+
return false;
48+
49+
stream.Printf(" strong=%" PRIu64, uses);
50+
}
51+
52+
// _Weaks is the number of weak references - (_Uses != 0).
53+
if (auto weak_count_sp = ctrl_sp->GetChildMemberWithName("_Weaks")) {
54+
bool success;
55+
uint64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
56+
if (!success)
57+
return false;
58+
59+
stream.Printf(" weak=%" PRIu64, count - (uses != 0));
60+
}
61+
62+
return true;
63+
}
64+
65+
namespace lldb_private {
66+
namespace formatters {
67+
68+
class MsvcStlSmartPointerSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
69+
public:
70+
MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
71+
72+
llvm::Expected<uint32_t> CalculateNumChildren() override;
73+
74+
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
75+
76+
lldb::ChildCacheState Update() override;
77+
78+
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
79+
80+
~MsvcStlSmartPointerSyntheticFrontEnd() override;
81+
82+
private:
83+
ValueObject *m_ptr_obj = nullptr;
84+
};
85+
86+
} // namespace formatters
87+
} // namespace lldb_private
88+
89+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
90+
MsvcStlSmartPointerSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
91+
: SyntheticChildrenFrontEnd(*valobj_sp) {
92+
if (valobj_sp)
93+
Update();
94+
}
95+
96+
llvm::Expected<uint32_t> lldb_private::formatters::
97+
MsvcStlSmartPointerSyntheticFrontEnd::CalculateNumChildren() {
98+
return (m_ptr_obj ? 1 : 0);
99+
}
100+
101+
lldb::ValueObjectSP
102+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::GetChildAtIndex(
103+
uint32_t idx) {
104+
if (!m_ptr_obj)
105+
return lldb::ValueObjectSP();
106+
107+
ValueObjectSP valobj_sp = m_backend.GetSP();
108+
if (!valobj_sp)
109+
return lldb::ValueObjectSP();
110+
111+
if (idx == 0)
112+
return m_ptr_obj->GetSP();
113+
114+
if (idx == 1) {
115+
Status status;
116+
ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
117+
if (status.Success())
118+
return value_sp;
119+
}
120+
121+
return lldb::ValueObjectSP();
122+
}
123+
124+
lldb::ChildCacheState
125+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::Update() {
126+
m_ptr_obj = nullptr;
127+
128+
ValueObjectSP valobj_sp = m_backend.GetSP();
129+
if (!valobj_sp)
130+
return lldb::ChildCacheState::eRefetch;
131+
132+
auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_Ptr");
133+
if (!ptr_obj_sp)
134+
return lldb::ChildCacheState::eRefetch;
135+
136+
auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
137+
if (!cast_ptr_sp)
138+
return lldb::ChildCacheState::eRefetch;
139+
140+
m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();
141+
return lldb::ChildCacheState::eRefetch;
142+
}
143+
144+
llvm::Expected<size_t>
145+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
146+
GetIndexOfChildWithName(ConstString name) {
147+
if (name == "_Ptr" || name == "pointer")
148+
return 0;
149+
150+
if (name == "object" || name == "$$dereference$$")
151+
return 1;
152+
153+
return llvm::createStringError("Type has no child named '%s'",
154+
name.AsCString());
155+
}
156+
157+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEnd::
158+
~MsvcStlSmartPointerSyntheticFrontEnd() = default;
159+
160+
lldb_private::SyntheticChildrenFrontEnd *
161+
lldb_private::formatters::MsvcStlSmartPointerSyntheticFrontEndCreator(
162+
lldb::ValueObjectSP valobj_sp) {
163+
if (!valobj_sp)
164+
return nullptr;
165+
166+
if (!IsMsvcStlSmartPointer(*valobj_sp))
167+
return nullptr;
168+
169+
return new MsvcStlSmartPointerSyntheticFrontEnd(valobj_sp);
170+
}

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/shared_ptr/TestDataFormatterStdSharedPtr.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,9 @@ def test_libcxx(self):
118118
def test_libstdcxx(self):
119119
self.build(dictionary={"USE_LIBSTDCPP": 1})
120120
self.do_test()
121+
122+
@add_test_categories(["msvcstl"])
123+
def test_msvcstl(self):
124+
# No flags, because the "msvcstl" category checks that the MSVC STL is used by default.
125+
self.build(dictionary={})
126+
self.do_test()

0 commit comments

Comments
 (0)