summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Language
diff options
context:
space:
mode:
authornerix <nerixdev@outlook.de>2025-07-08 10:55:18 +0200
committerGitHub <noreply@github.com>2025-07-08 09:55:18 +0100
commit45689b26eb4bfa619127013dccea8efd8de4d21a (patch)
tree232bae8e440a57b8b1ec54583ae72047e7bdb97b /lldb/source/Plugins/Language
parent29487759e3cc8fc056a599a38b3a6d2d8849a20e (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')
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp138
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp155
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h35
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