[Lldb-commits] [lldb] 9a57d1e - [lldb] Allow dumping the state of all scratch TypeSystems

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 19 03:05:34 PDT 2021


Author: Raphael Isemann
Date: 2021-10-19T12:05:14+02:00
New Revision: 9a57d1e52680ac05c29d6d0d2cfbaf3b05a5cbce

URL: https://github.com/llvm/llvm-project/commit/9a57d1e52680ac05c29d6d0d2cfbaf3b05a5cbce
DIFF: https://github.com/llvm/llvm-project/commit/9a57d1e52680ac05c29d6d0d2cfbaf3b05a5cbce.diff

LOG: [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

Added: 
    lldb/test/API/commands/target/dump/Makefile
    lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
    lldb/test/API/commands/target/dump/main.cpp

Modified: 
    lldb/include/lldb/Symbol/TypeSystem.h
    lldb/source/Commands/CommandObjectTarget.cpp
    lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
    lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
    lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
    lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h
index a37c1040b16e7..e695f65807671 100644
--- a/lldb/include/lldb/Symbol/TypeSystem.h
+++ b/lldb/include/lldb/Symbol/TypeSystem.h
@@ -392,6 +392,12 @@ class TypeSystem : public PluginInterface {
       lldb::opaque_compiler_type_t type, Stream *s,
       lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) = 0;
 
+  /// Dump a textual representation of the internal TypeSystem state to the
+  /// given stream.
+  ///
+  /// This should not modify the state of the TypeSystem if possible.
+  virtual void Dump(llvm::raw_ostream &output) = 0;
+
   // TODO: These methods appear unused. Should they be removed?
 
   virtual bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) = 0;

diff  --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 3112216f8a352..e0a88a710fb97 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -4990,6 +4990,55 @@ class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword {
   ~CommandObjectMultiwordTargetStopHooks() override = default;
 };
 
+#pragma mark CommandObjectTargetDumpTypesystem
+
+/// Dumps the TypeSystem of the selected Target.
+class CommandObjectTargetDumpTypesystem : public CommandObjectParsed {
+public:
+  CommandObjectTargetDumpTypesystem(CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "target dump typesystem",
+            "Dump the state of the target's internal type system.\n"
+            "Intended to be used for debugging LLDB itself.",
+            nullptr, eCommandRequiresTarget) {}
+
+  ~CommandObjectTargetDumpTypesystem() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    if (!command.empty()) {
+      result.AppendError("target dump typesystem doesn't take arguments.");
+      return result.Succeeded();
+    }
+
+    // Go over every scratch TypeSystem and dump to the command output.
+    for (TypeSystem *ts : GetSelectedTarget().GetScratchTypeSystems())
+      ts->Dump(result.GetOutputStream().AsRawOstream());
+
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+};
+
+#pragma mark CommandObjectTargetDump
+
+/// Multi-word command for 'target dump'.
+class CommandObjectTargetDump : public CommandObjectMultiword {
+public:
+  // Constructors and Destructors
+  CommandObjectTargetDump(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(
+            interpreter, "target dump",
+            "Commands for dumping information about the target.",
+            "target dump [typesystem]") {
+    LoadSubCommand(
+        "typesystem",
+        CommandObjectSP(new CommandObjectTargetDumpTypesystem(interpreter)));
+  }
+
+  ~CommandObjectTargetDump() override = default;
+};
+
 #pragma mark CommandObjectMultiwordTarget
 
 // CommandObjectMultiwordTarget
@@ -5003,6 +5052,8 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget(
                  CommandObjectSP(new CommandObjectTargetCreate(interpreter)));
   LoadSubCommand("delete",
                  CommandObjectSP(new CommandObjectTargetDelete(interpreter)));
+  LoadSubCommand("dump",
+                 CommandObjectSP(new CommandObjectTargetDump(interpreter)));
   LoadSubCommand("list",
                  CommandObjectSP(new CommandObjectTargetList(interpreter)));
   LoadSubCommand("select",

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 81c730539604e..c396e591ddc45 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3846,7 +3846,7 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) {
       llvm::dyn_cast_or_null<TypeSystemClang>(&ts_or_err.get());
   if (!clang)
     return;
-  clang->Dump(s);
+  clang->Dump(s.AsRawOstream());
 }
 
 SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {

diff  --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 43cf262016c2f..8856c7e72e08a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -1358,4 +1358,6 @@ PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
   return static_cast<clang::DeclContext *>(context.GetOpaqueDeclContext());
 }
 
-void PdbAstBuilder::Dump(Stream &stream) { m_clang.Dump(stream); }
+void PdbAstBuilder::Dump(Stream &stream) {
+  m_clang.Dump(stream.AsRawOstream());
+}

diff  --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 9c98ce76ba40e..f6e34285138ce 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1461,7 +1461,7 @@ void SymbolFilePDB::DumpClangAST(Stream &s) {
       llvm::dyn_cast_or_null<TypeSystemClang>(&type_system_or_err.get());
   if (!clang_type_system)
     return;
-  clang_type_system->Dump(s);
+  clang_type_system->Dump(s.AsRawOstream());
 }
 
 void SymbolFilePDB::FindTypesByRegex(

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 6db0f5a5d2af5..00daaad41a6e1 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -8358,9 +8358,8 @@ TypeSystemClang::dump(lldb::opaque_compiler_type_t type) const {
 }
 #endif
 
-void TypeSystemClang::Dump(Stream &s) {
-  Decl *tu = Decl::castFromDeclContext(GetTranslationUnitDecl());
-  tu->dump(s.AsRawOstream());
+void TypeSystemClang::Dump(llvm::raw_ostream &output) {
+  GetTranslationUnitDecl()->dump(output);
 }
 
 void TypeSystemClang::DumpFromSymbolFile(Stream &s,
@@ -9746,6 +9745,41 @@ ScratchTypeSystemClang::GetForTarget(Target &target,
   return &scratch_ast.GetIsolatedAST(*ast_kind);
 }
 
+/// Returns a human-readable name that uniquely identifiers the sub-AST kind.
+static llvm::StringRef
+GetNameForIsolatedASTKind(ScratchTypeSystemClang::IsolatedASTKind kind) {
+  switch (kind) {
+  case ScratchTypeSystemClang::IsolatedASTKind::CppModules:
+    return "C++ modules";
+  }
+  llvm_unreachable("Unimplemented IsolatedASTKind?");
+}
+
+void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output) {
+  // First dump the main scratch AST.
+  output << "State of scratch Clang type system:\n";
+  TypeSystemClang::Dump(output);
+
+  // Now sort the isolated sub-ASTs.
+  typedef std::pair<IsolatedASTKey, TypeSystem *> KeyAndTS;
+  std::vector<KeyAndTS> sorted_typesystems;
+  for (const auto &a : m_isolated_asts)
+    sorted_typesystems.emplace_back(a.first, a.second.get());
+  llvm::stable_sort(sorted_typesystems,
+                    [](const KeyAndTS &lhs, const KeyAndTS &rhs) {
+                      return lhs.first < rhs.first;
+                    });
+
+  // Dump each sub-AST too.
+  for (const auto &a : sorted_typesystems) {
+    IsolatedASTKind kind =
+        static_cast<ScratchTypeSystemClang::IsolatedASTKind>(a.first);
+    output << "State of scratch Clang type subsystem "
+           << GetNameForIsolatedASTKind(kind) << ":\n";
+    a.second->Dump(output);
+  }
+}
+
 UserExpression *ScratchTypeSystemClang::GetUserExpression(
     llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
     Expression::ResultType desired_type,

diff  --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 1c57440fda29c..93300439806d4 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -938,7 +938,8 @@ class TypeSystemClang : public TypeSystem {
   LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override;
 #endif
 
-  void Dump(Stream &s);
+  /// \see lldb_private::TypeSystem::Dump
+  void Dump(llvm::raw_ostream &output) override;
 
   /// Dump clang AST types from the symbol file.
   ///
@@ -1162,6 +1163,9 @@ class ScratchTypeSystemClang : public TypeSystemClang {
     return GetForTarget(target, InferIsolatedASTKindFromLangOpts(lang_opts));
   }
 
+  /// \see lldb_private::TypeSystem::Dump
+  void Dump(llvm::raw_ostream &output) override;
+
   UserExpression *
   GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
                     lldb::LanguageType language,

diff  --git a/lldb/test/API/commands/target/dump/Makefile b/lldb/test/API/commands/target/dump/Makefile
new file mode 100644
index 0000000000000..99998b20bcb05
--- /dev/null
+++ b/lldb/test/API/commands/target/dump/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git a/lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py b/lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
new file mode 100644
index 0000000000000..c9a20b8aa1e41
--- /dev/null
+++ b/lldb/test/API/commands/target/dump/TestTargetDumpTypeSystem.py
@@ -0,0 +1,33 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test_dumping(self):
+        """ Tests dumping an empty and non-empty scratch AST. """
+        self.build()
+        self.createTestTarget()
+
+        # Make sure DummyStruct is not in the scratch AST by default.
+        self.expect("target dump typesystem", matching=False, substrs=["struct DummyStruct"])
+
+        # Move DummyStruct into the scratch AST via the expression evaluator.
+        # FIXME: Once there is an SB API for using variable paths on globals
+        # then this should be done this way.
+        self.expect_expr("s", result_type="DummyStruct")
+
+        # Dump the scratch AST and make sure DummyStruct is in there.
+        self.expect("target dump typesystem", substrs=["struct DummyStruct"])
+
+    @no_debug_info_test
+    def test_invalid_arg(self):
+        """ Test an invalid invocation on 'target dump typesystem'. """
+        self.build()
+        self.createTestTarget()
+        self.expect("target dump typesystem arg", error=True,
+                    substrs=["error: target dump typesystem doesn't take arguments."])

diff  --git a/lldb/test/API/commands/target/dump/main.cpp b/lldb/test/API/commands/target/dump/main.cpp
new file mode 100644
index 0000000000000..4db770ece5335
--- /dev/null
+++ b/lldb/test/API/commands/target/dump/main.cpp
@@ -0,0 +1,7 @@
+struct DummyStruct {
+  int i;
+};
+
+DummyStruct s;
+
+int main() { return s.i; }


        


More information about the lldb-commits mailing list