Skip to content

Commit 9a57d1e

Browse files
committed
[lldb] Allow dumping the state of all scratch TypeSystems
This adds the `target dump typesystem'`command which dumps the TypeSystem of the target itself (aka the 'scratch TypeSystem'). This is similar to `target modules dump ast` which dumps the AST of lldb::Modules associated with a selected target. Unlike `target modules dump ast`, the new command is not a subcommand of `target modules dump` as it's not touching the modules of a target at all. Also unlike `target modules dump ast` I tried to keep the implementation language-neutral, so this patch moves our Clang `Dump` to the `TypeSystem` interface so it will also dump the state of any future/downstream scratch TypeSystems (e.g., Swift). That's also why the command just refers to a 'typesystem' instead of an 'ast' (which is only how Clang is necessarily modelling the internal TypeSystem state). The main motivation for this patch is that I need to write some tests that check for duplicates in the ScratchTypeSystemClang of a target. There is currently no way to check for this at the moment (beside measuring memory consumption of course). It's probably also useful for debugging LLDB itself. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D111936
1 parent 134e181 commit 9a57d1e

File tree

10 files changed

+147
-7
lines changed

10 files changed

+147
-7
lines changed

lldb/include/lldb/Symbol/TypeSystem.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,12 @@ class TypeSystem : public PluginInterface {
392392
lldb::opaque_compiler_type_t type, Stream *s,
393393
lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) = 0;
394394

395+
/// Dump a textual representation of the internal TypeSystem state to the
396+
/// given stream.
397+
///
398+
/// This should not modify the state of the TypeSystem if possible.
399+
virtual void Dump(llvm::raw_ostream &output) = 0;
400+
395401
// TODO: These methods appear unused. Should they be removed?
396402

397403
virtual bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) = 0;

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4990,6 +4990,55 @@ class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword {
49904990
~CommandObjectMultiwordTargetStopHooks() override = default;
49914991
};
49924992

4993+
#pragma mark CommandObjectTargetDumpTypesystem
4994+
4995+
/// Dumps the TypeSystem of the selected Target.
4996+
class CommandObjectTargetDumpTypesystem : public CommandObjectParsed {
4997+
public:
4998+
CommandObjectTargetDumpTypesystem(CommandInterpreter &interpreter)
4999+
: CommandObjectParsed(
5000+
interpreter, "target dump typesystem",
5001+
"Dump the state of the target's internal type system.\n"
5002+
"Intended to be used for debugging LLDB itself.",
5003+
nullptr, eCommandRequiresTarget) {}
5004+
5005+
~CommandObjectTargetDumpTypesystem() override = default;
5006+
5007+
protected:
5008+
bool DoExecute(Args &command, CommandReturnObject &result) override {
5009+
if (!command.empty()) {
5010+
result.AppendError("target dump typesystem doesn't take arguments.");
5011+
return result.Succeeded();
5012+
}
5013+
5014+
// Go over every scratch TypeSystem and dump to the command output.
5015+
for (TypeSystem *ts : GetSelectedTarget().GetScratchTypeSystems())
5016+
ts->Dump(result.GetOutputStream().AsRawOstream());
5017+
5018+
result.SetStatus(eReturnStatusSuccessFinishResult);
5019+
return result.Succeeded();
5020+
}
5021+
};
5022+
5023+
#pragma mark CommandObjectTargetDump
5024+
5025+
/// Multi-word command for 'target dump'.
5026+
class CommandObjectTargetDump : public CommandObjectMultiword {
5027+
public:
5028+
// Constructors and Destructors
5029+
CommandObjectTargetDump(CommandInterpreter &interpreter)
5030+
: CommandObjectMultiword(
5031+
interpreter, "target dump",
5032+
"Commands for dumping information about the target.",
5033+
"target dump [typesystem]") {
5034+
LoadSubCommand(
5035+
"typesystem",
5036+
CommandObjectSP(new CommandObjectTargetDumpTypesystem(interpreter)));
5037+
}
5038+
5039+
~CommandObjectTargetDump() override = default;
5040+
};
5041+
49935042
#pragma mark CommandObjectMultiwordTarget
49945043

49955044
// CommandObjectMultiwordTarget
@@ -5003,6 +5052,8 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget(
50035052
CommandObjectSP(new CommandObjectTargetCreate(interpreter)));
50045053
LoadSubCommand("delete",
50055054
CommandObjectSP(new CommandObjectTargetDelete(interpreter)));
5055+
LoadSubCommand("dump",
5056+
CommandObjectSP(new CommandObjectTargetDump(interpreter)));
50065057
LoadSubCommand("list",
50075058
CommandObjectSP(new CommandObjectTargetList(interpreter)));
50085059
LoadSubCommand("select",

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3846,7 +3846,7 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) {
38463846
llvm::dyn_cast_or_null<TypeSystemClang>(&ts_or_err.get());
38473847
if (!clang)
38483848
return;
3849-
clang->Dump(s);
3849+
clang->Dump(s.AsRawOstream());
38503850
}
38513851

38523852
SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {

lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,4 +1358,6 @@ PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
13581358
return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
13591359
}
13601360

1361-
void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }
1361+
void PdbAstBuilder::Dump(Stream &stream) {
1362+
m_clang.Dump(stream.AsRawOstream());
1363+
}

lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1461,7 +1461,7 @@ void SymbolFilePDB::DumpClangAST(Stream &s) {
14611461
llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get());
14621462
if (!clang_type_system)
14631463
return;
1464-
clang_type_system->Dump(s);
1464+
clang_type_system->Dump(s.AsRawOstream());
14651465
}
14661466

14671467
void SymbolFilePDB::FindTypesByRegex(

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8358,9 +8358,8 @@ TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const {
83588358
}
83598359
#endif
83608360

8361-
void TypeSystemClang::Dump(Stream &s) {
8362-
Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl());
8363-
tu->dump(s.AsRawOstream());
8361+
void TypeSystemClang::Dump(llvm::raw_ostream &output) {
8362+
GetTranslationUnitDecl()->dump(output);
83648363
}
83658364

83668365
void TypeSystemClang::DumpFromSymbolFile(Stream &s,
@@ -9746,6 +9745,41 @@ ScratchTypeSystemClang::GetForTarget(Target &target,
97469745
return &scratch_ast.GetIsolatedAST(*ast_kind);
97479746
}
97489747

9748+
/// Returns a human-readable name that uniquely identifiers the sub-AST kind.
9749+
static llvm::StringRef
9750+
GetNameForIsolatedASTKind(ScratchTypeSystemClang::IsolatedASTKind kind) {
9751+
switch (kind) {
9752+
case ScratchTypeSystemClang::IsolatedASTKind::CppModules:
9753+
return "C++ modules";
9754+
}
9755+
llvm_unreachable("Unimplemented IsolatedASTKind?");
9756+
}
9757+
9758+
void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output) {
9759+
// First dump the main scratch AST.
9760+
output << "State of scratch Clang type system:\n";
9761+
TypeSystemClang::Dump(output);
9762+
9763+
// Now sort the isolated sub-ASTs.
9764+
typedef std::pair<IsolatedASTKey, TypeSystem *> KeyAndTS;
9765+
std::vector<KeyAndTS> sorted_typesystems;
9766+
for (const auto &a : m_isolated_asts)
9767+
sorted_typesystems.emplace_back(a.first, a.second.get());
9768+
llvm::stable_sort(sorted_typesystems,
9769+
[](const KeyAndTS &lhs, const KeyAndTS &rhs) {
9770+
return lhs.first < rhs.first;
9771+
});
9772+
9773+
// Dump each sub-AST too.
9774+
for (const auto &a : sorted_typesystems) {
9775+
IsolatedASTKind kind =
9776+
static_cast<ScratchTypeSystemClang::IsolatedASTKind>(a.first);
9777+
output << "State of scratch Clang type subsystem "
9778+
<< GetNameForIsolatedASTKind(kind) << ":\n";
9779+
a.second->Dump(output);
9780+
}
9781+
}
9782+
97499783
UserExpression *ScratchTypeSystemClang::GetUserExpression(
97509784
llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
97519785
Expression::ResultType desired_type,

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,8 @@ class TypeSystemClang : public TypeSystem {
938938
LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override;
939939
#endif
940940

941-
void Dump(Stream &s);
941+
/// \see lldb_private::TypeSystem::Dump
942+
void Dump(llvm::raw_ostream &output) override;
942943

943944
/// Dump clang AST types from the symbol file.
944945
///
@@ -1162,6 +1163,9 @@ class ScratchTypeSystemClang : public TypeSystemClang {
11621163
return GetForTarget(target, InferIsolatedASTKindFromLangOpts(lang_opts));
11631164
}
11641165

1166+
/// \see lldb_private::TypeSystem::Dump
1167+
void Dump(llvm::raw_ostream &output) override;
1168+
11651169
UserExpression *
11661170
GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
11671171
lldb::LanguageType language,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import lldb
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test.decorators import *
4+
import lldbsuite.test.lldbutil as lldbutil
5+
6+
class TestCase(TestBase):
7+
8+
mydir = TestBase.compute_mydir(__file__)
9+
10+
@no_debug_info_test
11+
def test_dumping(self):
12+
""" Tests dumping an empty and non-empty scratch AST. """
13+
self.build()
14+
self.createTestTarget()
15+
16+
# Make sure DummyStruct is not in the scratch AST by default.
17+
self.expect("target dump typesystem", matching=False, substrs=["struct DummyStruct"])
18+
19+
# Move DummyStruct into the scratch AST via the expression evaluator.
20+
# FIXME: Once there is an SB API for using variable paths on globals
21+
# then this should be done this way.
22+
self.expect_expr("s", result_type="DummyStruct")
23+
24+
# Dump the scratch AST and make sure DummyStruct is in there.
25+
self.expect("target dump typesystem", substrs=["struct DummyStruct"])
26+
27+
@no_debug_info_test
28+
def test_invalid_arg(self):
29+
""" Test an invalid invocation on 'target dump typesystem'. """
30+
self.build()
31+
self.createTestTarget()
32+
self.expect("target dump typesystem arg", error=True,
33+
substrs=["error: target dump typesystem doesn't take arguments."])
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct DummyStruct {
2+
int i;
3+
};
4+
5+
DummyStruct s;
6+
7+
int main() { return s.i; }

0 commit comments

Comments
 (0)