[clang] b5ccfeb - [lldb] Add image dump pcm-info command

Dave Lee via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 13 16:57:13 PDT 2022


Author: Dave Lee
Date: 2022-07-13T16:56:53-07:00
New Revision: b5ccfeb6bfbbc5436b91a1e317f88e2c499c9306

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

LOG: [lldb] Add image dump pcm-info command

Add `pcm-info` to the `target module dump` subcommands.

This dump command shows information about clang .pcm files. This command
effectively runs `clang -module-file-info` and produces identical output.

The .pcm file format is tightly coupled to the clang version. The clang
embedded in lldb is not guaranteed to match the version of the clang executable
available on the local system.

There have been times when I've needed to view the details about a .pcm file
produced by lldb's embedded clang, but because the clang executable was a
slightly different version, the `-module-file-info` invocation failed. With
this command, users can inspect .pcm files generated by lldb too.

Differential Revision: https://reviews.llvm.org/D129456

Added: 
    lldb/test/API/commands/target/dump-pcm-info/Makefile
    lldb/test/API/commands/target/dump-pcm-info/TestDumpPCMInfo.py
    lldb/test/API/commands/target/dump-pcm-info/main.m

Modified: 
    clang/include/clang/Frontend/FrontendActions.h
    clang/lib/Frontend/FrontendActions.cpp
    lldb/source/Commands/CommandObjectTarget.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h
index ae829d741152a..fe399850bd447 100644
--- a/clang/include/clang/Frontend/FrontendActions.h
+++ b/clang/include/clang/Frontend/FrontendActions.h
@@ -190,6 +190,10 @@ class SyntaxOnlyAction : public ASTFrontendAction {
 /// Dump information about the given module file, to be used for
 /// basic debugging and discovery.
 class DumpModuleInfoAction : public ASTFrontendAction {
+public:
+  // Allow other tools (ex lldb) to direct output for their use.
+  llvm::raw_ostream *OutputStream = nullptr;
+
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override;

diff  --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index f61c83a2a465e..f833541caa25c 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -854,8 +854,9 @@ void DumpModuleInfoAction::ExecuteAction() {
     std::error_code EC;
     OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
                                            llvm::sys::fs::OF_TextWithCRLF));
+    OutputStream = OutFile.get();
   }
-  llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
+  llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
 
   Out << "Information for module file '" << getCurrentFile() << "':\n";
   auto &FileMgr = getCompilerInstance().getFileManager();

diff  --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 2b71f1bc7bc86..51978878c8b9d 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -47,12 +47,18 @@
 #include "lldb/Target/Thread.h"
 #include "lldb/Target/ThreadSpec.h"
 #include "lldb/Utility/Args.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
 #include "lldb/Utility/LLDBLog.h"
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Timer.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-private-enumerations.h"
 
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatAdapters.h"
@@ -2155,6 +2161,59 @@ class CommandObjectTargetModulesDumpSections
   }
 };
 
+class CommandObjectTargetModulesDumpClangPCMInfo : public CommandObjectParsed {
+public:
+  CommandObjectTargetModulesDumpClangPCMInfo(CommandInterpreter &interpreter)
+      : CommandObjectParsed(
+            interpreter, "target modules dump pcm-info",
+            "Dump information about the given clang module (pcm).") {
+    // Take a single file argument.
+    CommandArgumentData arg{eArgTypeFilename, eArgRepeatPlain};
+    m_arguments.push_back({arg});
+  }
+
+  ~CommandObjectTargetModulesDumpClangPCMInfo() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    if (command.GetArgumentCount() != 1) {
+      result.AppendErrorWithFormat("'%s' takes exactly one pcm path argument.",
+                                   m_cmd_name.c_str());
+      return false;
+    }
+
+    const char *pcm_path = command.GetArgumentAtIndex(0);
+    FileSpec pcm_file{pcm_path};
+
+    if (pcm_file.GetFileNameExtension().GetStringRef() != ".pcm") {
+      result.AppendError("file must have a .pcm extension");
+      return false;
+    }
+
+    if (!FileSystem::Instance().Exists(pcm_file)) {
+      result.AppendError("pcm file does not exist");
+      return false;
+    }
+
+    clang::CompilerInstance compiler;
+    compiler.createDiagnostics();
+
+    const char *clang_args[] = {"clang", pcm_path};
+    compiler.setInvocation(clang::createInvocation(clang_args));
+
+    clang::DumpModuleInfoAction dump_module_info;
+    dump_module_info.OutputStream = &result.GetOutputStream().AsRawOstream();
+    // DumpModuleInfoAction requires ObjectFilePCHContainerReader.
+    compiler.getPCHContainerOperations()->registerReader(
+        std::make_unique<clang::ObjectFilePCHContainerReader>());
+
+    if (compiler.ExecuteAction(dump_module_info))
+      result.SetStatus(eReturnStatusSuccessFinishResult);
+
+    return result.Succeeded();
+  }
+};
+
 #pragma mark CommandObjectTargetModulesDumpClangAST
 
 // Clang AST dumping command
@@ -2406,10 +2465,10 @@ class CommandObjectTargetModulesDump : public CommandObjectMultiword {
   CommandObjectTargetModulesDump(CommandInterpreter &interpreter)
       : CommandObjectMultiword(
             interpreter, "target modules dump",
-            "Commands for dumping information about one or "
-            "more target modules.",
+            "Commands for dumping information about one or more target "
+            "modules.",
             "target modules dump "
-            "[headers|symtab|sections|ast|symfile|line-table] "
+            "[objfile|symtab|sections|ast|symfile|line-table|pcm-info] "
             "[<file1> <file2> ...]") {
     LoadSubCommand("objfile",
                    CommandObjectSP(
@@ -2429,6 +2488,10 @@ class CommandObjectTargetModulesDump : public CommandObjectMultiword {
     LoadSubCommand("line-table",
                    CommandObjectSP(new CommandObjectTargetModulesDumpLineTable(
                        interpreter)));
+    LoadSubCommand(
+        "pcm-info",
+        CommandObjectSP(
+            new CommandObjectTargetModulesDumpClangPCMInfo(interpreter)));
   }
 
   ~CommandObjectTargetModulesDump() override = default;

diff  --git a/lldb/test/API/commands/target/dump-pcm-info/Makefile b/lldb/test/API/commands/target/dump-pcm-info/Makefile
new file mode 100644
index 0000000000000..2d19fa74b8cf2
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-pcm-info/Makefile
@@ -0,0 +1,4 @@
+OBJC_SOURCES := main.m
+USE_PRIVATE_MODULE_CACHE = YES
+include Makefile.rules
+

diff  --git a/lldb/test/API/commands/target/dump-pcm-info/TestDumpPCMInfo.py b/lldb/test/API/commands/target/dump-pcm-info/TestDumpPCMInfo.py
new file mode 100644
index 0000000000000..a3c9dda7bb160
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-pcm-info/TestDumpPCMInfo.py
@@ -0,0 +1,40 @@
+"""
+Test 'target modules dump pcm-info'.
+"""
+
+import os
+import shutil
+import glob
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+    @no_debug_info_test
+    @skipUnlessDarwin
+    def test(self):
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(
+            self, "return", lldb.SBFileSpec("main.m"))
+
+        mod_cache = self.getBuildArtifact("private-module-cache")
+        if os.path.isdir(mod_cache):
+            shutil.rmtree(mod_cache)
+
+        self.runCmd(f"settings set symbols.clang-modules-cache-path '{mod_cache}'")
+
+        # Cause lldb to generate a Darwin-*.pcm
+        self.runCmd("p @import Darwin")
+
+        # root/<config-hash>/<module-name>-<modulemap-path-hash>.pcm
+        pcm_paths = glob.glob(os.path.join(mod_cache, '*', 'Darwin-*.pcm'))
+        self.assertEqual(len(pcm_paths), 1, "Expected one Darwin pcm")
+        pcm_path = pcm_paths[0]
+
+        self.expect(
+            f"target modules dump pcm-info '{pcm_path}'",
+            startstr=f"Information for module file '{pcm_path}'",
+            substrs=["Module name: Darwin"])

diff  --git a/lldb/test/API/commands/target/dump-pcm-info/main.m b/lldb/test/API/commands/target/dump-pcm-info/main.m
new file mode 100644
index 0000000000000..76e8197013aab
--- /dev/null
+++ b/lldb/test/API/commands/target/dump-pcm-info/main.m
@@ -0,0 +1 @@
+int main() { return 0; }


        


More information about the cfe-commits mailing list