zturner created this revision.
zturner added reviewers: vsk, davide, labath, jingham, aleksandr.urakov, 
clayborg.
Herald added subscribers: JDevlieghere, aprantl.

This can be useful when diagnosing AST related problems.  For example, I had a 
bug where I was accidentally creating a record type multiple times instead of 
re-using the first one.  This is easy to see with a dump of the AST, because it 
will look like this:

  TranslationUnitDecl 0x18a2bc53b98 <<invalid sloc>> <invalid sloc>
  |-CXXRecordDecl 0x18a2bc54458 <<invalid sloc>> <invalid sloc> class 
ClassWithPadding
  |-CXXRecordDecl 0x18a2bc54520 <<invalid sloc>> <invalid sloc> class 
ClassWithPadding
  |-CXXRecordDecl 0x18a2bc545e0 <<invalid sloc>> <invalid sloc> class 
ClassWithPadding definition
  | |-DefinitionData pass_in_registers standard_layout trivially_copyable 
trivial literal
  | | |-DefaultConstructor exists trivial needs_implicit
  | | |-CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
  | | |-MoveConstructor exists simple trivial needs_implicit
  | | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
  | | |-MoveAssignment exists simple trivial needs_implicit
  | | `-Destructor simple irrelevant trivial needs_implicit
  | |-MSInheritanceAttr 0x18a2bc546a0 <<invalid sloc>> Implicit 
__single_inheritance
  | |-FieldDecl 0x18a2bc54748 <<invalid sloc>> <invalid sloc> a 'char'
  | |-FieldDecl 0x18a2bc54798 <<invalid sloc>> <invalid sloc> b 'short'
  | |-FieldDecl 0x18a2bc54828 <<invalid sloc>> <invalid sloc> c 'char [2]'
  | |-FieldDecl 0x18a2bc54878 <<invalid sloc>> <invalid sloc> d 'int'
  | |-FieldDecl 0x18a2bc548c8 <<invalid sloc>> <invalid sloc> e 'char'
  | |-FieldDecl 0x18a2bc54918 <<invalid sloc>> <invalid sloc> f 'int'
  | |-FieldDecl 0x18a2bc54968 <<invalid sloc>> <invalid sloc> g 'long long'
  | |-FieldDecl 0x18a2bc549f8 <<invalid sloc>> <invalid sloc> h 'char [3]'
  | |-FieldDecl 0x18a2bc54a48 <<invalid sloc>> <invalid sloc> i 'long long'
  | |-FieldDecl 0x18a2bc54a98 <<invalid sloc>> <invalid sloc> j 'char [2]'
  | |-FieldDecl 0x18a2bc54ae8 <<invalid sloc>> <invalid sloc> k 'long long'
  | |-FieldDecl 0x18a2bc54b38 <<invalid sloc>> <invalid sloc> l 'char'
  | `-FieldDecl 0x18a2bd96f00 <<invalid sloc>> <invalid sloc> m 'long long'
  `-<undeserialized declarations>

Note there are 3 `CXXRecordDecl`s with the same name, but only one definition.  
Given the complex interactions between debug info and AST reconstruction, a 
command like this makes problems within the AST very obvious.  I found several 
other AST-related problems, so this was not even the only one, so I think this 
is a largely unexplored front when it comes to areas for potentially improved 
test coverage.  And since it's in the REPL, it makes it very easy to test out 
commands in different orders, get a dump, do something else, get another dump, 
etc to see how the order of commands affects things.


https://reviews.llvm.org/D54072

Files:
  lldb/include/lldb/Symbol/SymbolFile.h
  lldb/source/Commands/CommandObjectTarget.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
  lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h

Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -169,6 +169,8 @@
 
   const llvm::pdb::IPDBSession &GetPDBSession() const;
 
+  void DumpClangAST() override;
+
 private:
   struct SecContribInfo {
     uint32_t Offset;
Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1356,6 +1356,14 @@
   return types.GetSize();
 }
 
+void SymbolFilePDB::DumpClangAST() {
+  auto type_system = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+  auto clang_type_system = llvm::dyn_cast_or_null<ClangASTContext>(type_system);
+  if (!clang_type_system)
+    return;
+  clang_type_system->getASTContext()->getTranslationUnitDecl()->dumpColor();
+}
+
 void SymbolFilePDB::FindTypesByRegex(
     const lldb_private::RegularExpression &regex, uint32_t max_matches,
     lldb_private::TypeMap &types) {
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -155,6 +155,8 @@
   ClangASTContext &GetASTContext() { return *m_clang; }
   ClangASTImporter &GetASTImporter() { return *m_importer; }
 
+  void DumpClangAST() override;
+
 private:
   size_t FindTypesByName(llvm::StringRef name, uint32_t max_matches,
                          TypeMap &types);
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1391,6 +1391,12 @@
   return 0;
 }
 
+void SymbolFileNativePDB::DumpClangAST() {
+  if (!m_clang)
+    return;
+  m_clang->getASTContext()->getTranslationUnitDecl()->dumpColor();
+}
+
 uint32_t SymbolFileNativePDB::FindGlobalVariables(
     const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
     uint32_t max_matches, VariableList &variables) {
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -126,6 +126,8 @@
   std::vector<lldb_private::CallEdge>
   ParseCallEdgesInFunction(lldb_private::UserID func_id) override;
 
+  void DumpClangAST() override;
+
   //------------------------------------------------------------------
   // PluginInterface protocol
   //------------------------------------------------------------------
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1227,6 +1227,13 @@
   return matching_namespace;
 }
 
+void SymbolFileDWARFDebugMap::DumpClangAST() {
+  ForEachSymbolFile([](SymbolFileDWARF *oso_dwarf) -> bool {
+    oso_dwarf->DumpClangAST();
+    return true;
+  });
+}
+
 //------------------------------------------------------------------
 // PluginInterface protocol
 //------------------------------------------------------------------
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -329,6 +329,8 @@
 
   void Dump(lldb_private::Stream &s) override;
 
+  void DumpClangAST() override;
+
 protected:
   typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *>
       DIEToTypePtr;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3854,6 +3854,14 @@
 
 void SymbolFileDWARF::Dump(lldb_private::Stream &s) { m_index->Dump(s); }
 
+void SymbolFileDWARF::DumpClangAST() {
+  TypeSystem *ts = GetTypeSystemForLanguage(eLanguageTypeC_plus_plus);
+  ClangASTContext *clang = llvm::dyn_cast_or_null<ClangASTContext>(ts);
+  if (!clang)
+    return;
+  clang->getASTContext()->getTranslationUnitDecl()->dumpColor();
+}
+
 SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {
   if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) {
     lldb::ModuleSP module_sp(m_debug_map_module_wp.lock());
Index: lldb/source/Commands/CommandObjectTarget.cpp
===================================================================
--- lldb/source/Commands/CommandObjectTarget.cpp
+++ lldb/source/Commands/CommandObjectTarget.cpp
@@ -2227,6 +2227,85 @@
   }
 };
 
+#pragma mark CommandObjectTargetModulesDumpSections
+
+//----------------------------------------------------------------------
+// Clang AST dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpClangAST
+  : public CommandObjectTargetModulesModuleAutoComplete {
+public:
+  CommandObjectTargetModulesDumpClangAST(CommandInterpreter &interpreter)
+    : CommandObjectTargetModulesModuleAutoComplete(
+      interpreter, "target modules dump ast",
+      "Dump the clang ast for a given module's symbol file.",
+      //"target modules dump ast [<file1> ...]")
+      nullptr) {}
+
+  ~CommandObjectTargetModulesDumpClangAST() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+    if (target == nullptr) {
+      result.AppendError("invalid target, create a debug target using the "
+        "'target create' command");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    const size_t num_modules = target->GetImages().GetSize();
+    if (num_modules == 0) {
+      result.AppendError("the target has no associated executable images");
+      result.SetStatus(eReturnStatusFailed);
+      return false;
+    }
+
+    if (command.GetArgumentCount() == 0) {
+      // Dump all ASTs for all modules images
+      result.GetOutputStream().Printf("Dumping clang ast for %" PRIu64
+        " modules.\n",
+        (uint64_t)num_modules);
+      for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) {
+        if (m_interpreter.WasInterrupted())
+          break;
+        Module *m = target->GetImages().GetModulePointerAtIndex(image_idx);
+        SymbolFile *sf = m->GetSymbolVendor()->GetSymbolFile();
+        sf->DumpClangAST();
+      }
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+      return true;
+    }
+
+    // Dump specified ASTs (by basename or fullpath)
+    for (const Args::ArgEntry &arg : command.entries()) {
+      ModuleList module_list;
+      const size_t num_matches =
+        FindModulesByName(target, arg.c_str(), module_list, true);
+      if (num_matches == 0) {
+        // Check the global list
+        std::lock_guard<std::recursive_mutex> guard(
+          Module::GetAllocationModuleCollectionMutex());
+
+        result.AppendWarningWithFormat(
+          "Unable to find an image that matches '%s'.\n", arg.c_str());
+        continue;
+      }
+
+      for (size_t i = 0; i < num_matches; ++i) {
+        if (m_interpreter.WasInterrupted())
+          break;
+        Module *m = module_list.GetModulePointerAtIndex(i);
+        SymbolFile *sf = m->GetSymbolVendor()->GetSymbolFile();
+        sf->DumpClangAST();
+      }
+    }
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return true;
+  }
+};
+
 #pragma mark CommandObjectTargetModulesDumpSymfile
 
 //----------------------------------------------------------------------
@@ -2406,7 +2485,7 @@
                                "Commands for dumping information about one or "
                                "more target modules.",
                                "target modules dump "
-                               "[headers|symtab|sections|symfile|line-table] "
+                               "[headers|symtab|sections|ast|symfile|line-table] "
                                "[<file1> <file2> ...]") {
     LoadSubCommand("objfile",
                    CommandObjectSP(
@@ -2420,6 +2499,9 @@
     LoadSubCommand("symfile",
                    CommandObjectSP(
                        new CommandObjectTargetModulesDumpSymfile(interpreter)));
+    LoadSubCommand("ast",
+      CommandObjectSP(new CommandObjectTargetModulesDumpClangAST(
+        interpreter)));
     LoadSubCommand("line-table",
                    CommandObjectSP(new CommandObjectTargetModulesDumpLineTable(
                        interpreter)));
Index: lldb/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -161,6 +161,8 @@
                                         uint32_t line, bool check_inlines,
                                         lldb::SymbolContextItem resolve_scope,
                                         SymbolContextList &sc_list);
+
+  virtual void DumpClangAST() {}
   virtual uint32_t
   FindGlobalVariables(const ConstString &name,
                       const CompilerDeclContext *parent_decl_ctx,
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to