diff options
| author | nerix <nerixdev@outlook.de> | 2025-07-08 10:55:18 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-08 09:55:18 +0100 |
| commit | 45689b26eb4bfa619127013dccea8efd8de4d21a (patch) | |
| tree | 232bae8e440a57b8b1ec54583ae72047e7bdb97b /lldb/source/Plugins/Language | |
| parent | 29487759e3cc8fc056a599a38b3a6d2d8849a20e (diff) | |
[LLDB] Add type summaries for MSVC STL strings (#143177)
This PR adds type summaries for
`std::{string,wstring,u8string,u16string,u32string}` from the MSVC STL.
See https://github.com/llvm/llvm-project/issues/24834 for the MSVC STL
issue.
The following changes were made:
- `dotest.py` now detects if the MSVC STL is available. It does so by
looking at the target triple, which is an additional argument passed
from Lit. It specifically checks for `windows-msvc` to not match on
`windows-gnu` (i.e. MinGW/Cygwin).
- (The main part): Added support for summarizing `std::(w)string` from
MSVC's STL. Because the type names from the libstdc++ (pre C++ 11)
string types are the same as on MSVC's STL, `CXXCompositeSummaryFormat`
is used with two entries, one for MSVC's STL and one for libstdc++.
With MSVC's STL, `std::u{8,16,32}string` is also handled. These aren't
handled for libstdc++, so I put them in `LoadMsvcStlFormatters`.
Diffstat (limited to 'lldb/source/Plugins/Language')
4 files changed, 300 insertions, 29 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 5ba2567c80cc..bbfc31a722f2 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -32,6 +32,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibStdcpp.cpp LibStdcppTuple.cpp LibStdcppUniquePointer.cpp + MsvcStl.cpp MSVCUndecoratedNameParser.cpp LINK_COMPONENTS diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index e64b3ebabd74..17963c0273ba 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -46,6 +46,7 @@ #include "LibCxxVariant.h" #include "LibStdcpp.h" #include "MSVCUndecoratedNameParser.h" +#include "MsvcStl.h" #include "lldb/lldb-enumerations.h" using namespace lldb; @@ -1331,6 +1332,37 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "${var.__y_} ${var.__m_} ${var.__wdl_}"))); } +static void RegisterStdStringSummaryProvider( + const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty, + llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) { + auto makeSpecifier = [](llvm::StringRef name) { + return std::make_shared<lldb_private::TypeNameSpecifierImpl>( + name, eFormatterMatchExact); + }; + + category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp); + + // std::basic_string<char> + category_sp->AddTypeSummary( + makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()), + summary_sp); + // std::basic_string<char,std::char_traits<char>,std::allocator<char> > + category_sp->AddTypeSummary( + makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>," + "std::allocator<{0}> >", + char_ty) + .str()), + summary_sp); + // std::basic_string<char, std::char_traits<char>, std::allocator<char> > + category_sp->AddTypeSummary( + makeSpecifier( + llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, " + "std::allocator<{0}> >", + char_ty) + .str()), + summary_sp); +} + static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) return; @@ -1347,18 +1379,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb::TypeSummaryImplSP string_summary_sp(new CXXFunctionSummaryFormat( stl_summary_flags, LibStdcppStringSummaryProvider, "libstdc++ std::(w)string summary provider")); - - cpp_category_sp->AddTypeSummary("std::string", eFormatterMatchExact, - string_summary_sp); - cpp_category_sp->AddTypeSummary("std::basic_string<char>", - eFormatterMatchExact, string_summary_sp); - cpp_category_sp->AddTypeSummary( - "std::basic_string<char,std::char_traits<char>,std::allocator<char> >", - eFormatterMatchExact, string_summary_sp); - cpp_category_sp->AddTypeSummary( - "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", - eFormatterMatchExact, string_summary_sp); - cpp_category_sp->AddTypeSummary("std::__cxx11::string", eFormatterMatchExact, string_summary_sp); cpp_category_sp->AddTypeSummary( @@ -1370,23 +1390,6 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "std::allocator<unsigned char> >", eFormatterMatchExact, string_summary_sp); - // making sure we force-pick the summary for printing wstring (_M_p is a - // wchar_t*) - lldb::TypeSummaryImplSP std_wstring_summary_sp( - new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}")); - - cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact, - std_wstring_summary_sp); - cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t>", - eFormatterMatchExact, std_wstring_summary_sp); - cpp_category_sp->AddTypeSummary("std::basic_string<wchar_t,std::char_traits<" - "wchar_t>,std::allocator<wchar_t> >", - eFormatterMatchExact, std_wstring_summary_sp); - cpp_category_sp->AddTypeSummary( - "std::basic_string<wchar_t, std::char_traits<wchar_t>, " - "std::allocator<wchar_t> >", - eFormatterMatchExact, std_wstring_summary_sp); - cpp_category_sp->AddTypeSummary("std::__cxx11::wstring", eFormatterMatchExact, string_summary_sp); cpp_category_sp->AddTypeSummary( @@ -1595,6 +1598,81 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "^std::optional<.+>(( )?&)?$", stl_summary_flags, true); } +/// Load formatters that are formatting types from more than one STL +static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { + if (!cpp_category_sp) + return; + + TypeSummaryImpl::Flags stl_summary_flags; + stl_summary_flags.SetCascades(true) + .SetSkipPointers(false) + .SetSkipReferences(false) + .SetDontShowChildren(true) + .SetDontShowValue(false) + .SetShowMembersOneLiner(false) + .SetHideItemNames(false); + using StringElementType = StringPrinter::StringElementType; + + RegisterStdStringSummaryProvider( + cpp_category_sp, "std::string", "char", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + [](ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + if (IsMsvcStlStringType(valobj)) + return MsvcStlStringSummaryProvider<StringElementType::ASCII>( + valobj, stream, options); + return LibStdcppStringSummaryProvider(valobj, stream, options); + }, + "MSVC STL/libstdc++ std::string summary provider")); + RegisterStdStringSummaryProvider( + cpp_category_sp, "std::wstring", "wchar_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + [](ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + if (IsMsvcStlStringType(valobj)) + return MsvcStlWStringSummaryProvider(valobj, stream, options); + return LibStdcppStringSummaryProvider(valobj, stream, options); + }, + "MSVC STL/libstdc++ std::wstring summary provider")); +} + +static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { + if (!cpp_category_sp) + return; + + TypeSummaryImpl::Flags stl_summary_flags; + stl_summary_flags.SetCascades(true) + .SetSkipPointers(false) + .SetSkipReferences(false) + .SetDontShowChildren(true) + .SetDontShowValue(false) + .SetShowMembersOneLiner(false) + .SetHideItemNames(false); + + using StringElementType = StringPrinter::StringElementType; + + RegisterStdStringSummaryProvider( + cpp_category_sp, "std::u8string", "char8_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringSummaryProvider<StringElementType::UTF8>, + "MSVC STL std::u8string summary provider")); + RegisterStdStringSummaryProvider( + cpp_category_sp, "std::u16string", "char16_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringSummaryProvider<StringElementType::UTF16>, + "MSVC STL std::u16string summary provider")); + RegisterStdStringSummaryProvider( + cpp_category_sp, "std::u32string", "char32_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringSummaryProvider<StringElementType::UTF32>, + "MSVC STL std::u32string summary provider")); +} + static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) return; @@ -1709,6 +1787,8 @@ lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { // LLDB prioritizes the last loaded matching formatter. LoadLibCxxFormatters(g_category); LoadLibStdcppFormatters(g_category); + LoadMsvcStlFormatters(g_category); + LoadCommonStlFormatters(g_category); LoadSystemFormatters(g_category); } }); diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp new file mode 100644 index 000000000000..5d0f20b1beaa --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp @@ -0,0 +1,155 @@ +//===-- MsvcStl.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 "MsvcStl.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/FormatEntity.h" +#include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/ValueObject/ValueObject.h" + +#include "Plugins/Language/CPlusPlus/CxxStringTypes.h" + +#include "lldb/lldb-forward.h" +#include <optional> +#include <tuple> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +using StringElementType = StringPrinter::StringElementType; + +template <StringElementType element_type> +static constexpr uint64_t StringElementByteSize() { + switch (element_type) { + case StringElementType::ASCII: + case StringElementType::UTF8: + return 1; + case StringElementType::UTF16: + return 2; + case StringElementType::UTF32: + return 3; + } + return 0; +} + +static ValueObjectSP ExtractMsvcStlStringData(ValueObject &valobj) { + return valobj.GetChildAtNamePath({"_Mypair", "_Myval2"}); +} + +/// Determine the size in bytes of \p valobj (a MSVC STL std::string object) and +/// extract its data payload. Return the size + payload pair. +static std::optional<std::pair<uint64_t, ValueObjectSP>> +ExtractMsvcStlStringInfo(ValueObject &valobj, uint64_t element_size) { + ValueObjectSP valobj_pair_sp = ExtractMsvcStlStringData(valobj); + if (!valobj_pair_sp || !valobj_pair_sp->GetError().Success()) + return {}; + + ValueObjectSP size_sp = valobj_pair_sp->GetChildMemberWithName("_Mysize"); + ValueObjectSP capacity_sp = valobj_pair_sp->GetChildMemberWithName("_Myres"); + ValueObjectSP bx_sp = valobj_pair_sp->GetChildMemberWithName("_Bx"); + if (!size_sp || !capacity_sp || !bx_sp) + return {}; + + bool success = false; + uint64_t size = size_sp->GetValueAsUnsigned(0, &success); + if (!success) + return {}; + uint64_t capacity = capacity_sp->GetValueAsUnsigned(0, &success); + if (!success) + return {}; + + size_t bufSize = std::max<size_t>(16 / element_size, 1); + bool isShortString = capacity < bufSize; + + if (isShortString) { + ValueObjectSP buf_sp = bx_sp->GetChildMemberWithName("_Buf"); + if (buf_sp) + return std::make_pair(size, buf_sp); + return {}; + } + ValueObjectSP ptr_sp = bx_sp->GetChildMemberWithName("_Ptr"); + if (ptr_sp) + return std::make_pair(size, ptr_sp); + return {}; +} + +template <StringPrinter::StringElementType element_type> +static bool +MsvcStlStringSummaryProviderImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + auto string_info = + ExtractMsvcStlStringInfo(valobj, StringElementByteSize<element_type>()); + if (!string_info) + return false; + auto [size, location_sp] = *string_info; + + return StringBufferSummaryProvider<element_type>( + stream, summary_options, location_sp, size, prefix_token); +} +template <StringPrinter::StringElementType element_type> +static bool formatStringImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + StreamString scratch_stream; + const bool success = MsvcStlStringSummaryProviderImpl<element_type>( + valobj, scratch_stream, summary_options, prefix_token); + if (success) + stream << scratch_stream.GetData(); + else + stream << "Summary Unavailable"; + return true; +} + +bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) { + std::vector<uint32_t> indexes; + return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true, + indexes) > 0; +} + +bool lldb_private::formatters::MsvcStlWStringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringImpl<StringElementType::UTF16>(valobj, stream, + summary_options, "L"); +} + +template <> +bool lldb_private::formatters::MsvcStlStringSummaryProvider< + StringElementType::ASCII>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return MsvcStlStringSummaryProviderImpl<StringElementType::ASCII>( + valobj, stream, summary_options, ""); +} +template <> +bool lldb_private::formatters::MsvcStlStringSummaryProvider< + StringElementType::UTF8>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return MsvcStlStringSummaryProviderImpl<StringElementType::UTF8>( + valobj, stream, summary_options, "u8"); +} +template <> +bool lldb_private::formatters::MsvcStlStringSummaryProvider< + StringElementType::UTF16>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return MsvcStlStringSummaryProviderImpl<StringElementType::UTF16>( + valobj, stream, summary_options, "u"); +} +template <> +bool lldb_private::formatters::MsvcStlStringSummaryProvider< + StringElementType::UTF32>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>( + valobj, stream, summary_options, "U"); +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h new file mode 100644 index 000000000000..e4ed923033aa --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -0,0 +1,35 @@ +//===-- MsvcStl.h -----------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H +#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_MSVCSTL_H + +#include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/Utility/Stream.h" +#include "lldb/ValueObject/ValueObject.h" + +namespace lldb_private { +namespace formatters { + +bool IsMsvcStlStringType(ValueObject &valobj); + +template <StringPrinter::StringElementType element_type> +bool MsvcStlStringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions + &summary_options); // VC 2015+ std::string,u8string,u16string,u32string + +bool MsvcStlWStringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // VC 2015+ std::wstring + +} // namespace formatters +} // namespace lldb_private + +#endif |
