mirror of
https://github.com/intel/llvm.git
synced 2026-01-14 03:50:17 +08:00
[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`.
This commit is contained in:
@@ -831,6 +831,46 @@ def checkLibstdcxxSupport():
|
||||
configuration.skip_categories.append("libstdcxx")
|
||||
|
||||
|
||||
def canRunMsvcStlTests():
|
||||
from lldbsuite.test import lldbplatformutil
|
||||
|
||||
platform = lldbplatformutil.getPlatform()
|
||||
if platform != "windows":
|
||||
return False, f"Don't know how to build with MSVC's STL on {platform}"
|
||||
|
||||
with tempfile.NamedTemporaryFile() as f:
|
||||
cmd = [configuration.compiler, "-xc++", "-o", f.name, "-E", "-"]
|
||||
p = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
_, stderr = p.communicate(
|
||||
"""
|
||||
#include <yvals_core.h>
|
||||
#ifndef _MSVC_STL_VERSION
|
||||
#error _MSVC_STL_VERSION not defined
|
||||
#endif
|
||||
"""
|
||||
)
|
||||
if not p.returncode:
|
||||
return True, "Compiling with MSVC STL"
|
||||
return (False, f"Not compiling with MSVC STL: {stderr}")
|
||||
|
||||
|
||||
def checkMsvcStlSupport():
|
||||
result, reason = canRunMsvcStlTests()
|
||||
if result:
|
||||
return # msvcstl supported
|
||||
if "msvcstl" in configuration.categories_list:
|
||||
return # msvcstl category explicitly requested, let it run.
|
||||
if configuration.verbose:
|
||||
print(f"msvcstl tests will not be run because: {reason}")
|
||||
configuration.skip_categories.append("msvcstl")
|
||||
|
||||
|
||||
def canRunWatchpointTests():
|
||||
from lldbsuite.test import lldbplatformutil
|
||||
|
||||
@@ -1044,6 +1084,7 @@ def run_suite():
|
||||
|
||||
checkLibcxxSupport()
|
||||
checkLibstdcxxSupport()
|
||||
checkMsvcStlSupport()
|
||||
checkWatchpointSupport()
|
||||
checkDebugInfoSupport()
|
||||
checkDebugServerSupport()
|
||||
|
||||
@@ -33,6 +33,7 @@ all_categories = {
|
||||
"lldb-server": "Tests related to lldb-server",
|
||||
"lldb-dap": "Tests for the Debug Adapter Protocol with lldb-dap",
|
||||
"llgs": "Tests for the gdb-server functionality of lldb-server",
|
||||
"msvcstl": "Test for MSVC STL data formatters",
|
||||
"pexpect": "Tests requiring the pexpect library to be available",
|
||||
"objc": "Tests related to the Objective-C programming language support",
|
||||
"pyapi": "Tests related to the Python API",
|
||||
|
||||
@@ -32,6 +32,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
|
||||
LibStdcpp.cpp
|
||||
LibStdcppTuple.cpp
|
||||
LibStdcppUniquePointer.cpp
|
||||
MsvcStl.cpp
|
||||
MSVCUndecoratedNameParser.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
155
lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
Normal file
155
lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp
Normal file
@@ -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");
|
||||
}
|
||||
35
lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
Normal file
35
lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h
Normal file
@@ -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
|
||||
@@ -10,10 +10,6 @@ from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class SkipSummaryDataFormatterTestCase(TestBase):
|
||||
@expectedFailureAll(
|
||||
oslist=["windows"],
|
||||
bugnumber="llvm.org/pr24462, Data formatters have problems on Windows",
|
||||
)
|
||||
def test_with_run_command(self):
|
||||
"""Test data formatter commands."""
|
||||
self.build()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,120 @@
|
||||
# coding=utf8
|
||||
"""
|
||||
Test std::*string summaries with MSVC's STL.
|
||||
"""
|
||||
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class MsvcStlStringDataFormatterTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
@add_test_categories(["msvcstl"])
|
||||
def test_with_run_command(self):
|
||||
"""Test that that file and class static variables display correctly."""
|
||||
self.build()
|
||||
|
||||
main_spec = lldb.SBFileSpec("main.cpp")
|
||||
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
|
||||
self, "Set break point at this line.", main_spec
|
||||
)
|
||||
frame = thread.frames[0]
|
||||
|
||||
# This is the function to remove the custom formats in order to have a
|
||||
# clean slate for the next test case.
|
||||
def cleanup():
|
||||
self.runCmd("type format clear", check=False)
|
||||
self.runCmd("type summary clear", check=False)
|
||||
self.runCmd("type filter clear", check=False)
|
||||
self.runCmd("type synth clear", check=False)
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
self.expect(
|
||||
"frame variable",
|
||||
substrs=[
|
||||
'(std::wstring) wempty = L""',
|
||||
'(std::wstring) s = L"hello world! מזל טוב!"',
|
||||
'(std::wstring) S = L"!!!!"',
|
||||
"(const wchar_t *) mazeltov = 0x",
|
||||
'L"מזל טוב"',
|
||||
'(std::string) empty = ""',
|
||||
'(std::string) q = "hello world"',
|
||||
'(std::string) Q = "quite a long std::strin with lots of info inside it"',
|
||||
'(std::string) overwritten_zero = "abc"',
|
||||
'(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
|
||||
'(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
|
||||
'(std::u16string) u16_string = u"ß水氶"',
|
||||
'(std::u16string) u16_empty = u""',
|
||||
'(std::u32string) u32_string = U"🍄🍅🍆🍌"',
|
||||
'(std::u32string) u32_empty = U""',
|
||||
"(std::string *) null_str = nullptr",
|
||||
],
|
||||
)
|
||||
|
||||
thread.StepOver()
|
||||
|
||||
TheVeryLongOne = frame.FindVariable("TheVeryLongOne")
|
||||
summaryOptions = lldb.SBTypeSummaryOptions()
|
||||
summaryOptions.SetCapping(lldb.eTypeSummaryUncapped)
|
||||
uncappedSummaryStream = lldb.SBStream()
|
||||
TheVeryLongOne.GetSummary(uncappedSummaryStream, summaryOptions)
|
||||
uncappedSummary = uncappedSummaryStream.GetData()
|
||||
self.assertGreater(
|
||||
uncappedSummary.find("someText"),
|
||||
0,
|
||||
"uncappedSummary does not include the full string",
|
||||
)
|
||||
summaryOptions.SetCapping(lldb.eTypeSummaryCapped)
|
||||
cappedSummaryStream = lldb.SBStream()
|
||||
TheVeryLongOne.GetSummary(cappedSummaryStream, summaryOptions)
|
||||
cappedSummary = cappedSummaryStream.GetData()
|
||||
self.assertLessEqual(
|
||||
cappedSummary.find("someText"), 0, "cappedSummary includes the full string"
|
||||
)
|
||||
|
||||
self.expect_expr(
|
||||
"s", result_type="std::wstring", result_summary='L"hello world! מזל טוב!"'
|
||||
)
|
||||
|
||||
self.expect_expr("q", result_type="std::string", result_summary='"hello world"')
|
||||
|
||||
self.expect_expr(
|
||||
"Q",
|
||||
result_type="std::string",
|
||||
result_summary='"quite a long std::strin with lots of info inside it"',
|
||||
)
|
||||
|
||||
self.expect(
|
||||
"frame variable",
|
||||
substrs=[
|
||||
'(std::wstring) S = L"!!!!!"',
|
||||
"(const wchar_t *) mazeltov = 0x",
|
||||
'L"מזל טוב"',
|
||||
'(std::string) q = "hello world"',
|
||||
'(std::string) Q = "quite a long std::strin with lots of info inside it"',
|
||||
'(std::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
|
||||
'(std::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
|
||||
'(std::u16string) u16_string = u"ß水氶"',
|
||||
'(std::u32string) u32_string = U"🍄🍅🍆🍌"',
|
||||
'(std::u32string) u32_empty = U""',
|
||||
"(std::string *) null_str = nullptr",
|
||||
],
|
||||
)
|
||||
|
||||
# Finally, make sure that if the string is not readable, we give an error:
|
||||
bkpt_2 = target.BreakpointCreateBySourceRegex(
|
||||
"Break here to look at bad string", main_spec
|
||||
)
|
||||
self.assertEqual(bkpt_2.GetNumLocations(), 1, "Got one location")
|
||||
threads = lldbutil.continue_to_breakpoint(process, bkpt_2)
|
||||
self.assertEqual(len(threads), 1, "Stopped at second breakpoint")
|
||||
frame = threads[0].frames[0]
|
||||
var = frame.FindVariable("in_str")
|
||||
self.assertTrue(var.GetError().Success(), "Made variable")
|
||||
self.assertIsNone(var.GetSummary())
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
CXXFLAGS_EXTRAS := -std=c++20 -O0
|
||||
include Makefile.rules
|
||||
@@ -0,0 +1,33 @@
|
||||
# coding=utf8
|
||||
"""
|
||||
Test std::u8string summary with MSVC's STL.
|
||||
"""
|
||||
|
||||
|
||||
import lldb
|
||||
from lldbsuite.test.decorators import *
|
||||
from lldbsuite.test.lldbtest import *
|
||||
from lldbsuite.test import lldbutil
|
||||
|
||||
|
||||
class MsvcStlU8StringDataFormatterTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
@add_test_categories(["msvcstl"])
|
||||
def test_with_run_command(self):
|
||||
"""Test that that file and class static variables display correctly."""
|
||||
self.build()
|
||||
|
||||
lldbutil.run_to_source_breakpoint(
|
||||
self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
|
||||
)
|
||||
|
||||
self.expect(
|
||||
"frame variable",
|
||||
substrs=[
|
||||
'(std::u8string) u8_string_small = u8"🍄"',
|
||||
'(std::u8string) u8_string = u8"❤️👍📄📁😃🧑🌾"',
|
||||
'(std::u8string) u8_empty = u8""',
|
||||
'(std::u8string) u8_text = u8"ABC"',
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <string>
|
||||
|
||||
#ifndef _MSVC_STL_VERSION
|
||||
// this is more of a sanity check that the categories work as expected
|
||||
#error Not using MSVC STL
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
std::u8string u8_string_small(u8"🍄");
|
||||
std::u8string u8_string(u8"❤️👍📄📁😃🧑🌾");
|
||||
std::u8string u8_empty(u8"");
|
||||
std::u8string u8_text(u8"ABC");
|
||||
u8_text.assign(u8"ABCd"); // Set break point at this line.
|
||||
}
|
||||
@@ -4,5 +4,4 @@ from lldbsuite.test import decorators
|
||||
lldbinline.MakeInlineTest(
|
||||
__file__,
|
||||
globals(),
|
||||
[decorators.expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772")],
|
||||
)
|
||||
|
||||
@@ -10,7 +10,6 @@ from lldbsuite.test import lldbutil
|
||||
class SBValuePersistTestCase(TestBase):
|
||||
NO_DEBUG_INFO_TESTCASE = True
|
||||
|
||||
@expectedFailureAll(oslist=["windows"], bugnumber="llvm.org/pr24772")
|
||||
def test(self):
|
||||
"""Test SBValue::Persist"""
|
||||
self.build()
|
||||
|
||||
Reference in New Issue
Block a user