JDevlieghere updated this revision to Diff 188244.
JDevlieghere marked 4 inline comments as done.
JDevlieghere added a comment.

Add comments


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58564/new/

https://reviews.llvm.org/D58564

Files:
  lldb/include/lldb/Interpreter/CommandInterpreter.h
  lldb/source/Commands/CommandObjectReproducer.cpp
  lldb/source/Interpreter/CommandInterpreter.cpp

Index: lldb/source/Interpreter/CommandInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/CommandInterpreter.cpp
+++ lldb/source/Interpreter/CommandInterpreter.cpp
@@ -45,6 +45,7 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Utility/Log.h"
+#include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
@@ -74,6 +75,7 @@
 
 using namespace lldb;
 using namespace lldb_private;
+using namespace llvm;
 
 static const char *k_white_space = " \t\v";
 
@@ -116,6 +118,51 @@
   eEchoCommentCommands = 5
 };
 
+/// Provider for the command interpreter. Every command is logged to file which
+/// is used as input during replay. The latter takes place at the SB API layer
+/// by changing the input file handle.
+class lldb_private::CommandProvider
+    : public repro::Provider<lldb_private::CommandProvider> {
+public:
+  typedef CommandProviderInfo info;
+
+  CommandProvider(const FileSpec &directory) : Provider(directory) {}
+
+  /// Capture a single command.
+  void CaptureCommand(std::string command) {
+    m_commands.push_back(std::move(command));
+  }
+
+  /// Commands are kept in memory and written to a file when the reproducer
+  /// needs to be kept.
+  void Keep() override {
+    FileSpec file =
+        GetRoot().CopyByAppendingPathComponent(CommandProviderInfo::file);
+
+    std::error_code ec;
+    llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::F_Text);
+
+    if (ec)
+      return;
+
+    for (auto &command : m_commands)
+      os << command << '\n';
+  }
+
+  /// Commands are kept in memory and are cleared when the reproducer is
+  /// discarded.
+  void Discard() override { m_commands.clear(); }
+
+  static char ID;
+
+private:
+  std::vector<std::string> m_commands;
+};
+
+char CommandProvider::ID = 0;
+const char *CommandProviderInfo::name = "command-interpreter";
+const char *CommandProviderInfo::file = "command-interpreter.txt";
+
 ConstString &CommandInterpreter::GetStaticBroadcasterClass() {
   static ConstString class_name("lldb.commandInterpreter");
   return class_name;
@@ -141,6 +188,9 @@
   SetEventName(eBroadcastBitQuitCommandReceived, "quit");
   CheckInWithManager();
   m_collection_sp->Initialize(g_properties);
+
+  if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator())
+    m_provider = &g->GetOrCreate<CommandProvider>();
 }
 
 bool CommandInterpreter::GetExpandRegexAliases() const {
@@ -1694,6 +1744,9 @@
 
   Status error(PreprocessCommand(command_string));
 
+  if (m_provider)
+    m_provider->CaptureCommand(original_command_string);
+
   if (error.Fail()) {
     result.AppendError(error.AsCString());
     result.SetStatus(eReturnStatusFailed);
Index: lldb/source/Commands/CommandObjectReproducer.cpp
===================================================================
--- lldb/source/Commands/CommandObjectReproducer.cpp
+++ lldb/source/Commands/CommandObjectReproducer.cpp
@@ -37,8 +37,13 @@
     auto &r = repro::Reproducer::Instance();
     if (auto generator = r.GetGenerator()) {
       generator->Keep();
+    } else if (r.GetLoader()) {
+      // Make this operation a NOP in replay mode.
+      result.SetStatus(eReturnStatusSuccessFinishNoResult);
+      return result.Succeeded();
     } else {
       result.AppendErrorWithFormat("Unable to get the reproducer generator");
+      result.SetStatus(eReturnStatusFailed);
       return false;
     }
 
Index: lldb/include/lldb/Interpreter/CommandInterpreter.h
===================================================================
--- lldb/include/lldb/Interpreter/CommandInterpreter.h
+++ lldb/include/lldb/Interpreter/CommandInterpreter.h
@@ -27,6 +27,14 @@
 
 namespace lldb_private {
 
+/// Reproducer provider for the command interpreter. The info struct needs to
+/// be public because replay takes place at the SB API layer.
+class CommandProvider;
+struct CommandProviderInfo {
+  static const char *name;
+  static const char *file;
+};
+
 class CommandInterpreterRunOptions {
 public:
   //------------------------------------------------------------------
@@ -606,6 +614,9 @@
   bool m_quit_requested;
   bool m_stopped_for_crash;
 
+  /// Reproducer provider.
+  CommandProvider *m_provider = nullptr;
+
   // The exit code the user has requested when calling the 'quit' command.
   // No value means the user hasn't set a custom exit code so far.
   llvm::Optional<int> m_quit_exit_code;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to