Skip to content

Commit 519f089

Browse files
committed
[LLDB] Add type summaries for MSVC STL strings
1 parent e64f8e0 commit 519f089

File tree

23 files changed

+951
-209
lines changed

23 files changed

+951
-209
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: 88 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+
eCascading,
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,55 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl {
372400
operator=(const CXXFunctionSummaryFormat &) = delete;
373401
};
374402

403+
// Multiple summaries for the same type name but different type layouts.
404+
// A validator function checks the layout.
405+
struct CXXCascadingSummaryFormat : public TypeSummaryImpl {
406+
using Validator = bool(ValueObject &valobj);
407+
using Impl = std::variant<CXXFunctionSummaryData, StringSummaryData>;
408+
using ImplEntry = std::pair<Validator *, Impl>;
409+
using ImplList = llvm::SmallVector<ImplEntry, 2>;
410+
411+
ImplList m_impls;
412+
std::string m_description;
413+
414+
CXXCascadingSummaryFormat(const TypeSummaryImpl::Flags &flags,
415+
const char *description, ImplList impls = {},
416+
uint32_t ptr_match_depth = 1);
417+
418+
~CXXCascadingSummaryFormat() override = default;
419+
420+
const char *GetTextualInfo() const { return m_description.c_str(); }
421+
422+
CXXCascadingSummaryFormat *Append(Validator *validator, Impl impl);
423+
424+
void SetTextualInfo(const char *descr) {
425+
if (descr)
426+
m_description.assign(descr);
427+
else
428+
m_description.clear();
429+
}
430+
431+
ImplList CopyImpls() const;
432+
433+
bool FormatObject(ValueObject *valobj, std::string &dest,
434+
const TypeSummaryOptions &options) override;
435+
436+
std::string GetDescription() override;
437+
438+
static bool classof(const TypeSummaryImpl *S) {
439+
return S->GetKind() == Kind::eCascading;
440+
}
441+
442+
std::string GetName() override;
443+
444+
using SharedPointer = std::shared_ptr<CXXCascadingSummaryFormat>;
445+
446+
private:
447+
CXXCascadingSummaryFormat(const CXXCascadingSummaryFormat &) = delete;
448+
const CXXCascadingSummaryFormat &
449+
operator=(const CXXCascadingSummaryFormat &) = delete;
450+
};
451+
375452
// Python-based summaries, running script code to show data
376453
struct ScriptSummaryFormat : public TypeSummaryImpl {
377454
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/dotest.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,26 @@ def checkLibstdcxxSupport():
831831
configuration.skip_categories.append("libstdcxx")
832832

833833

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

@@ -1044,6 +1064,7 @@ def run_suite():
10441064

10451065
checkLibcxxSupport()
10461066
checkLibstdcxxSupport()
1067+
checkMsvcStlSupport()
10471068
checkWatchpointSupport()
10481069
checkDebugInfoSupport()
10491070
checkDebugServerSupport()

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: 9 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::eCascading:
374+
return llvm::dyn_cast<CXXCascadingSummaryFormat>(m_opaque_sp.get()) ==
375+
llvm::dyn_cast<CXXCascadingSummaryFormat>(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,11 @@ 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 (CXXCascadingSummaryFormat *current_summary_ptr =
424+
llvm::dyn_cast<CXXCascadingSummaryFormat>(m_opaque_sp.get())) {
425+
new_sp = TypeSummaryImplSP(new CXXCascadingSummaryFormat(
426+
GetOptions(), current_summary_ptr->GetTextualInfo(),
427+
current_summary_ptr->CopyImpls()));
420428
}
421429

422430
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)