Skip to content

Commit df58984

Browse files
committed
[LLDB] Add type summaries for MSVC STL strings
1 parent 463ce01 commit df58984

File tree

18 files changed

+564
-159
lines changed

18 files changed

+564
-159
lines changed

lldb/packages/Python/lldbsuite/test/dotest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,46 @@ def checkLibstdcxxSupport():
831831
configuration.skip_categories.append("libstdcxx")
832832

833833

834+
def canRunMsvcStlTests():
835+
from lldbsuite.test import lldbplatformutil
836+
837+
platform = lldbplatformutil.getPlatform()
838+
if platform != "windows":
839+
return False, f"Don't know how to build with MSVC's STL on {platform}"
840+
841+
with tempfile.NamedTemporaryFile() as f:
842+
cmd = [configuration.compiler, "-xc++", "-o", f.name, "-E", "-"]
843+
p = subprocess.Popen(
844+
cmd,
845+
stdin=subprocess.PIPE,
846+
stdout=subprocess.PIPE,
847+
stderr=subprocess.PIPE,
848+
universal_newlines=True,
849+
)
850+
_, stderr = p.communicate(
851+
"""
852+
#include <yvals_core.h>
853+
#ifndef _MSVC_STL_VERSION
854+
#error _MSVC_STL_VERSION not defined
855+
#endif
856+
"""
857+
)
858+
if not p.returncode:
859+
return True, "Compiling with MSVC STL"
860+
return (False, f"Not compiling with MSVC STL: {stderr}")
861+
862+
863+
def checkMsvcStlSupport():
864+
result, reason = canRunMsvcStlTests()
865+
if result:
866+
return # msvcstl supported
867+
if "msvcstl" in configuration.categories_list:
868+
return # msvcstl category explicitly requested, let it run.
869+
if configuration.verbose:
870+
print(f"msvcstl tests will not be run because: {reason}")
871+
configuration.skip_categories.append("msvcstl")
872+
873+
834874
def canRunWatchpointTests():
835875
from lldbsuite.test import lldbplatformutil
836876

@@ -1044,6 +1084,7 @@ def run_suite():
10441084

10451085
checkLibcxxSupport()
10461086
checkLibstdcxxSupport()
1087+
checkMsvcStlSupport()
10471088
checkWatchpointSupport()
10481089
checkDebugInfoSupport()
10491090
checkDebugServerSupport()

lldb/packages/Python/lldbsuite/test/test_categories.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"lldb-server": "Tests related to lldb-server",
3434
"lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
3535
"llgs": "Tests for the gdb-server functionality of lldb-server",
36+
"msvcstl": "Test for MSVC STL data formatters",
3637
"pexpect": "Tests requiring the pexpect library to be available",
3738
"objc": "Tests related to the Objective-C programming language support",
3839
"pyapi": "Tests related to the Python API",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
3232
LibStdcpp.cpp
3333
LibStdcppTuple.cpp
3434
LibStdcppUniquePointer.cpp
35+
MsvcStl.cpp
3536
MSVCUndecoratedNameParser.cpp
3637

3738
LINK_COMPONENTS

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

Lines changed: 110 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "LibCxxVariant.h"
4747
#include "LibStdcpp.h"
4848
#include "MSVCUndecoratedNameParser.h"
49+
#include "MsvcStl.h"
4950
#include "lldb/lldb-enumerations.h"
5051

5152
using namespace lldb;
@@ -1372,6 +1373,37 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
13721373
"${var.__y_} ${var.__m_} ${var.__wdl_}")));
13731374
}
13741375

1376+
static void RegisterStdStringSummaryProvider(
1377+
const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
1378+
llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
1379+
auto makeSpecifier = [](llvm::StringRef name) {
1380+
return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
1381+
name, eFormatterMatchExact);
1382+
};
1383+
1384+
category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
1385+
1386+
// std::basic_string<char>
1387+
category_sp->AddTypeSummary(
1388+
makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
1389+
summary_sp);
1390+
// std::basic_string<char,std::char_traits<char>,std::allocator<char> >
1391+
category_sp->AddTypeSummary(
1392+
makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>,"
1393+
"std::allocator<{0}> >",
1394+
char_ty)
1395+
.str()),
1396+
summary_sp);
1397+
// std::basic_string<char, std::char_traits<char>, std::allocator<char> >
1398+
category_sp->AddTypeSummary(
1399+
makeSpecifier(
1400+
llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, "
1401+
"std::allocator<{0}> >",
1402+
char_ty)
1403+
.str()),
1404+
summary_sp);
1405+
}
1406+
13751407
static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
13761408
if (!cpp_category_sp)
13771409
return;
@@ -1385,27 +1417,13 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
13851417
.SetShowMembersOneLiner(false)
13861418
.SetHideItemNames(false);
13871419

1388-
lldb::TypeSummaryImplSP std_string_summary_sp(
1389-
new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}"));
1390-
13911420
lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat(
13921421
stl_summary_flags, LibStdcppStringSummaryProvider,
13931422
"libstdc++ c++11 std::string summary provider"));
13941423
lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat(
1395-
stl_summary_flags, LibStdcppWStringSummaryProvider,
1424+
stl_summary_flags, LibStdcppStringSummaryProvider,
13961425
"libstdc++ c++11 std::wstring summary provider"));
13971426

1398-
cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact,
1399-
std_string_summary_sp);
1400-
cpp_category_sp->AddTypeSummary("std::basic_string<char>",
1401-
eFormatterMatchExact, std_string_summary_sp);
1402-
cpp_category_sp->AddTypeSummary(
1403-
"std::basic_string<char,std::char_traits<char>,std::allocator<char> >",
1404-
eFormatterMatchExact, std_string_summary_sp);
1405-
cpp_category_sp->AddTypeSummary(
1406-
"std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
1407-
eFormatterMatchExact, std_string_summary_sp);
1408-
14091427
cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact,
14101428
cxx11_string_summary_sp);
14111429
cpp_category_sp->AddTypeSummary(
@@ -1418,23 +1436,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
14181436
eFormatterMatchExact,
14191437
cxx11_string_summary_sp);
14201438

1421-
// making sure we force-pick the summary for printing wstring (_M_p is a
1422-
// wchar_t*)
1423-
lldb::TypeSummaryImplSP std_wstring_summary_sp(
1424-
new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}"));
1425-
1426-
cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact,
1427-
std_wstring_summary_sp);
1428-
cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t>",
1429-
eFormatterMatchExact, std_wstring_summary_sp);
1430-
cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t,std::char_traits<"
1431-
"wchar_t>,std::allocator<wchar_t> >",
1432-
eFormatterMatchExact, std_wstring_summary_sp);
1433-
cpp_category_sp->AddTypeSummary(
1434-
"std::basic_string<wchar_t, std::char_traits<wchar_t>, "
1435-
"std::allocator<wchar_t> >",
1436-
eFormatterMatchExact, std_wstring_summary_sp);
1437-
14381439
cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact,
14391440
cxx11_wstring_summary_sp);
14401441
cpp_category_sp->AddTypeSummary(
@@ -1629,6 +1630,81 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16291630
"^std::optional<.+>(( )?&)?$", stl_summary_flags, true);
16301631
}
16311632

1633+
/// Load formatters that are formatting types from more than one STL
1634+
static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1635+
if (!cpp_category_sp)
1636+
return;
1637+
1638+
TypeSummaryImpl::Flags stl_summary_flags;
1639+
stl_summary_flags.SetCascades(true)
1640+
.SetSkipPointers(false)
1641+
.SetSkipReferences(false)
1642+
.SetDontShowChildren(true)
1643+
.SetDontShowValue(false)
1644+
.SetShowMembersOneLiner(false)
1645+
.SetHideItemNames(false);
1646+
using StringElementType = StringPrinter::StringElementType;
1647+
1648+
RegisterStdStringSummaryProvider(
1649+
cpp_category_sp, "std::string", "char",
1650+
std::make_shared<CXXFunctionSummaryFormat>(
1651+
stl_summary_flags,
1652+
[](ValueObject &valobj, Stream &stream,
1653+
const TypeSummaryOptions &options) {
1654+
if (IsMsvcStlStringType(valobj))
1655+
return MsvcStlStringSummaryProvider<StringElementType::ASCII>(
1656+
valobj, stream, options);
1657+
return LibStdcppStringSummaryProvider(valobj, stream, options);
1658+
},
1659+
"MSVC STL/libstdc++ std::string summary provider"));
1660+
RegisterStdStringSummaryProvider(
1661+
cpp_category_sp, "std::wstring", "wchar_t",
1662+
std::make_shared<CXXFunctionSummaryFormat>(
1663+
stl_summary_flags,
1664+
[](ValueObject &valobj, Stream &stream,
1665+
const TypeSummaryOptions &options) {
1666+
if (IsMsvcStlStringType(valobj))
1667+
return MsvcStlWStringSummaryProvider(valobj, stream, options);
1668+
return LibStdcppStringSummaryProvider(valobj, stream, options);
1669+
},
1670+
"MSVC STL/libstdc++ std::wstring summary provider"));
1671+
}
1672+
1673+
static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
1674+
if (!cpp_category_sp)
1675+
return;
1676+
1677+
TypeSummaryImpl::Flags stl_summary_flags;
1678+
stl_summary_flags.SetCascades(true)
1679+
.SetSkipPointers(false)
1680+
.SetSkipReferences(false)
1681+
.SetDontShowChildren(true)
1682+
.SetDontShowValue(false)
1683+
.SetShowMembersOneLiner(false)
1684+
.SetHideItemNames(false);
1685+
1686+
using StringElementType = StringPrinter::StringElementType;
1687+
1688+
RegisterStdStringSummaryProvider(
1689+
cpp_category_sp, "std::u8string", "char8_t",
1690+
std::make_shared<CXXFunctionSummaryFormat>(
1691+
stl_summary_flags,
1692+
MsvcStlStringSummaryProvider<StringElementType::UTF8>,
1693+
"MSVC STL std::u8string summary provider"));
1694+
RegisterStdStringSummaryProvider(
1695+
cpp_category_sp, "std::u16string", "char16_t",
1696+
std::make_shared<CXXFunctionSummaryFormat>(
1697+
stl_summary_flags,
1698+
MsvcStlStringSummaryProvider<StringElementType::UTF16>,
1699+
"MSVC STL std::u16string summary provider"));
1700+
RegisterStdStringSummaryProvider(
1701+
cpp_category_sp, "std::u32string", "char32_t",
1702+
std::make_shared<CXXFunctionSummaryFormat>(
1703+
stl_summary_flags,
1704+
MsvcStlStringSummaryProvider<StringElementType::UTF32>,
1705+
"MSVC STL std::u32string summary provider"));
1706+
}
1707+
16321708
static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
16331709
if (!cpp_category_sp)
16341710
return;
@@ -1743,6 +1819,8 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() {
17431819
// LLDB prioritizes the last loaded matching formatter.
17441820
LoadLibCxxFormatters(g_category);
17451821
LoadLibStdcppFormatters(g_category);
1822+
LoadMsvcStlFormatters(g_category);
1823+
LoadCommonStlFormatters(g_category);
17461824
LoadSystemFormatters(g_category);
17471825
}
17481826
});

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

Lines changed: 6 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "LibStdcpp.h"
10+
#include "CxxStringTypes.h"
1011
#include "LibCxx.h"
1112

1213
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
@@ -239,122 +240,12 @@ VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
239240

240241
bool lldb_private::formatters::LibStdcppStringSummaryProvider(
241242
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
242-
const bool scalar_is_load_addr = true;
243-
auto [addr_of_string, addr_type] =
244-
valobj.IsPointerOrReferenceType()
245-
? valobj.GetPointerValue()
246-
: valobj.GetAddressOf(scalar_is_load_addr);
247-
if (addr_of_string != LLDB_INVALID_ADDRESS) {
248-
switch (addr_type) {
249-
case eAddressTypeLoad: {
250-
ProcessSP process_sp(valobj.GetProcessSP());
251-
if (!process_sp)
252-
return false;
253-
254-
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
255-
Status error;
256-
lldb::addr_t addr_of_data =
257-
process_sp->ReadPointerFromMemory(addr_of_string, error);
258-
if (error.Fail() || addr_of_data == 0 ||
259-
addr_of_data == LLDB_INVALID_ADDRESS)
260-
return false;
261-
options.SetLocation(addr_of_data);
262-
options.SetTargetSP(valobj.GetTargetSP());
263-
options.SetStream(&stream);
264-
options.SetNeedsZeroTermination(false);
265-
options.SetBinaryZeroIsTerminator(true);
266-
lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
267-
addr_of_string + process_sp->GetAddressByteSize(), error);
268-
if (error.Fail())
269-
return false;
270-
options.SetSourceSize(size_of_data);
271-
options.SetHasSourceSize(true);
272-
273-
if (!StringPrinter::ReadStringAndDumpToStream<
274-
StringPrinter::StringElementType::UTF8>(options)) {
275-
stream.Printf("Summary Unavailable");
276-
return true;
277-
} else
278-
return true;
279-
} break;
280-
case eAddressTypeHost:
281-
break;
282-
case eAddressTypeInvalid:
283-
case eAddressTypeFile:
284-
break;
285-
}
286-
}
287-
return false;
288-
}
243+
ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
244+
if (!ptr)
245+
return false;
289246

290-
bool lldb_private::formatters::LibStdcppWStringSummaryProvider(
291-
ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
292-
const bool scalar_is_load_addr = true;
293-
auto [addr_of_string, addr_type] = valobj.GetAddressOf(scalar_is_load_addr);
294-
if (addr_of_string != LLDB_INVALID_ADDRESS) {
295-
switch (addr_type) {
296-
case eAddressTypeLoad: {
297-
ProcessSP process_sp(valobj.GetProcessSP());
298-
if (!process_sp)
299-
return false;
300-
301-
CompilerType wchar_compiler_type =
302-
valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
303-
304-
if (!wchar_compiler_type)
305-
return false;
306-
307-
// Safe to pass nullptr for exe_scope here.
308-
std::optional<uint64_t> size =
309-
llvm::expectedToOptional(wchar_compiler_type.GetBitSize(nullptr));
310-
if (!size)
311-
return false;
312-
const uint32_t wchar_size = *size;
313-
314-
StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
315-
Status error;
316-
lldb::addr_t addr_of_data =
317-
process_sp->ReadPointerFromMemory(addr_of_string, error);
318-
if (error.Fail() || addr_of_data == 0 ||
319-
addr_of_data == LLDB_INVALID_ADDRESS)
320-
return false;
321-
options.SetLocation(addr_of_data);
322-
options.SetTargetSP(valobj.GetTargetSP());
323-
options.SetStream(&stream);
324-
options.SetNeedsZeroTermination(false);
325-
options.SetBinaryZeroIsTerminator(false);
326-
lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(
327-
addr_of_string + process_sp->GetAddressByteSize(), error);
328-
if (error.Fail())
329-
return false;
330-
options.SetSourceSize(size_of_data);
331-
options.SetHasSourceSize(true);
332-
options.SetPrefixToken("L");
333-
334-
switch (wchar_size) {
335-
case 8:
336-
return StringPrinter::ReadStringAndDumpToStream<
337-
StringPrinter::StringElementType::UTF8>(options);
338-
case 16:
339-
return StringPrinter::ReadStringAndDumpToStream<
340-
StringPrinter::StringElementType::UTF16>(options);
341-
case 32:
342-
return StringPrinter::ReadStringAndDumpToStream<
343-
StringPrinter::StringElementType::UTF32>(options);
344-
default:
345-
stream.Printf("size for wchar_t is not valid");
346-
return true;
347-
}
348-
return true;
349-
} break;
350-
case eAddressTypeHost:
351-
break;
352-
case eAddressTypeInvalid:
353-
case eAddressTypeFile:
354-
break;
355-
}
356-
}
357-
return false;
247+
stream << ptr->GetSummaryAsCString();
248+
return true;
358249
}
359250

360251
LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(

0 commit comments

Comments
 (0)