Skip to content

Commit 3033eb6

Browse files
committed
[LLDB] Add type summaries for MSVC STL strings
1 parent 1f10c6a commit 3033eb6

File tree

21 files changed

+768
-78
lines changed

21 files changed

+768
-78
lines changed

lldb/include/lldb/DataFormatters/StringPrinter.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,21 @@ class StringPrinter {
152152
template <StringElementType element_type>
153153
static bool
154154
ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options);
155+
156+
template <StringElementType element_type>
157+
static constexpr uint64_t ElementByteSize() {
158+
switch (element_type) {
159+
case StringElementType::ASCII:
160+
case StringElementType::UTF8:
161+
return 1;
162+
case StringElementType::UTF16:
163+
return 2;
164+
case StringElementType::UTF32:
165+
return 3;
166+
default:
167+
return 0;
168+
}
169+
}
155170
};
156171

157172
} // namespace formatters

lldb/include/lldb/DataFormatters/TypeSummary.h

Lines changed: 91 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,14 @@ class TypeSummaryOptions {
4848

4949
class TypeSummaryImpl {
5050
public:
51-
enum class Kind { eSummaryString, eScript, eBytecode, eCallback, eInternal };
51+
enum class Kind {
52+
eSummaryString,
53+
eScript,
54+
eBytecode,
55+
eCallback,
56+
eComposite,
57+
eInternal
58+
};
5259

5360
virtual ~TypeSummaryImpl() = default;
5461

@@ -292,18 +299,29 @@ class TypeSummaryImpl {
292299
const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete;
293300
};
294301

295-
// simple string-based summaries, using ${var to show data
296-
struct StringSummaryFormat : public TypeSummaryImpl {
302+
struct StringSummaryData {
297303
std::string m_format_str;
298304
FormatEntity::Entry m_format;
299305
Status m_error;
300306

307+
StringSummaryData(const char *f);
308+
void SetFormat(const char *f);
309+
310+
bool FormatObject(ValueObject *valobj, std::string &dest,
311+
const TypeSummaryOptions &options,
312+
const TypeSummaryImpl &summary);
313+
};
314+
315+
// simple string-based summaries, using ${var to show data
316+
struct StringSummaryFormat : public TypeSummaryImpl {
317+
StringSummaryData m_data;
318+
301319
StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f,
302320
uint32_t ptr_match_depth = 1);
303321

304322
~StringSummaryFormat() override = default;
305323

306-
const char *GetSummaryString() const { return m_format_str.c_str(); }
324+
const char *GetSummaryString() const { return m_data.m_format_str.c_str(); }
307325

308326
void SetSummaryString(const char *f);
309327

@@ -323,15 +341,23 @@ struct StringSummaryFormat : public TypeSummaryImpl {
323341
const StringSummaryFormat &operator=(const StringSummaryFormat &) = delete;
324342
};
325343

326-
// summaries implemented via a C++ function
327-
struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
344+
struct CXXFunctionSummaryData {
328345
// we should convert these to SBValue and SBStream if we ever cross the
329346
// boundary towards the external world
330-
typedef std::function<bool(ValueObject &, Stream &,
331-
const TypeSummaryOptions &)>
332-
Callback;
347+
using Callback =
348+
std::function<bool(ValueObject &, Stream &, const TypeSummaryOptions &)>;
333349

334350
Callback m_impl;
351+
352+
bool FormatObject(ValueObject *valobj, std::string &dest,
353+
const TypeSummaryOptions &options,
354+
const TypeSummaryImpl &summary);
355+
};
356+
357+
// summaries implemented via a C++ function
358+
struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
359+
using Callback = CXXFunctionSummaryData::Callback;
360+
CXXFunctionSummaryData m_data;
335361
std::string m_description;
336362

337363
CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl,
@@ -340,11 +366,13 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
340366

341367
~CXXFunctionSummaryFormat() override = default;
342368

343-
Callback GetBackendFunction() const { return m_impl; }
369+
Callback GetBackendFunction() const { return m_data.m_impl; }
344370

345371
const char *GetTextualInfo() const { return m_description.c_str(); }
346372

347-
void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); }
373+
void SetBackendFunction(Callback cb_func) {
374+
m_data.m_impl = std::move(cb_func);
375+
}
348376

349377
void SetTextualInfo(const char *descr) {
350378
if (descr)
@@ -372,6 +400,58 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
372400
operator=(const CXXFunctionSummaryFormat &) = delete;
373401
};
374402

403+
/// A summary that supports multiple type layouts for the same type name.
404+
///
405+
/// This summary maintains a list of child summaries, each paired with a
406+
/// validator function. An associated validator is used to determine which child
407+
/// is appropriate for formatting a given ValueObject.
408+
struct CXXCompositeSummaryFormat : public TypeSummaryImpl {
409+
using Validator = bool(ValueObject &valobj);
410+
using ChildData = std::variant<CXXFunctionSummaryData, StringSummaryData>;
411+
using Child = std::pair<Validator *, ChildData>;
412+
using Children = llvm::SmallVector<Child, 2>;
413+
414+
Children m_children;
415+
std::string m_description;
416+
417+
CXXCompositeSummaryFormat(const TypeSummaryImpl::Flags &flags,
418+
const char *description, Children impls = {},
419+
uint32_t ptr_match_depth = 1);
420+
421+
~CXXCompositeSummaryFormat() override = default;
422+
423+
const char *GetTextualInfo() const { return m_description.c_str(); }
424+
425+
CXXCompositeSummaryFormat *Append(Validator *validator, ChildData impl);
426+
427+
void SetTextualInfo(const char *descr) {
428+
if (descr)
429+
m_description.assign(descr);
430+
else
431+
m_description.clear();
432+
}
433+
434+
Children CopyChildren() const;
435+
436+
bool FormatObject(ValueObject *valobj, std::string &dest,
437+
const TypeSummaryOptions &options) override;
438+
439+
std::string GetDescription() override;
440+
441+
static bool classof(const TypeSummaryImpl *S) {
442+
return S->GetKind() == Kind::eComposite;
443+
}
444+
445+
std::string GetName() override;
446+
447+
using SharedPointer = std::shared_ptr<CXXCompositeSummaryFormat>;
448+
449+
private:
450+
CXXCompositeSummaryFormat(const CXXCompositeSummaryFormat &) = delete;
451+
const CXXCompositeSummaryFormat &
452+
operator=(const CXXCompositeSummaryFormat &) = delete;
453+
};
454+
375455
// Python-based summaries, running script code to show data
376456
struct ScriptSummaryFormat : public TypeSummaryImpl {
377457
std::string m_function_name;

lldb/include/lldb/DataFormatters/ValueObjectPrinter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class ValueObjectPrinter {
165165
std::string m_error;
166166
bool m_val_summary_ok;
167167

168-
friend struct StringSummaryFormat;
168+
friend struct StringSummaryData;
169169

170170
ValueObjectPrinter(const ValueObjectPrinter &) = delete;
171171
const ValueObjectPrinter &operator=(const ValueObjectPrinter &) = delete;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
libcxx_include_target_dir = None
135135
libcxx_library_dir = None
136136

137+
target_triple = None
138+
137139
# A plugin whose tests will be enabled, like intel-pt.
138140
enabled_plugins = []
139141

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ def parseOptionsAndInitTestdirs():
299299
configuration.libcxx_library_dir = args.libcxx_library_dir
300300
configuration.cmake_build_type = args.cmake_build_type.lower()
301301

302+
configuration.target_triple = args.target_triple
303+
302304
if args.channels:
303305
lldbtest_config.channels = args.channels
304306

@@ -831,6 +833,26 @@ def checkLibstdcxxSupport():
831833
configuration.skip_categories.append("libstdcxx")
832834

833835

836+
def canRunMsvcStlTests():
837+
if "windows-msvc" in configuration.target_triple:
838+
return True, "MSVC STL is present on *windows-msvc*"
839+
return (
840+
False,
841+
f"Don't know how to build with MSVC's STL on {configuration.target_triple}",
842+
)
843+
844+
845+
def checkMsvcStlSupport():
846+
result, reason = canRunMsvcStlTests()
847+
if result:
848+
return # msvcstl supported
849+
if "msvcstl" in configuration.categories_list:
850+
return # msvcstl category explicitly requested, let it run.
851+
if configuration.verbose:
852+
print(f"msvcstl tests will not be run because: {reason}")
853+
configuration.skip_categories.append("msvcstl")
854+
855+
834856
def canRunWatchpointTests():
835857
from lldbsuite.test import lldbplatformutil
836858

@@ -1044,6 +1066,7 @@ def run_suite():
10441066

10451067
checkLibcxxSupport()
10461068
checkLibstdcxxSupport()
1069+
checkMsvcStlSupport()
10471070
checkWatchpointSupport()
10481071
checkDebugInfoSupport()
10491072
checkDebugServerSupport()

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ def create_parser():
116116
"The location of llvm tools used for testing (yaml2obj, FileCheck, etc.)."
117117
),
118118
)
119+
group.add_argument(
120+
"--target-triple",
121+
help=textwrap.dedent(
122+
"The target triple the tests will run on (e.g. x86_64-pc-windows-msvc)."
123+
),
124+
)
119125

120126
# Test filtering options
121127
group = parser.add_argument_group("Test filtering options")

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/API/SBTypeSummary.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ bool SBTypeSummary::IsEqualTo(lldb::SBTypeSummary &rhs) {
370370
if (IsSummaryString() != rhs.IsSummaryString())
371371
return false;
372372
return GetOptions() == rhs.GetOptions();
373+
case TypeSummaryImpl::Kind::eComposite:
374+
return llvm::dyn_cast<CXXCompositeSummaryFormat>(m_opaque_sp.get()) ==
375+
llvm::dyn_cast<CXXCompositeSummaryFormat>(rhs.m_opaque_sp.get());
373376
case TypeSummaryImpl::Kind::eInternal:
374377
return (m_opaque_sp.get() == rhs.m_opaque_sp.get());
375378
}
@@ -406,7 +409,7 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
406409
if (CXXFunctionSummaryFormat *current_summary_ptr =
407410
llvm::dyn_cast<CXXFunctionSummaryFormat>(m_opaque_sp.get())) {
408411
new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(
409-
GetOptions(), current_summary_ptr->m_impl,
412+
GetOptions(), current_summary_ptr->m_data.m_impl,
410413
current_summary_ptr->m_description.c_str()));
411414
} else if (ScriptSummaryFormat *current_summary_ptr =
412415
llvm::dyn_cast<ScriptSummaryFormat>(m_opaque_sp.get())) {
@@ -417,6 +420,12 @@ bool SBTypeSummary::CopyOnWrite_Impl() {
417420
llvm::dyn_cast<StringSummaryFormat>(m_opaque_sp.get())) {
418421
new_sp = TypeSummaryImplSP(new StringSummaryFormat(
419422
GetOptions(), current_summary_ptr->GetSummaryString()));
423+
} else if (CXXCompositeSummaryFormat *current_summary_ptr =
424+
llvm::dyn_cast<CXXCompositeSummaryFormat>(m_opaque_sp.get())) {
425+
new_sp = TypeSummaryImplSP(new CXXCompositeSummaryFormat(
426+
GetOptions(), current_summary_ptr->GetTextualInfo(),
427+
current_summary_ptr->CopyChildren(),
428+
current_summary_ptr->GetPtrMatchDepth()));
420429
}
421430

422431
SetSP(new_sp);

lldb/source/Commands/CommandObjectType.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,9 +1397,10 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
13971397
result.AppendError("summary creation failed");
13981398
return false;
13991399
}
1400-
if (string_format->m_error.Fail()) {
1401-
result.AppendErrorWithFormat("syntax error: %s",
1402-
string_format->m_error.AsCString("<unknown>"));
1400+
if (string_format->m_data.m_error.Fail()) {
1401+
result.AppendErrorWithFormat(
1402+
"syntax error: %s",
1403+
string_format->m_data.m_error.AsCString("<unknown>"));
14031404
return false;
14041405
}
14051406
lldb::TypeSummaryImplSP entry(string_format.release());

0 commit comments

Comments
 (0)