Author: Jonas Devlieghere
Date: 2023-06-26T10:40:08-07:00
New Revision: d49caf4afc1bc460600b316f9736e01ceeebded5

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

LOG: [lldb] Add `source cache dump` and `source cache clear` subcommand

Add two new source subcommands: source cache dump and source cache
clear. As the name implies the first one dumps the source cache while
the later clears the cache.

This patch was motivated by a handful of (internal) bug reports related
to sources not being available. Right now those issues can be hard to
diagnose. The new commands give users, as well as us as developers, more
insight into and control over the source cache.

Differential revision: https://reviews.llvm.org/D153685

Added: 
    

Modified: 
    lldb/include/lldb/Core/Debugger.h
    lldb/include/lldb/Core/SourceManager.h
    lldb/source/Commands/CommandObjectSource.cpp
    lldb/source/Commands/CommandObjectTarget.cpp
    lldb/source/Core/SourceManager.cpp
    lldb/test/API/source-manager/TestSourceManager.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/Debugger.h 
b/lldb/include/lldb/Core/Debugger.h
index 4e3c177d33e59..3996c4c58e2ba 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -76,8 +76,6 @@ class DataRecorder;
 class Debugger : public std::enable_shared_from_this<Debugger>,
                  public UserID,
                  public Properties {
-  friend class SourceManager; // For GetSourceFileCache.
-
 public:
   /// Broadcaster event bits definitions.
   enum {
@@ -515,6 +513,10 @@ class Debugger : public 
std::enable_shared_from_this<Debugger>,
   void FlushProcessOutput(Process &process, bool flush_stdout,
                           bool flush_stderr);
 
+  SourceManager::SourceFileCache &GetSourceFileCache() {
+    return m_source_file_cache;
+  }
+
 protected:
   friend class CommandInterpreter;
   friend class REPL;
@@ -599,10 +601,6 @@ class Debugger : public 
std::enable_shared_from_this<Debugger>,
   // Ensures two threads don't attempt to flush process output in parallel.
   std::mutex m_output_flush_mutex;
 
-  SourceManager::SourceFileCache &GetSourceFileCache() {
-    return m_source_file_cache;
-  }
-
   void InstanceInitialize();
 
   // these should never be NULL

diff  --git a/lldb/include/lldb/Core/SourceManager.h 
b/lldb/include/lldb/Core/SourceManager.h
index c272f7f431129..2ad6294e0f6cc 100644
--- a/lldb/include/lldb/Core/SourceManager.h
+++ b/lldb/include/lldb/Core/SourceManager.h
@@ -65,6 +65,8 @@ class SourceManager {
 
     uint32_t GetNumLines();
 
+    llvm::sys::TimePoint<> GetTimestamp() const { return m_mod_time; }
+
   protected:
     bool CalculateLineOffsets(uint32_t line = UINT32_MAX);
 
@@ -105,6 +107,8 @@ class SourceManager {
     // Removes all elements from the cache.
     void Clear() { m_file_cache.clear(); }
 
+    void Dump(Stream &stream) const;
+
   protected:
     typedef std::map<FileSpec, FileSP> FileCache;
     FileCache m_file_cache;

diff  --git a/lldb/source/Commands/CommandObjectSource.cpp 
b/lldb/source/Commands/CommandObjectSource.cpp
index bbc3142c51be6..5fdf15767def4 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -1201,6 +1201,62 @@ class CommandObjectSourceList : public 
CommandObjectParsed {
   std::string m_reverse_name;
 };
 
+class CommandObjectSourceCacheDump : public CommandObjectParsed {
+public:
+  CommandObjectSourceCacheDump(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "source cache dump",
+                            "Dump the state of the source code cache. Intended 
"
+                            "to be used for debugging LLDB itself.",
+                            nullptr) {}
+
+  ~CommandObjectSourceCacheDump() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
+    cache.Dump(result.GetOutputStream());
+    result.SetStatus(eReturnStatusSuccessFinishResult);
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectSourceCacheClear : public CommandObjectParsed {
+public:
+  CommandObjectSourceCacheClear(CommandInterpreter &interpreter)
+      : CommandObjectParsed(interpreter, "source cache clear",
+                            "Clear the source code cache.\n", nullptr) {}
+
+  ~CommandObjectSourceCacheClear() override = default;
+
+protected:
+  bool DoExecute(Args &command, CommandReturnObject &result) override {
+    SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
+    cache.Clear();
+    result.SetStatus(eReturnStatusSuccessFinishNoResult);
+    return result.Succeeded();
+  }
+};
+
+class CommandObjectSourceCache : public CommandObjectMultiword {
+public:
+  CommandObjectSourceCache(CommandInterpreter &interpreter)
+      : CommandObjectMultiword(interpreter, "source cache",
+                               "Commands for managing the source code cache.",
+                               "source cache <sub-command>") {
+    LoadSubCommand(
+        "dump", CommandObjectSP(new 
CommandObjectSourceCacheDump(interpreter)));
+    LoadSubCommand("clear", CommandObjectSP(new CommandObjectSourceCacheClear(
+                                interpreter)));
+  }
+
+  ~CommandObjectSourceCache() override = default;
+
+private:
+  CommandObjectSourceCache(const CommandObjectSourceCache &) = delete;
+  const CommandObjectSourceCache &
+  operator=(const CommandObjectSourceCache &) = delete;
+};
+
 #pragma mark CommandObjectMultiwordSource
 // CommandObjectMultiwordSource
 
@@ -1216,6 +1272,8 @@ 
CommandObjectMultiwordSource::CommandObjectMultiwordSource(
                  CommandObjectSP(new CommandObjectSourceInfo(interpreter)));
   LoadSubCommand("list",
                  CommandObjectSP(new CommandObjectSourceList(interpreter)));
+  LoadSubCommand("cache",
+                 CommandObjectSP(new CommandObjectSourceCache(interpreter)));
 }
 
 CommandObjectMultiwordSource::~CommandObjectMultiwordSource() = default;

diff  --git a/lldb/source/Commands/CommandObjectTarget.cpp 
b/lldb/source/Commands/CommandObjectTarget.cpp
index 300053bcf5ed7..81a2fe4c9f2ba 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -5105,8 +5105,8 @@ class CommandObjectTargetDumpTypesystem : public 
CommandObjectParsed {
   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.",
+            "Dump the state of the target's internal type system. Intended to "
+            "be used for debugging LLDB itself.",
             nullptr, eCommandRequiresTarget) {}
 
   ~CommandObjectTargetDumpTypesystem() override = default;

diff  --git a/lldb/source/Core/SourceManager.cpp 
b/lldb/source/Core/SourceManager.cpp
index b8460383f0f3c..1cb119fb9397b 100644
--- a/lldb/source/Core/SourceManager.cpp
+++ b/lldb/source/Core/SourceManager.cpp
@@ -727,3 +727,15 @@ SourceManager::FileSP 
SourceManager::SourceFileCache::FindSourceFile(
     file_sp = pos->second;
   return file_sp;
 }
+
+void SourceManager::SourceFileCache::Dump(Stream &stream) const {
+  stream << "Modification time   Lines    Path\n";
+  stream << "------------------- -------- --------------------------------\n";
+  for (auto &entry : m_file_cache) {
+    if (!entry.second)
+      continue;
+    FileSP file = entry.second;
+    stream.Format("{0:%Y-%m-%d %H:%M:%S} {1,8:d} {2}\n", file->GetTimestamp(),
+                  file->GetNumLines(), entry.first.GetPath());
+  }
+}

diff  --git a/lldb/test/API/source-manager/TestSourceManager.py 
b/lldb/test/API/source-manager/TestSourceManager.py
index 7675d1f1018fe..bcad327dce8a6 100644
--- a/lldb/test/API/source-manager/TestSourceManager.py
+++ b/lldb/test/API/source-manager/TestSourceManager.py
@@ -317,3 +317,24 @@ def test_artificial_source_location(self):
                 "that has no source code associated " "with it.",
             ],
         )
+
+    def test_source_cache_dump_and_clear(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+        lldbutil.run_break_set_by_file_and_line(
+            self, self.file, self.line, num_expected_locations=1, 
loc_exact=True
+        )
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # Make sure the main source file is in the source cache.
+        self.expect(
+            "source cache dump",
+            substrs=["Modification time", "Lines", "Path", " 7", self.file],
+        )
+
+        # Clear the cache.
+        self.expect("source cache clear")
+
+        # Make sure the main source file is no longer in the source cache.
+        self.expect("source cache dump", matching=False, substrs=[self.file])


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to