https://github.com/Nerixyz created https://github.com/llvm/llvm-project/pull/143177
This PR explores if type summaries for MSVC's STL can be added without modifying the data formatter infrastructure. The string summary function for libstdc++ now checks for MSVC's STL string as well (as both have the same type name). `Libcxx(W)StringSummaryProvider` was moved to `CxxStringTypes.h` so MSVC STL types can use it as well. This still needs tests and summaries for u{8,16,32} strings (libstdc++ doesn't seem to have them either). See https://github.com/llvm/llvm-project/issues/24834 for the MSVC STL issue. >From cb01d6a9d73730b304d001d4b54de436698a5d57 Mon Sep 17 00:00:00 2001 From: Nerixyz <nerix...@outlook.de> Date: Fri, 6 Jun 2025 19:23:04 +0200 Subject: [PATCH] [LLDB] Add type summaries for MSVC STL strings --- .../lldb/DataFormatters/StringPrinter.h | 15 ++ .../Plugins/Language/CPlusPlus/CMakeLists.txt | 1 + .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 42 ++++- .../Language/CPlusPlus/CxxStringTypes.cpp | 158 +++++++++++++++++- .../Language/CPlusPlus/CxxStringTypes.h | 35 ++++ .../Plugins/Language/CPlusPlus/LibCxx.cpp | 121 +------------- .../Plugins/Language/CPlusPlus/MsvcStl.cpp | 140 ++++++++++++++++ .../Plugins/Language/CPlusPlus/MsvcStl.h | 32 ++++ 8 files changed, 419 insertions(+), 125 deletions(-) create mode 100644 lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp create mode 100644 lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h index 4169f53e63f38..4ebe712be60e1 100644 --- a/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -152,6 +152,21 @@ class StringPrinter { template <StringElementType element_type> static bool ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options); + + template <StringElementType element_type> + static constexpr uint64_t ElementByteSize() { + switch (element_type) { + case StringElementType::ASCII: + case StringElementType::UTF8: + return 1; + case StringElementType::UTF16: + return 2; + case StringElementType::UTF32: + return 3; + default: + return 0; + } + } }; } // namespace formatters diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 5ba2567c80cc3..bbfc31a722f27 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 0f18abb47591d..1f186a16d45dc 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; @@ -1372,6 +1373,33 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "${var.__y_} ${var.__m_} ${var.__wdl_}"))); } +template <StringPrinter::StringElementType element_type> +static bool +LibstdcppOrMsvcStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + ValueObjectSP libstdcpp = valobj.GetChildMemberWithName("_M_dataplus"); + if (libstdcpp) { + ValueObjectSP ptr = libstdcpp->GetChildMemberWithName("_M_p"); + if (!ptr) + return false; + return CharTStringSummaryProvider<element_type>(*ptr, stream); + } + return MsvcStlStringSummaryProvider<element_type>(valobj, stream, options); +} + +static bool +LibstdcppOrMsvcWStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + ValueObjectSP libstdcpp = valobj.GetChildMemberWithName("_M_dataplus"); + if (libstdcpp) { + ValueObjectSP ptr = libstdcpp->GetChildMemberWithName("_M_p"); + if (!ptr) + return false; + return WCharStringSummaryProvider(*ptr, stream, options); + } + return MsvcStlWStringSummaryProvider(valobj, stream, options); +} + static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) return; @@ -1385,8 +1413,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { .SetShowMembersOneLiner(false) .SetHideItemNames(false); - lldb::TypeSummaryImplSP std_string_summary_sp( - new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}")); + lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat( + stl_summary_flags, + LibstdcppOrMsvcStringSummaryProvider< + StringPrinter::StringElementType::ASCII>, + "libstdc++/MSVC STL std::string summary provider")); lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat( stl_summary_flags, LibStdcppStringSummaryProvider, @@ -1418,10 +1449,9 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { eFormatterMatchExact, cxx11_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}")); + lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat( + stl_summary_flags, LibstdcppOrMsvcWStringSummaryProvider, + "libstdc++/MSVC STL std::wstring summary provider")); cpp_category_sp->AddTypeSummary("std::wstring", eFormatterMatchExact, std_wstring_summary_sp); diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index fc17b76804d9f..c3d5b7bc1ba26 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -37,6 +37,8 @@ using StringElementType = StringPrinter::StringElementType; static constexpr std::pair<const char *, Format> getElementTraits(StringElementType ElemType) { switch (ElemType) { + case StringElementType::ASCII: + return std::make_pair("", lldb::eFormatUnicode8); case StringElementType::UTF8: return std::make_pair("u8", lldb::eFormatUnicode8); case StringElementType::UTF16: @@ -49,7 +51,8 @@ getElementTraits(StringElementType ElemType) { } template <StringElementType ElemType> -static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) { +bool lldb_private::formatters::CharTStringSummaryProvider(ValueObject &valobj, + Stream &stream) { Address valobj_addr = GetArrayAddressOrPointerValue(valobj); if (!valobj_addr.IsValid()) return false; @@ -66,6 +69,11 @@ static bool CharStringSummaryProvider(ValueObject &valobj, Stream &stream) { return true; } +// explicit instantiation for ASCII strings +template bool +lldb_private::formatters::CharTStringSummaryProvider<StringElementType::ASCII>( + ValueObject &, Stream &); + template <StringElementType ElemType> static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) { DataExtractor data; @@ -96,17 +104,17 @@ static bool CharSummaryProvider(ValueObject &valobj, Stream &stream) { bool lldb_private::formatters::Char8StringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) { - return CharStringSummaryProvider<StringElementType::UTF8>(valobj, stream); + return CharTStringSummaryProvider<StringElementType::UTF8>(valobj, stream); } bool lldb_private::formatters::Char16StringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) { - return CharStringSummaryProvider<StringElementType::UTF16>(valobj, stream); + return CharTStringSummaryProvider<StringElementType::UTF16>(valobj, stream); } bool lldb_private::formatters::Char32StringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &) { - return CharStringSummaryProvider<StringElementType::UTF32>(valobj, stream); + return CharTStringSummaryProvider<StringElementType::UTF32>(valobj, stream); } bool lldb_private::formatters::WCharStringSummaryProvider( @@ -183,7 +191,7 @@ bool lldb_private::formatters::WCharSummaryProvider( if (!wchar_compiler_type) return false; - // Safe to pass nullptr for exe_scope here. + // Safe to pass nullptr for exe_scope here. std::optional<uint64_t> size = llvm::expectedToOptional(wchar_compiler_type.GetBitSize(nullptr)); if (!size) @@ -214,3 +222,143 @@ bool lldb_private::formatters::WCharSummaryProvider( } return true; } + +template <StringPrinter::StringElementType element_type> +bool lldb_private::formatters::StdStringSummaryProviderImpl( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + ValueObjectSP location_sp, uint64_t size) { + + if (size == 0) { + stream.PutCString(prefix_token); + stream.PutCString("\"\""); + return true; + } + + if (!location_sp) + return false; + + StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); + + if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { + const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); + if (size > max_size) { + size = max_size; + options.SetIsTruncated(true); + } + } + + { + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; + + options.SetData(std::move(extractor)); + } + options.SetStream(&stream); + if (prefix_token.empty()) + options.SetPrefixToken(nullptr); + else + options.SetPrefixToken(prefix_token); + options.SetQuote('"'); + options.SetSourceSize(size); + options.SetBinaryZeroIsTerminator(false); + return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); +} + +bool lldb_private::formatters::StdStringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size) { + return StdStringSummaryProviderImpl<StringPrinter::StringElementType::ASCII>( + valobj, stream, summary_options, prefix_token, location_sp, size); +} + +bool lldb_private::formatters::StdU8StringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size) { + return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF8>( + valobj, stream, summary_options, prefix_token, location_sp, size); +} + +bool lldb_private::formatters::StdU16StringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size) { + return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF16>( + valobj, stream, summary_options, prefix_token, location_sp, size); +} + +bool lldb_private::formatters::StdU32StringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size) { + return StdStringSummaryProviderImpl<StringPrinter::StringElementType::UTF32>( + valobj, stream, summary_options, prefix_token, location_sp, size); +} + +bool lldb_private::formatters::StdWStringSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size) { + if (size == 0) { + stream.Printf("L\"\""); + return true; + } + if (!location_sp) + return false; + + StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); + if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { + const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); + if (size > max_size) { + size = max_size; + options.SetIsTruncated(true); + } + } + + DataExtractor extractor; + const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); + if (bytes_read < size) + return false; + + // std::wstring::size() is measured in 'characters', not bytes + TypeSystemClangSP scratch_ts_sp = + ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); + if (!scratch_ts_sp) + return false; + + auto wchar_t_size = + scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr); + if (!wchar_t_size) + return false; + + options.SetData(std::move(extractor)); + options.SetStream(&stream); + options.SetPrefixToken("L"); + options.SetQuote('"'); + options.SetSourceSize(size); + options.SetBinaryZeroIsTerminator(false); + + switch (*wchar_t_size) { + case 1: + return StringPrinter::ReadBufferAndDumpToStream< + lldb_private::formatters::StringPrinter::StringElementType::UTF8>( + options); + break; + + case 2: + return StringPrinter::ReadBufferAndDumpToStream< + lldb_private::formatters::StringPrinter::StringElementType::UTF16>( + options); + break; + + case 4: + return StringPrinter::ReadBufferAndDumpToStream< + lldb_private::formatters::StringPrinter::StringElementType::UTF32>( + options); + } + return false; +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h index a2b606d28cac1..c4e938e89535d 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.h @@ -10,12 +10,17 @@ #ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_H #define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CXXSTRINGTYPES_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 { + +template <StringPrinter::StringElementType element_type> +bool CharTStringSummaryProvider(ValueObject &valobj, Stream &stream); + bool Char8StringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // char8_t* @@ -43,6 +48,36 @@ bool Char32SummaryProvider(ValueObject &valobj, Stream &stream, bool WCharSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // wchar_t +template <StringPrinter::StringElementType element_type> +bool StdStringSummaryProviderImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, + uint64_t size); + +bool StdStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size); +bool StdU8StringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size); +bool StdU16StringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, + uint64_t size); +bool StdU32StringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, + uint64_t size); +bool StdWStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token, + lldb::ValueObjectSP location_sp, uint64_t size); + } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 358cf7d78fa21..f640bc8f5ab69 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -24,6 +24,7 @@ #include "lldb/ValueObject/ValueObject.h" #include "lldb/ValueObject/ValueObjectConstResult.h" +#include "Plugins/Language/CPlusPlus/CxxStringTypes.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/lldb-enumerations.h" @@ -535,70 +536,6 @@ ExtractLibcxxStringInfo(ValueObject &valobj) { return std::make_pair(size, location_sp); } -static bool -LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &summary_options, - ValueObjectSP location_sp, size_t size) { - if (size == 0) { - stream.Printf("L\"\""); - return true; - } - if (!location_sp) - return false; - - StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { - const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); - if (size > max_size) { - size = max_size; - options.SetIsTruncated(true); - } - } - - DataExtractor extractor; - const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); - if (bytes_read < size) - return false; - - // std::wstring::size() is measured in 'characters', not bytes - TypeSystemClangSP scratch_ts_sp = - ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); - if (!scratch_ts_sp) - return false; - - auto wchar_t_size = - scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr); - if (!wchar_t_size) - return false; - - options.SetData(std::move(extractor)); - options.SetStream(&stream); - options.SetPrefixToken("L"); - options.SetQuote('"'); - options.SetSourceSize(size); - options.SetBinaryZeroIsTerminator(false); - - switch (*wchar_t_size) { - case 1: - return StringPrinter::ReadBufferAndDumpToStream< - lldb_private::formatters::StringPrinter::StringElementType::UTF8>( - options); - break; - - case 2: - return StringPrinter::ReadBufferAndDumpToStream< - lldb_private::formatters::StringPrinter::StringElementType::UTF16>( - options); - break; - - case 4: - return StringPrinter::ReadBufferAndDumpToStream< - lldb_private::formatters::StringPrinter::StringElementType::UTF32>( - options); - } - return false; -} - bool lldb_private::formatters::LibcxxWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options) { @@ -609,52 +546,8 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( ValueObjectSP location_sp; std::tie(size, location_sp) = *string_info; - return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options, - location_sp, size); -} - -template <StringPrinter::StringElementType element_type> -static bool -LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, - const TypeSummaryOptions &summary_options, - std::string prefix_token, ValueObjectSP location_sp, - uint64_t size) { - - if (size == 0) { - stream.Printf("\"\""); - return true; - } - - if (!location_sp) - return false; - - StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj); - - if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) { - const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary(); - if (size > max_size) { - size = max_size; - options.SetIsTruncated(true); - } - } - - { - DataExtractor extractor; - const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size); - if (bytes_read < size) - return false; - - options.SetData(std::move(extractor)); - } - options.SetStream(&stream); - if (prefix_token.empty()) - options.SetPrefixToken(nullptr); - else - options.SetPrefixToken(prefix_token); - options.SetQuote('"'); - options.SetSourceSize(size); - options.SetBinaryZeroIsTerminator(false); - return StringPrinter::ReadBufferAndDumpToStream<element_type>(options); + return lldb_private::formatters::StdWStringSummaryProvider( + valobj, stream, summary_options, "L", location_sp, size); } template <StringPrinter::StringElementType element_type> @@ -669,7 +562,7 @@ LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, ValueObjectSP location_sp; std::tie(size, location_sp) = *string_info; - return LibcxxStringSummaryProvider<element_type>( + return StdStringSummaryProviderImpl<element_type>( valobj, stream, summary_options, prefix_token, location_sp, size); } template <StringPrinter::StringElementType element_type> @@ -742,7 +635,7 @@ static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, return true; } - return LibcxxStringSummaryProvider<element_type>( + return StdStringSummaryProviderImpl<element_type>( valobj, stream, summary_options, prefix_token, dataobj, size); } @@ -781,8 +674,8 @@ bool lldb_private::formatters::LibcxxWStringViewSummaryProvider( return true; } - return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options, - dataobj, size); + return StdWStringSummaryProvider(valobj, stream, summary_options, "L", + dataobj, size); } static bool diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp new file mode 100644 index 0000000000000..8bb22cfe0aaca --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp @@ -0,0 +1,140 @@ +//===-- 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; + +static ValueObjectSP ExtractMsvcStlStringData(ValueObject &valobj) { + auto pair = valobj.GetChildMemberWithName("_Mypair"); + if (!pair) + return nullptr; + return pair->GetChildMemberWithName("_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, StringPrinter::ElementByteSize<element_type>()); + if (!string_info) + return false; + uint64_t size; + ValueObjectSP location_sp; + std::tie(size, location_sp) = *string_info; + + return StdStringSummaryProviderImpl<element_type>( + valobj, stream, summary_options, prefix_token, location_sp, size); +} +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::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::ASCII>( + 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 0000000000000..ffad55f13066a --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -0,0 +1,32 @@ +//===-- 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/TypeSummary.h" +#include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/Utility/Stream.h" +#include "lldb/ValueObject/ValueObject.h" + +namespace lldb_private { +namespace formatters { + +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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits